2

I'm using Bounded trait from preimages frame that allows to store dispatchable calls, e.g. similar to the one that is used in pallet-democracy:

pub type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
pub type BoundedCallOf<T> = Bounded<CallOf<T>>;

See the source code for reference: https://github.com/paritytech/substrate/blob/2dbf62591fd35725c6e39f8ddfd27c3695dab594/frame/democracy/src/lib.rs#L206

There is a possibility to decode it via preimages peek function on the backend side:

fn peek<T: Decode>(bounded: &Bounded<T>) -> Result<(T, Option<u32>), DispatchError>

here: https://github.com/paritytech/substrate/blob/2dbf62591fd35725c6e39f8ddfd27c3695dab594/frame/support/src/traits/preimages.rs#L183

and retrieve dispatch data.

However when I receive data via storage view call on the client side, the response looks like this:

Inline: “0x30000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22"

So the question is - is there a possibility to decode the dispatchable data? I'm not able to pre-process storage view functions unwrapping the encoded bounded data.

I've tried to use parity scale codec TS implementation: https://github.com/paritytech/scale-ts but the examples described there are not clear.

Any help is appreciated.

Thanks in advance!

2
  • Where do you want to decode this? The peek function already decodes it for you. And what are storage view call on the client side? Means that the value will not be in the preimages storage, but directly stored in the Bounded. Jan 27, 2023 at 23:34
  • @OliverTale-Yazdi Thanks for your comment! The idea is to decode it on the frontend side. By 'storage view call' I mean the storage getter macro: #[pallet::storage] #[pallet::getter(fn proposal_of)] If you use Bounded as a storage item, on the client side you will see the following item: Inline: “0x30000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22" Jan 30, 2023 at 10:13

2 Answers 2

1

The Bounded that you got there already is decoded.
What you want to do now is to decode the content of the Bounded<Call>.
I just tried that locally and it did not work but could work with your node.
The code for PolkadotJS is probably very similar to the python-substrate-interface. The idea is to decode the Inline data as a Call. Obviously this data is generally opaque, and you need to decide on a case-by-case basis what the type of the enclosed data actually is.


from substrateinterface import SubstrateInterface

URL = "ws://127.0.0.1:9944"

substrate = SubstrateInterface(URL)

data = '0x30000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22'
substrate.decode_scale('Call', data)

1
  • Thanks for reply but it doesn't quite answear the question. However the direction is absolutely correct. Please see my answear below - that's exactly what I needed. I've also attached link to the offline decode solution. Feb 6, 2023 at 10:45
0

I found the solution in the Polkadot JS itself, however it wasn't that straightforward and not described well in the docs.

Here is the guide on how to decode the Call inside the Bounded(taken from Polkadot-JS sources):

try {
      // cater for an extrinsic input
      const tx = api.tx(hex);

      // ensure that the full data matches here
      assert(tx.toHex() === hex, 'Cannot decode data as extrinsic, length mismatch');

      decoded = tx;
      extrinsicCall = api.createType('Call', decoded.method);
    } catch {
      try {
        // attempt to decode as Call
        extrinsicCall = api.createType('Call', hex);

        const callHex = extrinsicCall.toHex();

        if (callHex === hex) {
          // all good, we have a call
          isCall = true;
        } else if (hex.startsWith(callHex)) {
          // this could be an un-prefixed payload...
          const prefixed = u8aConcat(compactToU8a(extrinsicCall.encodedLength), hex);

          extrinsicPayload = api.createType('ExtrinsicPayload', prefixed);

          assert(u8aEq(extrinsicPayload.toU8a(), prefixed), 'Unable to decode data as un-prefixed ExtrinsicPayload');

          extrinsicCall = api.createType('Call', extrinsicPayload.method.toHex());
        } else {
          throw new Error('Unable to decode data as Call, length mismatch in supplied data');
        }
      } catch {
        // final attempt, we try this as-is as a (prefixed) payload
        extrinsicPayload = api.createType('ExtrinsicPayload', hex);

        assert(extrinsicPayload.toHex() === hex, 'Unable to decode input data as Call, Extrinsic or ExtrinsicPayload');

        extrinsicCall = api.createType('Call', extrinsicPayload.method.toHex());
      }
    }

After that you'll basically have all that you need: section, method, args that describe the call.

Here is the link to Polkadot-JS sources: Decoder.tsx

P.S. Inspired by this thread that will be useful for offline decoding as well: How can I manually decode hex extrinsic

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.