I'm trying to create a poc to separate out the signing of transactions from the libraries such as subxt or polkadot-js. I was trying subxt and schnorrkel libs to create partial signed transaction and sign it using noble/curve lib of js or I don't know if I can use any other libs from any other languages. Basically trying to sign a transaction using any crypto libs so that signing becomes language agnostic. I'm trying to extract out this specific line(never mind the code). I tried to sign it using schnorr from noble/curve or even sign it using signer.sign() from polkadot-js and both created a bad signature when I try to submit the transaction. I guess maybe the metadata or the type might not be correct as expected.

const sig = schnorr.sign(msg, priv);


y = alice.sign(x)

Is is possible to do this? Am I missing something to in creation of the signature?

1 Answer 1


In the case of Subxt, you have a couple of options:

1. Get the signer payload, sign it and hand back to Subxt

At the end of the day, the bytes that needs signing is a signer payload which contains the transaction bytes plus some additional/extra details (or possibly a hashed version of this).

In Subxt, you can do something like this to get the bytes needed to sign some transaction and then hand back a signature and submit it:

// 1. Create a "partial" transaction:
let partial_tx = client.tx().create_partial_signed(

// 2. Fetch the bytes that need to be signed:
let signer_payload = partial_tx.signer_payload();

// 3. go off and sign them
let signature: &[u8] = {/* ... */} 

// 4. Hand signature back to Subxt and submit the tx.
//    At this point you need to provide the "from" address
//    that corresponds to the key used to sign it.
let tx = partial_tx.sign_with_address_and_signature(

// 5. Now you can `tx.submit_and_watch()` or whatever to 
//    submit the signed tx.

See https://docs.rs/subxt/latest/subxt/book/usage/transactions/index.html for more information on signing transactions.

If you end up with a bad signature here, it can be hard to tell why. The address and signature need to match (ie the address is derived from the public key of the signer you used), and the signature algorithm needs to be suitable for the given chain (ie for Polkadot we'd expect an sr25519 signature).

2. Gather details needed for wallets like Talisman and have it sign.

Wallets like Talisman can't be simply given the signer payload bytes to be signed, and instead must be given a JSON object containing various details.

This payload has the shape:

export interface SignerPayloadSON {
  /* The ss-58 encoded address */
  address: string;
  /* The checkpoint hash of the block, in hex */
  blockHash: string;
  /* The checkpoint block number, in hex */
  blockNumber: string;
  /* The era for this transaction, in hex */
  era: string;
  /* The genesis hash of the chain, in hex */
  genesisHash: string;
  /* The encoded method (with arguments) in hex */
  method: string;
  /* The nonce for this transaction, in hex */
  nonce: string;
  /* The current spec version for the runtime */
  specVersion: string;
  /* The tip for this transaction, in hex */
  tip: string;
  /* The current transaction version for the runtime */
  transactionVersion: string;
  /* The applicable signed extensions for this runtime */
  signedExtensions: string[];
  /* The version of the extrinsic we are dealing with */
  version: number;

(see https://github.com/polkadot-js/api/blob/52e36534cfde94d4f032e88fee9ba0d24ccb4fb1/packages/types/src/types/extrinsic.ts#L32)

The wallet itself then takes these details and constructs a signer payload and then signs it using the selected account, handing back the signature.

We have an example in Subxt wherein we build this type in a Subxt WASM app and submit it to a browser wallet for signing; see https://github.com/paritytech/subxt/blob/ab84228af45a7d5ba5e2494172554e000da05898/examples/wasm-example/src/services.rs#L125, and more generally check out the example to learn more.

In the case of using polkadot.js itself, I think it accepts a JSON object similar to the above to sign transactions, but I'm not sure offhand!

  • Hey thanks for the reply, makes sense to me. One thing that I'm confused is that eventhough the code I gave doesn't did the partial_extrinsic creation of subxt I had tried that before. It gave a bad signature error when using Alice keyring. But as said the I gave u8 array to sign for polkadot-js rather than JSON which could also be the case.
    – kroos47
    Aug 21 at 20:12
  • One more doubt that I have is that, even through creation of payload is a success, If I use rust only and sign it through schnorrkel lib to sign, it works. I assume there should be some kind of an implementation in polkadot-js or gsrpc where there is some cryptographic signing happening. Thats where I found the noble-curves lib which I think is also used in polkadot-js. Is it possible to extract that part out or as mentioned the bytes should contain enough information to sign?.
    – kroos47
    Aug 21 at 20:16
  • 1
    I can't really speak for polkadot-js I'm afraid. Subxt has a "separate" signing crate called subxt-signer which can be used to sign arbitrary bytes etc though if that helps at all (or you can do as you did of course). I assume that polkadot-js probably wants some JSON object, and internally constructs a signer payload and uses some lib to sign it. At a glance it looks like hre is the code: github.com/polkadot-js/common/blob/master/packages/util-crypto/…, so you may be able to depend only on the bit you need.
    – jsdw
    Aug 24 at 16:40
  • Yeh makes sense on that, but signing should be the same on whatever the lib that is used right? I see that the js takes JSON to sign with is kinda different from how its in subxt. I see subxt is using schnorrkel lib to sign, but I have seem some glimps of schnor lib in js also. So is it possible to sign it with those libs? schnorrkel is partity maintained and schnor in js is general lib. So I wonder if its possible to sign an extrinsic with those signing libs where users can sign without thinking about subxt or polkadot-js or even gsrpc.
    – kroos47
    Sep 20 at 7:31
  • Ultimately, the signer payload bytes that you can ask Subxt for are exactly the bytes that need signing. As long as you take the same approach to sign them as eg github.com/paritytech/subxt/blob/…, you can use any language of course to do so. Browser wallets like Talisman cannot be handed these raw bytes to sign though; they expect a JSON payload (and internally then construct the raw bytes themselves). I think Polkadot.js expects similar, but as you say, ultiamtely they will all sign the same bytes that Subxt provides.
    – jsdw
    Sep 22 at 11:00

Your Answer

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

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