From 79da77234e2ee2ed2e4c7b15af56babf683c6777 Mon Sep 17 00:00:00 2001 From: Jaco Date: Fri, 2 Sep 2022 08:25:12 +0300 Subject: [PATCH] Support for ink! v4 metadata (#5195) * Support for ink! v4 metadata * Adjust * Export v4ToLatest * Adjust expectations --- CHANGELOG.md | 1 + packages/api-contract/src/Abi/Abi.spec.ts | 5 ++++- packages/api-contract/src/Abi/index.ts | 17 ++++++++++++++--- packages/api-contract/src/Abi/toLatest.spec.ts | 17 ++++++++++++++++- packages/api-contract/src/Abi/toLatest.ts | 11 +++++++---- packages/api-contract/src/Abi/toV4.ts | 9 +++++++++ .../compare/ink_v4_flipperContract.test.json | 9 +++++++++ .../compare/ink_v4_flipperMetadata.test.json | 9 +++++++++ .../src/test/contracts/ink/index.ts | 4 ++-- .../types-augment/src/registry/interfaces.ts | 4 +++- .../src/interfaces/contractsAbi/definitions.ts | 9 +++++++-- .../types/src/interfaces/contractsAbi/types.ts | 15 +++++++++++++-- 12 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 packages/api-contract/src/Abi/toV4.ts create mode 100644 packages/api-contract/src/test/compare/ink_v4_flipperContract.test.json create mode 100644 packages/api-contract/src/test/compare/ink_v4_flipperMetadata.test.json diff --git a/CHANGELOG.md b/CHANGELOG.md index ca2ed2de36..5b44f5fc3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Changes: +- Support for ink! v4 metadata - Adjust `pendingRewards` for pools runtime calls - Support for `AccountId33` (raw/compressed 33-byte ecdsa) - Update to latest Substrate, Polkadot & Kusama metadata diff --git a/packages/api-contract/src/Abi/Abi.spec.ts b/packages/api-contract/src/Abi/Abi.spec.ts index 2c9c6c8d7a..b048df9876 100644 --- a/packages/api-contract/src/Abi/Abi.spec.ts +++ b/packages/api-contract/src/Abi/Abi.spec.ts @@ -35,6 +35,9 @@ interface JSONAbi { }, V3: { spec: SpecDef; + }, + V4: { + spec: SpecDef; } } @@ -59,7 +62,7 @@ describe('Abi', (): void => { it(`initializes from a contract ABI (${abiName})`, (): void => { try { - const messageIds = (abi.V3 || abi.V2 || abi.V1 || abi).spec.messages.map(({ label, name }) => + const messageIds = (abi.V4 || abi.V3 || abi.V2 || abi.V1 || abi).spec.messages.map(({ label, name }) => label || ( Array.isArray(name) ? name.join('::') diff --git a/packages/api-contract/src/Abi/index.ts b/packages/api-contract/src/Abi/index.ts index fd4bd29bd1..ed013b8918 100644 --- a/packages/api-contract/src/Abi/index.ts +++ b/packages/api-contract/src/Abi/index.ts @@ -27,12 +27,23 @@ function findMessage (list: T[], messageOrId: T | string } function getLatestMeta (registry: Registry, json: Record): ContractMetadataLatest { + // this is for V1, V2, V3 const vx = enumVersions.find((v) => isObject(json[v])); - const metadata = registry.createType('ContractMetadata', + + // this was added in V4 + const jsonVersion = json.version as string; + + if (!vx && jsonVersion && !enumVersions.find((v) => v === `V${jsonVersion}`)) { + throw new Error(`Unable to handle version ${jsonVersion}`); + } + + const metadata = registry.createType('ContractMetadata', vx ? { [vx]: json[vx] } - : { V0: json } - ) as unknown as ContractMetadata; + : jsonVersion + ? { [`V${jsonVersion}`]: json } + : { V0: json } + ); const converter = convertVersions.find(([v]) => metadata[`is${v}`]); if (!converter) { diff --git a/packages/api-contract/src/Abi/toLatest.spec.ts b/packages/api-contract/src/Abi/toLatest.spec.ts index cd311879be..ecce86e526 100644 --- a/packages/api-contract/src/Abi/toLatest.spec.ts +++ b/packages/api-contract/src/Abi/toLatest.spec.ts @@ -1,10 +1,10 @@ // Copyright 2017-2022 @polkadot/api-contract authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { v0ToLatest, v1ToLatest, v2ToLatest, v3ToLatest } from '@polkadot/api-contract/Abi/toLatest'; import { TypeRegistry } from '@polkadot/types'; import abis from '../test/contracts'; +import { v0ToLatest, v1ToLatest, v2ToLatest, v3ToLatest, v4ToLatest } from './toLatest'; describe('v0ToLatest', (): void => { const registry = new TypeRegistry(); @@ -120,3 +120,18 @@ describe('v3ToLatest', (): void => { ]); }); }); + +describe('v4ToLatest', (): void => { + const registry = new TypeRegistry(); + const contract = registry.createType('ContractMetadata', { V4: abis.ink_v4_flipperContract }); + const latest = v4ToLatest(registry, contract.asV4); + + it('has the correct constructor flags', (): void => { + expect( + latest.spec.constructors[0].payable.isTrue + ).toEqual(false); + expect( + latest.spec.constructors[1].payable.isTrue + ).toEqual(false); + }); +}); diff --git a/packages/api-contract/src/Abi/toLatest.ts b/packages/api-contract/src/Abi/toLatest.ts index 46a4c23dfd..c13ea7bbcc 100644 --- a/packages/api-contract/src/Abi/toLatest.ts +++ b/packages/api-contract/src/Abi/toLatest.ts @@ -1,16 +1,17 @@ // Copyright 2017-2022 @polkadot/api-contract authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { ContractMetadataLatest, ContractMetadataV3 } from '@polkadot/types/interfaces'; +import type { ContractMetadataLatest, ContractMetadataV4 } from '@polkadot/types/interfaces'; import type { Registry } from '@polkadot/types/types'; import { v0ToV1 } from './toV1'; import { v1ToV2 } from './toV2'; import { v2ToV3 } from './toV3'; +import { v3ToV4 } from './toV4'; // The versions where an enum is used, aka V0 is missing // (Order from newest, i.e. we expect more on newest vs oldest) -export const enumVersions = ['V3', 'V2', 'V1']; +export const enumVersions = ['V4', 'V3', 'V2', 'V1']; type Versions = typeof enumVersions[number] | 'V0'; @@ -22,15 +23,17 @@ function createConverter (next: (registry: Registry, input: O) => Contrac next(registry, step(registry, input)); } -export function v3ToLatest (registry: Registry, v3: ContractMetadataV3): ContractMetadataLatest { - return v3; +export function v4ToLatest (registry: Registry, v4: ContractMetadataV4): ContractMetadataLatest { + return v4; } +export const v3ToLatest = createConverter(v4ToLatest, v3ToV4); export const v2ToLatest = createConverter(v3ToLatest, v2ToV3); export const v1ToLatest = createConverter(v2ToLatest, v1ToV2); export const v0ToLatest = createConverter(v1ToLatest, v0ToV1); export const convertVersions: [Versions, Converter][] = [ + ['V4', v4ToLatest], ['V3', v3ToLatest], ['V2', v2ToLatest], ['V1', v1ToLatest], diff --git a/packages/api-contract/src/Abi/toV4.ts b/packages/api-contract/src/Abi/toV4.ts new file mode 100644 index 0000000000..12db921d4d --- /dev/null +++ b/packages/api-contract/src/Abi/toV4.ts @@ -0,0 +1,9 @@ +// Copyright 2017-2022 @polkadot/api-contract authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { ContractMetadataV3, ContractMetadataV4 } from '@polkadot/types/interfaces'; +import type { Registry } from '@polkadot/types/types'; + +export function v3ToV4 (registry: Registry, v3: ContractMetadataV3): ContractMetadataV4 { + return v3; +} diff --git a/packages/api-contract/src/test/compare/ink_v4_flipperContract.test.json b/packages/api-contract/src/test/compare/ink_v4_flipperContract.test.json new file mode 100644 index 0000000000..e7e9211fa2 --- /dev/null +++ b/packages/api-contract/src/test/compare/ink_v4_flipperContract.test.json @@ -0,0 +1,9 @@ +[ + { + "info": "Plain", + "lookupIndex": 0, + "type": "bool", + "docs": [], + "namespace": "" + } +] \ No newline at end of file diff --git a/packages/api-contract/src/test/compare/ink_v4_flipperMetadata.test.json b/packages/api-contract/src/test/compare/ink_v4_flipperMetadata.test.json new file mode 100644 index 0000000000..e7e9211fa2 --- /dev/null +++ b/packages/api-contract/src/test/compare/ink_v4_flipperMetadata.test.json @@ -0,0 +1,9 @@ +[ + { + "info": "Plain", + "lookupIndex": 0, + "type": "bool", + "docs": [], + "namespace": "" + } +] \ No newline at end of file diff --git a/packages/api-contract/src/test/contracts/ink/index.ts b/packages/api-contract/src/test/contracts/ink/index.ts index ce076a2181..9514b8b579 100644 --- a/packages/api-contract/src/test/contracts/ink/index.ts +++ b/packages/api-contract/src/test/contracts/ink/index.ts @@ -6,6 +6,6 @@ import * as v0 from './v0'; import * as v1 from './v1'; import * as v2 from './v2'; import * as v3 from './v3'; -// import * as v4 from './v4'; +import * as v4 from './v4'; -export default createVersionedExport({ v0, v1, v2, v3 }); +export default createVersionedExport({ v0, v1, v2, v3, v4 }); diff --git a/packages/types-augment/src/registry/interfaces.ts b/packages/types-augment/src/registry/interfaces.ts index be57e64572..198a9ead4a 100644 --- a/packages/types-augment/src/registry/interfaces.ts +++ b/packages/types-augment/src/registry/interfaces.ts @@ -24,7 +24,7 @@ import type { StatementKind } from '@polkadot/types/interfaces/claims'; import type { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective'; import type { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus'; import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; -import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi'; +import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractMetadataV4, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi'; import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan'; import type { CollationInfo, CollationInfoV1, ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus'; import type { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy'; @@ -253,6 +253,7 @@ declare module '@polkadot/types/types/registry' { ContractContractSpecV1: ContractContractSpecV1; ContractContractSpecV2: ContractContractSpecV2; ContractContractSpecV3: ContractContractSpecV3; + ContractContractSpecV4: ContractContractSpecV4; ContractCryptoHasher: ContractCryptoHasher; ContractDiscriminant: ContractDiscriminant; ContractDisplayName: ContractDisplayName; @@ -296,6 +297,7 @@ declare module '@polkadot/types/types/registry' { ContractMetadataV1: ContractMetadataV1; ContractMetadataV2: ContractMetadataV2; ContractMetadataV3: ContractMetadataV3; + ContractMetadataV4: ContractMetadataV4; ContractProject: ContractProject; ContractProjectContract: ContractProjectContract; ContractProjectInfo: ContractProjectInfo; diff --git a/packages/types/src/interfaces/contractsAbi/definitions.ts b/packages/types/src/interfaces/contractsAbi/definitions.ts index 20d2430aa5..904bd1130c 100644 --- a/packages/types/src/interfaces/contractsAbi/definitions.ts +++ b/packages/types/src/interfaces/contractsAbi/definitions.ts @@ -106,6 +106,7 @@ const spec = { events: 'Vec', docs: 'Vec' }, + ContractContractSpecV4: 'ContractContractSpecV3', ContractDisplayName: 'SiPath', ContractEventParamSpecV0: { name: 'Text', @@ -197,6 +198,8 @@ const ContractMetadataV3 = { spec: 'ContractContractSpecV3' }; +const ContractMetadataV4 = ContractMetadataV3; + const ContractProjectInfo = { source: 'ContractProjectSource', contract: 'ContractProjectContract' @@ -208,7 +211,7 @@ const latest = { ContractEventParamSpecLatest: 'ContractEventParamSpecV2', ContractMessageParamSpecLatest: 'ContractMessageParamSpecV2', ContractMessageSpecLatest: 'ContractMessageSpecV2', - ContractMetadataLatest: 'ContractMetadataV3' + ContractMetadataLatest: 'ContractMetadataV4' }; export default { @@ -219,12 +222,14 @@ export default { ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, + ContractMetadataV4, ContractMetadata: { _enum: { V0: 'ContractMetadataV0', V1: 'ContractMetadataV1', V2: 'ContractMetadataV2', - V3: 'ContractMetadataV3' + V3: 'ContractMetadataV3', + V4: 'ContractMetadataV4' } }, ContractProjectV0: objectSpread({ metadataVersion: 'Text' }, ContractProjectInfo, ContractMetadataV0), diff --git a/packages/types/src/interfaces/contractsAbi/types.ts b/packages/types/src/interfaces/contractsAbi/types.ts index 39e411a42f..f58598897b 100644 --- a/packages/types/src/interfaces/contractsAbi/types.ts +++ b/packages/types/src/interfaces/contractsAbi/types.ts @@ -74,6 +74,9 @@ export interface ContractContractSpecV3 extends Struct { readonly docs: Vec; } +/** @name ContractContractSpecV4 */ +export interface ContractContractSpecV4 extends ContractContractSpecV3 {} + /** @name ContractCryptoHasher */ export interface ContractCryptoHasher extends Enum { readonly isBlake2x256: boolean; @@ -240,11 +243,13 @@ export interface ContractMetadata extends Enum { readonly asV2: ContractMetadataV2; readonly isV3: boolean; readonly asV3: ContractMetadataV3; - readonly type: 'V0' | 'V1' | 'V2' | 'V3'; + readonly isV4: boolean; + readonly asV4: ContractMetadataV4; + readonly type: 'V0' | 'V1' | 'V2' | 'V3' | 'V4'; } /** @name ContractMetadataLatest */ -export interface ContractMetadataLatest extends ContractMetadataV3 {} +export interface ContractMetadataLatest extends ContractMetadataV4 {} /** @name ContractMetadataV0 */ export interface ContractMetadataV0 extends Struct { @@ -271,6 +276,12 @@ export interface ContractMetadataV3 extends Struct { readonly spec: ContractContractSpecV3; } +/** @name ContractMetadataV4 */ +export interface ContractMetadataV4 extends Struct { + readonly types: Vec; + readonly spec: ContractContractSpecV3; +} + /** @name ContractProject */ export interface ContractProject extends ITuple<[ContractProjectInfo, ContractMetadata]> {}