Minting an On-Chain NFT with a Hardware Wallet

In this post, I want to explore two things: How to create an on-chain NFT and how to use a hardware wallet for the minting instead of creating (and needing to fund) a lot of file-based keys as in the usual guides.

On-Chain NFTs

Usually NFTs reference an off-chain location – a URI reachable by HTTP(S), IPFS, or Arweave, for example – where the content resides. If this location ceases to be reachable, the content of the NFT will no longer be available. The NFT continues to exist on the blockchain, can still be transferred from address to address, but we cannot see the image, watch the video, or hear the song that it refers to, anymore.

For on-chain NFTs, we use data: URIs, which do not reference an external resource, but directly contain the content in an encoded form. This way, the content of the NFT resides on the blockchain inside the metadata and remains available as long as the blockchain keeps running.

Data URIs can contain arbitrary file types, but it is quite common that a combination of HTML, CSS, and Javascript is used to create (inter)active NFTs. The art is to keep the content small enough that it can still be embedded into the minting transaction, which is restricted to 16 KiB at the moment. Examples of such on-chain NFTs include Stellar Hood and Mesmerizer.

(If we talk about the far future, we would also have to consider that maybe clients look way different then. It is possible that it won’t be usual anymore that they can interpret the content types that we put into our NFTs, that HTML/CSS/JS gets outdated, that SVG/JPG/PNG become as exotic as IFF or Koala Painter are today. It will probably not become impossible to view them, since knowledge about these technologies is very wide-spread, but it may happen that not every computer can readily display them without effort, anymore. This would be a problem for off-chain as well as on-chain NFTs.)

The Assets

The example NFT will be something like a business card with a logo that on click is exchanged for a page with a headline and a QR code (pointing to my forum profile). As assets we need the logo, the QR code, and the font for the headline.

My logo is a hand-crafted SVG, the source of which is:

<?xml version="1.0" encoding="UTF-8"?>
<svg width="1600px" height="1600px" viewBox="0 0 1600 1600"
     xmlns="http://www.w3.org/2000/svg">
    <style>
        #b {
            fill: #162633;
        }
        #s {
            stroke: #446987;
        }
        #h {
            stroke: #bcdaf8;
        }
        path {
            fill: none;
            stroke-width: 25;
            stroke-linecap: round;
            stroke-linejoin: round;
        }
    </style>
    <rect id="b" width="1600" height="1600" x="0" y="0" />
    <path id="s"
          d="M 100 800 A 700 700 0 0 1 1500 800 A 650 650 0 0 1 200 800
                       A 600 600 0 0 1 1400 800 A 550 550 0 0 1 300 800
                       A 500 500 0 0 1 1300 800 A 450 450 0 0 1 400 800
                       A 400 400 0 0 1 1200 800 A 350 350 0 0 1 500 800
                       A 300 300 0 0 1 1100 800 A 250 250 0 0 1 600 800
                       A 200 200 0 0 1 1000 800 A 150 150 0 0 1 700 800
                       A 100 100 0 0 1  900 800 A  50  50 0 0 1 800 800" />
    <path id="h"
          d="M 800 100 L 1104 1431 L  253 364 L 1482  956
                       L  118  956 L 1347 364 L  496 1431 Z" />
</svg>

I have used https://www.svgminify.com/ (which does a good job in minimising among other things the paths by using different ways of expressing the coordinates of the next point on the path) and some manual edits afterwards to minify this from 1199 bytes to 665 bytes.

In the HTML, I will use the SVG code directly, but for using this as the preview image of the NFT, I also want to have the Base64-encoded data URI:

$ (echo -n 'data:image/svg+xml;base64,'; base64 -w 0 HeptaLogo-minimal.svg) > HeptaLogo-minimal.base64
$ cat HeptaLogo-minimal.base64
data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+PHN2ZyB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxNjAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzdHlsZT4jYntmaWxsOiMxNjI2MzN9I3N7c3Ryb2tlOiM0NDY5ODd9I2h7c3Ryb2tlOiNiY2RhZjh9cGF0aHtmaWxsOm5vbmU7c3Ryb2tlLXdpZHRoOjI1O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZH08L3N0eWxlPjxyZWN0IGlkPSJiIiB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxNjAwIi8+PHBhdGggaWQ9InMiIGQ9Im0xMDAgODAwYTcwMCA3MDAgMCAwIDEgMTQwMCAwIDY1MCA2NTAgMCAwIDEtMTMwMCAwIDYwMCA2MDAgMCAwIDEgMTIwMCAwIDU1MCA1NTAgMCAwIDEtMTEwMCAwIDUwMCA1MDAgMCAwIDEgMWUzIDAgNDUwIDQ1MCAwIDAgMS05MDAgMCA0MDAgNDAwIDAgMCAxIDgwMCAwIDM1MCAzNTAgMCAwIDEtNzAwIDAgMzAwIDMwMCAwIDAgMSA2MDAgMCAyNTAgMjUwIDAgMCAxLTUwMCAwIDIwMCAyMDAgMCAwIDEgNDAwIDAgMTUwIDE1MCAwIDAgMS0zMDAgMCAxMDAgMTAwIDAgMCAxIDIwMCAwIDUwIDUwIDAgMCAxLTEwMCAwIi8+PHBhdGggaWQ9ImgiIGQ9Im04MDAgMTAwIDMwNCAxMzMxLTg1MS0xMDY3IDEyMjkgNTkyaC0xMzY0bDEyMjktNTkyLTg1MSAxMDY3eiIvPjwvc3ZnPgo=

(This URI can just be copied into the address bar of a browser and we can see the logo.)

For the QR code, I first also used SVG, but, since QR codes consist of lots of small squares, this is not the most efficient file format for them. In the end, I generated a PNG file on https://www.qrcode-monkey.com/ and edited it with Gimp to remove the border and choose some options (saving it with indexed colours – it only has two, not embedding any metadata) resulting in a 627 byte file.

Since, we want to later embed this into the HTML code, I’m again converting it to a data URI:

$ (echo -n 'data:image/png;base64,'; base64 -w 0 QR-CardanoForum.png) > QR-CardanoForum.base64
$ cat QR-CardanoForum.base64
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQUAAAEFAgMAAACX+BoCAAAADFBMVEUWJjNIXW9xiZ+82vhw6NWbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5ggMCicIr+YZxwAAAfpJREFUeNrt28tRwzAQgGGBC/CdJijBLdIGVKFSKCEFZFgmOF7vy49wzPw6CWJ9vuyspJXcmm+DiPt7FHH/meTSDhoExL29fWn7WIl7507cRg5L52Ud8Dk//C7avk8Rr+uAH4gnJi5L5P0RIv2QWF4DAfEA4QaIXFu7oePcEQiIfxPzAFnC1LcJAuIBws+pcwi2JRYVvRriYFqGeAIirsEPibwGzzsBN4PmzpnNBASEpKZTadgSXKuHb4ELAVERGnA6g4af7bazSoUNAmKHsFvKEKZS5zv9CQJim9CdZHORp7HoXtPCkq5DQJSEyXculw1uk+kImxxDyoSAkHAGlBb2V9MxP2ng9vQaCIhAVKVVHallC3GpUBNfmlMhIGIshvqFzXcuise0gIOA2CVMp2+XLfr6Gn0YAuKAcNPkYDaZZktgbuqMEBD7RLdli+PdpnmmQUBsE9XEaeZUSYlvDOs2CIiacGt6vxQLRYqYEyEgDohennBrtULSyVAL5TMIiJrIJ9zuVr2/FT0VxVYIiGmvCF8NMAeTl+LM0q7bICASkb/omdbSqqTr9eI2mVsff0BA7H65MaWVXAsHk/PDEBBniDrfSVq3GRQC4jzhb1Hkor/Y6xQQEDURP/7o4WA7Z8BwiwLiCYn8Rc/DRLUTGENFTBIhobIPAeGJX4h4Mcgb+NL9AAAAAElFTkSuQmCC

In order to use a custom font for the headline, I have used https://www.fontsquirrel.com/tools/webfont-generator and selected in “Expert” mode that I only want the WOFF format, that I want a custom subset with only the characters needed for my headline, and that I want Base64-encoded version embedded in CSS. From the generated archive, I only need the snippet in stylesheet.css:

@font-face {
    font-family: 'senextrabold';
    src: url(data:application/font-woff;charset=utf-8;base64,[…]) format('woff');
    font-weight: normal;
    font-style: normal;
}

The HTML

Putting all of these together, I have created the following HTML code:

<!doctype html>
<html lang=en>
    <meta charset=utf-8>
    <title>HeptaSean's Card</title>
    <style>
        @font-face{font-family:'Sen';src:url(data:application/font-woff;charset=utf-8;base64,[…taken from FontSquirrel's stylesheet.css…])format('woff')}
        body{background:#bcdaf8;color:#162633;margin:0}
        div{width:100%;height:100vh;overflow:hidden;text-align:center}
        #b{fill:#162633}
        #s{stroke:#446987}
        #h{stroke:#bcdaf8}
        path{fill:none;stroke-width:25;stroke-linecap:round;stroke-linejoin:round}
        h1{font-family:'Sen'}
        img{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
    </style>
    <script>
        function q(){document.getElementById('l').style.display='none';
                     document.getElementById('q').style.display='block'}
        function l(){document.getElementById('q').style.display='none';
                     document.getElementById('l').style.display='block'}
    </script>
    <body>
        <div id=l onclick=q()>
            <svg width="100%" height="100%" viewbox="0 0 1600 1600" xmlns="http://www.w3.org/2000/svg">
                […taken from HeptaLogo-minimal.svg…]
            </svg>
        </div>
        <div id=q onclick=l() style=display:none>
            <h1>HeptaSean</h1>
            <a href=https://forum.cardano.org/u/heptasean onclick=event.stopPropagation()>
                <img src="data:image/png;base64,[…taken from QR-CardanoForum.base64…]" alt="">
            </a>
        </div>

The two pages for the logo and the QR code are divs with IDs l and q and the – quite silly – Javascript functions q() and l() switch between them and are called on clicks on the pages.

One thing to note: Clients presenting your NFT will typically show it in an iframe, where they decide the size. Giving absolute sizes for divs (which I first tried) will, hence, not work nicely. If the iframe is larger, the NFT will be in the top-left corner, if it is smaller, it will get scrollbars. Setting the divs to 100% width and 100vh height and then letting the childs fill this space or centering them in it, seems to work okayish.

The code is already quite minimal – omitting all unnecessary quotes around attribute values, omitting unrequired closing tags, omitting some of the unrequired white space – but I have kept some newlines and indentation to keep it mostly readable.

However, the validator https://validator.w3.org/nu/#file of the W3C still is happy with this and does not give a single error.

We can get the size of the HTML further down from 5427 bytes to 5078 bytes by removing the remaining whitespace (more than half of the size is the custom font subset):

$ cat HeptaCard.html | tr '\n' ' ' | sed -e 's/>[[:space:]]\+/>/g' -e 's/;[[:space:]]\+/;/g' -e 's/}[[:space:]]\+/}/g' > HeptaCard-minimal.html

(This removes all white space after >, ;, and }. This might not be safe for all HTML files, but for my example it is.)

Finally, we create a Base64-encoded data URI for the whole HTML file (which, by the way, contains some of our previous Base64-encoded data URIs):

$ (echo -n 'data:text/html;base64,'; base64 -w 0 HeptaCard-minimal.html) > HeptaCard-minimal.base64

The Metadata

Now, we need to put this into a metadata.json file according to CIP 25. (I am still using version 1, since version 2 does not seem to be widely supported, yet.)

Strings in Cardano metadata are restricted to be at most 64 bytes long. So, we have to turn our data URIs into arrays of strings of at most 64 bytes:

$ fold -w 64 HeptaLogo-minimal.base64
data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+PHN2ZyB3aW
[…]
Y3eiIvPjwvc3ZnPgo=
$ fold -w 64 HeptaCard-minimal.base64
data:text/html;base64,PCFkb2N0eXBlIGh0bWw+PGh0bWwgbGFuZz1lbj48bW
[…]
48L2Rpdj4=

We can then create the metadata.json:

{
  "721": {
    "00000000000000000000000000000000000000000000000000000000": {
      "HeptaCard": {
        "name": "HeptaSean's Card",
        "mediaType": "image/svg+xml",
        "image": [
          "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+PHN2ZyB3aW",
          […]
          "Y3eiIvPjwvc3ZnPgo="
        ],
        "files": [
          {
            "mediaType": "text/html",
            "src": [
              "data:text/html;base64,PCFkb2N0eXBlIGh0bWw+PGh0bWwgbGFuZz1lbj48bW",
              […]
              "48L2Rpdj4="
            ]
          }
        ]
      }
    }
  }
}

Testing this metadata file in https://pool.pm/test/metadata looks good:

The all-zero policy ID still has to be replaced with the real one, which we will find in the minting process.

Minting with a Hardware Wallet

Most NFT minting guides – like https://developers.cardano.org/docs/native-tokens/minting-nfts/ – advise to generate keys with cardano-cli. But then we have to take care of our secret key files and we have to send funds to their addresses to cover the fees and minimal accompanying ADA during minting. Since I have all of my funds on my Ledger now, I want to use that to secure the minting policy as well as to pay for the minting. Fortunately, the documentation of cardano-hw-cli even contains a page about that: https://github.com/vacuumlabs/cardano-hw-cli/blob/develop/docs/token-minting.md

At least version 1.11.0 of cardano-hw-cli is needed, since the previous version(s) had a bug making the metadata hash of the transaction invalid: https://github.com/vacuumlabs/cardano-hw-cli/releases

The Policy

According to the cardano-hw-cli guide and CIP 1855, I will use the key with the derivation path m/1855’/1815’/7’ for this NFT. A .vkey file with the public key and a .hwsfile containing configuration to later ask the Ledger to sign our minting transaction can be requested from the hardware wallet by:

$ cardano-hw-cli address key-gen --path 1855H/1815H/7H \
--verification-key-file policy.vkey --hw-signing-file policy.hwsfile

(The hardware wallet will ask permission to export a public key during this command.)

The hash of the public key can then be queried as usual by:

$ cardano-cli address key-hash --payment-verification-key-file policy.vkey
c77c5ee379e2f6b21e63206010467a1abe3e54703aeccb558cf0bb19

I want the policy to lock at the beginning of the next epoch (357 at the time of writing). That is slot (357−208)×432 000+4 492 800=68 860 800.

Altogether, this gives the following policy.script file:

{
    "type": "all",
    "scripts": [
        {
            "type": "before",
            "slot": 68860800
        },
        {
            "type": "sig",
            "keyHash": "c77c5ee379e2f6b21e63206010467a1abe3e54703aeccb558cf0bb19"
        }
    ]
}

We can now get the policy ID:

$ cardano-cli transaction policyid --script-file policy.script
43c4b46c9635b3a57c9731de817a20b3d099ee2c7f44a0e2723c4bb6

And we put it into the metadata.json file created above:

{
    "721": {
        "43c4b46c9635b3a57c9731de817a20b3d099ee2c7f44a0e2723c4bb6": {
            "HeptaCard": {
[…]

The NFT, the token, the asset is identified by the combination of policy ID and asset name. For the cardano-cli transaction build command line, we need the hex encoding of the asset name. We can get that, for example, by:

$ echo -n HeptaCard | basenc --base16
486570746143617264

The Payment Key

Since I want the second account on the Ledger to pay for the mint and receive the NFT, and I am using this account in single-address mode in other wallet apps, the key that I have to export from the Ledger is m/1852’/1815’/1’/0/0. Again, I get a .vkey and a .hwsfile:

$ cardano-hw-cli address key-gen --path 1852H/1815H/1H/0/0 \
--verification-key-file payment.vkey --hw-signing-file payment.hwsfile

(Again, the hardware wallet will ask permission to export a public key during this command.)

I already know the address that I want to spend from and that I want to receive the NFT on, but just to show how it works: It is a delegated address, so we need to have the public stake key as well and then can put it into cardano-cli address build:

$ cardano-hw-cli address key-gen --path 1852H/1815H/1H/2/0 \
--verification-key-file stake.vkey --hw-signing-file stake.hwsfile
$ cardano-cli address build --mainnet \
--payment-verification-key-file payment.vkey --stake-verification-key-file stake.vkey
addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q

Yep, that is the address I already know from my wallet apps.

As usual, we can search for an unspent transaction output (UTxO) to pay for our minting by:

$ cardano-cli query utxo --mainnet \
--address addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q
                           TxHash                                 TxIx        Amount
--------------------------------------------------------------------------------------
[…]
dec49e5f9fb6d8bdbd5f4c9add67ad0a3d3e8f7b1853a5d2ef078dd053620768     2        12363808 lovelace + TxOutDatumNone
[…]

(Searching for an UTxO in a wallet app, e.g., Eternl, might be more comfortable.)

The Mint Transaction

We now have everything we need to build the mint transaction:

$ cardano-cli transaction build --mainnet \
--tx-in dec49e5f9fb6d8bdbd5f4c9add67ad0a3d3e8f7b1853a5d2ef078dd053620768#2 \
--mint "1 43c4b46c9635b3a57c9731de817a20b3d099ee2c7f44a0e2723c4bb6.486570746143617264" \
--mint-script-file policy.script --invalid-hereafter 68860800 --metadata-json-file metadata.json \
--tx-out "addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q+2824075+1 43c4b46c9635b3a57c9731de817a20b3d099ee2c7f44a0e2723c4bb6.486570746143617264" \
--change-address addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q \
--witness-override 2 --cddl-format --out-file transaction.raw
Estimated transaction fee: Lovelace 537345
  • The --tx-in is the UTxO, we have found at the end of The Payment Key.
  • The policy ID and hex-encoded asset name in --mint were derived at the end of The Policy and we want to mint one token, since it’s supposed to be an NFT.
  • The --mint-script-file was also constructed in The Policy. The slot in --invalid-hereafter is exactly the one given in the policy. The --metadata-json-file is the one built in The Metadata and later updated with the policy ID.
  • The address to send to in --tx-out and --change-address was derived in The Payment Key (but it could be any other of the user’s choice). The 2824075 Lovelace were chosen, because it is also the amount accompanying every other token in my wallet (by Eternl’s choice). We could have given an amount that is surely too small – say 1 ADA, 1000000 Lovelace – and cardano-cli would have complained giving the minimal amount needed. The asset part of --tx-out is exactly the one we have already seen in --mint.
  • We need a --witness-override of 2, because we want to sign with two keys – the policy and the payment key.
  • Using the new --cddl-format is important, so that cardano-hw-cli can deal with the transaction.

The raw format has to be transformed by cardano-hw-cli into a form that it can use:

$ cardano-hw-cli transaction transform --tx-file transaction.raw --out-file transaction.canonical
The transaction contains following fixable errors:
- CBOR is not canonical (transaction)
- Optional empty lists and maps must not be included as part of the transaction body or its elements (transaction_body.collaterals)
- Optional empty lists and maps must not be included as part of the transaction body or its elements (transaction_body.required_signers)
Transformed transaction will be written to the output file.

Now, we can sign the raw transaction with both witnesses – the policy key as well as the payment key:

$ cardano-hw-cli transaction witness --mainnet \
--tx-file transaction.canonical --hw-signing-file policy.hwsfile --out-file policy.witness
$ cardano-hw-cli transaction witness --mainnet \
--tx-file transaction.canonical --hw-signing-file payment.hwsfile --out-file payment.witness

(For both commands, the hardware wallet will ask if it is okay to sign – giving a lot of detailed information about the transaction before that.)

Finally, we just have to assemble the canonical transaction and the witnesses and submit:

$ cardano-cli transaction assemble --tx-body-file transaction.canonical \
--witness-file policy.witness --witness-file payment.witness --out-file transaction.signed
$ cardano-cli transaction submit --mainnet --tx-file transaction.signed
Transaction successfully submitted.

Et Voilà

The minting transaction can now be seen on Cardanoscan: https://cardanoscan.io/transaction/de3271da5fc532947b344f53771391370c2bd0b9a69ba0981b68b1581de6a811

While I just navigated there from my wallet, I could have found the transaction ID by:

$ cardano-cli transaction txid --tx-file transaction.signed
de3271da5fc532947b344f53771391370c2bd0b9a69ba0981b68b1581de6a811

(… and that works even before the transaction is submitted, so it can be used to wait for the transaction showing up on Cardanoscan or in an API.)

And our minted on-chain NFT is visible on pool.pm: https://pool.pm/asset10zsrgd7329r73aq7ms3hvv0k2c727q55uszdfc

I also just navigated there from my wallet. Unfortunately, cardano-cli and other standard tools do not have an option to derive the asset1… fingerprint. It is specified in CIP 14 and the reference implementation is here: https://www.npmjs.com/package/@emurgo/cip14-js

5 Likes

EDIT: There previously was a bug in cardano-hw-cli that is fixed in version 1.11.0 (https://github.com/vacuumlabs/cardano-hw-cli/releases/tag/v1.11.0). This part of the original post and the post below were about finding that bug:

In case someone finds this interesting, the cause of the metadata reordering bug is that cardano-hw-cli uses a CBOR library with an option to canonically order keys in a map according to https://www.rfc-editor.org/rfc/rfc7049#section-3.9. (This does not mean alphabetically ordered, but by its byte representation, which in effect means first by length, then alphabetically.)

So from the ordering in our JSON

           […]
                "name": "HeptaSean's Card",
                "mediaType": "image/svg+xml",
                "image": […],
                "files": [
                    {
                        "mediaType": "text/html",
                        "src": […]
                    }
                ]
           […]

cardano-cli first derives this order in the CBOR representation

$ cardano-cli text-view decode-cbor --in-file transaction.broken
                  […]
                  a4  # map(4)
                      # key
                     65 66 69 6c 65 73  # text("files")
                      # value
                     81  # list(1)
                        a2  # map(2)
                            # key
                           69 6d 65 64 69 61 54 79 70 65  # text("mediaType")
                           […]
                            # key
                           63 73 72 63  # text("src")
                           […]
                      # key
                     65 69 6d 61 67 65  # text("image")
                     […]
                      # key
                     69 6d 65 64 69 61 54 79 70 65  # text("mediaType")
                     […]
                      # key
                     64 6e 61 6d 65  # text("name")
                     […]

(which is not the order in the JSON, but seems to be alphabetically sorted) and cardano-hw-cli then canonicalises it to

$ cardano-cli text-view decode-cbor --in-file transaction.canonical
                  […]
                  a4  # map(4)
                      # key
                     64 6e 61 6d 65  # text("name")
                     […]
                      # key
                     65 66 69 6c 65 73  # text("files")
                      # value
                     81  # list(1)
                        a2  # map(2)
                            # key
                           63 73 72 63  # text("src")
                           […]
                            # key
                           69 6d 65 64 69 61 54 79 70 65  # text("mediaType")
                           […]
                      # key
                     65 69 6d 61 67 65  # text("image")
                     […]
                      # key
                     69 6d 65 64 69 61 54 79 70 65  # text("mediaType")
                     […]

breaking the hash in the process.

It seems cardano-cli is also partly responsible for this, so another bug had to be filed: https://github.com/input-output-hk/cardano-node/issues/4335

EDIT: this worked in the past, looks like there is currently an issue with that correct!

1 Like

Thanks for looking into it!

Really hope that I can remove that “bummer” soon. :grinning:
It was such a nice article flow without it.

Version 1.11.0, published today, fixes this!

Thanks for your support in that Github issue and thanks to the cardano-hw-cli team for the quick fix!

I have moved the overly complicated description of bug and work-around from the main post to the second one, so that we have a nice article again.