4

I am creating a Subxt call where I need to add support for a signed extension that my chain uses. Is there an example of where I can add support for a signed extension?

1 Answer 1

8

Edit Oct 16 2023:

As of Subxt 0.32, there is now a SignedExtension trait in Subxt, and an signed_extensions::AnyOf type which can be given some Config and tuple ofSignedExtensionimpls, and itself implementsExtrinsicParams. This AnyOf` type is also smart, and will only apply the necessary signed extensions and in the correct order based on the chain metadata.

So, nowadays one can implement new SignedExtensions as needed, add them to the list of signed extensions provided in AnyOf (see the SubstrateConfig for the default list), and then write some function or interface if you want to make configuing the user parameters easier for people.

See an example of this here: https://github.com/paritytech/subxt/blob/cd5060a5a08c9bd73477477cd2cadc16015e77bf/subxt/examples/setup_config_signed_extension.rs

You can, however, still do as before and implement ExtrinsicParams yourself if preferred, which is explained below.

Original answer:

So, when you create a client in Subxt (eg an OnlineClient) you pass it some Config (eg SubstrateConfig or PolkadotConfig). One of the things that this config does it describe how to encode the signed extensions for an extrinsic.

To implement your own encoding of custom signed extensions, implement the ExtrinsicParams trait (https://docs.rs/subxt/0.28.0/subxt/config/extrinsic_params/trait.ExtrinsicParams.html). This interface lets you define some "builder" type that users construct to pass params in to the relevant functions, and then how to encode the additional and extra params when asked to.

By default, we implement this trait for a BaseExtrinsicParams type which covers default Substrate/Polkadot params like so: https://docs.rs/subxt/0.28.0/src/subxt/config/extrinsic_params.rs.html#59. Hopefully this implementation can serve as inspiration :)

Side Note: How do you know which extra and additional things the node you're talking to expects? Well, if you look in the metadata downloaded from a node you want to connect to, it will contain an extrinsic property which then contains a list of—in order—each extra and additional type that it's expecting. You can make sure to encode the same types in your implementation of ExtrinsicParams.

Once you have implemented this trait on your custom type, create some config like MyConfig which uses it:

enum MyConfig {}
impl Config for MyConfig {
    type Index = <SubstrateConfig as Config>::Index;
    type Hash = <SubstrateConfig as Config>::Hash;
    type Hasher = <SubstrateConfig as Config>::Hasher;
    type Header = <SubstrateConfig as Config>::Header;
    type AccountId = <SubstrateConfig as Config>::AccountId;
    type Address = <SubstrateConfig as Config>::Address;
    type Signature = <SubstrateConfig as Config>::Signature;
    // ExtrinsicParams are different; use the custom type:
    type ExtrinsicParams = MyCustomExtrinsicParams;
}

(in this case, we are just using the same params as the SubstrateConfig and only changing how the extra/additional params are encoded; you may have other things you need to change though)

Finally, use this config:

let client = OnlineClient::<MyConfig>::new().await?;

And now when you create extrinsics, the correct additional/extra params will be encoded by default, or can be provided by the user as an argument to calls like api.tx().sign_and_submit_then_watch(...).

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.