一键导入
v5-extrinsic-signatures
Use when extrinsics unexpectedly report is_signed() == false or a missing signature, or when handling V5 "General" extrinsics/transactions
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when extrinsics unexpectedly report is_signed() == false or a missing signature, or when handling V5 "General" extrinsics/transactions
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when fetching or decoding chain data (blocks, extrinsics, events, storage, runtime APIs) and tempted to make manual RPC calls (legacy_rpc, rpc_params!, chain_getBlock, state_call), or when writing code that branches on metadata versions
Use when decoding SCALE bytes, defining value types for dynamic storage queries, or choosing between parity_scale_codec::Decode and scale_decode::DecodeAsType — including when decoded values look subtly wrong without any error
| name | v5-extrinsic-signatures |
| description | Use when extrinsics unexpectedly report is_signed() == false or a missing signature, or when handling V5 "General" extrinsics/transactions |
Subxt decodes V5 extrinsics fine, but V5 General transactions appear unsigned: extrinsic.signature_bytes() == None and extrinsic.is_signed() == false. This is not a bug — the signature moved into the transaction extensions.
Look for the VerifySignature transaction extension:
use subxt::config::transaction_extensions::VerifySignature;
let details = extrinsic
.transaction_extensions()
.and_then(|exts| exts.find::<VerifySignature<_>>()) // config is inferred from the extrinsic
.transpose()?; // find returns Option<Result<_>>: Some(Err(_)) = matched but undecodable, None = no match
// details: Option<VerifySignatureDetails> — Disabled, or Signed { signature, account }
In this repo the client is SubstrateConfig (crates/server/src/state.rs), so leave the config as VerifySignature<_> and let it infer — a hardcoded VerifySignature<PolkadotConfig> won't satisfy find's bound. Put the lookup alongside the other shared extension types in crates/server/src/utils/transaction_extensions.rs rather than hand-rolling it per handler.
The on-chain identifier the extension matches against changed:
| subxt version | identifier matched |
|---|---|
< 0.50.1 (the beta.4 in crates/server/Cargo.toml) | "VerifySignature" |
0.50.1+ | "VerifyMultiSignature" (rename, subxt#2197) |
The Rust type is unchanged — you keep writing find::<VerifySignature<_>>() on both sides of the bump. What changed is the extension name in chain metadata that the lookup matches: < 0.50.1 only finds runtimes calling it VerifySignature; 0.50.1+ only finds runtimes calling it VerifyMultiSignature. A find name mismatch silently returns None.
You don't have to change subxt versions to fix it — match either name yourself:
let sig = match extrinsic.transaction_extensions() {
Some(exts) => exts
.iter()
.find(|ext| matches!(ext.name(), "VerifySignature" | "VerifyMultiSignature"))
.map(|ext| ext.decode_unchecked_as::<VerifySignatureDetails<SubstrateConfig>>())
.transpose()?,
None => None,
};
decode_unchecked_as skips the name check that find enforces, so one path handles both identifiers. Unlike find (which infers the config from the extrinsic), decode_unchecked_as can't infer it — name the config explicitly (SubstrateConfig in this repo).
Chains can opt to use different extensions or handle signatures in arbitrary ways under V5 — don't assume VerifySignature is universal across chains.