3

I am attempting to sign and submit a simple "always succeeds" transaction body built by the CLI and signed with nami wallet.

cardano-cli transaction build-raw \ --alonzo-era \ --fee 200000 \ --tx-in {NAMI_ADDRESS_UTXO} \ --tx-out {SCRIPT_ADDRESS}+1800000 \ --tx-out {NAMI_ADDRESS}+998000000 \ --invalid-hereafter 50000000 \ --protocol-params-file protocol.json \ --out-file tx-script.draft

Signing this file with an initial key in the CLI, I then sign it with nami using const witnessSet = await window.cardano.signTx(transaction, true);

Generating the following hex CBOR: a10081825820863d383db3cc7494604d02d3bf214706a18a178ce50eb1f04ad3ef45f50815735840da3ef50001e801bb9580ea361cff86fedef6aab41ebf835dbd246afae02a8b380cbfef0bb1c1ad299b57837dcc04d22a8fc81d713989160513fb14020b7ca203

This hex is sent to the back-end where I do some transformations to get the set in the form of [0, [vkey witnesses]].

let bufferWitness = Buffer.from(witnessSet, "hex");
let witnessDecoded = await cbor.decodeFirst(bufferWitness);

const newWitness = [0]; // Array format accepted by the CLI
newWitness.push(witnessDecoded.get(0)[0]); // vkey witness generated by Nami
console.log('Result:', cbor.encode(newWitness).toString("hex"));

This generates the following hex CBOR: 8200825820863d383db3cc7494604d02d3bf214706a18a178ce50eb1f04ad3ef45f50815735840da3ef50001e801bb9580ea361cff86fedef6aab41ebf835dbd246afae02a8b380cbfef0bb1c1ad299b57837dcc04d22a8fc81d713989160513fb14020b7ca203

Decoded as: [0, [h'863D383DB3CC7494604D02D3BF214706A18A178CE50EB1F04AD3EF45F5081573', h'DA3EF50001E801BB9580EA361CFF86FEDEF6AAB41EBF835DBD246AFAE02A8B380CBFEF0BB1C1AD299B57837DCC04D22A8FC81D713989160513FB14020B7CA203']]

When I use cardano-cli assemble to generate the final transaction and submit, I get this error:

ShelleyTxValidationError ShelleyBasedEraAlonzo (ApplyTxError [UtxowFailure (WrappedShelleyEraFailure (InvalidWitnessesUTXOW [VKey (VerKeyEd25519DSIGN "863d383db3cc7494604d02d3bf214706a18a178ce50eb1f04ad3ef45f5081573")]))])

Which I do not understand as the tx body is not altered by the time it is sent to Nami, only signed with a dummy key but I'm assuming that should not affect the witness generated?

Any help would be appreciated, thanks.

3 Answers 3

2

I also struggled getting this to work via the cli. I went with a solution using the Java cardano-client-lib on the backend to create the base tx, and the cardano-serialization-lib browser package in the browser to add a sig.

here's the relevant browser code (selectively copy-pasted from my project, YMMV)

import * as CardanoSerdes from '@emurgo/cardano-serialization-lib-browser'
const Buffer = require('buffer/').Buffer

// helpers
function toHex(bytes) { return Buffer.from(bytes).toString("hex") }
function fromHex(str) { return Buffer.from(str, "hex") }

const txCborHex = "YOUR BASE TX CBOR HEX HERE"

const namiAddr = "nami wallet addr here"

// parse the base tx into the serialization lib model
const transaction = CardanoSerdes.Transaction.from_bytes(Buffer.from(txCborHex, "hex"))
const transactionWitnessSet = transaction.witness_set()
const transactionBody = transaction.body()

// get a handle on the PubKeyHash for the wallet
const walletAddress = CardanoSerdes.Address.from_bech32(namiAddr)
const baseAddress = CardanoSerdes.BaseAddress.from_address(walletAddress);
const baseAddrBytes = baseAddress.payment_cred().to_keyhash().to_bytes()
const pkh = CardanoSerdes.Ed25519KeyHash.from_bytes(baseAddrBytes)

// Add the pkh as a required signer
const requiredSigners = CardanoSerdes.Ed25519KeyHashes.new();
requiredSigners.add(pkh);
transactionBody.set_required_signers(requiredSigners);

// draft a new tx for the user to sign
let toSign = CardanoSerdes.Transaction.new(transactionBody, transactionWitnessSet);

// get the user to sign the base tx in the browser via nami
let txVkeyWitnesses = await cardano.signTx(
    toHex(toSign.to_bytes()),
    true
);
txVkeyWitnesses = CardanoSerdes.TransactionWitnessSet.from_bytes(
    fromHex(txVkeyWitnesses)
);

// add the sig to the base tx witness set
transactionWitnessSet.set_vkeys(txVkeyWitnesses.vkeys());

// compose a new tx
const readyToSubmit = CardanoSerdes.Transaction.new(transactionBody, transactionWitnessSet);

// convert to cbor hex.  you can submit this in the browser with cardano.submitTx() or using cli on the backend
const finalTx = toHex(readyToSubmit.to_bytes())

the npm deps in use are:

    "@emurgo/cardano-serialization-lib-browser": "^9.1.2",
    "buffer": "^6.0.3",

java dep

'com.bloxbean.cardano:cardano-client-lib:0.2.0-preview2'
1
  • This turned out to be a very useful answer for integrating a multi-sig pattern with Nami wallet. Thanks for the detailed answer and code.
    – spirois
    Commented Mar 8, 2022 at 14:22
1

I made a post on this, maybe this can help you. Basically you'd need to first sign transaction with cli, load transaction to cardano-serialization-lib, clear vkeys from witness-set, sign transaction on the frontend and add vkeys from signature witness-set.

Here's a link to my blogpost: https://srdjanstankovic.com/2021/12/24/how-to-sign-and-submit-cardano-cli-transaction-using-nami-wallet.html

1

The problem is that cardano-serialisazion-lib reorders the transaction and that makes the original witness invalid, https://github.com/Emurgo/cardano-serialization-lib/issues/311

My solution was

  • create tx with cardano-cli
  • deserialize with cardano-serialisazion-lib
  • serialize with cardano-serialisazion-lib
  • sign with cli

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.