diff --git a/packages/types/src/extrinsic/ExtrinsicPayload.spec.ts b/packages/types/src/extrinsic/ExtrinsicPayload.spec.ts index 880ecf711fe..78ee1af8893 100644 --- a/packages/types/src/extrinsic/ExtrinsicPayload.spec.ts +++ b/packages/types/src/extrinsic/ExtrinsicPayload.spec.ts @@ -95,4 +95,22 @@ describe('ExtrinsicPayload', (): void => { '0x940600ffd7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9e56c0703d148e25901007b000000dcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025bde8f69eeb5e065e18c6950ff708d7e551f68dc9bf59a07c52367c0280f805ec7' ); }); + + it('has a sane inspect of an empty value', (): void => { + const reg = new TypeRegistry(); + + reg.setSignedExtensions(fallbackExtensions.concat(['ChargeAssetTxPayment'])); + expect(new ExtrinsicPayload(reg, undefined).inspect()).toEqual({ + inner: [ + { name: 'method', outer: [new Uint8Array()] }, + { inner: undefined, name: 'era', outer: [new Uint8Array([0]), new Uint8Array([0])] }, + { name: 'nonce', outer: [new Uint8Array([0])] }, + { name: 'tip', outer: [new Uint8Array([0])] }, + { name: 'assetId', outer: [new Uint8Array([0])] }, + { name: 'specVersion', outer: [new Uint8Array([0, 0, 0, 0])] }, + { name: 'genesisHash', outer: [new Uint8Array(32)] }, + { name: 'blockHash', outer: [new Uint8Array(32)] } + ] + }); + }); }); diff --git a/packages/types/src/extrinsic/ExtrinsicPayload.ts b/packages/types/src/extrinsic/ExtrinsicPayload.ts index 0dadb432809..0542ed5b9f0 100644 --- a/packages/types/src/extrinsic/ExtrinsicPayload.ts +++ b/packages/types/src/extrinsic/ExtrinsicPayload.ts @@ -39,39 +39,43 @@ const PREAMBLES = { general: 'ExtrinsicPayloadV5' }; -/** @internal */ -function decodeExtrinsicPayload (registry: Registry, value?: GenericExtrinsicPayload | ExtrinsicPayloadValue | Uint8Array | string, version = LATEST_EXTRINSIC_VERSION, preamble: Preamble = DEFAULT_PREAMBLE): ExtrinsicPayloadVx { - if (value instanceof GenericExtrinsicPayload) { - return value.unwrap(); - } - - const extVersion = version === 5 ? PREAMBLES[preamble] : VERSIONS[version] || VERSIONS[0]; +/** + * HACK: In order to change the assetId from `number | object` to HexString (While maintaining the true type ie Option), + * to allow for easier generalization of the SignerPayloadJSON interface the below check is necessary. The ExtrinsicPayloadV4 class does not like + * 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 + * JSON value. + * + * ref: https://github.com/polkadot-js/api/pull/5968 + * ref: https://github.com/polkadot-js/api/pull/5967 + */ +export function decodeAssetId (registry: Registry, payload?: ExtrinsicPayloadValue | Uint8Array | HexString) { + const maybeAsset = (payload as ExtrinsicPayloadValue)?.assetId; - /** - * HACK: In order to change the assetId from `number | object` to HexString (While maintaining the true type ie Option), - * to allow for easier generalization of the SignerPayloadJSON interface the below check is necessary. The ExtrinsicPayloadV4 class does not like - * 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 - * JSON value. - * - * ref: https://github.com/polkadot-js/api/pull/5968 - * ref: https://github.com/polkadot-js/api/pull/5967 - */ - if (value && (value as ExtrinsicPayloadValue).assetId && isHex((value as ExtrinsicPayloadValue).assetId)) { - const assetId = registry.createType('TAssetConversion', hexToU8a((value as ExtrinsicPayloadValue).assetId)); + if (maybeAsset && isHex(maybeAsset)) { + const assetId = registry.createType('TAssetConversion', hexToU8a(maybeAsset)); // we only want to adjust the payload if the hex passed has the option - if ((value as ExtrinsicPayloadValue).assetId === '0x00' || - (value as ExtrinsicPayloadValue).assetId === '0x01' + assetId.toHex().slice(2)) { - const adjustedPayload = { - ...(value as ExtrinsicPayloadValue), + if (maybeAsset === '0x00' || maybeAsset === '0x01' + assetId.toHex().slice(2)) { + return { + ...(payload as ExtrinsicPayloadValue), assetId: assetId.toJSON() }; - - return registry.createTypeUnsafe(extVersion, [adjustedPayload, { version }]); } } - return registry.createTypeUnsafe(extVersion, [value, { version }]); + return payload; +} + +/** @internal */ +function decodeExtrinsicPayload (registry: Registry, value?: GenericExtrinsicPayload | ExtrinsicPayloadValue | Uint8Array | string, version = LATEST_EXTRINSIC_VERSION, preamble: Preamble = DEFAULT_PREAMBLE): ExtrinsicPayloadVx { + if (value instanceof GenericExtrinsicPayload) { + return value.unwrap(); + } + + const extVersion = version === 5 ? PREAMBLES[preamble] : VERSIONS[version] || VERSIONS[0]; + const payload = decodeAssetId(registry, value as ExtrinsicPayloadValue); + + return registry.createTypeUnsafe(extVersion, [payload, { version }]); } /** diff --git a/packages/types/src/extrinsic/v4/ExtrinsicPayload.spec.ts b/packages/types/src/extrinsic/v4/ExtrinsicPayload.spec.ts index 92c6015012c..317453b7691 100644 --- a/packages/types/src/extrinsic/v4/ExtrinsicPayload.spec.ts +++ b/packages/types/src/extrinsic/v4/ExtrinsicPayload.spec.ts @@ -38,24 +38,24 @@ describe('ExtrinsicPayload', (): void => { }); }); - it('correctly decodes assetId', () => { - const TEST_WITH_ASSET = { - address: '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFabHE', - assetId: '0x0002043205011f' as `0x${string}`, - blockHash: '0xde8f69eeb5e065e18c6950ff708d7e551f68dc9bf59a07c52367c0280f805ec7', - era: '0x0703', - genesisHash: '0xdcd1346701ca8396496e52aa2785b1748deb6db09551b72159dcb3e08991025b', - method: '0x0600ffd7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9e56c', - nonce: '0x00001234', - specVersion: 123, - tip: '0x00000000000000000000000000005678', - transactionVersion: '0x00' + it('Correctly decodes assetId', () => { + const TEST_VALUE = { + address: 'J97drEQy6sYPXf2D1uj1hJfeHsxjvwr4tVGKs9o8VDSht8r', + assetId: '0x010002043205011f' as `0x${string}`, + blockHash: '0x28a464e6b40fccec3b9e7989db97d2627d3653c644a3c801f8239910eaaa58a8', + era: '0x4401', + genesisHash: '0x48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a', + method: '0x0a0300d27001b334c34489c67b81dfbbdc86eba5b433163bd08226d89b081914e9aa490284d717', + nonce: '0x0000000a', + specVersion: '0x000f4dfc', + tip: '0x00000000000000000000000000000000', + transactionVersion: '0x0000000f' }; const reg = new TypeRegistry(); reg.setSignedExtensions(fallbackExtensions.concat(['ChargeAssetTxPayment'])); - const ext = new ExtrinsicPayload(reg, TEST_WITH_ASSET); + const ext = new ExtrinsicPayload(reg, TEST_VALUE); expect(ext.assetId.toJSON()).toEqual({ interior: { diff --git a/packages/types/src/extrinsic/v4/ExtrinsicPayload.ts b/packages/types/src/extrinsic/v4/ExtrinsicPayload.ts index 81eceac0727..b54ef990ec3 100644 --- a/packages/types/src/extrinsic/v4/ExtrinsicPayload.ts +++ b/packages/types/src/extrinsic/v4/ExtrinsicPayload.ts @@ -13,6 +13,7 @@ import type { ExtrinsicPayloadValue, ICompact, IKeyringPair, INumber, IOption } import { Enum, Struct } from '@polkadot/types-codec'; import { objectSpread } from '@polkadot/util'; +import { decodeAssetId } from '../ExtrinsicPayload.js'; import { sign } from '../util.js'; /** @@ -29,7 +30,7 @@ export class GenericExtrinsicPayloadV4 extends Struct { { method: 'Bytes' }, registry.getSignedExtensionTypes(), registry.getSignedExtensionExtra() - ), value); + ), decodeAssetId(registry, value)); // Do detection for the type of extrinsic, in the case of MultiSignature // this is an enum, in the case of AnySignature, this is a Hash only