1 | import { AbstractBase } from '@polkadot/types-codec';
|
2 | import { compactAddLength, compactFromU8a, compactToU8a, isHex, isU8a, objectProperty, objectSpread, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
|
3 | import { BARE_EXTRINSIC, BIT_SIGNED, BIT_UNSIGNED, DEFAULT_PREAMBLE, GENERAL_EXTRINSIC, LATEST_EXTRINSIC_VERSION, LOWEST_SUPPORTED_EXTRINSIC_FORMAT_VERSION, SIGNED_EXTRINSIC, TYPE_MASK, VERSION_MASK } from './constants.js';
|
4 | const VERSIONS = [
|
5 | 'ExtrinsicUnknown',
|
6 | 'ExtrinsicUnknown',
|
7 | 'ExtrinsicUnknown',
|
8 | 'ExtrinsicUnknown',
|
9 | 'ExtrinsicV4',
|
10 | 'ExtrinsicV5'
|
11 | ];
|
12 | const PREAMBLE = {
|
13 | bare: 'ExtrinsicV5',
|
14 | general: 'GeneralExtrinsic',
|
15 | signed: 'ExtrinsicV5'
|
16 | };
|
17 | const PreambleMask = {
|
18 | bare: BARE_EXTRINSIC,
|
19 | general: GENERAL_EXTRINSIC,
|
20 | signed: SIGNED_EXTRINSIC
|
21 | };
|
22 | const preambleUnMask = {
|
23 | 0: 'bare',
|
24 |
|
25 | 64: 'general',
|
26 |
|
27 | 128: 'signed'
|
28 | };
|
29 | export { LATEST_EXTRINSIC_VERSION };
|
30 |
|
31 | function newFromValue(registry, value, version, preamble) {
|
32 | if (value instanceof GenericExtrinsic) {
|
33 | return value.unwrap();
|
34 | }
|
35 | const isSigned = (version & BIT_SIGNED) === BIT_SIGNED;
|
36 | const type = (version & VERSION_MASK) === 5 ? PREAMBLE[preamble] : VERSIONS[version & VERSION_MASK] || VERSIONS[0];
|
37 |
|
38 |
|
39 | return registry.createTypeUnsafe(type, [value, { isSigned, version }]);
|
40 | }
|
41 |
|
42 | function decodeExtrinsic(registry, value, version = LOWEST_SUPPORTED_EXTRINSIC_FORMAT_VERSION, preamble = DEFAULT_PREAMBLE) {
|
43 | if (isU8a(value) || Array.isArray(value) || isHex(value)) {
|
44 | return decodeU8a(registry, u8aToU8a(value), version, preamble);
|
45 | }
|
46 | else if (value instanceof registry.createClassUnsafe('Call')) {
|
47 | return newFromValue(registry, { method: value }, version, preamble);
|
48 | }
|
49 | return newFromValue(registry, value, version, preamble);
|
50 | }
|
51 |
|
52 | function decodeU8a(registry, value, version, preamble) {
|
53 | if (!value.length) {
|
54 | return newFromValue(registry, new Uint8Array(), version, preamble);
|
55 | }
|
56 | const [offset, length] = compactFromU8a(value);
|
57 | const total = offset + length.toNumber();
|
58 | if (total > value.length) {
|
59 | throw new Error(`Extrinsic: length less than remainder, expected at least ${total}, found ${value.length}`);
|
60 | }
|
61 | const data = value.subarray(offset, total);
|
62 | const unmaskedPreamble = data[0] & TYPE_MASK;
|
63 | if (preambleUnMask[`${unmaskedPreamble}`] === 'general') {
|
64 |
|
65 | return newFromValue(registry, value, data[0], preambleUnMask[`${unmaskedPreamble}`] || preamble);
|
66 | }
|
67 | else {
|
68 | return newFromValue(registry, data.subarray(1), data[0], preambleUnMask[`${unmaskedPreamble}`] || preamble);
|
69 | }
|
70 | }
|
71 | class ExtrinsicBase extends AbstractBase {
|
72 | __internal__preamble;
|
73 | constructor(registry, value, initialU8aLength, preamble) {
|
74 | super(registry, value, initialU8aLength);
|
75 | const signKeys = Object.keys(registry.getSignedExtensionTypes());
|
76 | if (this.version === 5 && preamble !== 'general') {
|
77 | const getter = (key) => this.inner.signature[key];
|
78 |
|
79 |
|
80 | for (let i = 0, count = signKeys.length; i < count; i++) {
|
81 | objectProperty(this, signKeys[i], getter);
|
82 | }
|
83 | }
|
84 | const unmaskedPreamble = this.type & TYPE_MASK;
|
85 | this.__internal__preamble = preamble || preambleUnMask[`${unmaskedPreamble}`];
|
86 | }
|
87 | isGeneral() {
|
88 | return this.__internal__preamble === 'general';
|
89 | }
|
90 | |
91 |
|
92 |
|
93 | get args() {
|
94 | return this.method.args;
|
95 | }
|
96 | |
97 |
|
98 |
|
99 | get argsDef() {
|
100 | return this.method.argsDef;
|
101 | }
|
102 | |
103 |
|
104 |
|
105 | get callIndex() {
|
106 | return this.method.callIndex;
|
107 | }
|
108 | |
109 |
|
110 |
|
111 | get data() {
|
112 | return this.method.data;
|
113 | }
|
114 | |
115 |
|
116 |
|
117 | get era() {
|
118 | return this.isGeneral()
|
119 | ? this.inner.era
|
120 | : this.inner.signature.era;
|
121 | }
|
122 | |
123 |
|
124 |
|
125 | get encodedLength() {
|
126 | return this.toU8a().length;
|
127 | }
|
128 | |
129 |
|
130 |
|
131 | get isSigned() {
|
132 | return this.isGeneral()
|
133 | ? false
|
134 | : this.inner.signature.isSigned;
|
135 | }
|
136 | |
137 |
|
138 |
|
139 | get length() {
|
140 | return this.toU8a(true).length;
|
141 | }
|
142 | |
143 |
|
144 |
|
145 | get meta() {
|
146 | return this.method.meta;
|
147 | }
|
148 | |
149 |
|
150 |
|
151 | get method() {
|
152 | return this.inner.method;
|
153 | }
|
154 | |
155 |
|
156 |
|
157 | get nonce() {
|
158 | return this.isGeneral()
|
159 | ? this.inner.nonce
|
160 | : this.inner.signature.nonce;
|
161 | }
|
162 | |
163 |
|
164 |
|
165 | get signature() {
|
166 | if (this.isGeneral()) {
|
167 | throw new Error('Extrinsic: GeneralExtrinsic does not have signature implemented');
|
168 | }
|
169 | return this.inner.signature.signature;
|
170 | }
|
171 | |
172 |
|
173 |
|
174 | get signer() {
|
175 | if (this.isGeneral()) {
|
176 | throw new Error('Extrinsic: GeneralExtrinsic does not have signer implemented');
|
177 | }
|
178 | return this.inner.signature.signer;
|
179 | }
|
180 | |
181 |
|
182 |
|
183 | get tip() {
|
184 | return this.isGeneral()
|
185 | ? this.inner.tip
|
186 | : this.inner.signature.tip;
|
187 | }
|
188 | |
189 |
|
190 |
|
191 | get assetId() {
|
192 | return this.isGeneral()
|
193 | ? this.inner.assetId
|
194 | : this.inner.signature.assetId;
|
195 | }
|
196 | |
197 |
|
198 |
|
199 | get metadataHash() {
|
200 | return this.isGeneral()
|
201 | ? this.inner.metadataHash
|
202 | : this.inner.signature.metadataHash;
|
203 | }
|
204 | |
205 |
|
206 |
|
207 | get mode() {
|
208 | return this.isGeneral()
|
209 | ? this.inner.mode
|
210 | : this.inner.signature.mode;
|
211 | }
|
212 | |
213 |
|
214 |
|
215 | get type() {
|
216 | return this.inner.version;
|
217 | }
|
218 | get inner() {
|
219 | return this.unwrap();
|
220 | }
|
221 | |
222 |
|
223 |
|
224 | get version() {
|
225 | if (this.type <= LOWEST_SUPPORTED_EXTRINSIC_FORMAT_VERSION) {
|
226 | return this.type | (this.isSigned ? BIT_SIGNED : BIT_UNSIGNED);
|
227 | }
|
228 | else {
|
229 | return this.type | (this.isSigned ? PreambleMask.signed : this.isGeneral() ? PreambleMask.general : PreambleMask.bare);
|
230 | }
|
231 | }
|
232 | |
233 |
|
234 |
|
235 | is(other) {
|
236 | return this.method.is(other);
|
237 | }
|
238 | unwrap() {
|
239 | return super.unwrap();
|
240 | }
|
241 | }
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 | export class GenericExtrinsic extends ExtrinsicBase {
|
255 | __internal__hashCache;
|
256 | static LATEST_EXTRINSIC_VERSION = LATEST_EXTRINSIC_VERSION;
|
257 | constructor(registry, value, { preamble, version } = {}) {
|
258 | super(registry, decodeExtrinsic(registry, value, version || registry.metadata.extrinsic.version?.toNumber(), preamble), undefined, preamble);
|
259 | }
|
260 | |
261 |
|
262 |
|
263 | get hash() {
|
264 | if (!this.__internal__hashCache) {
|
265 | this.__internal__hashCache = super.hash;
|
266 | }
|
267 | return this.__internal__hashCache;
|
268 | }
|
269 | |
270 |
|
271 |
|
272 | addSignature(signer, signature, payload) {
|
273 | this.inner.addSignature(signer, signature, payload);
|
274 | this.__internal__hashCache = undefined;
|
275 | return this;
|
276 | }
|
277 | |
278 |
|
279 |
|
280 | inspect() {
|
281 | const encoded = u8aConcat(...this.toU8aInner());
|
282 | return {
|
283 | inner: this.isSigned
|
284 | ? this.inner.inspect().inner
|
285 | : this.inner.method.inspect().inner,
|
286 | outer: [compactToU8a(encoded.length), new Uint8Array([this.version])]
|
287 | };
|
288 | }
|
289 | |
290 |
|
291 |
|
292 | sign(account, options) {
|
293 | this.inner.sign(account, options);
|
294 | this.__internal__hashCache = undefined;
|
295 | return this;
|
296 | }
|
297 | |
298 |
|
299 |
|
300 | signFake(signer, options) {
|
301 | this.inner.signFake(signer, options);
|
302 | this.__internal__hashCache = undefined;
|
303 | return this;
|
304 | }
|
305 | |
306 |
|
307 |
|
308 | toHex(isBare) {
|
309 | return u8aToHex(this.toU8a(isBare));
|
310 | }
|
311 | |
312 |
|
313 |
|
314 | toHuman(isExpanded, disableAscii) {
|
315 | return objectSpread({}, {
|
316 | isSigned: this.isSigned,
|
317 | method: this.method.toHuman(isExpanded, disableAscii)
|
318 | }, this.isSigned
|
319 | ? {
|
320 | assetId: this.assetId ? this.assetId.toHuman(isExpanded, disableAscii) : null,
|
321 | era: this.era.toHuman(isExpanded, disableAscii),
|
322 | metadataHash: this.metadataHash ? this.metadataHash.toHex() : null,
|
323 | mode: this.mode ? this.mode.toHuman() : null,
|
324 | nonce: this.nonce.toHuman(isExpanded, disableAscii),
|
325 | signature: this.signature.toHex(),
|
326 | signer: this.signer.toHuman(isExpanded, disableAscii),
|
327 | tip: this.tip.toHuman(isExpanded, disableAscii)
|
328 | }
|
329 | : null);
|
330 | }
|
331 | |
332 |
|
333 |
|
334 | toJSON() {
|
335 | return this.toHex();
|
336 | }
|
337 | |
338 |
|
339 |
|
340 | toRawType() {
|
341 | return 'Extrinsic';
|
342 | }
|
343 | |
344 |
|
345 |
|
346 |
|
347 | toU8a(isBare) {
|
348 | const encoded = u8aConcat(...this.toU8aInner());
|
349 | return isBare
|
350 | ? encoded
|
351 | : compactAddLength(encoded);
|
352 | }
|
353 | toU8aInner() {
|
354 |
|
355 |
|
356 | return [
|
357 | new Uint8Array([this.version]),
|
358 | this.inner.toU8a()
|
359 | ];
|
360 | }
|
361 | }
|