Add additional method to parse raw call data bytes into an unsigned payload so it can be signed and submitted later on
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 489
- Forks
- 293
- Avg merge
- 18h 35m
- Merged PRs (30d)
- 3
Description
Hi @jsdw,
Opening this issue to share what I'm currently doing since I haven't found a default option on the latest version of subxt and I think it might be good to have something similar available.
I often find it useful to keep the raw bytes exported from here tx().call_data(&proxy_call)? around, and only sign and submit on a second stage. I couldn't find a method on the latest version that could easily decode these bytes, the option tx().from_bytes(encoded) requires the encoded data to be already signed. I have looked to the other methods on how to create partial transaction, but they don't seem to apply here.
Do you have any suggestions?
Sharing the steps and code blocks to demonstrate my case:
- Export call data:
pub fn wrap_call_into_proxy(
api: &ClientAtBlock<SubstrateConfig, OnlineClientAtBlockImpl<SubstrateConfig>>,
call: RuntimeCall,
proxied_account: &AccountId32,
) -> Result<Vec<u8>, Error> {
let proxy_call = node_runtime::tx().proxy().proxy(
(*proxied_account).into(),
Some(ProxyType::NonTransfer),
call,
);
let payload = api.tx().call_data(&proxy_call).boxed()?;
Ok(payload)
}
- With the chain Metadata available, decode the original call data from previous method
wrap_call_into_proxy, sign it with a validKeypairand submit:
async fn sign_and_submit_call_data(
&self,
api: &OnlineClient<SubstrateConfig>,
proxy_signer: &Keypair,
call_data: &[u8],
) -> Result<Response, Error> {
let at_block = api.at_current_block().await.boxed()?;
let metadata = at_block.metadata();
let payload = RawPayload::from_bytes(&metadata, call_data).boxed()?;
let response = api
.tx()
.await
.boxed()?
.sign_and_submit_then_watch_default(&payload, proxy_signer)
.await
.boxed()?;
Ok(Response::transaction_submitted(response))
}
RawPayloadimplementation:
use scale_encode::{EncodeAsFields, Error as EncodeError, FieldIter, TypeResolver};
use subxt::{
transactions::{Payload, ValidationDetails},
Metadata,
};
pub type Bytes = Vec<u8>;
pub struct RawPayload {
pallet_name: String,
call_name: String,
field_bytes: RawFields,
}
pub struct RawFields(Bytes);
impl EncodeAsFields for RawFields {
fn encode_as_fields_to<R: TypeResolver>(
&self,
_fields: &mut dyn FieldIter<'_, R::TypeId>,
_types: &R,
out: &mut Bytes,
) -> Result<(), EncodeError> {
out.extend_from_slice(&self.0);
Ok(())
}
}
impl Payload for RawPayload {
type CallData = RawFields;
fn pallet_name(&self) -> &str {
&self.pallet_name
}
fn call_name(&self) -> &str {
&self.call_name
}
fn call_data(&self) -> &RawFields {
&self.field_bytes
}
fn validation_details(&self) -> Option<ValidationDetails<'_>> {
None
}
}
impl RawPayload {
pub fn from_bytes(metadata: &Metadata, bytes: &[u8]) -> Result<Self, Error> {
let pallet = metadata
.pallet_by_call_index(bytes[0])
.ok_or(Error::PalletNotFound)?;
let call_variant = pallet
.call_variant_by_index(bytes[1])
.ok_or(Error::CallNotFound)?;
Ok(Self {
pallet_name: pallet.name().to_string(),
call_name: call_variant.name.clone(),
field_bytes: RawFields(bytes[2..].to_vec()),
})
}
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Pallet not found")]
PalletNotFound,
#[error("Call not found")]
CallNotFound,
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the tx().call_data and tx().from_bytes entry points, then compare them with the RawPayload and Payload implementation shown in the issue. Check how metadata resolves pallet and call indexes and how transaction signing consumes Payload. Done means a supported path exists for decoding exported raw call data and signing and submitting it later, with coverage for the demonstrated flow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, blockchain
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100