Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ tmp/
.env.production.local
.npmrc
.yarn/*
!.yarn/patches
!.yarn/patches/**
!.yarn/releases
!.yarn/plugins
.pnp.*
Expand Down
136 changes: 136 additions & 0 deletions .yarn/patches/@polkadot-types-npm-16.5.6-6fe2703ed8.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
diff --git a/cjs/extrinsic/v4/ExtrinsicSignature.js b/cjs/extrinsic/v4/ExtrinsicSignature.js
index d2809f1b7a761c2140ea82c132e22bc883ed3dbb..2d020950a8aa88f15541aa5d89cee849043bbb91 100644
--- a/cjs/extrinsic/v4/ExtrinsicSignature.js
+++ b/cjs/extrinsic/v4/ExtrinsicSignature.js
@@ -15,12 +15,16 @@ function toAddress(registry, address) {
* A container for the [[Signature]] associated with a specific [[Extrinsic]]
*/
class GenericExtrinsicSignatureV4 extends types_codec_1.Struct {
+ #isSigned;
#signKeys;
constructor(registry, value, { isSigned } = {}) {
const signTypes = registry.getSignedExtensionTypes();
super(registry, (0, util_1.objectSpread)(
// eslint-disable-next-line sort-keys
{ signer: 'Address', signature: 'ExtrinsicSignature' }, signTypes), GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned));
+ this.#isSigned = isSigned === undefined
+ ? !this.signature.isEmpty
+ : isSigned;
this.#signKeys = Object.keys(signTypes);
(0, util_1.objectProperties)(this, this.#signKeys, (k) => this.get(k));
}
@@ -48,7 +52,7 @@ class GenericExtrinsicSignatureV4 extends types_codec_1.Struct {
* @description `true` if the signature is valid
*/
get isSigned() {
- return !this.signature.isEmpty;
+ return this.#isSigned;
}
/**
* @description The [[ExtrinsicEra]] (mortal or immortal) this signature applies to
@@ -117,6 +121,7 @@ class GenericExtrinsicSignatureV4 extends types_codec_1.Struct {
// additional fields (exposed in struct itself)
this.set('signer', signer);
this.set('signature', signature);
+ this.#isSigned = true;
return this;
}
/**
diff --git a/cjs/extrinsic/v5/ExtrinsicSignature.js b/cjs/extrinsic/v5/ExtrinsicSignature.js
index 10e370372d98a496aa8af1584d89c540b8db5ddf..2db1afa1ecfeabcbd3e419c27ad0114755b5217a 100644
--- a/cjs/extrinsic/v5/ExtrinsicSignature.js
+++ b/cjs/extrinsic/v5/ExtrinsicSignature.js
@@ -11,12 +11,16 @@ const ExtrinsicPayload_js_1 = require("./ExtrinsicPayload.js");
* A container for the [[Signature]] associated with a specific [[Extrinsic]]
*/
class GenericExtrinsicSignatureV5 extends types_codec_1.Struct {
+ #isSigned;
#signKeys;
constructor(registry, value, { isSigned } = {}) {
const signTypes = registry.getSignedExtensionTypes();
super(registry, (0, util_1.objectSpread)(
// eslint-disable-next-line sort-keys
{ signer: 'Address', signature: 'ExtrinsicSignature', transactionExtensionVersion: 'u8' }, signTypes), GenericExtrinsicSignatureV5.decodeExtrinsicSignature(value, isSigned));
+ this.#isSigned = isSigned === undefined
+ ? !this.signature.isEmpty
+ : isSigned;
this.#signKeys = Object.keys(signTypes);
(0, util_1.objectProperties)(this, this.#signKeys, (k) => this.get(k));
}
@@ -44,7 +48,7 @@ class GenericExtrinsicSignatureV5 extends types_codec_1.Struct {
* @description `true` if the signature is valid
*/
get isSigned() {
- return !this.signature.isEmpty;
+ return this.#isSigned;
}
/**
* @description The [[ExtrinsicEra]] (mortal or immortal) this signature applies to
diff --git a/extrinsic/v4/ExtrinsicSignature.js b/extrinsic/v4/ExtrinsicSignature.js
index ba67bdb4e530d0df4efce7615ef70f50026248e9..9fa3bf9e02dfe49e147e496b5a3d50a8ac81feec 100644
--- a/extrinsic/v4/ExtrinsicSignature.js
+++ b/extrinsic/v4/ExtrinsicSignature.js
@@ -12,12 +12,16 @@ function toAddress(registry, address) {
* A container for the [[Signature]] associated with a specific [[Extrinsic]]
*/
export class GenericExtrinsicSignatureV4 extends Struct {
+ #isSigned;
#signKeys;
constructor(registry, value, { isSigned } = {}) {
const signTypes = registry.getSignedExtensionTypes();
super(registry, objectSpread(
// eslint-disable-next-line sort-keys
{ signer: 'Address', signature: 'ExtrinsicSignature' }, signTypes), GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned));
+ this.#isSigned = isSigned === undefined
+ ? !this.signature.isEmpty
+ : isSigned;
this.#signKeys = Object.keys(signTypes);
objectProperties(this, this.#signKeys, (k) => this.get(k));
}
@@ -45,7 +49,7 @@ export class GenericExtrinsicSignatureV4 extends Struct {
* @description `true` if the signature is valid
*/
get isSigned() {
- return !this.signature.isEmpty;
+ return this.#isSigned;
}
/**
* @description The [[ExtrinsicEra]] (mortal or immortal) this signature applies to
@@ -114,6 +118,7 @@ export class GenericExtrinsicSignatureV4 extends Struct {
// additional fields (exposed in struct itself)
this.set('signer', signer);
this.set('signature', signature);
+ this.#isSigned = true;
return this;
}
/**
diff --git a/extrinsic/v5/ExtrinsicSignature.js b/extrinsic/v5/ExtrinsicSignature.js
index 845a2f828b837f7d2340daaad6238b9ed12164a3..e0af841efab043f809835cf86b8e126c567ceffc 100644
--- a/extrinsic/v5/ExtrinsicSignature.js
+++ b/extrinsic/v5/ExtrinsicSignature.js
@@ -8,12 +8,16 @@ import { GenericExtrinsicPayloadV5 } from './ExtrinsicPayload.js';
* A container for the [[Signature]] associated with a specific [[Extrinsic]]
*/
export class GenericExtrinsicSignatureV5 extends Struct {
+ #isSigned;
#signKeys;
constructor(registry, value, { isSigned } = {}) {
const signTypes = registry.getSignedExtensionTypes();
super(registry, objectSpread(
// eslint-disable-next-line sort-keys
{ signer: 'Address', signature: 'ExtrinsicSignature', transactionExtensionVersion: 'u8' }, signTypes), GenericExtrinsicSignatureV5.decodeExtrinsicSignature(value, isSigned));
+ this.#isSigned = isSigned === undefined
+ ? !this.signature.isEmpty
+ : isSigned;
this.#signKeys = Object.keys(signTypes);
objectProperties(this, this.#signKeys, (k) => this.get(k));
}
@@ -41,7 +45,7 @@ export class GenericExtrinsicSignatureV5 extends Struct {
* @description `true` if the signature is valid
*/
get isSigned() {
- return !this.signature.isEmpty;
+ return this.#isSigned;
}
/**
* @description The [[ExtrinsicEra]] (mortal or immortal) this signature applies to
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ To get started -
5. Ready! Now you can launch the UI (assuming you have a local Polkadot Node running), via `yarn run start`
6. Access the UI via [http://localhost:3000](http://localhost:3000)

### Quip extrinsic decoding

This fork carries a Yarn patch for `@polkadot/types` so Apps can decode Quip
blocks that contain V5 bare inherents and V4 signed transactions. Quip uses a
custom hybrid transaction signature envelope instead of the standard
`MultiSignature`. The upstream decoder previously inferred signed-ness from
whether the decoded signature object looked empty; that heuristic breaks for a
struct-like custom signature because a default struct can look non-empty even
when the extrinsic wire byte marks the item as bare/unsigned.

The patch makes the decoder trust the explicit `isSigned` flag derived from the
extrinsic version/type byte. This preserves compatibility with valid SDK-format
blocks such as `0x05` bare V5 inherents followed by `0x84` signed V4
transactions.


## Docker

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"@polkadot/rpc-core": "^16.5.6",
"@polkadot/rpc-provider": "^16.5.6",
"@polkadot/typegen": "^16.5.6",
"@polkadot/types": "^16.5.6",
"@polkadot/types": "patch:@polkadot/types@npm%3A16.5.6#~/.yarn/patches/@polkadot-types-npm-16.5.6-6fe2703ed8.patch",

@augmentcode augmentcode Bot Jul 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the patch: protocol can introduce a distinct package locator; it’s worth confirming the dependency graph doesn’t end up with both patched and unpatched @polkadot/types copies, since mixed instances can lead to inconsistent extrinsic decoding and/or codec type mismatches at runtime.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

"@polkadot/types-augment": "^16.5.6",
"@polkadot/types-codec": "^16.5.6",
"@polkadot/types-create": "^16.5.6",
Expand Down
18 changes: 17 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2776,7 +2776,7 @@ __metadata:
languageName: node
linkType: hard

"@polkadot/types@npm:^16.5.6":
"@polkadot/types@npm:16.5.6":
version: 16.5.6
resolution: "@polkadot/types@npm:16.5.6"
dependencies:
Expand All @@ -2792,6 +2792,22 @@ __metadata:
languageName: node
linkType: hard

"@polkadot/types@patch:@polkadot/types@npm%3A16.5.6#~/.yarn/patches/@polkadot-types-npm-16.5.6-6fe2703ed8.patch":
version: 16.5.6
resolution: "@polkadot/types@patch:@polkadot/types@npm%3A16.5.6#~/.yarn/patches/@polkadot-types-npm-16.5.6-6fe2703ed8.patch::version=16.5.6&hash=9b49a6"
dependencies:
"@polkadot/keyring": "npm:^14.0.3"
"@polkadot/types-augment": "npm:16.5.6"
"@polkadot/types-codec": "npm:16.5.6"
"@polkadot/types-create": "npm:16.5.6"
"@polkadot/util": "npm:^14.0.3"
"@polkadot/util-crypto": "npm:^14.0.3"
rxjs: "npm:^7.8.1"
tslib: "npm:^2.8.1"
checksum: 10/364794496a194162575e2e4d3e008905419e71de7195733311a4da1d057d3653cf3a1f918743c7e2a95cadc44e8fed9e1cc806e5374bd9f88ccc3cfd19a48760
languageName: node
linkType: hard

"@polkadot/ui-keyring@npm:^3.16.7":
version: 3.16.7
resolution: "@polkadot/ui-keyring@npm:3.16.7"
Expand Down