Ensure assetId is handled correctly when addSignature is used (#6083)
* Ensure assetId is handled correctly when addSignature is used * Adjust test to mirror real failure * test empty input on GenericExtrinsicPayload
This commit is contained in:
@@ -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)] }
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,6 +39,33 @@ const PREAMBLES = {
|
||||
general: 'ExtrinsicPayloadV5'
|
||||
};
|
||||
|
||||
/**
|
||||
* HACK: In order to change the assetId from `number | object` to HexString (While maintaining the true type ie Option<TAssetConversion>),
|
||||
* 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;
|
||||
|
||||
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 (maybeAsset === '0x00' || maybeAsset === '0x01' + assetId.toHex().slice(2)) {
|
||||
return {
|
||||
...(payload as ExtrinsicPayloadValue),
|
||||
assetId: assetId.toJSON()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -46,32 +73,9 @@ function decodeExtrinsicPayload (registry: Registry, value?: GenericExtrinsicPay
|
||||
}
|
||||
|
||||
const extVersion = version === 5 ? PREAMBLES[preamble] : VERSIONS[version] || VERSIONS[0];
|
||||
const payload = decodeAssetId(registry, value as ExtrinsicPayloadValue);
|
||||
|
||||
/**
|
||||
* HACK: In order to change the assetId from `number | object` to HexString (While maintaining the true type ie Option<TAssetConversion>),
|
||||
* 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));
|
||||
|
||||
// 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),
|
||||
assetId: assetId.toJSON()
|
||||
};
|
||||
|
||||
return registry.createTypeUnsafe(extVersion, [adjustedPayload, { version }]);
|
||||
}
|
||||
}
|
||||
|
||||
return registry.createTypeUnsafe(extVersion, [value, { version }]);
|
||||
return registry.createTypeUnsafe(extVersion, [payload, { version }]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user