How to use signature and public key returned from Raw Signing (Cardano)?

Hi everyone,

has anyone successfully used Fireblocks’ Raw Signing functionality and successfully integrated the signature provided back by the API?

Considering we’re trying to sign Cardano transactions, we’re having issues because Cardano transactions usually require a payment.skey which doesn’t support binary data that Fireblocks returned? I’m not sure how to use the HEX encoded binary data that’s returned as the signature to create a witness for the Cardano transaction.

Any information would be greatly appreciated.

Hey @rsmolcic-3milab – you can build your witness data by converting Fireblocks’ raw signing hex responses for the pubKey and signature to byte arrays:

// assuming "sig_res" holds your raw signature response object
pub_key = sig_res['signedMessages'][0]['publicKey']
sig     = sig_res['signedMessages'][0]['signature']['fullSig']
witness = [pubkey, sig]

At which it you can build your transaction payload and serialize it for broadcasting:

// assuming "message" held the original TX payload
deserialized_tx = [deserialized_tx_payload, {0: [witness]}, None]
serialized_tx = cbor2.dumps(deserialized_tx)

I hope this is helpful–you might also find our Cardano staking script useful as a reference (ada_staking::staking.py). Out of curiosity, is there a reason you’re building Cardano TXs manually?

Hi @yoji ! Thank you for answering.

The reason we’re building the Cardano TX manually is because other than sending only ADA (Cardano), we’re also trying to send a Cardano Native Token (CNT), and it seems this isn’t available by default because once the transaction would complete, you can’t see the status or the amount of CNT. We’re trying to see if we can use Raw Signing to send CNTs from our Fireblocks Vault address, and then perhaps use something like a webhook to get notified that CNTs have arrived on a different address.

But given that this is new for us, we might be doing something wrong, but everything pointed to Raw Signing for SEND transactions (sending CNT from a Fireblocks address), because we’ve received confirmation that RECEIVE isn’t covered at all.

Any additional information regarding this scenario is always appreciated!
Thanks for your time!

Hey @rsmolcic-3milab –I see, using raw signing for outgoing CNT transactions certainly makes sense! You’re right about the receive-side limitation, since Fireblocks doesn’t support CNT natively, we won’t watch vault addresses for new CNT transfers.

A way around this can be using an external service to watch these addresses, whether a blockchain data provider sending webhooks or even a Cardano node scanning new blocks for CNT transfers to your addresses to update your own CNT ledger. This way, you can store and transfer CNTs from your Fireblocks vaults and process incoming transactions automatically.

Hey @yoji , thanks once again for replying!

A way around this can be using an external service to watch these addresses, whether a blockchain data provider sending webhooks

Do you happen to know (or can you recommend) such a provider? We’ve thought of testing a Blockfrost webhook monitoring the incoming transaction for a specific address, but we haven’t tested it yet so we have no idea whether it’s going to be able to recognize the CNT or the ADA only.

Also, thanks a lot of recommending the staking.py code example previously, I’m changing it now so that I can go through the process of creating the transaction and signing it in a similar manner shown inside the staking example :slight_smile:

@rsmolcic-3milab – Of course, happy to help!

Blockfrost is a great one–I think it’ll be your best option here. Good luck with the implementation!

Hi @yoji , first and foremost thanks once again for your help regarding this issue.

We’ve come to the end of the road, and there’s only 1 issue currently in the way of us confirming our POC of Raw Signing for CNTs, and I was wondering if you could maybe help me out.

Based on the code you’ve recommended (the example for staking ADA), as well as the PyCardano library and their documentation, I was able to construct a transaction that sends some ADA, as well some of my own CNT from my Fireblocks Sandbox address, to an address of my Yoroi wallet.

However, when trying to submit the transaction, we’ve received an error from Blockfrost that says that the witness information (the key and signature we’ve received from Fireblocks’ Raw Signing API) wasn’t what was expected.

sig_res = self.__wait_for_transaction_confirmation(tx_res['id'])

        pub_key = sig_res['signedMessages'][0]['publicKey']
        sig = sig_res['signedMessages'][0]['signature']['fullSig']

        witness = CardanoWitness(bytearray.fromhex(pub_key), bytearray.fromhex(sig))

        return witness

This is the part from the staking example which creates a witness based on the information received from Raw Signing API. Later on, when embedding that signature into the transaction, I’ve used the PyCardano library:

@staticmethod
    def __embed_signatures_in_tx(deserialized_tx_payload: dict, signature: CardanoWitness) -> bytes:

        vkey = VerificationKey(signature.pub_key)
        vkey_witness = VerificationKeyWitness(
            vkey=vkey,
            signature=bytes(signature.signature)
        )

        witness_set = TransactionWitnessSet(
            vkey_witnesses=[vkey_witness]
        )

        tx_body = TransactionBody.from_primitive(deserialized_tx_payload)

        transaction = Transaction(
            tx_body,
            witness_set
        )
        
        return transaction.to_cbor()

However in the end we submit the transaction that has the signatures embedded, we receive this error:

Tx submission res 400:b’{“error”:“Bad Request”,“message”:“{\“contents\”:{\“contents\”:{\“contents\”:{\“era\”:\“ShelleyBasedEraBabbage\”,\“error\”:[{\“contents\”:{\“contents\”:{\“contents\”:{\“contents\”:[\“VKey (VerKeyEd25519DSIGN \\\“9b4e380a414d16ced14e9cc00b6fd63ff3a22d5648a2f4a320aae0d6833920a3\\\”)\”],\“tag\”:\“InvalidWitnessesUTXOW\”},\“tag\”:\“ShelleyInAlonzoUtxowPredFailure\”},\“tag\”:\“AlonzoInBabbageUtxowPredFailure\”},\“tag\”:\“UtxowFailure\”}],\“kind\”:\“ShelleyTxValidationError\”},\“tag\”:\“TxValidationErrorInCardanoMode\”},\“tag\”:\“TxCmdTxSubmitValidationError\”},\“tag\”:\“TxSubmitFail\”}”,“status_code”:400}’

I know it’s a wall of text, but I’ve tried to go a bit in detail. Can you maybe spot what’s wrong? Are we using the Fireblocks signature in an incorrect way? Can the Fireblocks signature even work with the PyCardano TransactionWitnessSet and their VerificationKey?

As always, any information and insight is very appreciated.

Have a nice day!