disclaimer: agent-created report. but human reproduced and confirmed the issue
Summary
Decoding a V5 cross-consensus Location (e.g. bridged-from-Polkadot USDC on
Asset Hub Kusama: parents:2, X4[GlobalConsensus(Polkadot), Parachain(1000), PalletInstance(50), GeneralIndex(1337)]) fails when it arrives via the
assetId field of a SignerPayloadJSON for AssetHubKusama (which the chain's
pallet_asset_conversion_tx_payment resolves through TAssetConversion →
Option<Location>):
createType(ExtrinsicPayload):: createType(TAssetConversion)::
decodeU8aStruct: failed at 0x090200a10f043205e514… on interior (index 2/2):
{"_enum":{"Here":"Null","X1":"[JunctionV5;1]","X2":"[JunctionV5;2]",
"X3":"[JunctionV5;3]","X4":"[JunctionV5;4]","X5":"[JunctionV5;5]",
"X6":"[JunctionV5;6]","X7":"[JunctionV5;7]","X8":"[JunctionV5;8]"}}::
Unable to create Enum via index 9, in Here, X1, X2, X3, X4, X5, X6, X7, X8
The decoder reads parents=02 and Junctions::X4=04, then for the
[JunctionV5; 4] payload it reads 0x09 (which is the inner
Junction::GlobalConsensus variant) as a fresh outer Junctions variant
byte. Junctions only has variants Here, X1..X8 (indices 0–8), so index 9 is
out of range and decoding aborts.
The bytes themselves are well-formed runtime-valid SCALE; the chain accepts
them, and a tx that includes them in ChargeAssetTxPayment.value = 0x00010204090200a10f043205e514 runs fine. PAPI also encodes / decodes them
correctly. The failure is specifically in TAssetConversion's type resolution
for AssetHubKusama.
Reproduction
import { ApiPromise, WsProvider } from '@polkadot/api';
const api = await ApiPromise.create({
provider: new WsProvider('wss://kusama-asset-hub-rpc.polkadot.io'),
});
// bridged-from-Polkadot USDC on KAH (V5 cross-consensus Location)
const assetId = '0x0204090200a10f043205e514';
api.createType('TAssetConversion', assetId); // throws "Unable to create Enum
via index 9"
// or, equivalently, via the path the extensions exercise:
// api.createType('ExtrinsicPayload', { ..., assetId, ... })
Real-world impact
This is hit by every dApp using pallet_asset_conversion_tx_payment on
AssetHubKusama with a bridged asset as the fee asset. The polkadot.js extension
and SubWallet both crash their signing popups on the resulting
SignerPayloadJSON, and the React error boundary doesn't recover — every
subsequent signing prompt in the session also shows the error screen until the
browser is fully restarted.
Downstream issues with full traces, sticky-state details, and a npx serve .
HTML reproduction:
Suggested fix area
- Verify the AssetHubKusama types bundle has
JunctionV5 (singular) registered
with all V5 variants — including GlobalConsensus(StagingXcmV5NetworkId) at
index 9 — so '[JunctionV5;4]' resolves to the correct inner type and the
decoder reads each X4 payload entry as a Junction rather than a fresh
Junctions.
- Confirm
TAssetConversion for chains where
pallet_asset_conversion_tx_payment::Config::AssetId = Location resolves to
Option<StagingXcmV5Location>, not an older MultiLocation.
- Adding a regression test that round-trips a cross-consensus
Location (with
parents:2 and a GlobalConsensus junction) through TAssetConversion for
AssetHubKusama / AssetHubPolkadot would prevent re-introduction.
Environment
- Tested chain: Asset Hub Kusama (
wss://kusama-asset-hub-rpc.polkadot.io)
- Runtime spec version: 2002000
disclaimer: agent-created report. but human reproduced and confirmed the issue
Summary
Decoding a V5 cross-consensus
Location(e.g. bridged-from-Polkadot USDC onAsset Hub Kusama:
parents:2, X4[GlobalConsensus(Polkadot), Parachain(1000), PalletInstance(50), GeneralIndex(1337)]) fails when it arrives via theassetIdfield of aSignerPayloadJSONfor AssetHubKusama (which the chain'spallet_asset_conversion_tx_paymentresolves throughTAssetConversion→Option<Location>):The decoder reads
parents=02andJunctions::X4=04, then for the[JunctionV5; 4]payload it reads0x09(which is the innerJunction::GlobalConsensusvariant) as a fresh outerJunctionsvariantbyte.
Junctionsonly has variantsHere, X1..X8(indices 0–8), so index 9 isout of range and decoding aborts.
The bytes themselves are well-formed runtime-valid SCALE; the chain accepts
them, and a tx that includes them in
ChargeAssetTxPayment.value = 0x00010204090200a10f043205e514runs fine. PAPI also encodes / decodes themcorrectly. The failure is specifically in
TAssetConversion's type resolutionfor AssetHubKusama.
Reproduction
Real-world impact
This is hit by every dApp using
pallet_asset_conversion_tx_paymentonAssetHubKusama with a bridged asset as the fee asset. The polkadot.js extension
and SubWallet both crash their signing popups on the resulting
SignerPayloadJSON, and the React error boundary doesn't recover — everysubsequent signing prompt in the session also shows the error screen until the
browser is fully restarted.
Downstream issues with full traces, sticky-state details, and a
npx serve .HTML reproduction:
Suggested fix area
JunctionV5(singular) registeredwith all V5 variants — including
GlobalConsensus(StagingXcmV5NetworkId)atindex 9 — so
'[JunctionV5;4]'resolves to the correct inner type and thedecoder reads each X4 payload entry as a
Junctionrather than a freshJunctions.TAssetConversionfor chains wherepallet_asset_conversion_tx_payment::Config::AssetId = Locationresolves toOption<StagingXcmV5Location>, not an olderMultiLocation.Location(withparents:2and aGlobalConsensusjunction) throughTAssetConversionforAssetHubKusama / AssetHubPolkadot would prevent re-introduction.
Environment
wss://kusama-asset-hub-rpc.polkadot.io)