diff --git a/packages/types/src/extrinsic/Extrinsic.spec.ts b/packages/types/src/extrinsic/Extrinsic.spec.ts index 5ff4a5dccb7..e50792ad474 100644 --- a/packages/types/src/extrinsic/Extrinsic.spec.ts +++ b/packages/types/src/extrinsic/Extrinsic.spec.ts @@ -57,36 +57,19 @@ describe('Extrinsic', (): void => { registry.setMetadata(metadata); describe('SignedExtrinsic', () => { - it('Should work when the version and preamble is passed in', () => { - const extrinsic = new Extrinsic( + it('Should error with a signed extrinsic, when the version is passed in', () => { + expect(() => new Extrinsic( registry, '0x51028500d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d011e0b7d9438899333c50121f8e10144952d51c3bb8d0ea11dd1f24940d8ff615ad351d95ed9f41f078748ed7cf182864a20b38eebfaef6629433365eb90c0148c007502000000000603008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480b00a0724e1809', - { preamble: 'signed', version: 5 } - ); - - expect(extrinsic.signer.toString()).toEqual('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'); - expect(extrinsic.era.toHuman()).toEqual({ MortalEra: { period: '64', phase: '39' } }); - expect(extrinsic.nonce.toNumber()).toEqual(0); - expect(extrinsic.tip.toHuman()).toEqual('0'); - expect(extrinsic.callIndex).toEqual(new Uint8Array([6, 3])); - expect(extrinsic.args[0].toHex()).toEqual('0x008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48'); - expect(extrinsic.args[1].toHuman()).toEqual('10,000,000,000,000'); + { version: 5 } + )).toThrow('Signed Extrinsics are currently only available for ExtrinsicV4'); }); - it('Should work when the version and preamble is not passed in', () => { - const extrinsic = new Extrinsic( + it('Should error when the version and preamble is not passed in, and its a signed extrinsic', () => { + expect(() => new Extrinsic( registry, '0x51028500d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d011e0b7d9438899333c50121f8e10144952d51c3bb8d0ea11dd1f24940d8ff615ad351d95ed9f41f078748ed7cf182864a20b38eebfaef6629433365eb90c0148c007502000000000603008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480b00a0724e1809' - ); - - expect(extrinsic.version).toEqual(133); - expect(extrinsic.signer.toString()).toEqual('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'); - expect(extrinsic.era.toHuman()).toEqual({ MortalEra: { period: '64', phase: '39' } }); - expect(extrinsic.nonce.toNumber()).toEqual(0); - expect(extrinsic.tip.toHuman()).toEqual('0'); - expect(extrinsic.callIndex).toEqual(new Uint8Array([6, 3])); - expect(extrinsic.args[0].toHex()).toEqual('0x008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48'); - expect(extrinsic.args[1].toHuman()).toEqual('10,000,000,000,000'); + )).toThrow('Signed Extrinsics are currently only available for ExtrinsicV4'); }); }); diff --git a/packages/types/src/extrinsic/Extrinsic.ts b/packages/types/src/extrinsic/Extrinsic.ts index a1d17faa4ac..ac7c0f368de 100644 --- a/packages/types/src/extrinsic/Extrinsic.ts +++ b/packages/types/src/extrinsic/Extrinsic.ts @@ -16,7 +16,7 @@ import type { ExtrinsicValueV5 } from './v5/Extrinsic.js'; import { AbstractBase } from '@polkadot/types-codec'; import { compactAddLength, compactFromU8a, compactToU8a, isHex, isU8a, objectProperty, objectSpread, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util'; -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'; +import { BARE_EXTRINSIC, BIT_SIGNED, BIT_UNSIGNED, DEFAULT_PREAMBLE, GENERAL_EXTRINSIC, LATEST_EXTRINSIC_VERSION, LOWEST_SUPPORTED_EXTRINSIC_FORMAT_VERSION, TYPE_MASK, VERSION_MASK } from './constants.js'; interface CreateOptions { version?: number; @@ -40,22 +40,18 @@ const VERSIONS = [ const PREAMBLE = { bare: 'ExtrinsicV5', - general: 'GeneralExtrinsic', - signed: 'ExtrinsicV5' + general: 'GeneralExtrinsic' }; const PreambleMask = { bare: BARE_EXTRINSIC, - general: GENERAL_EXTRINSIC, - signed: SIGNED_EXTRINSIC + general: GENERAL_EXTRINSIC }; const preambleUnMask: Record = { 0: 'bare', // eslint-disable-next-line sort-keys - 64: 'general', - // eslint-disable-next-line sort-keys - 128: 'signed' + 64: 'general' }; export { LATEST_EXTRINSIC_VERSION }; @@ -295,7 +291,11 @@ abstract class ExtrinsicBase extends AbstractBase { ); }); - it('creates a signed extrinsic', (): void => { + it('Errors when creating a signed Extrinsic', (): void => { expect( - new Extrinsic( + () => new Extrinsic( registry, tx['balances']['transferAllowDeath'](keyring.bob.publicKey, 6969n) ).sign(keyring.alice, { @@ -69,19 +69,6 @@ describe('ExtrinsicV5', (): void => { }, tip: 2 }).toHex() - ).toEqual( - '0x' + - '00' + - 'd172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f' + - '00' + // ed25519 - '84181ebef350cc212e70e042b6ebcd33ca955bf9497711a64aa7c64e2b8c2732' + - 'ab837715364eab7be5cc76f74eefa36d3ba9ee698264ed28a286c8360fc9aa0c' + - '00' + // TransactionExtension version - '0004080000' + // era. nonce, tip, mode - '0600' + - '00' + - 'd7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9' + - 'e56c' - ); + ).toThrow('Extrinsic: ExtrinsicV5 does not include signing support'); }); }); diff --git a/packages/types/src/extrinsic/v5/Extrinsic.ts b/packages/types/src/extrinsic/v5/Extrinsic.ts index 473732ce58a..e9ab494dfd4 100644 --- a/packages/types/src/extrinsic/v5/Extrinsic.ts +++ b/packages/types/src/extrinsic/v5/Extrinsic.ts @@ -89,28 +89,28 @@ export class GenericExtrinsicV5 extends Struct implements IExtrinsicV5Impl { /** * @description Add an [[ExtrinsicSignatureV5]] to the extrinsic (already generated) + * + * [Disabled for ExtrinsicV5] */ - public addSignature (signer: Address | Uint8Array | string, signature: Uint8Array | HexString, payload: ExtrinsicPayloadValue | Uint8Array | HexString): GenericExtrinsicV5 { - this.signature.addSignature(signer, signature, payload); - - return this; + public addSignature (_signer: Address | Uint8Array | string, _signature: Uint8Array | HexString, _payload: ExtrinsicPayloadValue | Uint8Array | HexString): GenericExtrinsicV5 { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } /** * @description Sign the extrinsic with a specific keypair + * + * [Disabled for ExtrinsicV5] */ - public sign (account: IKeyringPair, options: SignatureOptions): GenericExtrinsicV5 { - this.signature.sign(this.method, account, options); - - return this; + public sign (_account: IKeyringPair, _options: SignatureOptions): GenericExtrinsicV5 { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } /** * @describe Adds a fake signature to the extrinsic + * + * [Disabled for ExtrinsicV5] */ - public signFake (signer: Address | Uint8Array | string, options: SignatureOptions): GenericExtrinsicV5 { - this.signature.signFake(this.method, signer, options); - - return this; + public signFake (_signer: Address | Uint8Array | string, _options: SignatureOptions): GenericExtrinsicV5 { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } } diff --git a/packages/types/src/extrinsic/v5/ExtrinsicPayload.ts b/packages/types/src/extrinsic/v5/ExtrinsicPayload.ts index 1d2222b3eb0..789da526862 100644 --- a/packages/types/src/extrinsic/v5/ExtrinsicPayload.ts +++ b/packages/types/src/extrinsic/v5/ExtrinsicPayload.ts @@ -1,7 +1,6 @@ // Copyright 2017-2024 @polkadot/types authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { SignOptions } from '@polkadot/keyring/types'; import type { Hash, MultiLocation } from '@polkadot/types/interfaces'; import type { Bytes } from '@polkadot/types-codec'; import type { Inspect, Registry } from '@polkadot/types-codec/types'; @@ -10,11 +9,9 @@ import type { BlockHash } from '../../interfaces/chain/index.js'; import type { ExtrinsicEra } from '../../interfaces/extrinsics/index.js'; import type { ExtrinsicPayloadValue, ICompact, IKeyringPair, INumber, IOption } from '../../types/index.js'; -import { Enum, Struct } from '@polkadot/types-codec'; +import { Struct } from '@polkadot/types-codec'; import { objectSpread } from '@polkadot/util'; -import { signV5 } from '../util.js'; - /** * @name GenericExtrinsicPayloadV5 * @description @@ -22,21 +19,12 @@ import { signV5 } from '../util.js'; * variable length based on the contents included */ export class GenericExtrinsicPayloadV5 extends Struct { - #signOptions: SignOptions; - constructor (registry: Registry, value?: ExtrinsicPayloadValue | Uint8Array | HexString) { super(registry, objectSpread( { method: 'Bytes' }, registry.getSignedExtensionTypes(), registry.getSignedExtensionExtra() ), 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 - // (which may be 64 or 65 bytes) - this.#signOptions = { - withType: registry.createTypeUnsafe('ExtrinsicSignature', []) instanceof Enum - }; } /** @@ -118,13 +106,10 @@ export class GenericExtrinsicPayloadV5 extends Struct { /** * @description Sign the payload with the keypair + * + * [Disabled for ExtrinsicV5] */ - public sign (signerPair: IKeyringPair): Uint8Array { - // NOTE The `toU8a({ method: true })` argument is absolutely critical, we - // don't want the method (Bytes) to have the length prefix included. This - // means that the data-as-signed is un-decodable, but is also doesn't need - // the extra information, only the pure data (and is not decoded) ... - // The same applies to V1..V3, if we have a V6, carry this comment - return signV5(this.registry, signerPair, this.toU8a({ method: true }), this.#signOptions); + public sign (_signerPair: IKeyringPair): Uint8Array { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } } diff --git a/packages/types/src/extrinsic/v5/ExtrinsicSignature.spec.ts b/packages/types/src/extrinsic/v5/ExtrinsicSignature.spec.ts index 7fd7d58f9d7..ebeca3e4af5 100644 --- a/packages/types/src/extrinsic/v5/ExtrinsicSignature.spec.ts +++ b/packages/types/src/extrinsic/v5/ExtrinsicSignature.spec.ts @@ -61,25 +61,15 @@ describe('ExtrinsicSignatureV4', (): void => { registry.setMetadata(metadata); expect( - new ExtrinsicSignature(registry).signFake( + () => new ExtrinsicSignature(registry).signFake( registry.createType('Call'), pairs.alice.publicKey, signOptions ).toHex() - ).toEqual( - '0x' + - '00' + // MultiAddress - 'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' + - '01' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '00' + // TransactionExtension version - '00a5010000' + - '00' // Mode - ); + ).toThrow('Extrinsic: ExtrinsicV5 does not include signing support'); }); - it('fake signs default (AccountId address)', (): void => { + it('Errors on fake sign', (): void => { const registry = new TypeRegistry(); const metadata = new Metadata(registry, metadataStatic); @@ -90,76 +80,26 @@ describe('ExtrinsicSignatureV4', (): void => { }); expect( - new ExtrinsicSignature(registry).signFake( + () => new ExtrinsicSignature(registry).signFake( registry.createType('Call'), pairs.alice.address, signOptions ).toHex() - ).toEqual( - '0x' + - // Address = AccountId, no prefix - 'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' + - // This is a prefix-less signature, anySignture as opposed to Multi above - '0101010101010101010101010101010101010101010101010101010101010101' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '00' + // TransactionExtension version - '00a5010000' + - '00' // mode - ); + ).toThrow('Extrinsic: ExtrinsicV5 does not include signing support'); }); - it('fake signs with non-enum signature', (): void => { - const registry = new TypeRegistry(); - const metadata = new Metadata(registry, metadataStatic); - - registry.setMetadata(metadata); - registry.register({ - Address: 'AccountId', - ExtrinsicSignature: '[u8;65]' - }); - - expect( - new ExtrinsicSignature(registry).signFake( - registry.createType('Call'), - pairs.alice.address, - signOptions - ).toHex() - ).toEqual( - '0x' + - // Address = AccountId, no prefix - 'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' + - // 65 bytes here - '01' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '00' + // TransactionExtension version - '00a5010000' + - '00' // mode - ); - }); - - it('injects a signature', (): void => { + it('Errors on injecting a signature', (): void => { const registry = new TypeRegistry(); const metadata = new Metadata(registry, metadataStatic); registry.setMetadata(metadata); expect( - new ExtrinsicSignature(registry).addSignature( + () => new ExtrinsicSignature(registry).addSignature( pairs.alice.publicKey, new Uint8Array(65).fill(1), new Uint8Array(0) ).toHex() - ).toEqual( - '0x' + - '00' + // MultiAddress - 'd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d' + - '01' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '0101010101010101010101010101010101010101010101010101010101010101' + - '00' + // TransactionExtension version - '00000000' + - '00' // mode - ); + ).toThrow('Extrinsic: ExtrinsicV5 does not include signing support'); }); }); diff --git a/packages/types/src/extrinsic/v5/ExtrinsicSignature.ts b/packages/types/src/extrinsic/v5/ExtrinsicSignature.ts index 9191850e47c..ab00da9bbcb 100644 --- a/packages/types/src/extrinsic/v5/ExtrinsicSignature.ts +++ b/packages/types/src/extrinsic/v5/ExtrinsicSignature.ts @@ -9,18 +9,11 @@ import type { ExtrinsicPayloadValue, ICompact, IExtrinsicSignature, IKeyringPair import type { ExtrinsicSignatureOptions } from '../types.js'; import { Struct } from '@polkadot/types-codec'; -import { isU8a, isUndefined, objectProperties, objectSpread, stringify, u8aToHex } from '@polkadot/util'; +import { objectProperties, objectSpread } from '@polkadot/util'; import { EMPTY_U8A, IMMORTAL_ERA } from '../constants.js'; import { GenericExtrinsicPayloadV5 } from './ExtrinsicPayload.js'; -// Ensure we have enough data for all types of signatures -const FAKE_SIGNATURE = new Uint8Array(256).fill(1); - -function toAddress (registry: Registry, address: Address | Uint8Array | string): Address { - return registry.createTypeUnsafe('Address', [isU8a(address) ? u8aToHex(address) : address]); -} - /** * @name GenericExtrinsicSignatureV5 * @description @@ -28,11 +21,9 @@ function toAddress (registry: Registry, address: Address | Uint8Array | string): */ export class GenericExtrinsicSignatureV5 extends Struct implements IExtrinsicSignature { #signKeys: string[]; - #transactionExtensionVersion: number; constructor (registry: Registry, value?: GenericExtrinsicSignatureV5 | Uint8Array, { isSigned }: ExtrinsicSignatureOptions = {}) { const signTypes = registry.getSignedExtensionTypes(); - const signedVersion = registry.getTransactionExtensionVersion(); super( registry, @@ -44,7 +35,6 @@ export class GenericExtrinsicSignatureV5 extends Struct implements IExtrinsicSig GenericExtrinsicSignatureV5.decodeExtrinsicSignature(value, isSigned) ); - this.#transactionExtensionVersion = signedVersion; this.#signKeys = Object.keys(signTypes); objectProperties(this, this.#signKeys, (k) => this.get(k)); @@ -150,35 +140,20 @@ export class GenericExtrinsicSignatureV5 extends Struct implements IExtrinsicSig return this.getT('transactionExtensionVersion'); } - protected _injectSignature (signer: Address, signature: ExtrinsicSignature, payload: GenericExtrinsicPayloadV5): IExtrinsicSignature { - // use the fields exposed to guide the getters - for (let i = 0, count = this.#signKeys.length; i < count; i++) { - const k = this.#signKeys[i]; - const v = payload.get(k); - - if (k === 'transactionExtensionVersion') { - this.set(k, this.registry.createType('u8', this.#transactionExtensionVersion)); - } else if (!isUndefined(v)) { - this.set(k, v); - } - } - - // additional fields (exposed in struct itself) - this.set('signer', signer); - this.set('signature', signature); - - return this; + /** + * [Disabled for ExtrinsicV5] + */ + protected _injectSignature (_signer: Address, _signature: ExtrinsicSignature, _payload: GenericExtrinsicPayloadV5): IExtrinsicSignature { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } /** * @description Adds a raw signature + * + * [Disabled for ExtrinsicV5] */ - public addSignature (signer: Address | Uint8Array | string, signature: Uint8Array | HexString, payload: ExtrinsicPayloadValue | Uint8Array | HexString): IExtrinsicSignature { - return this._injectSignature( - toAddress(this.registry, signer), - this.registry.createTypeUnsafe('ExtrinsicSignature', [signature]), - new GenericExtrinsicPayloadV5(this.registry, payload) - ); + public addSignature (_signer: Address | Uint8Array | string, _signature: Uint8Array | HexString, _payload: ExtrinsicPayloadValue | Uint8Array | HexString): IExtrinsicSignature { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } /** @@ -197,36 +172,20 @@ export class GenericExtrinsicSignatureV5 extends Struct implements IExtrinsicSig /** * @description Generate a payload and applies the signature from a keypair + * + * [Disabled for ExtrinsicV5] */ - public sign (method: Call, account: IKeyringPair, options: SignatureOptions): IExtrinsicSignature { - if (!account?.addressRaw) { - throw new Error(`Expected a valid keypair for signing, found ${stringify(account)}`); - } - - const payload = this.createPayload(method, options); - - return this._injectSignature( - toAddress(this.registry, account.addressRaw), - this.registry.createTypeUnsafe('ExtrinsicSignature', [payload.sign(account)]), - payload - ); + public sign (_method: Call, _account: IKeyringPair, _options: SignatureOptions): IExtrinsicSignature { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } /** * @description Generate a payload and applies a fake signature + * + * [Disabled for ExtrinsicV5] */ - public signFake (method: Call, address: Address | Uint8Array | string, options: SignatureOptions): IExtrinsicSignature { - if (!address) { - throw new Error(`Expected a valid address for signing, found ${stringify(address)}`); - } - - const payload = this.createPayload(method, options); - - return this._injectSignature( - toAddress(this.registry, address), - this.registry.createTypeUnsafe('ExtrinsicSignature', [FAKE_SIGNATURE]), - payload - ); + public signFake (_method: Call, _address: Address | Uint8Array | string, _options: SignatureOptions): IExtrinsicSignature { + throw new Error('Extrinsic: ExtrinsicV5 does not include signing support'); } /**