1 | import { AbstractBase } from '@polkadot/types-codec';
|
2 | import { hexToU8a, isHex, u8aToHex } from '@polkadot/util';
|
3 | import { DEFAULT_PREAMBLE, LATEST_EXTRINSIC_VERSION } from './constants.js';
|
4 | const VERSIONS = [
|
5 | 'ExtrinsicPayloadUnknown', // v0 is unknown
|
6 | 'ExtrinsicPayloadUnknown',
|
7 | 'ExtrinsicPayloadUnknown',
|
8 | 'ExtrinsicPayloadUnknown',
|
9 | 'ExtrinsicPayloadV4',
|
10 | 'ExtrinsicPayloadV5'
|
11 | ];
|
12 | const PREAMBLES = {
|
13 | bare: 'ExtrinsicPayloadV5',
|
14 | // Not supported yet
|
15 | general: 'ExtrinsicPayloadV5',
|
16 | signed: 'ExtrinsicPayloadV5'
|
17 | };
|
18 | /** @internal */
|
19 | function decodeExtrinsicPayload(registry, value, version = LATEST_EXTRINSIC_VERSION, preamble = DEFAULT_PREAMBLE) {
|
20 | if (value instanceof GenericExtrinsicPayload) {
|
21 | return value.unwrap();
|
22 | }
|
23 | const extVersion = version === 5 ? PREAMBLES[preamble] : VERSIONS[version] || VERSIONS[0];
|
24 | /**
|
25 | * HACK: In order to change the assetId from `number | object` to HexString (While maintaining the true type ie Option<TAssetConversion>),
|
26 | * to allow for easier generalization of the SignerPayloadJSON interface the below check is necessary. The ExtrinsicPayloadV4 class does not like
|
27 | * a value passed in as an Option, and can't decode it properly. Therefore, we ensure to convert the following below, and then pass the option as a unwrapped
|
28 | * JSON value.
|
29 | *
|
30 | * ref: https://github.com/polkadot-js/api/pull/5968
|
31 | * ref: https://github.com/polkadot-js/api/pull/5967
|
32 | */
|
33 | if (value && value.assetId && isHex(value.assetId)) {
|
34 | const adjustedPayload = {
|
35 | ...value,
|
36 | assetId: registry.createType('TAssetConversion', hexToU8a(value.assetId)).toJSON()
|
37 | };
|
38 | return registry.createTypeUnsafe(extVersion, [adjustedPayload, { version }]);
|
39 | }
|
40 | return registry.createTypeUnsafe(extVersion, [value, { version }]);
|
41 | }
|
42 | /**
|
43 | * @name GenericExtrinsicPayload
|
44 | * @description
|
45 | * A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based
|
46 | * on the contents included
|
47 | */
|
48 | export class GenericExtrinsicPayload extends AbstractBase {
|
49 | constructor(registry, value, { preamble, version } = {}) {
|
50 | super(registry, decodeExtrinsicPayload(registry, value, version, preamble));
|
51 | }
|
52 | /**
|
53 | * @description The block [[BlockHash]] the signature applies to (mortal/immortal)
|
54 | */
|
55 | get blockHash() {
|
56 | return this.inner.blockHash;
|
57 | }
|
58 | /**
|
59 | * @description The [[ExtrinsicEra]]
|
60 | */
|
61 | get era() {
|
62 | return this.inner.era;
|
63 | }
|
64 | /**
|
65 | * @description The genesis block [[BlockHash]] the signature applies to
|
66 | */
|
67 | get genesisHash() {
|
68 | // NOTE only v3+
|
69 | return this.inner.genesisHash || this.registry.createTypeUnsafe('Hash', []);
|
70 | }
|
71 | /**
|
72 | * @description The [[Bytes]] contained in the payload
|
73 | */
|
74 | get method() {
|
75 | return this.inner.method;
|
76 | }
|
77 | /**
|
78 | * @description The [[Index]]
|
79 | */
|
80 | get nonce() {
|
81 | return this.inner.nonce;
|
82 | }
|
83 | /**
|
84 | * @description The specVersion as a [[u32]] for this payload
|
85 | */
|
86 | get specVersion() {
|
87 | // NOTE only v3+
|
88 | return this.inner.specVersion || this.registry.createTypeUnsafe('u32', []);
|
89 | }
|
90 | /**
|
91 | * @description The [[Balance]]
|
92 | */
|
93 | get tip() {
|
94 | // NOTE from v2+
|
95 | return this.inner.tip || this.registry.createTypeUnsafe('Compact<Balance>', []);
|
96 | }
|
97 | /**
|
98 | * @description The transaction version as a [[u32]] for this payload
|
99 | */
|
100 | get transactionVersion() {
|
101 | // NOTE only v4+
|
102 | return this.inner.transactionVersion || this.registry.createTypeUnsafe('u32', []);
|
103 | }
|
104 | /**
|
105 | * @description The (optional) asset id as a [[u32]] or [[MultiLocation]] for this payload
|
106 | */
|
107 | get assetId() {
|
108 | return this.inner.assetId;
|
109 | }
|
110 | /**
|
111 | * @description The (optional) [[Hash]] of the genesis metadata for this payload
|
112 | */
|
113 | get metadataHash() {
|
114 | return this.inner.metadataHash;
|
115 | }
|
116 | /**
|
117 | * @description Compares the value of the input to see if there is a match
|
118 | */
|
119 | eq(other) {
|
120 | return this.inner.eq(other);
|
121 | }
|
122 | /**
|
123 | * @description Sign the payload with the keypair
|
124 | */
|
125 | sign(signerPair) {
|
126 | const signature = this.inner.sign(signerPair);
|
127 | // This is extensible, so we could quite readily extend to send back extra
|
128 | // information, such as for instance the payload, i.e. `payload: this.toHex()`
|
129 | // For the case here we sign via the extrinsic, we ignore the return, so generally
|
130 | // this is applicable for external signing
|
131 | return {
|
132 | signature: u8aToHex(signature)
|
133 | };
|
134 | }
|
135 | /**
|
136 | * @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
|
137 | */
|
138 | toHuman(isExtended, disableAscii) {
|
139 | return this.inner.toHuman(isExtended, disableAscii);
|
140 | }
|
141 | /**
|
142 | * @description Converts the Object to JSON, typically used for RPC transfers
|
143 | */
|
144 | toJSON() {
|
145 | return this.toHex();
|
146 | }
|
147 | /**
|
148 | * @description Returns the base runtime type name for this instance
|
149 | */
|
150 | toRawType() {
|
151 | return 'ExtrinsicPayload';
|
152 | }
|
153 | /**
|
154 | * @description Returns the string representation of the value
|
155 | */
|
156 | toString() {
|
157 | return this.toHex();
|
158 | }
|
159 | /**
|
160 | * @description Returns a serialized u8a form
|
161 | */
|
162 | toU8a(isBare) {
|
163 | // call our parent, with only the method stripped
|
164 | return super.toU8a(isBare ? { method: true } : false);
|
165 | }
|
166 | }
|