Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add suport for latest ink! metadata #5650

Merged
merged 11 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions packages/api-contract/src/Abi/custom_env.json

Large diffs are not rendered by default.

58 changes: 49 additions & 9 deletions packages/api-contract/src/Abi/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2017-2023 @polkadot/api-contract authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { Bytes } from '@polkadot/types';
import type { ChainProperties, ContractConstructorSpecLatest, ContractEventSpecLatest, ContractMessageParamSpecLatest, ContractMessageSpecLatest, ContractMetadata, ContractMetadataLatest, ContractProjectInfo } from '@polkadot/types/interfaces';
import type { Bytes, PortableRegistry } from '@polkadot/types';
import type { ChainProperties, ContractConstructorSpecLatest, ContractEnvironment, ContractEventSpecLatest, ContractMessageParamSpecLatest, ContractMessageSpecLatest, ContractMetadata, ContractMetadataLatest, ContractProjectInfo } from '@polkadot/types/interfaces';
import type { Codec, Registry } from '@polkadot/types/types';
import type { AbiConstructor, AbiEvent, AbiMessage, AbiParam, DecodedEvent, DecodedMessage } from '../types.js';

Expand Down Expand Up @@ -53,7 +53,23 @@ function getLatestMeta (registry: Registry, json: Record<string, unknown>): Cont
return converter[1](registry, metadata[`as${converter[0]}`]);
}

function parseJson (json: Record<string, unknown>, chainProperties?: ChainProperties): [Record<string, unknown>, Registry, ContractMetadataLatest, ContractProjectInfo] {
function getEnvTypes (env: ContractEnvironment | undefined, lookup: PortableRegistry) {
if (env) {
const keys = Object.keys(env);

return Object.values(env).map((t: unknown, i) => {
if (typeof t === 'object' && t !== null && 'type' in t) {
return { [keys[i]]: lookup.getTypeDef(t.type as number) };
}

return { [keys[i]]: t };
});
}

return [];
}

function parseJson (json: Record<string, unknown>, chainProperties?: ChainProperties): [Record<string, unknown>, Registry, ContractMetadataLatest, ContractProjectInfo, { [x: string]: unknown }[]] {
const registry = new TypeRegistry();
const info = registry.createType('ContractProjectInfo', json) as unknown as ContractProjectInfo;
const latest = getLatestMeta(registry, json);
Expand All @@ -71,7 +87,17 @@ function parseJson (json: Record<string, unknown>, chainProperties?: ChainProper
lookup.getTypeDef(id)
);

return [json, registry, latest, info];
let env: { [x: string]: unknown }[] = [];

try {
const { spec: { environment } } = json as unknown as ContractMetadataLatest;

env = getEnvTypes(environment, lookup);
} catch (e) {
console.error(e);
}

return [json, registry, latest, info, env];
}

export class Abi {
Expand All @@ -82,27 +108,38 @@ export class Abi {
readonly messages: AbiMessage[];
readonly metadata: ContractMetadataLatest;
readonly registry: Registry;
readonly environment?: { [x: string]: unknown }[];

constructor (abiJson: Record<string, unknown> | string, chainProperties?: ChainProperties) {
[this.json, this.registry, this.metadata, this.info] = parseJson(
[this.json, this.registry, this.metadata, this.info, this.environment] = parseJson(
isString(abiJson)
? JSON.parse(abiJson) as Record<string, unknown>
: abiJson,
chainProperties
);
this.constructors = this.metadata.spec.constructors.map((spec: ContractConstructorSpecLatest, index) =>
this.#createMessage(spec, index, {
this.constructors = this.metadata.spec.constructors.map((spec: ContractConstructorSpecLatest, index) => {
const isDefault = 'default' in spec ? spec.default.isTrue : undefined;
const typeSpec = 'returnType' in spec ? spec.returnType.unwrapOr(null) : null;

return this.#createMessage(spec, index, {
isConstructor: true,
isPayable: spec.payable.isTrue
})
isDefault,
isPayable: spec.payable.isTrue,
returnType: typeSpec
? this.registry.lookup.getTypeDef(typeSpec.type)
: null
});
}
);
this.events = this.metadata.spec.events.map((spec: ContractEventSpecLatest, index) =>
this.#createEvent(spec, index)
);
this.messages = this.metadata.spec.messages.map((spec: ContractMessageSpecLatest, index): AbiMessage => {
const typeSpec = spec.returnType.unwrapOr(null);
const isDefault = 'default' in spec ? spec.default.isTrue : undefined;

return this.#createMessage(spec, index, {
isDefault,
isMutating: spec.mutates.isTrue,
isPayable: spec.payable.isTrue,
returnType: typeSpec
Expand Down Expand Up @@ -205,6 +242,8 @@ export class Abi {
#createMessage = (spec: ContractMessageSpecLatest | ContractConstructorSpecLatest, index: number, add: Partial<AbiMessage> = {}): AbiMessage => {
const args = this.#createArgs(spec.args, spec);
const identifier = spec.label.toString();
const isDefault = 'default' in spec ? spec.default.isTrue : undefined;

const message = {
...add,
args,
Expand All @@ -215,6 +254,7 @@ export class Abi {
}),
identifier,
index,
isDefault,
method: stringCamelCase(identifier),
path: identifier.split('::').map((s) => stringCamelCase(s)),
selector: spec.selector,
Expand Down
6 changes: 4 additions & 2 deletions packages/api-contract/src/Abi/toV4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
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;
import { objectSpread } from '@polkadot/util';

export function v3ToV4 (registry: Registry, v3: ContractMetadataV3): ContractMetadataV4 {
return registry.createType('ContractMetadataV4', objectSpread({}, v3));
}
1 change: 1 addition & 0 deletions packages/api-contract/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface AbiMessage {
identifier: string;
index: number;
isConstructor?: boolean;
isDefault?: boolean;
isMutating?: boolean;
isPayable?: boolean;
method: string;
Expand Down
5 changes: 4 additions & 1 deletion packages/types-augment/src/registry/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, ContractExecResultU64, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractInstantiateResultU64, 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, 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 { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractConstructorSpecV4, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEnvironment, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMessageSpecV3, 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';
Expand Down Expand Up @@ -253,6 +253,7 @@ declare module '@polkadot/types/types/registry' {
ContractConstructorSpecV1: ContractConstructorSpecV1;
ContractConstructorSpecV2: ContractConstructorSpecV2;
ContractConstructorSpecV3: ContractConstructorSpecV3;
ContractConstructorSpecV4: ContractConstructorSpecV4;
ContractContractSpecV0: ContractContractSpecV0;
ContractContractSpecV1: ContractContractSpecV1;
ContractContractSpecV2: ContractContractSpecV2;
Expand All @@ -261,6 +262,7 @@ declare module '@polkadot/types/types/registry' {
ContractCryptoHasher: ContractCryptoHasher;
ContractDiscriminant: ContractDiscriminant;
ContractDisplayName: ContractDisplayName;
ContractEnvironment: ContractEnvironment;
ContractEventParamSpecLatest: ContractEventParamSpecLatest;
ContractEventParamSpecV0: ContractEventParamSpecV0;
ContractEventParamSpecV2: ContractEventParamSpecV2;
Expand Down Expand Up @@ -297,6 +299,7 @@ declare module '@polkadot/types/types/registry' {
ContractMessageSpecV0: ContractMessageSpecV0;
ContractMessageSpecV1: ContractMessageSpecV1;
ContractMessageSpecV2: ContractMessageSpecV2;
ContractMessageSpecV3: ContractMessageSpecV3;
ContractMetadata: ContractMetadata;
ContractMetadataLatest: ContractMetadataLatest;
ContractMetadataV0: ContractMetadataV0;
Expand Down
47 changes: 43 additions & 4 deletions packages/types/src/interfaces/contractsAbi/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ const spec = {
args: 'Vec<ContractMessageParamSpecV2>',
docs: 'Vec<Text>'
},
ContractConstructorSpecV4: {
label: 'Text',
selector: 'ContractSelector',
payable: 'bool',
args: 'Vec<ContractMessageParamSpecV2>',
docs: 'Vec<Text>',
default: 'bool',
returnType: 'Option<ContractTypeSpec>'
},
ContractContractSpecV0: {
constructors: 'Vec<ContractConstructorSpecV0>',
messages: 'Vec<ContractMessageSpecV0>',
Expand All @@ -104,7 +113,14 @@ const spec = {
events: 'Vec<ContractEventSpecV2>',
docs: 'Vec<Text>'
},
ContractContractSpecV4: 'ContractContractSpecV3',
ContractContractSpecV4: {
constructors: 'Vec<ContractConstructorSpecV4>',
messages: 'Vec<ContractMessageSpecV3>',
events: 'Vec<ContractEventSpecV2>',
docs: 'Vec<Text>',
environment: 'ContractEnvironment'
},

ContractDisplayName: 'SiPath',
ContractEventParamSpecV0: {
name: 'Text',
Expand Down Expand Up @@ -168,6 +184,16 @@ const spec = {
returnType: 'Option<ContractTypeSpec>',
docs: 'Vec<Text>'
},
ContractMessageSpecV3: {
label: 'Text',
selector: 'ContractSelector',
mutates: 'bool',
payable: 'bool',
args: 'Vec<ContractMessageParamSpecV2>',
returnType: 'Option<ContractTypeSpec>',
docs: 'Vec<Text>',
default: 'bool'
},
ContractSelector: '[u8; 4]',
ContractTypeSpec: {
type: 'SiLookupTypeId',
Expand All @@ -176,11 +202,11 @@ const spec = {
};

const latest = {
ContractConstructorSpecLatest: 'ContractConstructorSpecV3',
ContractConstructorSpecLatest: 'ContractConstructorSpecV4',
ContractEventSpecLatest: 'ContractEventSpecV2',
ContractEventParamSpecLatest: 'ContractEventParamSpecV2',
ContractMessageParamSpecLatest: 'ContractMessageParamSpecV2',
ContractMessageSpecLatest: 'ContractMessageSpecV2',
ContractMessageSpecLatest: 'ContractMessageSpecV3',
ContractMetadataLatest: 'ContractMetadataV4'
};

Expand Down Expand Up @@ -211,7 +237,10 @@ export default {
types: 'Vec<PortableType>',
spec: 'ContractContractSpecV3'
},
ContractMetadataV4: 'ContractMetadataV3',
ContractMetadataV4: {
types: 'Vec<PortableType>',
spec: 'ContractContractSpecV4'
},
ContractMetadata: {
_enum: {
V0: 'ContractMetadataV0',
Expand Down Expand Up @@ -250,6 +279,16 @@ export default {
language: 'Text',
compiler: 'Text',
wasm: 'Raw'
},
ContractEnvironment: {
_alias: {
hashType: 'hash'
},
accountId: 'ContractTypeSpec',
balance: 'ContractTypeSpec',
blockNumber: 'ContractTypeSpec',
hashType: 'ContractTypeSpec',
timestamp: 'ContractTypeSpec'
}
}
} as Definitions;
49 changes: 45 additions & 4 deletions packages/types/src/interfaces/contractsAbi/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { PortableType } from '@polkadot/types/interfaces/metadata';
import type { Si0Type, SiLookupTypeId, SiPath } from '@polkadot/types/interfaces/scaleInfo';

/** @name ContractConstructorSpecLatest */
export interface ContractConstructorSpecLatest extends ContractConstructorSpecV3 {}
export interface ContractConstructorSpecLatest extends ContractConstructorSpecV4 {}

/** @name ContractConstructorSpecV0 */
export interface ContractConstructorSpecV0 extends Struct {
Expand Down Expand Up @@ -42,6 +42,17 @@ export interface ContractConstructorSpecV3 extends Struct {
readonly docs: Vec<Text>;
}

/** @name ContractConstructorSpecV4 */
export interface ContractConstructorSpecV4 extends Struct {
readonly label: Text;
readonly selector: ContractSelector;
readonly payable: bool;
readonly args: Vec<ContractMessageParamSpecV2>;
readonly docs: Vec<Text>;
readonly default: bool;
readonly returnType: Option<ContractTypeSpec>;
}

/** @name ContractContractSpecV0 */
export interface ContractContractSpecV0 extends Struct {
readonly constructors: Vec<ContractConstructorSpecV0>;
Expand Down Expand Up @@ -75,7 +86,13 @@ export interface ContractContractSpecV3 extends Struct {
}

/** @name ContractContractSpecV4 */
export interface ContractContractSpecV4 extends ContractContractSpecV3 {}
export interface ContractContractSpecV4 extends Struct {
readonly constructors: Vec<ContractConstructorSpecV4>;
readonly messages: Vec<ContractMessageSpecV3>;
readonly events: Vec<ContractEventSpecV2>;
readonly docs: Vec<Text>;
readonly environment: ContractEnvironment;
}

/** @name ContractCryptoHasher */
export interface ContractCryptoHasher extends Enum {
Expand All @@ -91,6 +108,15 @@ export interface ContractDiscriminant extends u32 {}
/** @name ContractDisplayName */
export interface ContractDisplayName extends SiPath {}

/** @name ContractEnvironment */
export interface ContractEnvironment extends Struct {
readonly accountId: ContractTypeSpec;
readonly balance: ContractTypeSpec;
readonly blockNumber: ContractTypeSpec;
readonly hashType: ContractTypeSpec;
readonly timestamp: ContractTypeSpec;
}

/** @name ContractEventParamSpecLatest */
export interface ContractEventParamSpecLatest extends ContractEventParamSpecV2 {}

Expand Down Expand Up @@ -198,7 +224,7 @@ export interface ContractMessageParamSpecV2 extends Struct {
}

/** @name ContractMessageSpecLatest */
export interface ContractMessageSpecLatest extends ContractMessageSpecV2 {}
export interface ContractMessageSpecLatest extends ContractMessageSpecV3 {}

/** @name ContractMessageSpecV0 */
export interface ContractMessageSpecV0 extends Struct {
Expand Down Expand Up @@ -233,6 +259,18 @@ export interface ContractMessageSpecV2 extends Struct {
readonly docs: Vec<Text>;
}

/** @name ContractMessageSpecV3 */
export interface ContractMessageSpecV3 extends Struct {
readonly label: Text;
readonly selector: ContractSelector;
readonly mutates: bool;
readonly payable: bool;
readonly args: Vec<ContractMessageParamSpecV2>;
readonly returnType: Option<ContractTypeSpec>;
readonly docs: Vec<Text>;
readonly default: bool;
}

/** @name ContractMetadata */
export interface ContractMetadata extends Enum {
readonly isV0: boolean;
Expand Down Expand Up @@ -277,7 +315,10 @@ export interface ContractMetadataV3 extends Struct {
}

/** @name ContractMetadataV4 */
export interface ContractMetadataV4 extends ContractMetadataV3 {}
export interface ContractMetadataV4 extends Struct {
readonly types: Vec<PortableType>;
readonly spec: ContractContractSpecV4;
}

/** @name ContractProject */
export interface ContractProject extends ITuple<[ContractProjectInfo, ContractMetadata]> {}
Expand Down