From 05ec4964fed88cea504862c74b6fc962c43c0bdf Mon Sep 17 00:00:00 2001 From: kwingram25 Date: Tue, 8 Oct 2019 16:31:48 +0200 Subject: [PATCH] Generate types from new contract ABI JSON (#1320) * generate types from registry * cleanup * merge, rearrange * lint * built out * abi v2 creation * throw on unions * linting * version handling * split functions * cleanup * drop v1 support * special types * changes * requested changes * formatTYpe * rv outdated test * rv union test * codeclimate * codeclimate * codeclimate * codeclimate * codeclimate * review * cleanup encodeTypes * fix option sub * TypeDefInfo.Result --- packages/api-contract/src/Abi.spec.ts | 97 - packages/api-contract/src/Abi.ts | 34 +- packages/api-contract/src/ContractRegistry.ts | 175 ++ .../api-contract/src/MetaRegistry.spec.ts | 33 + packages/api-contract/src/MetaRegistry.ts | 385 +++ packages/api-contract/src/RxBase.ts | 4 +- packages/api-contract/src/RxBlueprint.ts | 10 +- packages/api-contract/src/RxCode.ts | 4 +- packages/api-contract/src/RxContract.ts | 6 +- packages/api-contract/src/erc20.test.json | 2362 ++++++++++++++++ packages/api-contract/src/flipper.test.json | 184 ++ packages/api-contract/src/method.ts | 57 +- .../api-contract/src/shared-vec.test.json | 2385 +++++++++++++++++ packages/api-contract/src/types.ts | 149 +- packages/api-contract/src/v2.test.json | 1414 ++++++++++ packages/api-contract/src/validation.ts | 50 - .../api-contract/test/contracts/Erc20.json | 1008 ++++++- .../test/contracts/FlipperV2.json | 201 ++ .../test/contracts/SharedVecV2.json | 935 +++++++ packages/api-contract/test/contracts/V2.json | 697 +++++ .../api/test/e2e/api/promise-contract.spec.ts | 2 +- .../test/e2e/rpc-core/child-storage.spec.ts | 2 +- .../types/src/codec/create/getTypeClass.ts | 2 +- packages/types/src/codec/create/getTypeDef.ts | 19 +- packages/types/src/codec/create/types.ts | 113 +- packages/types/src/codec/index.ts | 1 + packages/types/src/codec/utils/encodeTypes.ts | 171 ++ packages/types/src/codec/utils/index.ts | 1 + packages/types/src/index.ts | 1 + .../types/src/scripts/generateTypes/tsDef.ts | 2 +- packages/types/src/scripts/util/formatting.ts | 20 +- 31 files changed, 10253 insertions(+), 271 deletions(-) create mode 100644 packages/api-contract/src/ContractRegistry.ts create mode 100644 packages/api-contract/src/MetaRegistry.spec.ts create mode 100644 packages/api-contract/src/MetaRegistry.ts create mode 100644 packages/api-contract/src/erc20.test.json create mode 100644 packages/api-contract/src/flipper.test.json create mode 100644 packages/api-contract/src/shared-vec.test.json create mode 100644 packages/api-contract/src/v2.test.json delete mode 100644 packages/api-contract/src/validation.ts create mode 100644 packages/api-contract/test/contracts/FlipperV2.json create mode 100644 packages/api-contract/test/contracts/SharedVecV2.json create mode 100644 packages/api-contract/test/contracts/V2.json create mode 100644 packages/types/src/codec/utils/encodeTypes.ts diff --git a/packages/api-contract/src/Abi.spec.ts b/packages/api-contract/src/Abi.spec.ts index 07bc732c9e..212ff06e1d 100644 --- a/packages/api-contract/src/Abi.spec.ts +++ b/packages/api-contract/src/Abi.spec.ts @@ -2,108 +2,11 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { ContractABIArg } from './types'; - -import typesAbi from '../test/abi/types.json'; import erc20Abi from '../test/contracts/Erc20.json'; import { Abi } from '.'; describe('Abi', (): void => { - describe('types encoding', (): void => { - let abi: Abi; - - beforeAll((): void => { - abi = new Abi(typesAbi); - }); - - function check (method: string, args: ContractABIArg[], type: string | null): void { - const fn = abi.messages[method]; - - expect(fn.args).toEqual(args); - expect(fn.type).toEqual(type); - } - - it('has the primitive method with args & return', (): void => { - check( - 'primitive', - [ - { name: 'bool', type: 'bool' }, - { name: 'u32', type: 'u32' } - ], - 'bool' - ); - }); - - it('has the vector method with args & return', (): void => { - check( - 'vector', - [ - { name: 'vecU8', type: 'Vec' }, - { name: 'vecU32', type: 'Vec' } - ], - 'Vec' - ); - }); - - it('has the vector_fixed method with args & return', (): void => { - check( - 'vectorFixed', - [ - { name: 'vecU8Length32', type: '[u8;32]' } - ], - '[u32;8]' - ); - }); - - it('has the option method with args & return', (): void => { - check( - 'option', - [ - { name: 'optionU32', type: 'Option' } - ], - 'Option' - ); - }); - - it('has the result method with return (empty)', (): void => { - check( - 'result', - [], - '()' - ); - }); - - it('allows for nested args', (): void => { - check( - 'nested', - [ - { name: 'optionVec', type: 'Option>' } - ], - 'Vec<(u32,u64)>' - ); - }); - - describe('messages', (): void => { - it('fails when invalid args are supplied', (): void => { - expect( - (): Uint8Array => abi.messages.primitive(false) - ).toThrow(/Expected 2 arguments to contract messages.primitive, found 1/); - }); - - it('encodes primitives correctly', (): void => { - expect( - abi.messages.primitive(true, 0x12345678) - ).toEqual(new Uint8Array([ - 9 << 2, // total length (4 + 1 + 4) - 0x67, 0x2b, 0, 0, // 11111 -> hex (LE) - 1, // true - 0x78, 0x56, 0x34, 0x12 // u32 - ])); - }); - }); - }); - describe('erc20', (): void => { let abi: Abi; diff --git a/packages/api-contract/src/Abi.ts b/packages/api-contract/src/Abi.ts index 9c7ac5b10b..bc9a6fdeb7 100644 --- a/packages/api-contract/src/Abi.ts +++ b/packages/api-contract/src/Abi.ts @@ -2,30 +2,40 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { ContractABI, ContractABIFn, InterfaceAbi, AbiMessages } from './types'; - +import { ContractABI, ContractABIPre, ContractABIFn, InterfaceAbi, AbiMessages } from './types'; import { stringCamelCase } from '@polkadot/util'; -import { createMethod } from './method'; -import { validateAbi } from './validation'; +import ContractRegistry from './ContractRegistry'; -export default class ContractAbi implements InterfaceAbi { +export default class ContractAbi extends ContractRegistry implements InterfaceAbi { public readonly abi: ContractABI; - public readonly deploy: ContractABIFn; + public readonly constructors: ContractABIFn[]; public readonly messages: AbiMessages = {}; - public constructor (abi: ContractABI) { - validateAbi(abi); + public constructor (abi: ContractABIPre) { + super(abi); + [this.abi, this.constructors, this.messages] = this.decodeAbi(abi); + } - this.abi = abi; - this.deploy = createMethod('deploy', abi.deploy); + private decodeAbi (abiPre: ContractABIPre): [ContractABI, ContractABIFn[], AbiMessages] { + this.validateAbi(abiPre); - abi.messages.forEach((method): void => { + const abi = this.convertAbi(abiPre); + const constructors = abi.contract.constructors.map( + (constructor, index): ContractABIFn => { + return this.createMethod(`constructor ${index}`, constructor); + } + ); + + const messages: AbiMessages = {}; + abi.contract.messages.forEach((method): void => { const name = stringCamelCase(method.name); - this.messages[name] = createMethod(`messages.${name}`, method); + messages[name] = this.createMethod(`messages.${name}`, method); }); + + return [abi, constructors, messages]; } } diff --git a/packages/api-contract/src/ContractRegistry.ts b/packages/api-contract/src/ContractRegistry.ts new file mode 100644 index 0000000000..854e0757d4 --- /dev/null +++ b/packages/api-contract/src/ContractRegistry.ts @@ -0,0 +1,175 @@ +// Copyright 2017-2019 @polkadot/api-contract authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { CodecArg, TypeDef } from '@polkadot/types/types'; +import { ContractABIArgBasePre, ContractABIContract, ContractABIContractPre, ContractABIEvent, ContractABIEventPre, ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABIMethodPre, ContractABI, ContractABIPre, ContractABIRange, ContractABIRangePre, ContractABIStorage, ContractABIStorageLayout, ContractABIStorageLayoutPre, ContractABIStoragePre, ContractABIStorageStruct, ContractABIStorageStructPre, ContractABITypePre } from './types'; +import { Compact } from '@polkadot/types'; + +import { assert, isNumber, isString, isNull, isObject, isUndefined, stringCamelCase } from '@polkadot/util'; + +import MetaRegistry from './MetaRegistry'; +import { createArgClass } from './method'; + +export default class ContractRegistry extends MetaRegistry { + // Contract ABI helpers + public validateArgs (name: string, args: ContractABIArgBasePre[]): void { + assert(Array.isArray(args), `Expected 'args' to exist on ${name}`); + + args.forEach((arg): void => { + const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key)); + + assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`); + assert(isNumber(arg.name) && isString(this.stringAt(arg.name)), `${name} args should have valid name `); + assert(isNumber(arg.type.ty) && isObject(this.typeDefAt(arg.type.ty)), `${name} args should have valid type`); + }); + } + + public validateConstructors ({ contract: { constructors } }: ContractABIPre): void { + constructors.forEach((constructor: ContractABIMethodPre, index): void => { + const unknownKeys = Object.keys(constructor).filter((key): boolean => !['args', 'docs', 'name', 'selector'].includes(key)); + + assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI constructor`); + + this.validateArgs(`constructor ${index}`, constructor.args); + }); + } + + public validateMethods ({ contract: { messages } }: ContractABIPre): void { + messages.forEach((method): void => { + const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'docs', 'mutates', 'name', 'selector', 'return_type'].includes(key)); + + assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`); + const { name, selector, return_type: returnType } = method; + assert(isNumber(name) && isString(this.stringAt(name)), `Expected name for messages.${method.name}`); + assert(isNumber(selector), `Expected selector for messages.${method.name}`); + assert(isNull(returnType) || (isNumber(returnType.ty) && isObject(this.typeDefAt(returnType.ty))), `Expected return_type for messages.${method.name}`); + + this.validateArgs(`messages.${method.name}`, method.args); + }); + } + + public validateAbi (abi: ContractABIPre): void { + const unknownKeys = Object.keys(abi.contract).filter((key): boolean => !['constructors', 'docs', 'events', 'messages', 'name'].includes(key)); + assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`); + + const { contract: { constructors, messages, name } } = abi; + assert(constructors && messages && isString(this.stringAt(name)), 'ABI should have constructors, messages & name sections'); + + this.validateConstructors(abi); + this.validateMethods(abi); + } + + public createMethod (name: string, method: Partial & ContractABIMethodBase): ContractABIFn { + const args = method.args.map(({ name, type }): ContractABIFnArg => { + assert(isObject(type), `Invalid type at index ${type}`); + return { + name: stringCamelCase(name), + type + }; + }); + const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' }); + const baseStruct: { [index: string]: any } = { __selector: method.selector }; + const encoder = (...params: CodecArg[]): Uint8Array => { + assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`); + + const u8a = new Clazz( + args.reduce((mapped, { name }, index): Record => { + mapped[name] = params[index]; + + return mapped; + }, { ...baseStruct }) + ).toU8a(); + + return Compact.addLengthPrefix(u8a); + }; + + const fn = (encoder as ContractABIFn); + + fn.args = args; + fn.isConstant = !(method.mutates || false); + fn.type = method.returnType || null; + + return fn; + } + + public convertAbi ({ contract, storage }: ContractABIPre): ContractABI { + return { + contract: this.convertContract(contract), + storage: this.convertStorage(storage) + }; + } + + public convertArgs (args: ContractABIArgBasePre[]): any[] { + return args.map(({ name, type, ...arg }) => ({ ...arg, name: this.stringAt(name), type: this.convertType(type) })); + } + + public convertType ({ ty, display_name: displayNameIndices }: ContractABITypePre): TypeDef { + const displayName = this.stringsAt(displayNameIndices).join('::'); + return this.typeDefAt(ty, { displayName }); + } + + public convertContract ({ constructors, messages, name, events, ...contract }: ContractABIContractPre): ContractABIContract { + return { + constructors: this.convertConstructors(constructors), + messages: messages.map(method => this.convertMethod(method)), + name: this.stringAt(name), + ...(events + ? { events: events.map(event => this.convertEvent(event)) } + : {}), + ...contract + }; + } + + public convertConstructors (constructors: ContractABIMethodPre[]): ContractABIMethod[] { + return constructors.map( + (constructor: ContractABIMethodPre): ContractABIMethod => { + return this.convertMethod(constructor); + } + ); + } + + public convertMethod ({ args, name, return_type: returnType, ...method }: ContractABIMethodPre): ContractABIMethod { + return { + ...method, + args: this.convertArgs(args), + name: this.stringAt(name), + returnType: returnType ? this.convertType(returnType) : null + }; + } + + public convertEvent ({ args }: ContractABIEventPre): ContractABIEvent { + return { + args: this.convertArgs(args) + }; + } + + public convertStorage (storage: ContractABIStoragePre): ContractABIStorage { + return this.convertStorageStruct(storage); + } + + public convertStorageLayout (storageLayout: ContractABIStorageLayoutPre): ContractABIStorageLayout { + if ((storageLayout as ContractABIStorageStructPre)['struct.type']) { + return this.convertStorageStruct(storageLayout as ContractABIStorageStructPre); + } else { + return this.convertStorageRange(storageLayout as ContractABIRangePre); + } + } + + public convertStorageStruct ({ 'struct.type': structType, 'struct.fields': structFields }: ContractABIStorageStructPre): ContractABIStorageStruct { + return { + 'struct.type': this.typeDefAt(structType), + 'struct.fields': structFields.map(({ name, layout }) => ({ + name: this.stringAt(name), + layout: this.convertStorageLayout(layout) + })) + }; + } + + public convertStorageRange ({ 'range.elem_type': type, ...range }: ContractABIRangePre): ContractABIRange { + return { + ...range, + 'range.elem_type': this.typeDefAt(type) + }; + } +} diff --git a/packages/api-contract/src/MetaRegistry.spec.ts b/packages/api-contract/src/MetaRegistry.spec.ts new file mode 100644 index 0000000000..140d055a1b --- /dev/null +++ b/packages/api-contract/src/MetaRegistry.spec.ts @@ -0,0 +1,33 @@ +// Copyright 2017-2019 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import fs from 'fs'; +import path from 'path'; + +import MetaRegistry from './MetaRegistry'; + +import erc20Abi from '../test/contracts/Erc20.json'; +import sharedVecAbi from '../test/contracts/SharedVecV2.json'; + +describe('MetaRegistry', (): void => { + describe('construction', (): void => { + it('initializes from a contract ABI (ERC20)', (): void => { + const metaRegistry = new MetaRegistry(erc20Abi); + fs.writeFile(path.join(__dirname, 'erc20.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void { + if (err) throw err; + }); + + expect(true).toBe(true); + }); + + it('initializes from a contract ABI (SharedVec)', (): void => { + const metaRegistry = new MetaRegistry(sharedVecAbi); + fs.writeFile(path.join(__dirname, 'shared-vec.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void { + if (err) throw err; + }); + + expect(true).toBe(true); + }); + }); +}); diff --git a/packages/api-contract/src/MetaRegistry.ts b/packages/api-contract/src/MetaRegistry.ts new file mode 100644 index 0000000000..b5674f654a --- /dev/null +++ b/packages/api-contract/src/MetaRegistry.ts @@ -0,0 +1,385 @@ +// Copyright 2017-2019 @polkadot/api-contract authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { MetaRegistryItem, MetaRegistryJson, MetaTypeDefClikeEnum, MetaType, MetaTypeDefEnum, MetaTypeDefEnumVariant, MetaTypeDefEnumVariantStruct, MetaTypeDefEnumVariantTupleStruct, MetaTypeDefEnumVariantUnit, MetaTypeDefStruct, MetaTypeDefStructField, MetaTypeDefTupleStruct, MetaTypeDefUnion, MetaTypeIdArray, MetaTypeIdCustom, MetaTypeInfo, StringIndex, TypeDef, TypeDefInfo, TypeIndex } from '@polkadot/types/types'; + +import { assert } from '@polkadot/util'; +import { displayType, withTypeString } from '@polkadot/types'; + +const { + BuiltinPlain, + BuiltinTuple, + BuiltinArray, + ClikeEnum, + Enum, + Struct, + TupleStruct, + Null +} = MetaTypeInfo; + +const { + String, + Type, + TypeDef: TypeDefItem +} = MetaRegistryItem; + +export default class MetaRegistry { + private static detectedType ({ def, id }: MetaType): MetaTypeInfo { + assert(!(def as MetaTypeDefUnion)['union.fields'], 'Invalid union type definition found'); + + let metaTypeInfo = MetaTypeInfo.Null; + if (def === 'builtin') { + if (typeof id === 'string') { + metaTypeInfo = MetaTypeInfo.BuiltinPlain; + } + if (Array.isArray(id)) { + metaTypeInfo = MetaTypeInfo.BuiltinTuple; + } + if ((id as MetaTypeIdArray)['array.type']) { + metaTypeInfo = MetaTypeInfo.BuiltinArray; + } + } + + if ((def as MetaTypeDefEnum)['enum.variants']) { + metaTypeInfo = MetaTypeInfo.Enum; + } + + if ((def as MetaTypeDefClikeEnum)['clike_enum.variants']) { + metaTypeInfo = MetaTypeInfo.ClikeEnum; + } + + if ((def as MetaTypeDefStruct)['struct.fields']) { + metaTypeInfo = MetaTypeInfo.Struct; + } + + if ((def as MetaTypeDefTupleStruct)['tuple_struct.types']) { + metaTypeInfo = MetaTypeInfo.TupleStruct; + } + + return metaTypeInfo; + } + + private _strings: string[] = []; + + private _types: MetaType[] = []; + + public typeDefs: TypeDef[] = []; + + public constructor ({ registry: { strings, types } }: MetaRegistryJson) { + this._strings = strings; + this._types = types; + + // Generate TypeDefs for each provided registry type + this._types.forEach((_, index: number): void => this.setTypeDefAtIndex(index + 1)); + } + + private hasItemAt (index: number, variant: MetaRegistryItem): boolean { + switch (variant) { + case String: + return this._strings && !!this._strings[index - 1]; + case Type: + return this._types && !!this._types[index - 1]; + case TypeDefItem: + return this.typeDefs && !!this.typeDefs[index - 1]; + } + } + + private itemAt (index: number, variant: MetaRegistryItem): any { + assert(this.hasItemAt(index, variant), `MetaRegistry: Invalid ${variant} index ${index} found in metadata`); + + switch (variant) { + case String: + return this._strings[index - 1]; + case Type: + return this._types[index - 1]; + case TypeDefItem: + return this.typeDefs[index - 1]; + } + } + + private itemsAt (indices: number[], variant: MetaRegistryItem): any[] { + return indices.map( + (index: number): string => { + return this.itemAt(index, variant); + } + ); + } + + public stringAt (index: StringIndex): string { + return this.itemAt(index, String); + } + + public stringsAt (indices: StringIndex[]): string[] { + return this.itemsAt(indices, String); + } + + public typeAt (index: TypeIndex): MetaType { + return this.itemAt(index, Type); + } + + public typesAt (indices: TypeIndex[]): MetaType[] { + return this.itemsAt(indices, Type); + } + + public hasTypeDefAt (index: TypeIndex): boolean { + return this.hasItemAt(index, TypeDefItem); + } + + public typeDefAt (index: TypeIndex, extra: Pick = {}): TypeDef { + return { + ...this.itemAt(index, TypeDefItem), + ...extra + }; + } + + private typeDefIdFields ({ id }: MetaType): Pick { + const { 'custom.name': nameIndex, 'custom.namespace': namespaceIndices, 'custom.params': paramsIndices } = id as MetaTypeIdCustom; + + if (!nameIndex) { + return {}; + } + + return { + name: this.stringAt(nameIndex), + ...( + namespaceIndices && namespaceIndices.length + ? { namespace: this.stringsAt(namespaceIndices).join('::') } + : {} + ), + ...( + paramsIndices && paramsIndices.length + ? { params: this.typesAt(paramsIndices).map((type): TypeDef => this.typeDefFromMetaType(type)) } + : {} + ) + }; + } + + private typeDefDefFields (metaType: MetaType, typeIndex?: TypeIndex): Pick { + let typeDef; + switch (MetaRegistry.detectedType(metaType)) { + case BuiltinPlain: + typeDef = this.typeDefForBuiltinPlain(metaType.id as string); + break; + case BuiltinTuple: + typeDef = this.typeDefForBuiltinTuple(metaType.id as TypeIndex[]); + break; + case BuiltinArray: + typeDef = this.typeDefForBuiltinArray(metaType.id as MetaTypeIdArray, typeIndex); + break; + case Enum: + typeDef = this.typeDefForEnum(metaType.def as MetaTypeDefEnum, metaType.id as MetaTypeIdCustom, typeIndex); + break; + case ClikeEnum: + typeDef = this.typeDefForClikeEnum(metaType.def as MetaTypeDefClikeEnum); + break; + case Struct: + typeDef = this.typeDefForStruct(metaType.def as MetaTypeDefStruct); + break; + case TupleStruct: + typeDef = this.typeDefForTupleStruct(metaType.def as MetaTypeDefTupleStruct); + break; + case Null: + default: + throw new Error(`Invalid type detected at index ${typeIndex}`); + } + return typeDef; + } + + public typeDefFromMetaType (metaType: MetaType, typeIndex?: TypeIndex): TypeDef { + const typeDef: TypeDef = { + info: TypeDefInfo.Null, + type: '', + ...this.typeDefDefFields(metaType, typeIndex), + ...this.typeDefIdFields(metaType) + }; + + return withTypeString(typeDef) as TypeDef; + } + + public setTypeDefAtIndex (typeIndex: TypeIndex): void { + const metaType = this.typeAt(typeIndex); + + this.typeDefs[typeIndex - 1] = this.typeDefFromMetaType(metaType, typeIndex); + } + + public typeDefFromMetaTypeAt (typeIndex: TypeIndex): TypeDef { + if (!this.hasTypeDefAt(typeIndex)) { + this.setTypeDefAtIndex(typeIndex); + } + return this.typeDefAt(typeIndex)!; + } + + private typeDefForEnumVariant (variant: MetaTypeDefEnumVariant): Pick { + const { 'unit_variant.name': unitNameIndex } = variant as MetaTypeDefEnumVariantUnit; + if (unitNameIndex) { + return { + info: TypeDefInfo.Plain, + name: this.stringAt(unitNameIndex), + type: 'Null' + }; + } + + const { 'tuple_struct_variant.name': tupleStructVariantNameIndex } = variant as MetaTypeDefEnumVariantTupleStruct; + if (tupleStructVariantNameIndex) { + return this.typeDefForTupleStruct(variant as MetaTypeDefEnumVariantTupleStruct); + } + + const { 'struct_variant.name': structVariantNameIndex } = variant as MetaTypeDefEnumVariantStruct; + if (structVariantNameIndex) { + return this.typeDefForStruct(variant as MetaTypeDefEnumVariantStruct); + } + + return { + info: TypeDefInfo.Null, + type: 'Null' + }; + } + + private typeDefForBuiltinPlain (id: string): Pick { + return { + info: TypeDefInfo.Plain, + type: id + }; + } + + private typeDefForBuiltinTuple (id: TypeIndex[]): Pick { + const sub = id.map((tupleTypeIndex: number): TypeDef => this.typeDefFromMetaTypeAt(tupleTypeIndex)); + return { + info: TypeDefInfo.Tuple, + sub + }; + } + + private typeDefForBuiltinArray (id: MetaTypeIdArray, typeIndex?: TypeIndex): Pick { + const { 'array.type': vecTypeIndex, 'array.len': vecLength } = id; + + assert(!vecLength || vecLength <= 256, 'MetaRegistry: Only support for [Type; ], where length <= 256'); + assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`); + + const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex)); + assert(type && type.length > 0, `MetaRegistry: Invalid vector type found at index ${typeIndex}`); + + return { + ...( + vecLength + ? { + info: TypeDefInfo.VecFixed, + ext: { length: vecLength, type }, + type: `[${type};${vecLength}]` + } + : { + info: TypeDefInfo.Vec, + type: `Vec<${type}>` + } + ), + sub: this.typeDefFromMetaTypeAt(vecTypeIndex) + }; + } + + private typeDefForEnum (def: MetaTypeDefEnum, id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick { + const name = id && this.stringAt(id['custom.name']); + + switch (name) { + case 'Option': + return this.typeDefForOption(id, typeIndex); + case 'Result': + return this.typeDefForResult(id, typeIndex); + default: { + const sub = def['enum.variants'].map(variant => this.typeDefForEnumVariant(variant)); + + return { + info: TypeDefInfo.Enum, + sub + }; + } + } + } + + private typeDefForClikeEnum (def: MetaTypeDefClikeEnum): Pick { + const sub = def['clike_enum.variants'].map( + ({ name: nameIndex, discriminant }): TypeDef => { + return { + ext: { discriminant }, + info: TypeDefInfo.Plain, + name: this.stringAt(nameIndex), + type: 'Null' + }; + } + ); + + return { + info: TypeDefInfo.Enum, + sub + }; + } + + public typeDefForOption (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick { + assert(id['custom.params']![0], `Invalid Option type defined at index ${typeIndex}`); + + return { + info: TypeDefInfo.Option, + sub: this.typeDefFromMetaTypeAt(id['custom.params']![0]) + }; + } + + public typeDefForResult (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick { + assert(id['custom.params']![0] && id['custom.params']![1], `Invalid Result type defined at index ${typeIndex}`); + + return { + info: TypeDefInfo.Result, + sub: id['custom.params']!.map((typeIndex): TypeDef => this.typeDefFromMetaTypeAt(typeIndex)) + }; + } + + public typeDefForStruct (def: MetaTypeDefStruct | MetaTypeDefEnumVariantStruct): Pick { + const structFields = (def as MetaTypeDefStruct)['struct.fields'] || (def as MetaTypeDefEnumVariantStruct)['struct_variant.fields']; + const structNameIndex = (def as MetaTypeDefEnumVariantStruct)['struct_variant.name']; + const sub = structFields.map( + (field: MetaTypeDefStructField): TypeDef => { + const { name: nameIndex, type: fieldTypeIndex } = field; + return { + ...this.typeDefFromMetaTypeAt(fieldTypeIndex), + name: this.stringAt(nameIndex) + }; + } + ); + + return withTypeString({ + info: TypeDefInfo.Struct, + ...( + structNameIndex + ? { + name: this.stringAt(structNameIndex) + } + : {} + ), + sub + }); + } + + private typeDefForTupleStruct (def: MetaTypeDefTupleStruct | MetaTypeDefEnumVariantTupleStruct): Pick { + const tupleStructTypes = (def as MetaTypeDefTupleStruct)['tuple_struct.types'] || (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.types']; + const tupleStructNameIndex = (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.name']; + const sub: TypeDef[] = tupleStructTypes.map( + (tupleStructFieldTypeIndex: number, index: number): TypeDef => { + return { + ...this.typeDefFromMetaTypeAt(tupleStructFieldTypeIndex), + index + }; + } + ); + + return withTypeString({ + info: TypeDefInfo.Tuple, + ...( + tupleStructNameIndex + ? { + name: this.stringAt(tupleStructNameIndex) + } + : {} + ), + sub + }); + } +} diff --git a/packages/api-contract/src/RxBase.ts b/packages/api-contract/src/RxBase.ts index 8c023e1066..650cadd47e 100644 --- a/packages/api-contract/src/RxBase.ts +++ b/packages/api-contract/src/RxBase.ts @@ -3,7 +3,7 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { SubmittableModuleExtrinsics } from '@polkadot/api/types'; -import { ApiObject, ContractABI, ContractBase } from './types'; +import { ApiObject, ContractABIPre, ContractBase } from './types'; import { assert } from '@polkadot/util'; @@ -17,7 +17,7 @@ export default abstract class RxBase implements ContractBase<'rxjs'> { public readonly apiContracts: SubmittableModuleExtrinsics<'rxjs'>; - public constructor (api: ApiObject<'rxjs'>, abi: ContractABI | Abi) { + public constructor (api: ApiObject<'rxjs'>, abi: ContractABIPre | Abi) { this.abi = abi instanceof Abi ? abi : new Abi(abi); diff --git a/packages/api-contract/src/RxBlueprint.ts b/packages/api-contract/src/RxBlueprint.ts index 5c5e234f4c..f36863e93f 100644 --- a/packages/api-contract/src/RxBlueprint.ts +++ b/packages/api-contract/src/RxBlueprint.ts @@ -5,13 +5,14 @@ import { SubmittableResultImpl } from '@polkadot/api/types'; import { AccountId, Address, Hash } from '@polkadot/types/interfaces'; import { IKeyringPair } from '@polkadot/types/types'; -import { ContractABI } from './types'; +import { ContractABIPre } from './types'; import BN from 'bn.js'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiRx, SubmittableResult } from '@polkadot/api'; import { createType } from '@polkadot/types'; +import { assert } from '@polkadot/util'; import Abi from './Abi'; import RxBase from './RxBase'; @@ -37,16 +38,17 @@ class BlueprintCreateResult extends SubmittableResult { export default class Blueprint extends RxBase { public readonly codeHash: Hash; - public constructor (api: ApiRx, abi: ContractABI | Abi, codeHash: string | Hash) { + public constructor (api: ApiRx, abi: ContractABIPre | Abi, codeHash: string | Hash) { super(api, abi); this.codeHash = createType('Hash', codeHash); } - public deployContract (endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate { + public deployContract (constructorIndex = 0, endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate { + assert(!!this.abi.constructors[constructorIndex], `Specified constructor index ${constructorIndex} does not exist`); const signAndSend = (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription => { return this.apiContracts - .create(endowment, maxGas, this.codeHash, this.abi.deploy(...params)) + .create(endowment, maxGas, this.codeHash, this.abi.constructors[constructorIndex](...params)) .signAndSend(account) .pipe(map(this.createResult)); }; diff --git a/packages/api-contract/src/RxCode.ts b/packages/api-contract/src/RxCode.ts index c4716387fb..a419f574a5 100644 --- a/packages/api-contract/src/RxCode.ts +++ b/packages/api-contract/src/RxCode.ts @@ -5,7 +5,7 @@ import { SubmittableResultImpl } from '@polkadot/api/types'; import { AccountId, Address, Hash } from '@polkadot/types/interfaces'; import { IKeyringPair } from '@polkadot/types/types'; -import { ContractABI } from './types'; +import { ContractABIPre } from './types'; import BN from 'bn.js'; import { Observable } from 'rxjs'; @@ -50,7 +50,7 @@ class CodePutCodeResult extends SubmittableResult { export default class RxCode extends RxBase { public readonly code: Uint8Array; - public constructor (api: ApiRx, abi: ContractABI | Abi, wasm: string | Uint8Array) { + public constructor (api: ApiRx, abi: ContractABIPre | Abi, wasm: string | Uint8Array) { super(api, abi); this.code = u8aToU8a(wasm); diff --git a/packages/api-contract/src/RxContract.ts b/packages/api-contract/src/RxContract.ts index 6e09a7e346..1a5573a4f4 100644 --- a/packages/api-contract/src/RxContract.ts +++ b/packages/api-contract/src/RxContract.ts @@ -4,7 +4,7 @@ import { AccountId, Address } from '@polkadot/types/interfaces'; import { IKeyringPair } from '@polkadot/types/types'; -import { ContractABI, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types'; +import { ContractABIPre, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types'; import BN from 'bn.js'; import { Observable } from 'rxjs'; @@ -27,12 +27,12 @@ export default class RxContract extends RxBase implements InterfaceContract { public readonly calls: InterfaceContractCalls = {}; - public constructor (api: ApiRx, abi: ContractABI | Abi, address: string | AccountId | Address) { + public constructor (api: ApiRx, abi: ContractABIPre | Abi, address: string | AccountId | Address) { super(api, abi); this.address = createType('Address', address); - Object.entries(abi.messages).forEach(([name]): void => { + Object.entries(this.abi.messages).forEach(([name]): void => { this.calls[name] = (fn: ContractABIFn): CallResult => (value: BN | number, maxGas: BN | number, ...params: any[]): ContractCall => this.apiContracts.call(this.address, value, maxGas, fn(...params)); diff --git a/packages/api-contract/src/erc20.test.json b/packages/api-contract/src/erc20.test.json new file mode 100644 index 0000000000..c6d911f36d --- /dev/null +++ b/packages/api-contract/src/erc20.test.json @@ -0,0 +1,2362 @@ +[ + { + "info": 7, + "type": "{ \"_enum\": {\"total_supply\": \"{ \"_enum\": {\"cell\": \"{ \"_enum\": {\"cell\": \"([u8;32])\"} } typeToString(type)).join(',')})`; - } else if (type['Option']) { - return `Option<${typeToString(type['Option'].T)}>`; - } else if (type['Result']) { - return '()'; // Result is not supported, but only applicable for returns - } else if (type['Vec']) { - return `Vec<${typeToString(type['Vec'].T)}>`; - } else if (type['[T;n]']) { - return `[${typeToString(type['[T;n]'].T)};${type['[T;n]'].n}]`; - } - - throw new Error(`Unknown type specified ${JSON.stringify(type)}`); -} +import { createClass, encodeType } from '@polkadot/types'; export function createArgClass (args: ContractABIFnArg[], baseDef: Record): Constructor { return createClass( JSON.stringify( args.reduce((base: Record, { name, type }): Record => { - base[name] = type; + base[name] = encodeType(type); return base; }, baseDef) ) ); } - -export function createMethod (name: string, method: Partial & ContractABIMethodBase): ContractABIFn { - const args: ContractABIFnArg[] = method.args.map(({ name, type }): ContractABIFnArg => ({ - name: stringCamelCase(name), - type: typeToString(type) - })); - const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' }); - const baseStruct: { [index: string]: any } = { __selector: method.selector }; - const encoder = (...params: CodecArg[]): Uint8Array => { - assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`); - - const u8a = new Clazz( - args.reduce((mapped, { name }, index): Record => { - mapped[name] = params[index]; - - return mapped; - }, { ...baseStruct }) - ).toU8a(); - - return Compact.addLengthPrefix(u8a); - }; - - const fn = (encoder as ContractABIFn); - - fn.args = args; - fn.isConstant = !(method.mutates || false); - fn.type = method.return_type ? typeToString(method.return_type) : null; - - return fn; -} diff --git a/packages/api-contract/src/shared-vec.test.json b/packages/api-contract/src/shared-vec.test.json new file mode 100644 index 0000000000..6a51fe7e4d --- /dev/null +++ b/packages/api-contract/src/shared-vec.test.json @@ -0,0 +1,2385 @@ +[ + { + "info": 7, + "type": "{ \"_enum\": {\"mutators\": \"{ \"_enum\": {\"len\": \"{ \"_enum\": {\"cell\": \"{ \"_enum\": {\"cell\": \"([u8;32])\"} } = ApiType extends 'rxjs' ? ApiRx : ApiPromise; -export interface ContractABITypesStruct { - 'Option'?: { - T: ContractABITypes; - }; - 'Result'?: { - T: ContractABITypes; - E: ContractABITypes; - }; - 'Vec'?: { - T: ContractABITypes; - }; - '[T;n]'?: { - T: ContractABITypes; - n: number; - }; +export interface ContractABITypePre { + ty: TypeIndex; + display_name: StringIndex[]; } -export type ContractABITypes = string | ContractABITypesStruct | (string | ContractABITypesStruct)[]; +export interface ContractABIArgBasePre { + name: StringIndex; + type: ContractABITypePre; +} -export interface ContractABIArg { +export interface ContractABIArgBase { name: string; - type: ContractABITypes; + type: TypeDef; } +export type ContractABIMethodArgPre = ContractABIArgBasePre; + +export type ContractABIMethodArg = ContractABIArgBase; + export interface ContractABIMethodBase { - args: ContractABIArg[]; + args: ContractABIMethodArg[]; } -export interface ContractABIMethod extends ContractABIMethodBase { +export interface ContractABIMethodBasePre { + args: ContractABIMethodArgPre[]; +} + +export interface ContractABIMethodCommon { + docs?: ContractABIDocs; mutates?: boolean; - name: string; selector: number; - return_type: ContractABITypes | null; +} + +export interface ContractABIMethodPre extends ContractABIMethodCommon, ContractABIMethodBasePre { + name: StringIndex; + return_type: ContractABITypePre | null; +} + +export interface ContractABIMethod extends ContractABIMethodCommon { + args: ContractABIMethodArg[]; + name: string; + returnType: TypeDef | null; +} + +export interface ContractABIContractCommon { + docs?: ContractABIDocs; +} + +export interface ContractABIContractPre extends ContractABIContractCommon { + constructors: ContractABIMethodPre[]; + messages: ContractABIMethodPre[]; + name: StringIndex; + events?: ContractABIEventPre[]; + docs?: ContractABIDocs; +} + +export interface ContractABIContract extends ContractABIContractCommon { + constructors: ContractABIMethod[]; + messages: ContractABIMethod[]; + name: string; + events?: ContractABIEvent[]; + docs?: ContractABIDocs; +} + +export interface ContractABIPre extends MetaRegistryJson { + storage: ContractABIStoragePre; + contract: ContractABIContractPre; } export interface ContractABI { - deploy: ContractABIMethodBase; - messages: ContractABIMethod[]; - name: string; + storage: ContractABIStorage; + contract: ContractABIContract; } export interface ContractABIFnArg { name: string; - type: string; + type: TypeDef; } export interface ContractABIMeta { args: ContractABIFnArg[]; isConstant: boolean; - type: string | null; + type: TypeDef | null; } export interface ContractABIFn extends ContractABIMeta { (...args: CodecArg[]): Uint8Array; } +export interface ContractABIEventArgBase { + indexed: boolean; +} + +export interface ContractABIEventArgPre extends ContractABIArgBasePre, ContractABIEventArgBase {} + +export interface ContractABIEventArg extends ContractABIArgBase, ContractABIEventArgBase {} + +export type ContractABIDocs = string[]; + +export interface ContractABIEventPre { + args: ContractABIEventArgPre[]; +} + +export interface ContractABIEvent { + args: ContractABIEventArg[]; +} + +export interface ContractABIRangeBase { + 'range.offset': number[]; + 'range.len': number; +} + +export interface ContractABIRangePre extends ContractABIRangeBase { + 'range.elem_type': TypeIndex; +} + +export interface ContractABIRange extends ContractABIRangeBase { + 'range.elem_type': TypeDef; +} + +export type ContractABIStorageLayoutPre = ContractABIStorageStructPre | ContractABIRangePre; + +export type ContractABIStorageLayout = ContractABIStorageStruct | ContractABIRange; + +export interface ContractABIStorageStructFieldPre { + name: StringIndex; + layout: ContractABIStorageLayoutPre; +} + +export interface ContractABIStorageStructField { + name: string; + layout: ContractABIStorageLayout; +} + +export interface ContractABIStorageStructPre { + 'struct.type': TypeIndex; + 'struct.fields': ContractABIStorageStructFieldPre[]; +} + +export interface ContractABIStorageStruct { + 'struct.type': TypeDef; + 'struct.fields': ContractABIStorageStructField[]; +} + +export type ContractABIStoragePre = ContractABIStorageStructPre; + +export type ContractABIStorage = ContractABIStorageStruct; + export type AbiMessages = Record; export interface InterfaceAbi { readonly abi: ContractABI; - readonly deploy: ContractABIFn; + readonly constructors: ContractABIFn[]; readonly messages: AbiMessages; } diff --git a/packages/api-contract/src/v2.test.json b/packages/api-contract/src/v2.test.json new file mode 100644 index 0000000000..d2810895fa --- /dev/null +++ b/packages/api-contract/src/v2.test.json @@ -0,0 +1,1414 @@ +[ + { + "info": 7, + "type": "{\"my_tuple_struct\": {\"cell\": {\"cell\": ([u8;32])}}, \"my_struct\": {\"cell\": {\"cell\": ([u8;32])}}, \"my_clike_enum\": {\"cell\": {\"cell\": ([u8;32])}}, \"my_enum\": {\"cell\": {\"cell\": ([u8;32])}}, \"my_union\": {\"cell\": {\"cell\": ([u8;32])}}}", + "name": "RustStructures", + "namespace": "structures::normal", + "sub": [ + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "my_tuple_struct", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 8, + "type": "(u8, u16)", + "name": "TupleStruct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 8, + "type": "(u8, u16)", + "name": "TupleStruct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "my_struct", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 7, + "type": "{\"first\": u8, \"seconds\": u16}", + "name": "Struct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "seconds" + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 7, + "type": "{\"first\": u8, \"seconds\": u16}", + "name": "Struct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "seconds" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "my_clike_enum", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 2, + "type": "[\"FirstVariant\", \"SecondVariant\", \"ThirdVariant\"]", + "name": "ClikeEnum", + "namespace": "structures", + "sub": [ + { + "ext": { + "discriminant": 0 + }, + "info": 5, + "name": "FirstVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 1 + }, + "info": 5, + "name": "SecondVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 42 + }, + "info": 5, + "name": "ThirdVariant", + "type": "Null" + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 2, + "type": "[\"FirstVariant\", \"SecondVariant\", \"ThirdVariant\"]", + "name": "ClikeEnum", + "namespace": "structures", + "sub": [ + { + "ext": { + "discriminant": 0 + }, + "info": 5, + "name": "FirstVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 1 + }, + "info": 5, + "name": "SecondVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 42 + }, + "info": 5, + "name": "ThirdVariant", + "type": "Null" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "my_enum", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 2, + "type": "{\"NoData\": Null, \"TupleVariant\": (u8, u16), \"StructVariant\": {\"first\": u8, \"second\": u16}}", + "name": "RustEnum", + "namespace": "structures", + "sub": [ + { + "info": 5, + "name": "NoData", + "type": "Null" + }, + { + "info": 8, + "name": "TupleVariant", + "type": "(u8, u16)", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 7, + "name": "StructVariant", + "type": "{\"first\": u8, \"second\": u16}", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 2, + "type": "{\"NoData\": Null, \"TupleVariant\": (u8, u16), \"StructVariant\": {\"first\": u8, \"second\": u16}}", + "name": "RustEnum", + "namespace": "structures", + "sub": [ + { + "info": 5, + "name": "NoData", + "type": "Null" + }, + { + "info": 8, + "name": "TupleVariant", + "type": "(u8, u16)", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 7, + "name": "StructVariant", + "type": "{\"first\": u8, \"second\": u16}", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "my_union", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 9, + "type": "{\"first\": u8, \"second\": u16}", + "name": "Union", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 9, + "type": "{\"first\": u8, \"second\": u16}", + "name": "Union", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "Value", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 8, + "type": "(u8, u16)", + "name": "TupleStruct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 8, + "type": "(u8, u16)", + "name": "TupleStruct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 8, + "type": "(u8, u16)", + "name": "TupleStruct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 5, + "type": "u8" + }, + { + "info": 5, + "type": "u16" + }, + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "SyncCell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 8, + "type": "(u8, u16)", + "name": "TupleStruct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + }, + { + "info": 8, + "type": "([u8;32])", + "name": "Key", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + }, + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + } + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "Value", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 7, + "type": "{\"first\": u8, \"seconds\": u16}", + "name": "Struct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "seconds" + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 7, + "type": "{\"first\": u8, \"seconds\": u16}", + "name": "Struct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "seconds" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"first\": u8, \"seconds\": u16}", + "name": "Struct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "seconds" + } + ] + }, + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "SyncCell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 7, + "type": "{\"first\": u8, \"seconds\": u16}", + "name": "Struct", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "seconds" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "Value", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 2, + "type": "[\"FirstVariant\", \"SecondVariant\", \"ThirdVariant\"]", + "name": "ClikeEnum", + "namespace": "structures", + "sub": [ + { + "ext": { + "discriminant": 0 + }, + "info": 5, + "name": "FirstVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 1 + }, + "info": 5, + "name": "SecondVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 42 + }, + "info": 5, + "name": "ThirdVariant", + "type": "Null" + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 2, + "type": "[\"FirstVariant\", \"SecondVariant\", \"ThirdVariant\"]", + "name": "ClikeEnum", + "namespace": "structures", + "sub": [ + { + "ext": { + "discriminant": 0 + }, + "info": 5, + "name": "FirstVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 1 + }, + "info": 5, + "name": "SecondVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 42 + }, + "info": 5, + "name": "ThirdVariant", + "type": "Null" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 2, + "type": "[\"FirstVariant\", \"SecondVariant\", \"ThirdVariant\"]", + "name": "ClikeEnum", + "namespace": "structures", + "sub": [ + { + "ext": { + "discriminant": 0 + }, + "info": 5, + "name": "FirstVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 1 + }, + "info": 5, + "name": "SecondVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 42 + }, + "info": 5, + "name": "ThirdVariant", + "type": "Null" + } + ] + }, + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "SyncCell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 2, + "type": "[\"FirstVariant\", \"SecondVariant\", \"ThirdVariant\"]", + "name": "ClikeEnum", + "namespace": "structures", + "sub": [ + { + "ext": { + "discriminant": 0 + }, + "info": 5, + "name": "FirstVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 1 + }, + "info": 5, + "name": "SecondVariant", + "type": "Null" + }, + { + "ext": { + "discriminant": 42 + }, + "info": 5, + "name": "ThirdVariant", + "type": "Null" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "Value", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 2, + "type": "{\"NoData\": Null, \"TupleVariant\": (u8, u16), \"StructVariant\": {\"first\": u8, \"second\": u16}}", + "name": "RustEnum", + "namespace": "structures", + "sub": [ + { + "info": 5, + "name": "NoData", + "type": "Null" + }, + { + "info": 8, + "name": "TupleVariant", + "type": "(u8, u16)", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 7, + "name": "StructVariant", + "type": "{\"first\": u8, \"second\": u16}", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 2, + "type": "{\"NoData\": Null, \"TupleVariant\": (u8, u16), \"StructVariant\": {\"first\": u8, \"second\": u16}}", + "name": "RustEnum", + "namespace": "structures", + "sub": [ + { + "info": 5, + "name": "NoData", + "type": "Null" + }, + { + "info": 8, + "name": "TupleVariant", + "type": "(u8, u16)", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 7, + "name": "StructVariant", + "type": "{\"first\": u8, \"second\": u16}", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 2, + "type": "{\"NoData\": Null, \"TupleVariant\": (u8, u16), \"StructVariant\": {\"first\": u8, \"second\": u16}}", + "name": "RustEnum", + "namespace": "structures", + "sub": [ + { + "info": 5, + "name": "NoData", + "type": "Null" + }, + { + "info": 8, + "name": "TupleVariant", + "type": "(u8, u16)", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 7, + "name": "StructVariant", + "type": "{\"first\": u8, \"second\": u16}", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "SyncCell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 2, + "type": "{\"NoData\": Null, \"TupleVariant\": (u8, u16), \"StructVariant\": {\"first\": u8, \"second\": u16}}", + "name": "RustEnum", + "namespace": "structures", + "sub": [ + { + "info": 5, + "name": "NoData", + "type": "Null" + }, + { + "info": 8, + "name": "TupleVariant", + "type": "(u8, u16)", + "sub": [ + { + "info": 5, + "type": "u8", + "index": 0 + }, + { + "info": 5, + "type": "u16", + "index": 1 + } + ] + }, + { + "info": 7, + "name": "StructVariant", + "type": "{\"first\": u8, \"second\": u16}", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + }, + { + "info": 7, + "type": "{\"cell\": {\"cell\": ([u8;32])}}", + "name": "Value", + "namespace": "ink_core::storage::value", + "params": [ + { + "info": 9, + "type": "{\"first\": u8, \"second\": u16}", + "name": "Union", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ], + "sub": [ + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "cell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 9, + "type": "{\"first\": u8, \"second\": u16}", + "name": "Union", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } + ] + }, + { + "info": 9, + "type": "{\"first\": u8, \"second\": u16}", + "name": "Union", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + }, + { + "info": 7, + "type": "{\"cell\": ([u8;32])}", + "name": "SyncCell", + "namespace": "ink_core::storage::cell::sync_cell", + "params": [ + { + "info": 9, + "type": "{\"first\": u8, \"second\": u16}", + "name": "Union", + "namespace": "structures", + "sub": [ + { + "info": 5, + "type": "u8", + "name": "first" + }, + { + "info": 5, + "type": "u16", + "name": "second" + } + ] + } + ], + "sub": [ + { + "info": 8, + "type": "([u8;32])", + "name": "cell", + "namespace": "ink_core::storage::key", + "sub": [ + { + "info": 11, + "type": "[u8;32]", + "ext": { + "length": 32, + "type": "" + }, + "sub": { + "info": 5, + "type": "u8" + }, + "index": 0 + } + ] + } + ] + } +] \ No newline at end of file diff --git a/packages/api-contract/src/validation.ts b/packages/api-contract/src/validation.ts deleted file mode 100644 index db928c5d6b..0000000000 --- a/packages/api-contract/src/validation.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017-2019 @polkadot/api-contract authors & contributors -// This software may be modified and distributed under the terms -// of the Apache-2.0 license. See the LICENSE file for details. - -import { ContractABI, ContractABIArg } from './types'; - -import { assert, isNumber, isNull, isString, isObject } from '@polkadot/util'; - -export function validateArgs (name: string, args: ContractABIArg[]): void { - assert(Array.isArray(args), `Expected 'args' to exist on ${name}`); - - args.forEach((arg): void => { - const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key)); - - assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`); - assert(isString(arg.name), `${name} args should have valid name `); - assert(isString(arg.type) || isObject(arg.type), `${name} args should have valid type`); - }); -} - -export function validateDeploy ({ deploy }: ContractABI): void { - const unknownKeys = Object.keys(deploy).filter((key): boolean => !['args'].includes(key)); - - assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI deploy`); - - validateArgs('deploy', deploy.args); -} - -export function validateMethods ({ messages }: ContractABI): void { - messages.forEach((method): void => { - const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'mutates', 'name', 'selector', 'return_type'].includes(key)); - - assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`); - assert(isString(method.name), `Expected name for messages.${method.name}`); - assert(isNumber(method.selector), `Expected selector for messages.${method.name}`); - assert(isNull(method.return_type) || isString(method.return_type) || isObject(method.return_type), `Expected return_type for messages.${method.name}`); - - validateArgs(`messages.${method.name}`, method.args); - }); -} - -export function validateAbi (abi: ContractABI): void { - const unknownKeys = Object.keys(abi).filter((key): boolean => !['deploy', 'messages', 'name'].includes(key)); - - assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`); - assert(abi.deploy && abi.messages && isString(abi.name), 'ABI should have deploy, messages & name sections'); - - validateDeploy(abi); - validateMethods(abi); -} diff --git a/packages/api-contract/test/contracts/Erc20.json b/packages/api-contract/test/contracts/Erc20.json index ff85ddc86b..79f16146b2 100644 --- a/packages/api-contract/test/contracts/Erc20.json +++ b/packages/api-contract/test/contracts/Erc20.json @@ -1 +1,1007 @@ -{"name":"Erc20","deploy":{"args":[{"name":"init_value","type":"Balance"}]},"messages":[{"name":"total_supply","selector":949181842,"mutates":false,"args":[],"return_type":"Balance"},{"name":"balance_of","selector":3827153702,"mutates":false,"args":[{"name":"owner","type":"AccountId"}],"return_type":"Balance"},{"name":"allowance","selector":3057219184,"mutates":false,"args":[{"name":"owner","type":"AccountId"},{"name":"spender","type":"AccountId"}],"return_type":"Balance"},{"name":"transfer","selector":3374842663,"mutates":true,"args":[{"name":"to","type":"AccountId"},{"name":"value","type":"Balance"}],"return_type":"bool"},{"name":"approve","selector":431186122,"mutates":true,"args":[{"name":"spender","type":"AccountId"},{"name":"value","type":"Balance"}],"return_type":"bool"},{"name":"transfer_from","selector":197482595,"mutates":true,"args":[{"name":"from","type":"AccountId"},{"name":"to","type":"AccountId"},{"name":"value","type":"Balance"}],"return_type":"bool"}]} \ No newline at end of file +{ + "registry": { + "strings": [ + "Erc20", + "erc20", + "normal", + "total_supply", + "Value", + "ink_core", + "storage", + "value", + "cell", + "SyncCell", + "sync_cell", + "Key", + "key", + "balances", + "HashMap", + "collections", + "hash_map", + "impls", + "AccountId", + "env", + "srml", + "types", + "len", + "entries", + "SyncChunk", + "chunk", + "sync_chunk", + "Entry", + "Occupied", + "OccupiedEntry", + "val", + "Removed", + "cells_key", + "allowances", + "on_deploy", + "init_value", + "Balance", + "balance_of", + "owner", + "allowance", + "spender", + "transfer", + "to", + "bool", + "approve", + "transfer_from", + "from", + "Approval", + "Transfer", + "Option", + "None", + "Some" + ], + "types": [ + { + "id": { + "custom.name": 1, + "custom.namespace": [ + 2, + 3 + ], + "custom.params": [] + }, + "def": { + "struct.fields": [ + { + "name": 4, + "type": 2 + }, + { + "name": 14, + "type": 8 + }, + { + "name": 34, + "type": 16 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 9, + "type": 4 + } + ] + } + }, + { + "id": "u128", + "def": "builtin" + }, + { + "id": { + "custom.name": 10, + "custom.namespace": [ + 6, + 7, + 9, + 11 + ], + "custom.params": [ + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 9, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 12, + "custom.namespace": [ + 6, + 7, + 13 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 6 + ] + } + }, + { + "id": { + "array.len": 32, + "array.type": 7 + }, + "def": "builtin" + }, + { + "id": "u8", + "def": "builtin" + }, + { + "id": { + "custom.name": 15, + "custom.namespace": [ + 6, + 7, + 16, + 17, + 18 + ], + "custom.params": [ + 9, + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 23, + "type": 10 + }, + { + "name": 24, + "type": 13 + } + ] + } + }, + { + "id": { + "custom.name": 19, + "custom.namespace": [ + 6, + 20, + 21, + 22 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 6 + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 11 + ] + }, + "def": { + "struct.fields": [ + { + "name": 9, + "type": 12 + } + ] + } + }, + { + "id": "u32", + "def": "builtin" + }, + { + "id": { + "custom.name": 10, + "custom.namespace": [ + 6, + 7, + 9, + 11 + ], + "custom.params": [ + 11 + ] + }, + "def": { + "struct.fields": [ + { + "name": 9, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 25, + "custom.namespace": [ + 6, + 7, + 26, + 27, + 26 + ], + "custom.params": [ + 14 + ] + }, + "def": { + "struct.fields": [ + { + "name": 33, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 28, + "custom.namespace": [ + 6, + 7, + 16, + 17, + 18 + ], + "custom.params": [ + 9, + 3 + ] + }, + "def": { + "enum.variants": [ + { + "tuple_struct_variant.name": 29, + "tuple_struct_variant.types": [ + 15 + ] + }, + { + "unit_variant.name": 32 + } + ] + } + }, + { + "id": { + "custom.name": 30, + "custom.namespace": [ + 6, + 7, + 16, + 17, + 18 + ], + "custom.params": [ + 9, + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 13, + "type": 9 + }, + { + "name": 31, + "type": 3 + } + ] + } + }, + { + "id": { + "custom.name": 15, + "custom.namespace": [ + 6, + 7, + 16, + 17, + 18 + ], + "custom.params": [ + 17, + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 23, + "type": 10 + }, + { + "name": 24, + "type": 18 + } + ] + } + }, + { + "id": [ + 9, + 9 + ], + "def": "builtin" + }, + { + "id": { + "custom.name": 25, + "custom.namespace": [ + 6, + 7, + 26, + 27, + 26 + ], + "custom.params": [ + 19 + ] + }, + "def": { + "struct.fields": [ + { + "name": 33, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 28, + "custom.namespace": [ + 6, + 7, + 16, + 17, + 18 + ], + "custom.params": [ + 17, + 3 + ] + }, + "def": { + "enum.variants": [ + { + "tuple_struct_variant.name": 29, + "tuple_struct_variant.types": [ + 20 + ] + }, + { + "unit_variant.name": 32 + } + ] + } + }, + { + "id": { + "custom.name": 30, + "custom.namespace": [ + 6, + 7, + 16, + 17, + 18 + ], + "custom.params": [ + 17, + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 13, + "type": 17 + }, + { + "name": 31, + "type": 3 + } + ] + } + }, + { + "id": "bool", + "def": "builtin" + }, + { + "id": { + "custom.name": 50, + "custom.namespace": [], + "custom.params": [ + 9 + ] + }, + "def": { + "enum.variants": [ + { + "unit_variant.name": 51 + }, + { + "tuple_struct_variant.name": 52, + "tuple_struct_variant.types": [ + 9 + ] + } + ] + } + } + ] + }, + "storage": { + "struct.type": 1, + "struct.fields": [ + { + "name": 4, + "layout": { + "struct.type": 2, + "struct.fields": [ + { + "name": 9, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "range.len": 1, + "range.elem_type": 3 + } + } + ] + } + }, + { + "name": 14, + "layout": { + "struct.type": 8, + "struct.fields": [ + { + "name": 23, + "layout": { + "struct.type": 10, + "struct.fields": [ + { + "name": 9, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + "range.len": 1, + "range.elem_type": 11 + } + } + ] + } + }, + { + "name": 24, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2 + ], + "range.len": 4294967295, + "range.elem_type": 14 + } + } + ] + } + }, + { + "name": 34, + "layout": { + "struct.type": 16, + "struct.fields": [ + { + "name": 23, + "layout": { + "struct.type": 10, + "struct.fields": [ + { + "name": 9, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1 + ], + "range.len": 1, + "range.elem_type": 11 + } + } + ] + } + }, + { + "name": 24, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2 + ], + "range.len": 4294967295, + "range.elem_type": 19 + } + } + ] + } + } + ] + }, + "contract": { + "name": 1, + "constructors": [ + { + "name": 35, + "selector": 0, + "args": [ + { + "name": 36, + "type": { + "ty": 3, + "display_name": [ + 37 + ] + } + } + ], + "docs": [] + } + ], + "messages": [ + { + "name": 4, + "selector": 949181842, + "mutates": false, + "args": [], + "return_type": { + "ty": 3, + "display_name": [ + 37 + ] + }, + "docs": [ + "Returns the total number of tokens in existence." + ] + }, + { + "name": 38, + "selector": 3827153702, + "mutates": false, + "args": [ + { + "name": 39, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + } + ], + "return_type": { + "ty": 3, + "display_name": [ + 37 + ] + }, + "docs": [ + "Returns the balance of the given AccountId." + ] + }, + { + "name": 40, + "selector": 3057219184, + "mutates": false, + "args": [ + { + "name": 39, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 41, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + } + ], + "return_type": { + "ty": 3, + "display_name": [ + 37 + ] + }, + "docs": [ + "Returns the amount of tokens that an owner allowed to a spender." + ] + }, + { + "name": 42, + "selector": 3374842663, + "mutates": true, + "args": [ + { + "name": 43, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 8, + "type": { + "ty": 3, + "display_name": [ + 37 + ] + } + } + ], + "return_type": { + "ty": 21, + "display_name": [ + 44 + ] + }, + "docs": [ + "Transfers token from the sender to the `to` AccountId." + ] + }, + { + "name": 45, + "selector": 431186122, + "mutates": true, + "args": [ + { + "name": 41, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 8, + "type": { + "ty": 3, + "display_name": [ + 37 + ] + } + } + ], + "return_type": { + "ty": 21, + "display_name": [ + 44 + ] + }, + "docs": [ + "Approve the passed AccountId to spend the specified amount of tokens", + "on the behalf of the message\\'s sender." + ] + }, + { + "name": 46, + "selector": 197482595, + "mutates": true, + "args": [ + { + "name": 47, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 43, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 8, + "type": { + "ty": 3, + "display_name": [ + 37 + ] + } + } + ], + "return_type": { + "ty": 21, + "display_name": [ + 44 + ] + }, + "docs": [ + "Transfer tokens from one AccountId to another." + ] + } + ], + "events": [ + { + "name": 48, + "args": [ + { + "name": 39, + "indexed": false, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 41, + "indexed": false, + "type": { + "ty": 9, + "display_name": [ + 19 + ] + } + }, + { + "name": 8, + "indexed": false, + "type": { + "ty": 3, + "display_name": [ + 37 + ] + } + } + ], + "docs": [] + }, + { + "name": 49, + "args": [ + { + "name": 47, + "indexed": false, + "type": { + "ty": 22, + "display_name": [ + 50 + ] + } + }, + { + "name": 43, + "indexed": false, + "type": { + "ty": 22, + "display_name": [ + 50 + ] + } + }, + { + "name": 8, + "indexed": false, + "type": { + "ty": 3, + "display_name": [ + 37 + ] + } + } + ], + "docs": [] + } + ], + "docs": [] + } +} diff --git a/packages/api-contract/test/contracts/FlipperV2.json b/packages/api-contract/test/contracts/FlipperV2.json new file mode 100644 index 0000000000..0ee77a64ec --- /dev/null +++ b/packages/api-contract/test/contracts/FlipperV2.json @@ -0,0 +1,201 @@ +{ + "registry": { + "strings": [ + "Flipper", + "flipper", + "normal", + "value", + "Value", + "ink_core", + "storage", + "cell", + "SyncCell", + "sync_cell", + "Key", + "key", + "flip", + "get" + ], + "types": [ + { + "id": { + "custom.name": 1, + "custom.namespace": [ + 2, + 3 + ], + "custom.params": [] + }, + "def": { + "struct.fields": [ + { + "name": 4, + "type": 2 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 4 + ], + "custom.params": [ + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 8, + "type": 4 + } + ] + } + }, + { + "id": "bool", + "def": "builtin" + }, + { + "id": { + "custom.name": 9, + "custom.namespace": [ + 6, + 7, + 8, + 10 + ], + "custom.params": [ + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 8, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 7, + 12 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 6 + ] + } + }, + { + "id": { + "array.len": 32, + "array.type": 7 + }, + "def": "builtin" + }, + { + "id": "u8", + "def": "builtin" + } + ] + }, + "storage": { + "struct.type": 1, + "struct.fields": [ + { + "name": 4, + "layout": { + "struct.type": 2, + "struct.fields": [ + { + "name": 8, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "range.len": 1, + "range.elem_type": 3 + } + } + ] + } + } + ] + }, + "contract": { + "name": 1, + "deploy": { + "args": [], + "docs": [ + "Initializes our state to `false` upon deploying our smart contract." + ] + }, + "messages": [ + { + "name": 13, + "selector": 970692492, + "mutates": true, + "args": [], + "return_type": null, + "docs": [ + "Flips the current state of our smart contract." + ] + }, + { + "name": 14, + "selector": 4266279973, + "mutates": false, + "args": [], + "return_type": 3, + "docs": [ + "Returns the current state." + ] + } + ], + "events": [], + "docs": [] + } +} diff --git a/packages/api-contract/test/contracts/SharedVecV2.json b/packages/api-contract/test/contracts/SharedVecV2.json new file mode 100644 index 0000000000..b3416dd53b --- /dev/null +++ b/packages/api-contract/test/contracts/SharedVecV2.json @@ -0,0 +1,935 @@ +{ + "registry": { + "strings": [ + "SharedVec", + "shared_vec", + "normal", + "mutators", + "HashMap", + "ink_core", + "storage", + "collections", + "hash_map", + "impls", + "AccountId", + "env", + "srml", + "types", + "Access", + "begin", + "Option", + "None", + "Some", + "end", + "len", + "Value", + "value", + "cell", + "SyncCell", + "sync_cell", + "Key", + "key", + "entries", + "SyncChunk", + "chunk", + "sync_chunk", + "Entry", + "Occupied", + "OccupiedEntry", + "val", + "Removed", + "cells_key", + "vec", + "Vec", + "cells", + "on_deploy", + "push", + "i32", + "Result", + "Ok", + "Err", + "register", + "mutator", + "set", + "at", + "u32", + "to", + "get", + "Mutate", + "Push", + "Register" + ], + "types": [ + { + "id": { + "custom.name": 1, + "custom.namespace": [ + 2, + 3 + ], + "custom.params": [] + }, + "def": { + "struct.fields": [ + { + "name": 4, + "type": 2 + }, + { + "name": 39, + "type": 15 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8, + 9, + 10 + ], + "custom.params": [ + 3, + 6 + ] + }, + "def": { + "struct.fields": [ + { + "name": 21, + "type": 9 + }, + { + "name": 29, + "type": 12 + } + ] + } + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 12, + 13, + 14 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 4 + ] + } + }, + { + "id": { + "array.len": 32, + "array.type": 5 + }, + "def": "builtin" + }, + { + "id": "u8", + "def": "builtin" + }, + { + "id": { + "custom.name": 15, + "custom.namespace": [ + 2 + ], + "custom.params": [] + }, + "def": { + "struct.fields": [ + { + "name": 16, + "type": 7 + }, + { + "name": 20, + "type": 7 + } + ] + } + }, + { + "id": { + "custom.name": 17, + "custom.namespace": [], + "custom.params": [ + 8 + ] + }, + "def": { + "enum.variants": [ + { + "unit_variant.name": 18 + }, + { + "tuple_struct_variant.name": 19, + "tuple_struct_variant.types": [ + 8 + ] + } + ] + } + }, + { + "id": "u32", + "def": "builtin" + }, + { + "id": { + "custom.name": 22, + "custom.namespace": [ + 6, + 7, + 23 + ], + "custom.params": [ + 8 + ] + }, + "def": { + "struct.fields": [ + { + "name": 24, + "type": 10 + } + ] + } + }, + { + "id": { + "custom.name": 25, + "custom.namespace": [ + 6, + 7, + 24, + 26 + ], + "custom.params": [ + 8 + ] + }, + "def": { + "struct.fields": [ + { + "name": 24, + "type": 11 + } + ] + } + }, + { + "id": { + "custom.name": 27, + "custom.namespace": [ + 6, + 7, + 28 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 4 + ] + } + }, + { + "id": { + "custom.name": 30, + "custom.namespace": [ + 6, + 7, + 31, + 32, + 31 + ], + "custom.params": [ + 13 + ] + }, + "def": { + "struct.fields": [ + { + "name": 38, + "type": 11 + } + ] + } + }, + { + "id": { + "custom.name": 33, + "custom.namespace": [ + 6, + 7, + 8, + 9, + 10 + ], + "custom.params": [ + 3, + 6 + ] + }, + "def": { + "enum.variants": [ + { + "tuple_struct_variant.name": 34, + "tuple_struct_variant.types": [ + 14 + ] + }, + { + "unit_variant.name": 37 + } + ] + } + }, + { + "id": { + "custom.name": 35, + "custom.namespace": [ + 6, + 7, + 8, + 9, + 10 + ], + "custom.params": [ + 3, + 6 + ] + }, + "def": { + "struct.fields": [ + { + "name": 28, + "type": 3 + }, + { + "name": 36, + "type": 6 + } + ] + } + }, + { + "id": { + "custom.name": 40, + "custom.namespace": [ + 6, + 7, + 8, + 39, + 10 + ], + "custom.params": [ + 16 + ] + }, + "def": { + "struct.fields": [ + { + "name": 21, + "type": 9 + }, + { + "name": 41, + "type": 17 + } + ] + } + }, + { + "id": "i32", + "def": "builtin" + }, + { + "id": { + "custom.name": 30, + "custom.namespace": [ + 6, + 7, + 31, + 32, + 31 + ], + "custom.params": [ + 16 + ] + }, + "def": { + "struct.fields": [ + { + "name": 38, + "type": 11 + } + ] + } + }, + { + "id": { + "custom.name": 45, + "custom.namespace": [], + "custom.params": [ + 19, + 8 + ] + }, + "def": { + "enum.variants": [ + { + "tuple_struct_variant.name": 46, + "tuple_struct_variant.types": [ + 19 + ] + }, + { + "tuple_struct_variant.name": 47, + "tuple_struct_variant.types": [ + 8 + ] + } + ] + } + }, + { + "id": [], + "def": "builtin" + }, + { + "id": { + "custom.name": 45, + "custom.namespace": [], + "custom.params": [ + 16, + 8 + ] + }, + "def": { + "enum.variants": [ + { + "tuple_struct_variant.name": 46, + "tuple_struct_variant.types": [ + 16 + ] + }, + { + "tuple_struct_variant.name": 47, + "tuple_struct_variant.types": [ + 8 + ] + } + ] + } + }, + { + "id": { + "custom.name": 17, + "custom.namespace": [], + "custom.params": [ + 16 + ] + }, + "def": { + "enum.variants": [ + { + "unit_variant.name": 18 + }, + { + "tuple_struct_variant.name": 19, + "tuple_struct_variant.types": [ + 16 + ] + } + ] + } + } + ] + }, + "storage": { + "struct.type": 1, + "struct.fields": [ + { + "name": 4, + "layout": { + "struct.type": 2, + "struct.fields": [ + { + "name": 21, + "layout": { + "struct.type": 9, + "struct.fields": [ + { + "name": 24, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "range.len": 1, + "range.elem_type": 8 + } + } + ] + } + }, + { + "name": 29, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + "range.len": 4294967295, + "range.elem_type": 13 + } + } + ] + } + }, + { + "name": 39, + "layout": { + "struct.type": 15, + "struct.fields": [ + { + "name": 21, + "layout": { + "struct.type": 9, + "struct.fields": [ + { + "name": 24, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0 + ], + "range.len": 1, + "range.elem_type": 8 + } + } + ] + } + }, + { + "name": 41, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1 + ], + "range.len": 4294967295, + "range.elem_type": 16 + } + } + ] + } + } + ] + }, + "contract": { + "name": 1, + "constructors": [ + { + "name": 42, + "selector": 0, + "args": [], + "docs": [ + "Initializes the value to the initial value." + ] + } + ], + "messages": [ + { + "name": 43, + "selector": 865577567, + "mutates": true, + "args": [ + { + "name": 23, + "type": { + "ty": 16, + "display_name": [ + 44 + ] + } + } + ], + "return_type": { + "ty": 18, + "display_name": [ + 45 + ] + }, + "docs": [ + "Pushes a new value to the shared vector.", + "", + "# Errors", + "", + "- If the caller does not have unlimited access rights." + ] + }, + { + "name": 48, + "selector": 572030971, + "mutates": true, + "args": [ + { + "name": 49, + "type": { + "ty": 3, + "display_name": [ + 11 + ] + } + }, + { + "name": 16, + "type": { + "ty": 7, + "display_name": [ + 17 + ] + } + }, + { + "name": 20, + "type": { + "ty": 7, + "display_name": [ + 17 + ] + } + } + ], + "return_type": { + "ty": 18, + "display_name": [ + 45 + ] + }, + "docs": [ + "Registers a new user with the given access rights.", + "", + "Can also be used to change access rights of an already existing user.", + "", + "# Errors", + "", + "- If the caller does not have unlimited access rights." + ] + }, + { + "name": 50, + "selector": 2028185770, + "mutates": true, + "args": [ + { + "name": 51, + "type": { + "ty": 8, + "display_name": [ + 52 + ] + } + }, + { + "name": 53, + "type": { + "ty": 16, + "display_name": [ + 44 + ] + } + } + ], + "return_type": { + "ty": 20, + "display_name": [ + 45 + ] + }, + "docs": [ + "Sets the value at the given position to the given value.", + "", + "Returns the previous value.", + "", + "# Errors", + "", + "- If the given position is out of bounds.", + "- If the caller does not have the required access rights." + ] + }, + { + "name": 54, + "selector": 4266279973, + "mutates": false, + "args": [ + { + "name": 51, + "type": { + "ty": 8, + "display_name": [ + 52 + ] + } + } + ], + "return_type": { + "ty": 21, + "display_name": [ + 17 + ] + }, + "docs": [ + "Returns the value of the shared vector at the given position", + "or `None` if the access is out of bounds." + ] + }, + { + "name": 21, + "selector": 1403873684, + "mutates": false, + "args": [], + "return_type": { + "ty": 8, + "display_name": [ + 52 + ] + }, + "docs": [ + "Returns the length of the shared vector." + ] + } + ], + "events": [ + { + "name": 55, + "args": [ + { + "name": 51, + "indexed": false, + "type": { + "ty": 8, + "display_name": [ + 52 + ] + } + }, + { + "name": 23, + "indexed": false, + "type": { + "ty": 16, + "display_name": [ + 44 + ] + } + } + ], + "docs": [ + "Fires whenever a mutator changes the vector." + ] + }, + { + "name": 56, + "args": [ + { + "name": 49, + "indexed": false, + "type": { + "ty": 3, + "display_name": [ + 11 + ] + } + }, + { + "name": 23, + "indexed": false, + "type": { + "ty": 16, + "display_name": [ + 44 + ] + } + } + ], + "docs": [ + "Fires whenever a mutator pushes the vector successfully." + ] + }, + { + "name": 57, + "args": [ + { + "name": 49, + "indexed": false, + "type": { + "ty": 3, + "display_name": [ + 11 + ] + } + }, + { + "name": 16, + "indexed": false, + "type": { + "ty": 7, + "display_name": [ + 17 + ] + } + }, + { + "name": 20, + "indexed": false, + "type": { + "ty": 7, + "display_name": [ + 17 + ] + } + } + ], + "docs": [ + "Fires whenever a new mutator is registered", + "or when a mutators access rights are changed." + ] + } + ], + "docs": [] + } +} diff --git a/packages/api-contract/test/contracts/V2.json b/packages/api-contract/test/contracts/V2.json new file mode 100644 index 0000000000..4bb8db38e7 --- /dev/null +++ b/packages/api-contract/test/contracts/V2.json @@ -0,0 +1,697 @@ +{ + "registry": { + "strings": [ + "RustStructures", + "structures", + "normal", + "my_tuple_struct", + "Value", + "ink_core", + "storage", + "value", + "TupleStruct", + "cell", + "SyncCell", + "sync_cell", + "Key", + "key", + "my_struct", + "Struct", + "first", + "seconds", + "my_clike_enum", + "ClikeEnum", + "FirstVariant", + "SecondVariant", + "ThirdVariant", + "my_enum", + "RustEnum", + "NoData", + "TupleVariant", + "StructVariant", + "second", + "my_union", + "Union" + ], + "types": [ + { + "id": { + "custom.name": 1, + "custom.namespace": [ + 2, + 3 + ], + "custom.params": [] + }, + "def": { + "struct.fields": [ + { + "name": 4, + "type": 2 + }, + { + "name": 15, + "type": 9 + }, + { + "name": 19, + "type": 12 + }, + { + "name": 24, + "type": 15 + }, + { + "name": 30, + "type": 18 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 6 + } + ] + } + }, + { + "id": { + "custom.name": 9, + "custom.namespace": [ + 2 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 4, + 5 + ] + } + }, + { + "id": "u8", + "def": "builtin" + }, + { + "id": "u16", + "def": "builtin" + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 7, + 10, + 12 + ], + "custom.params": [ + 3 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 7 + } + ] + } + }, + { + "id": { + "custom.name": 13, + "custom.namespace": [ + 6, + 7, + 14 + ], + "custom.params": [] + }, + "def": { + "tuple_struct.types": [ + 8 + ] + } + }, + { + "id": { + "array.len": 32, + "array.type": 4 + }, + "def": "builtin" + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 10 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 11 + } + ] + } + }, + { + "id": { + "custom.name": 16, + "custom.namespace": [ + 2 + ], + "custom.params": [] + }, + "def": { + "struct.fields": [ + { + "name": 17, + "type": 4 + }, + { + "name": 18, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 7, + 10, + 12 + ], + "custom.params": [ + 10 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 7 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 13 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 14 + } + ] + } + }, + { + "id": { + "custom.name": 20, + "custom.namespace": [ + 2 + ], + "custom.params": [] + }, + "def": { + "clike_enum.variants": [ + { + "name": 21, + "discriminant": 0 + }, + { + "name": 22, + "discriminant": 1 + }, + { + "name": 23, + "discriminant": 42 + } + ] + } + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 7, + 10, + 12 + ], + "custom.params": [ + 13 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 7 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 16 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 17 + } + ] + } + }, + { + "id": { + "custom.name": 25, + "custom.namespace": [ + 2 + ], + "custom.params": [] + }, + "def": { + "enum.variants": [ + { + "unit_variant.name": 26 + }, + { + "tuple_struct_variant.name": 27, + "tuple_struct_variant.types": [ + 4, + 5 + ] + }, + { + "struct_variant.name": 28, + "struct_variant.fields": [ + { + "name": 17, + "type": 4 + }, + { + "name": 29, + "type": 5 + } + ] + } + ] + } + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 7, + 10, + 12 + ], + "custom.params": [ + 16 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 7 + } + ] + } + }, + { + "id": { + "custom.name": 5, + "custom.namespace": [ + 6, + 7, + 8 + ], + "custom.params": [ + 19 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 20 + } + ] + } + }, + { + "id": { + "custom.name": 31, + "custom.namespace": [ + 2 + ], + "custom.params": [] + }, + "def": { + "union.fields": [ + { + "name": 17, + "type": 4 + }, + { + "name": 29, + "type": 5 + } + ] + } + }, + { + "id": { + "custom.name": 11, + "custom.namespace": [ + 6, + 7, + 10, + 12 + ], + "custom.params": [ + 19 + ] + }, + "def": { + "struct.fields": [ + { + "name": 10, + "type": 7 + } + ] + } + } + ] + }, + "storage": { + "struct.type": 1, + "struct.fields": [ + { + "name": 4, + "layout": { + "struct.type": 2, + "struct.fields": [ + { + "name": 10, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "range.len": 1, + "range.elem_type": 3 + } + } + ] + } + }, + { + "name": 15, + "layout": { + "struct.type": 9, + "struct.fields": [ + { + "name": 10, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + "range.len": 1, + "range.elem_type": 10 + } + } + ] + } + }, + { + "name": 19, + "layout": { + "struct.type": 12, + "struct.fields": [ + { + "name": 10, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2 + ], + "range.len": 1, + "range.elem_type": 13 + } + } + ] + } + }, + { + "name": 24, + "layout": { + "struct.type": 15, + "struct.fields": [ + { + "name": 10, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3 + ], + "range.len": 1, + "range.elem_type": 16 + } + } + ] + } + }, + { + "name": 30, + "layout": { + "struct.type": 18, + "struct.fields": [ + { + "name": 10, + "layout": { + "range.offset": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4 + ], + "range.len": 1, + "range.elem_type": 19 + } + } + ] + } + } + ] + }, + "contract": { + "name": 1, + "deploy": { + "args": [], + "docs": [] + }, + "messages": [], + "events": [], + "docs": [] + } +} diff --git a/packages/api/test/e2e/api/promise-contract.spec.ts b/packages/api/test/e2e/api/promise-contract.spec.ts index ae98419b68..82a5169da1 100644 --- a/packages/api/test/e2e/api/promise-contract.spec.ts +++ b/packages/api/test/e2e/api/promise-contract.spec.ts @@ -79,7 +79,7 @@ describeE2E({ return ( api.tx.contracts - .create(CREATION_FEE, MAX_GAS, codeHash, abi.deploy(randomStart)) + .create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart)) .signAndSend(keyring.dave, (result: SubmittableResult): void => { // console.error('create', JSON.stringify(result)); diff --git a/packages/api/test/e2e/rpc-core/child-storage.spec.ts b/packages/api/test/e2e/rpc-core/child-storage.spec.ts index a408fdde1f..4db6f5008b 100644 --- a/packages/api/test/e2e/rpc-core/child-storage.spec.ts +++ b/packages/api/test/e2e/rpc-core/child-storage.spec.ts @@ -84,7 +84,7 @@ describeE2E({ return ( api.tx.contracts - .create(CREATION_FEE, MAX_GAS, codeHash, abi.deploy(randomStart)) + .create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart)) .signAndSend(keyring.dave, (result: SubmittableResult): void => { if (result.status.isFinalized) { const record = result.findRecord('contracts', 'Instantiated'); diff --git a/packages/types/src/codec/create/getTypeClass.ts b/packages/types/src/codec/create/getTypeClass.ts index 513d8a1a7f..905f96cba9 100644 --- a/packages/types/src/codec/create/getTypeClass.ts +++ b/packages/types/src/codec/create/getTypeClass.ts @@ -66,7 +66,7 @@ const infoMapping: Record Constructor> = { [TypeDefInfo.Linkage]: (value: TypeDef): Constructor => Linkage.withKey(getSubType(value)), // eslint-disable-next-line @typescript-eslint/no-unused-vars - [TypeDefInfo.Null]: (value: TypeDef): Constructor => ClassOf('Null'), + [TypeDefInfo.Null]: (_: TypeDef): Constructor => ClassOf('Null'), [TypeDefInfo.Option]: (value: TypeDef): Constructor => Option.with(getSubType(value)), diff --git a/packages/types/src/codec/create/getTypeDef.ts b/packages/types/src/codec/create/getTypeDef.ts index 7e571b5b00..3fb6e8b90f 100644 --- a/packages/types/src/codec/create/getTypeDef.ts +++ b/packages/types/src/codec/create/getTypeDef.ts @@ -24,7 +24,7 @@ function _decodeEnum (value: TypeDef, details: string[] | Record })) : Object.entries(details).map(([name, type]): TypeDef => // eslint-disable-next-line @typescript-eslint/no-use-before-define - getTypeDef(type || 'Null', name) + getTypeDef(type || 'Null', { name }) ); return value; @@ -46,7 +46,7 @@ function _decodeSet (value: TypeDef, details: Record): TypeDef { // decode a struct, set or enum // eslint-disable-next-line @typescript-eslint/no-unused-vars -function _decodeStruct (value: TypeDef, type: string, subType: string): TypeDef { +function _decodeStruct (value: TypeDef, type: string, _: string): TypeDef { const parsed = JSON.parse(type); const keys = Object.keys(parsed); @@ -58,7 +58,7 @@ function _decodeStruct (value: TypeDef, type: string, subType: string): TypeDef value.sub = keys.map((name): TypeDef => // eslint-disable-next-line @typescript-eslint/no-use-before-define - getTypeDef(parsed[name], name) + getTypeDef(parsed[name], { name }) ); return value; @@ -66,7 +66,7 @@ function _decodeStruct (value: TypeDef, type: string, subType: string): TypeDef // decode a fixed vector, e.g. [u8;32] // eslint-disable-next-line @typescript-eslint/no-unused-vars -function _decodeFixedVec (value: TypeDef, type: string, subType: string): TypeDef { +function _decodeFixedVec (value: TypeDef, type: string, _: string): TypeDef { const [vecType, _vecLen] = type.substr(1, type.length - 2).split(';'); const vecLen = parseInt(_vecLen.trim(), 10); @@ -79,7 +79,7 @@ function _decodeFixedVec (value: TypeDef, type: string, subType: string): TypeDe } // decode a tuple -function _decodeTuple (value: TypeDef, type: string, subType: string): TypeDef { +function _decodeTuple (value: TypeDef, _: string, subType: string): TypeDef { value.sub = typeSplit(subType).map((inner): TypeDef => // eslint-disable-next-line @typescript-eslint/no-use-before-define getTypeDef(inner) @@ -118,10 +118,15 @@ function extractSubType (type: string, [start, end]: [string, string, TypeDefInf return type.substr(start.length, type.length - start.length - end.length); } -export function getTypeDef (_type: string, name?: string): TypeDef { +interface TypeDefOptions { + name?: string; + displayName?: string; +} + +export function getTypeDef (_type: string, { name, displayName }: TypeDefOptions = {}): TypeDef { // create the type via Type, allowing types to be sanitized const type = sanitize(_type); - const value: TypeDef = { info: TypeDefInfo.Plain, name, type }; + const value: TypeDef = { info: TypeDefInfo.Plain, displayName, name, type }; const nested = nestedExtraction.find((nested): boolean => hasWrapper(type, nested) diff --git a/packages/types/src/codec/create/types.ts b/packages/types/src/codec/create/types.ts index b35a55132b..ab0e7a3231 100644 --- a/packages/types/src/codec/create/types.ts +++ b/packages/types/src/codec/create/types.ts @@ -33,11 +33,122 @@ export interface TypeDefExtVecFixed { type: string; } +export interface TypeDefExtEnumDiscriminant { + discriminant: number; +} + export interface TypeDef { info: TypeDefInfo; index?: number; - ext?: TypeDefExtVecFixed; // add additional here as required + displayName?: string; + ext?: TypeDefExtVecFixed | TypeDefExtEnumDiscriminant; // add additional here as required name?: string; + namespace?: string; + params?: TypeDef[]; type: string; sub?: TypeDef | TypeDef[]; } + +export type TypeIndex = number; + +export type StringIndex = number; + +export enum MetaTypeInfo { + BuiltinPlain, + BuiltinTuple, + BuiltinArray, + Enum, + ClikeEnum, + Struct, + TupleStruct, + Null +} + +export type MetaTypeIdPrimitive = string; + +export type MetaTypeIdTuple = TypeIndex[]; + +export interface MetaTypeIdArray { + 'array.len': number; + 'array.type': TypeIndex; +} + +export interface MetaTypeIdCustom { + 'custom.name': StringIndex; + 'custom.namespace'?: StringIndex[]; + 'custom.params'?: TypeIndex[]; +} + +export type MetaTypeId = MetaTypeIdPrimitive | MetaTypeIdTuple | MetaTypeIdArray | MetaTypeIdCustom; +// MetaTypeIdPrimitive | MetaTypeIdTuple | MetaTypeIdArray | MetaTypeIdCustom; +// export type MetaTypeId = Record; + +export interface MetaTypeDefClikeEnumVariant { + name: StringIndex; + discriminant: number; +} + +export interface MetaTypeDefClikeEnum { + 'clike_enum.variants': MetaTypeDefClikeEnumVariant[]; +} + +export type MetaTypeDefBuiltIn = 'builtin'; + +export interface MetaTypeDefEnumVariantUnit { + 'unit_variant.name': StringIndex; +} + +export interface MetaTypeDefEnumVariantTupleStruct { + 'tuple_struct_variant.name': StringIndex; + 'tuple_struct_variant.types': TypeIndex[]; +} + +export interface MetaTypeDefEnumVariantStruct { + 'struct_variant.name': StringIndex; + 'struct_variant.fields': MetaTypeDefStructField[]; +} + +export type MetaTypeDefEnumVariant = MetaTypeDefEnumVariantUnit | MetaTypeDefEnumVariantTupleStruct | MetaTypeDefEnumVariantStruct; + +export interface MetaTypeDefEnum { + 'enum.variants': MetaTypeDefEnumVariant[]; +} + +export interface MetaTypeDefStructField { + name: StringIndex; + type: TypeIndex; +} + +export type MetaTypeDefUnionField = MetaTypeDefStructField; + +export interface MetaTypeDefStruct { + 'struct.fields': MetaTypeDefStructField[]; +} + +export interface MetaTypeDefTupleStruct { + 'tuple_struct.types': TypeIndex[]; +} + +export interface MetaTypeDefUnion { + 'union.fields': MetaTypeDefUnionField[]; +} + +export type MetaTypeDef = MetaTypeDefBuiltIn | MetaTypeDefClikeEnum | MetaTypeDefEnum | MetaTypeDefStruct | MetaTypeDefTupleStruct | MetaTypeDefUnion; + +export interface MetaType { + def: MetaTypeDef; + id: MetaTypeId | null; +} + +export enum MetaRegistryItem { + String, + Type, + TypeDef +} + +export interface MetaRegistryJson { + registry: { + strings: string[]; + types: MetaType[]; + }; +} diff --git a/packages/types/src/codec/index.ts b/packages/types/src/codec/index.ts index 7a0a24777a..4b3f18dd4c 100644 --- a/packages/types/src/codec/index.ts +++ b/packages/types/src/codec/index.ts @@ -25,3 +25,4 @@ export { default as UInt } from './UInt'; // Type management helper functions export * from './create'; +export * from './utils/encodeTypes'; diff --git a/packages/types/src/codec/utils/encodeTypes.ts b/packages/types/src/codec/utils/encodeTypes.ts new file mode 100644 index 0000000000..376cc9282a --- /dev/null +++ b/packages/types/src/codec/utils/encodeTypes.ts @@ -0,0 +1,171 @@ +// Copyright 2017-2019 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { TypeDef, TypeDefInfo, TypeDefExtVecFixed } from '../types'; + +import { assert } from '@polkadot/util'; + +import { getTypeDef } from '../create'; + +const SPECIAL_TYPES = ['AccountId', 'AccountIndex', 'Address', 'Balance']; + +export function paramsNotation (outer: string, inner?: string | any[], transform?: (_: any) => string): string { + let array; + if (inner) { + array = Array.isArray(inner) ? inner : [inner]; + + if (transform) { + array = array.map(transform); + } + } + return `${outer}${array ? `<${array.join(', ')}>` : ''}`; +} + +class TypeEncoder { + private static enum (typeDef: Pick): string { + assert(typeDef.sub && Array.isArray(typeDef.sub), 'Unable to encode Enum type'); + + const sub = typeDef.sub as TypeDef[]; + + const isClikeEnum = sub.reduce( + (bool: boolean, { type }: TypeDef): boolean => bool && type === 'Null', + true + ); + + if (isClikeEnum) { + return `[${ + sub + .map(({ name }: TypeDef): string => `"${name}"`) + .join(', ') + }]`; + } + + return this.subTypes(sub, true); + } + + private static struct (typeDef: Pick): string { + assert(typeDef.sub && Array.isArray(typeDef.sub), 'Unable to encode Struct type'); + + const sub = typeDef.sub as TypeDef[]; + + return this.subTypes(sub); + } + + private static tuple (typeDef: Pick): string { + assert(typeDef.sub && Array.isArray(typeDef.sub), 'Unable to encode Tuple type'); + + const sub = typeDef.sub as TypeDef[]; + + return `(${ + sub + .map((type: TypeDef): string => TypeEncoder.withParams(type)) + .join(', ') + })`; + } + + private static vecFixed (typeDef: Pick): string { + assert(typeDef.ext, 'Unable to encode VecFixed type'); + + const { type, length } = typeDef.ext as TypeDefExtVecFixed; + + return `[${ + this.withParams(getTypeDef(type)) + };${ + length + }]`; + } + + private static subTypes (sub: TypeDef[], asEnum?: boolean): string { + return `{ ${asEnum ? '"_enum": { ' : ''}${ + sub + .map((type: TypeDef): string => `"${type.name}": "${this.withParams(type)}"`) + .join(', ') + }} }`; + } + + private static withParams (typeDef: Pick, outer = typeDef.displayName || typeDef.type): string { + const { params } = typeDef; + + return paramsNotation( + outer, + params, + (param: TypeDef) => TypeEncoder.display(param) + ); + } + + public static encode (typeDef: Pick): string { + switch (typeDef.info) { + case TypeDefInfo.Null: { + return '()'; + } + case TypeDefInfo.Plain: { + return typeDef.displayName || typeDef.type; + } + case TypeDefInfo.Compact: { + return TypeEncoder.withParams(typeDef, 'Compact'); + } + case TypeDefInfo.DoubleMap: { + return TypeEncoder.withParams(typeDef, 'DoubleMap'); + } + case TypeDefInfo.Linkage: { + return TypeEncoder.withParams(typeDef, 'Linkage'); + } + case TypeDefInfo.Option: { + return TypeEncoder.withParams(typeDef, 'Option'); + } + case TypeDefInfo.Result: { + return TypeEncoder.withParams(typeDef, 'Result'); + } + case TypeDefInfo.Vec: { + return TypeEncoder.withParams(typeDef, 'Vec'); + } + case TypeDefInfo.Enum: { + return TypeEncoder.enum(typeDef); + } + case TypeDefInfo.Struct: { + return TypeEncoder.struct(typeDef); + } + case TypeDefInfo.Tuple: { + return TypeEncoder.tuple(typeDef); + } + case TypeDefInfo.VecFixed: { + return TypeEncoder.vecFixed(typeDef); + } + default: { + throw new Error(`Cannot encode type: ${typeDef}.`); + } + } + } + + public static display (typeDef: Pick): string { + if (typeDef.displayName) { + return TypeEncoder.withParams(typeDef); + } + + switch (typeDef.info) { + case TypeDefInfo.Struct: + case TypeDefInfo.Enum: + return TypeEncoder.withParams(typeDef); + default: + return TypeEncoder.encode(typeDef); + } + } +} + +export function encodeType (typeDef: Pick): string { + return TypeEncoder.encode(typeDef); +} + +export function displayType (typeDef: Pick): string { + return TypeEncoder.display(typeDef); +} + +export function withTypeString (typeDef: Pick): Pick { + return { + ...typeDef, + type: SPECIAL_TYPES.includes(typeDef.name) + ? typeDef.name + : encodeType(typeDef) + }; +} diff --git a/packages/types/src/codec/utils/index.ts b/packages/types/src/codec/utils/index.ts index afdbb4fa77..b067072e86 100644 --- a/packages/types/src/codec/utils/index.ts +++ b/packages/types/src/codec/utils/index.ts @@ -5,4 +5,5 @@ export { default as compareArray } from './compareArray'; export { default as compareMap } from './compareMap'; export { default as decodeU8a } from './decodeU8a'; +export * from './encodeTypes'; export * from './mapToTypeMap'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 80d03abd3b..d164e9de29 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -23,3 +23,4 @@ assertSingletonPackage('@polkadot/types'); export * from './codec'; export * from './index.types'; +export { formatType } from './scripts/util/formatting'; diff --git a/packages/types/src/scripts/generateTypes/tsDef.ts b/packages/types/src/scripts/generateTypes/tsDef.ts index 3f3fca62fb..91f0b17aa8 100644 --- a/packages/types/src/scripts/generateTypes/tsDef.ts +++ b/packages/types/src/scripts/generateTypes/tsDef.ts @@ -234,7 +234,7 @@ function generateInterfaces ({ types }: { types: Record }, imports: }; return Object.entries(types).map(([name, type]): [string, string] => { - const def = getTypeDef(isString(type) ? type.toString() : JSON.stringify(type), name); + const def = getTypeDef(isString(type) ? type.toString() : JSON.stringify(type), { name }); return [name, generators[def.info](def, imports)]; }); diff --git a/packages/types/src/scripts/util/formatting.ts b/packages/types/src/scripts/util/formatting.ts index fc9a51044e..d8bd48c1af 100644 --- a/packages/types/src/scripts/util/formatting.ts +++ b/packages/types/src/scripts/util/formatting.ts @@ -5,6 +5,7 @@ import { TypeDef, TypeDefInfo } from '../../codec/types'; import { getTypeDef } from '../../codec/create'; +import { paramsNotation } from '../../codec/utils'; import { setImports, TypeImports } from './imports'; export const HEADER = '// Auto-generated via `yarn build:interfaces`, do not edit\n/* eslint-disable @typescript-eslint/no-empty-interface */\n\n'; @@ -37,7 +38,7 @@ export function exportType (name = '', base: string): string { * Given the inner `T`, return a `Compact` string */ export function formatCompact (inner: string): string { - return `Compact<${inner}>`; + return paramsNotation('Compact', inner); } /** @@ -51,28 +52,33 @@ export function formatResult (innerOk: string, innerError: string): string { * Given the inner `T`, return a `Option` string */ export function formatOption (inner: string): string { - return `Option<${inner}>`; + return paramsNotation('Option', inner); } /** * Given the inners `T[]`, return a `ITuple<...T>` string */ export function formatTuple (inners: string[]): string { - return `ITuple<[${inners.join(', ')}]>`; + return paramsNotation('ITuple', `[${inners.join(', ')}]`); } /** * Given the inner `T`, return a `Vec` string */ export function formatVec (inner: string): string { - return `Vec<${inner}>`; + return paramsNotation('Vec', inner); } /** * Correctly format a given type */ -export function formatType (type: string, imports: TypeImports): string { - const typeDef = getTypeDef(type); +export function formatType (type: string | TypeDef, imports: TypeImports): string { + let typeDef; + if (typeof type === 'string') { + typeDef = getTypeDef(type); + } else { + typeDef = type; + } switch (typeDef.info) { case TypeDefInfo.Compact: { @@ -82,7 +88,7 @@ export function formatType (type: string, imports: TypeImports): string { return formatOption(formatType((typeDef.sub as TypeDef).type, imports)); } case TypeDefInfo.Plain: { - return type; + return typeDef.type; } case TypeDefInfo.Vec: { return formatVec(formatType((typeDef.sub as TypeDef).type, imports));