Skip to content

Commit 0be50b2

Browse files
authored
Add suport for latest ink! metadata (#5650)
* add v5 * add environment * tov5 * use correct version * decode env types * fix tests * remove unnecesary checks * update fixtures * add maxEventTopics * get type defs for environment * fix conversion to v4
1 parent 2f07e1c commit 0be50b2

File tree

11 files changed

+741
-139
lines changed

11 files changed

+741
-139
lines changed

packages/api-contract/src/Abi/index.ts

+28-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import type { Bytes } from '@polkadot/types';
55
import type { ChainProperties, ContractConstructorSpecLatest, ContractEventSpecLatest, ContractMessageParamSpecLatest, ContractMessageSpecLatest, ContractMetadata, ContractMetadataLatest, ContractProjectInfo } from '@polkadot/types/interfaces';
6-
import type { Codec, Registry } from '@polkadot/types/types';
6+
import type { Codec, Registry, TypeDef } from '@polkadot/types/types';
77
import type { AbiConstructor, AbiEvent, AbiMessage, AbiParam, DecodedEvent, DecodedMessage } from '../types.js';
88

99
import { TypeRegistry } from '@polkadot/types';
@@ -82,6 +82,7 @@ export class Abi {
8282
readonly messages: AbiMessage[];
8383
readonly metadata: ContractMetadataLatest;
8484
readonly registry: Registry;
85+
readonly environment: Map<string, TypeDef | number> = new Map();
8586

8687
constructor (abiJson: Record<string, unknown> | string, chainProperties?: ChainProperties) {
8788
[this.json, this.registry, this.metadata, this.info] = parseJson(
@@ -90,11 +91,18 @@ export class Abi {
9091
: abiJson,
9192
chainProperties
9293
);
93-
this.constructors = this.metadata.spec.constructors.map((spec: ContractConstructorSpecLatest, index) =>
94-
this.#createMessage(spec, index, {
94+
this.constructors = this.metadata.spec.constructors.map((spec: ContractConstructorSpecLatest, index) => {
95+
const typeSpec = spec.returnType.unwrapOr(null);
96+
97+
return this.#createMessage(spec, index, {
9598
isConstructor: true,
96-
isPayable: spec.payable.isTrue
97-
})
99+
isDefault: spec.default.isTrue,
100+
isPayable: spec.payable.isTrue,
101+
returnType: typeSpec
102+
? this.registry.lookup.getTypeDef(typeSpec.type)
103+
: null
104+
});
105+
}
98106
);
99107
this.events = this.metadata.spec.events.map((spec: ContractEventSpecLatest, index) =>
100108
this.#createEvent(spec, index)
@@ -103,13 +111,27 @@ export class Abi {
103111
const typeSpec = spec.returnType.unwrapOr(null);
104112

105113
return this.#createMessage(spec, index, {
114+
isDefault: spec.default.isTrue,
106115
isMutating: spec.mutates.isTrue,
107116
isPayable: spec.payable.isTrue,
108117
returnType: typeSpec
109118
? this.registry.lookup.getTypeDef(typeSpec.type)
110119
: null
111120
});
112121
});
122+
const rawEnv = this.metadata.spec.environment.unwrapOr(null);
123+
124+
if (rawEnv) {
125+
for (const [key, value] of rawEnv.entries()) {
126+
const typeSpec = value.toPrimitive();
127+
128+
if (typeof typeSpec === 'object' && typeSpec !== null && 'type' in typeSpec) {
129+
this.environment.set(key, this.registry.lookup.getTypeDef(typeSpec.type as number));
130+
} else {
131+
this.environment.set(key, typeSpec as number);
132+
}
133+
}
134+
}
113135
}
114136

115137
/**
@@ -215,6 +237,7 @@ export class Abi {
215237
}),
216238
identifier,
217239
index,
240+
isDefault: spec.default.isTrue,
218241
method: stringCamelCase(identifier),
219242
path: identifier.split('::').map((s) => stringCamelCase(s)),
220243
selector: spec.selector,

packages/api-contract/src/Abi/toV4.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@
44
import type { ContractMetadataV3, ContractMetadataV4 } from '@polkadot/types/interfaces';
55
import type { Registry } from '@polkadot/types/types';
66

7-
export function v3ToV4 (_registry: Registry, v3: ContractMetadataV3): ContractMetadataV4 {
8-
return v3;
7+
import { objectSpread } from '@polkadot/util';
8+
9+
export function v3ToV4 (registry: Registry, v3: ContractMetadataV3): ContractMetadataV4 {
10+
return registry.createType('ContractMetadataV4', objectSpread({}, v3, {
11+
spec: objectSpread({}, v3.spec, {
12+
constructors: v3.spec.constructors.map((c) =>
13+
registry.createType('ContractConstructorSpecV4', objectSpread({}, c))
14+
),
15+
messages: v3.spec.messages.map((m) =>
16+
registry.createType('ContractMessageSpecV3', objectSpread({}, m))
17+
)
18+
})
19+
}));
920
}

packages/api-contract/src/test/compare/ink_v4_flipperContract.test.json

+146
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,151 @@
55
"type": "bool",
66
"docs": [],
77
"namespace": ""
8+
},
9+
{
10+
"info": "Result",
11+
"lookupIndex": 1,
12+
"type": "Result<Null, InkPrimitivesLangError>",
13+
"docs": [],
14+
"namespace": "Result",
15+
"sub": [
16+
{
17+
"name": "Ok",
18+
"info": "Null",
19+
"lookupIndex": 2,
20+
"type": "Null",
21+
"docs": [],
22+
"namespace": ""
23+
},
24+
{
25+
"name": "Error",
26+
"docs": [],
27+
"info": "Si",
28+
"lookupIndex": 3,
29+
"lookupName": "InkPrimitivesLangError",
30+
"type": "Lookup3"
31+
}
32+
]
33+
},
34+
{
35+
"info": "Null",
36+
"lookupIndex": 2,
37+
"type": "Null",
38+
"docs": [],
39+
"namespace": ""
40+
},
41+
{
42+
"info": "Enum",
43+
"lookupIndex": 3,
44+
"lookupName": "InkPrimitivesLangError",
45+
"type": "{\"_enum\":[\"__Unused0\",\"CouldNotReadInput\"]}",
46+
"docs": [],
47+
"namespace": "ink_primitives::LangError",
48+
"sub": [
49+
{
50+
"index": 0,
51+
"info": "Null",
52+
"name": "__Unused0",
53+
"type": "Null"
54+
},
55+
{
56+
"info": "Null",
57+
"type": "Null",
58+
"index": 1,
59+
"name": "CouldNotReadInput"
60+
}
61+
]
62+
},
63+
{
64+
"info": "Result",
65+
"lookupIndex": 4,
66+
"type": "Result<bool, InkPrimitivesLangError>",
67+
"docs": [],
68+
"namespace": "Result",
69+
"sub": [
70+
{
71+
"name": "Ok",
72+
"info": "Plain",
73+
"lookupIndex": 0,
74+
"type": "bool",
75+
"docs": [],
76+
"namespace": ""
77+
},
78+
{
79+
"name": "Error",
80+
"docs": [],
81+
"info": "Si",
82+
"lookupIndex": 3,
83+
"lookupName": "InkPrimitivesLangError",
84+
"type": "Lookup3"
85+
}
86+
]
87+
},
88+
{
89+
"info": "Plain",
90+
"lookupIndex": 5,
91+
"type": "AccountId",
92+
"docs": [],
93+
"namespace": "ink_primitives::types::AccountId",
94+
"lookupNameRoot": "InkPrimitivesAccountId"
95+
},
96+
{
97+
"info": "VecFixed",
98+
"lookupIndex": 6,
99+
"type": "[u8;32]",
100+
"docs": [],
101+
"namespace": "",
102+
"length": 32,
103+
"sub": {
104+
"info": "Plain",
105+
"lookupIndex": 7,
106+
"type": "u8",
107+
"docs": [],
108+
"namespace": ""
109+
}
110+
},
111+
{
112+
"info": "Plain",
113+
"lookupIndex": 7,
114+
"type": "u8",
115+
"docs": [],
116+
"namespace": ""
117+
},
118+
{
119+
"info": "Plain",
120+
"lookupIndex": 8,
121+
"type": "u128",
122+
"docs": [],
123+
"namespace": ""
124+
},
125+
{
126+
"info": "Plain",
127+
"lookupIndex": 9,
128+
"type": "Hash",
129+
"docs": [],
130+
"namespace": "ink_primitives::types::Hash",
131+
"lookupNameRoot": "InkPrimitivesHash"
132+
},
133+
{
134+
"info": "Plain",
135+
"lookupIndex": 10,
136+
"type": "u64",
137+
"docs": [],
138+
"namespace": ""
139+
},
140+
{
141+
"info": "Plain",
142+
"lookupIndex": 11,
143+
"type": "u32",
144+
"docs": [],
145+
"namespace": ""
146+
},
147+
{
148+
"info": "Plain",
149+
"lookupIndex": 12,
150+
"type": "NoChainExtension",
151+
"docs": [],
152+
"namespace": "ink_env::types::NoChainExtension",
153+
"lookupNameRoot": "InkEnvNoChainExtension"
8154
}
9155
]

0 commit comments

Comments
 (0)