Skip to content

Titan-C/cardano.el

Repository files navigation

Cardano transaction editor

Motivation

You interact with the Cardano blockchain through transactions. Your wallet software takes care of the common user tasks, yet for advanced endeavors you need the cardano-cli. Which gets really cumbersome as transactions grow in complexity. Bash scripts tame the problem only for a while, because their limitation is the very thing they offer: Bash scripts automate repetitive tasks at the cost of flexibility.

The command line is a great tool, yet if I ever write more than 4 words on the command line I go crazy. The command line is, for me, a tool for quick queries not a work environment. Bash scripts are good to automate simple things and keep dependencies low. However, I go crazy when maintaining large bash scripts. Bash scripts enslave you to the one dimensionality of the command line, because even when editing those scripts on an editor you must mark line breaks, and keep track of quoting your variables and input.

I want a tool that lets me craft my transactions, a powerful tool to interact with the cardano-node, which has all the features, does not get cumbersome as you increase the complexity of your tasks, and empowers you as a user.

I couldn’t find such a tool, thus I started building it myself. A text editable interface to create my transactions for the Cardano network. A tool that embraces the power of my text editor instead of the limitations of the command line.

Video Demos

I host a YouTube Channel called Ars magna for my Cardano related projects. If you doubt whether this project is for you, have a look at how it can change your workflow:

ContentLinkLength
Spending transactionshttps://www.youtube.com/watch?v=Sgvc3WaZlPY6:13
Token mintinghttps://www.youtube.com/watch?v=1hAv63NeJ-U9:22
Stake delegationhttps://www.youtube.com/watch?v=0A30HIS-BEw9:46
Key files & address managementhttps://www.youtube.com/watch?v=8ZIT9Uq_9A014:25
Cardano Wallet Interface & scriptshttps://youtu.be/Ma9nbhbz3wY14:59
Hardware wallet integrationhttps://www.youtube.com/watch?v=RbVH1YE1WW417:18

The videos are a show case of this project, yet as this project develops further, they naturally become obsolete. The documentation bellow is an up to date reference.

Word of caution

This project is a running experiment and in Alpha stage. Don’t rely on any of its functions or interfaces to be stable, because I’m still testing its user interface. Feedback is highly welcomed.

Warning aside, myself and other Cardano users believe this is an awesome way to interact with the Cardano blockchain, it frees you from the cumbersome CLI by offering you a declarative way to specify your transactions, without loosing fine grain control.

This project has received support from the Cardano community, it is a Catalyst Fund 7 & 9 funded projects and is a Plutus Pioneer Capstone 2021 challenge prize winner.

Installation

Dependencies

Cardano Node >= 1.35.4

You need a running Cardano node post Vasil Hard-Fork you can connect to.

For Mainnet follow the standard guide https://docs.cardano.org/getting-started/installing-the-cardano-node

Cardano-Addresses

It manages the key generation for HD wallets

Cardano-Wallet (Optional)

This package is the backend for Daedalus. It is another service that needs to run in the background, with it you have access to rich wallet functionalities.

Cardano-hw-cli (optional)

To work with hardware wallets you need a patched version of the cardano-hw-cli from vacuumlabs. This patch allows the editor to directly push information to that utility and avoids managing so many files. The patched binary is in this repository https://github.com/arsmagna-xyz/cardano-hw-cli/tree/witness-request

Make sure to build the witness-request branch.

Emacs 28

This is the latest release. Install it and also the following packages.

This package itself

This package is on MELPA. If you use use-package, get it directly with all its Emacs dependencies with.

(use-package cardano-tx
  :commands (cardano-tx-new cardano-tx-cli-tip))

Using the Guix package manager

The file guix.scm provides a specification on all the package dependencies. Binaries from IOHK as well as the Emacs dependencies.

You can install this package with:

guix package -f guix.scm

Or you can enter a developer container with all necessary dependencies using:

guix shell -D -f guix.scm -C

Configuration

There are some variables you need to configure.

;; Path to cli tool
(setq cardano-tx-cli-command "/full/path/to/the/cardano-cli")
;; Path to cardano-address binary
(setq cardano-tx-address-command (executable-find "cardano-address"))
;; Path to the running node socket
(setq cardano-tx-cli-node-socket "/full/path/to/the/testnet/socket")
;; These are the network arguments for the Preview testnet
(setq cardano-tx-cli-network-args '("--testnet-magic" "2"))
;; When connecting to mainnet use
;; (setq cardano-tx-cli-network-args '("--mainnet"))

;; This directory stores all your key pairs (verification & signing), it is your
;; wallet. It also holds your staking key. Make sure this folder exists, as this
;; tool will not create it. For wallet hygiene use separate directories for
;; mainnet and testnets. It also holds an SQLite database to administer known data.
;; WARNING: Keys stored here are not encrypted
(setq cardano-tx-db-keyring-dir (expand-file-name "~/cardano-wallet-keys/"))
;; In case you want to log the CLI commands used
(setq cardano-tx-log-level 'debug)

Cardano-Wallet (optional)

This package focuses on the low-level, high power interfaces for the cardano-cli and cardano-addresses. Yet, most of the time you just need a simple wallet to spend your ADA and keep track of that transaction history. To achieve that goal, this tool also integrates with cardano-wallet the middle-ware server that sits between your cardano-node and the Daedalus front-end.

cardano-wallet needs its own configuration to run the server that connects to your node and provides a local REST API to manage your wallet. Once you have configured it as specified on the official documentation, you only need to load the package and specify the API endpoint. Using use-package for example:

(use-package cardano-wallet
  :commands (cardano-wallet-balances cardano-wallet-helm-pick)
  :config
  (setq cardano-wallet-url "http://localhost:8090"))

Usage

Start by interactively querying the tip of the Blockchain. Use: M-x cardano-tx-cli-tip, you should see at the bottom of the screen on the mini-buffer the information about the tip.

At the time of writing it showed this:

block: 190408
epoch: 45
era: Babbage
hash: 4e422ef1108925a9b5a2d97b20a9938f1afc09297ae8d6522534dbc432bb1366
slot: 3971838
syncProgress: "100.00"

Create key pairs and manage addresses

Bag of keys

To create new keys and their corresponding addresses use: M-x cardano-tx-address-new-key-files. It will prompt you how to name your new keys. Type one name or more separating them by spaces. This will populate the directory you defined in cardano-tx-db-keyring-dir, with the keys.

This means:

M-x cardano-tx-address-new-key-files RET first second third RET

will generated the following folder structure:

~/cardano-wallet-keys/
├── cardano.db
├── first.skey
├── first.vkey
├── second.skey
├── second.vkey
├── stake.skey
├── stake.vkey
├── third.skey
└── third.vkey

In the background it will create you default reward(staking) key and interactively ask you whether to create addresses with your new key files using that reward key or not. The addresses information and the keys are stored in the SQLite database cardano.db.

⚠ WARNING: Please keep in mind, that all keys are plain text files on your system. Thus, when working with “mainnet” ADA, make sure you take the necessary precautions to secure your files, work on an air gapped machine.

To create a staking key (under the name stake2) use the ELisp command:

(cardano-tx-address-new-key "stake2" t)

The name stake is the default name for the reward key, and created automatically. After creating additional reward keys, you can generate new addresses that use those keys by calling cardano-tx-address-load. Select the spending key type, confirm whether to watch the new address and which reward key you want to use. All key file and addresses are stored in the SQLite database in the cardano.db file.

Hierarchical Deterministic Wallets

You can also install cardano-addresses and let this tool help you manage your keys following the CIP-3 specification, and CIP-11.

The function cardano-tx-address-gen-recovery-phrase will assist you creating a mnemonic seed recovery phrase and save it on your cardano-tx-db-keyring-dir.

⚠ WARNING: Please keep in mind, that all keys and recovery phrases are plain text files on your system. Thus when working with “mainnet” ADA, make sure you take the necessary precautions to secure your files, work on air gapped machine.

The function cardano-tx-address-new-hd-key-files prompts for a derivation path for your key, you can still call this with many space separated paths. Following CIP-11 the path 1852H/1815H/0H/2/0 will generate the staking key.

As in the previous section you can create the corresponding addresses calling interactively cardano-tx-address-load.

Hardware Wallets (Experimental)

Installing the patched version from cardano-hw-cli from arsmagna-xyz on the witness-request branch. Register the location of the binary, for example.

(setq cardano-tx-hw-command (executable-find "cardano-hw-cli"))

You can request the hardware wallet public keys by calling M-x cardano-tx-hw-request-extended-pubkeys. The intention is to only request the public keys following BIP32 until the account index, that is the path depth of 3. E.g.

1852H/1815H/0H

The editor stores this extended public key on the database and manages the key derivations, on demand in the database. You can access the stored keys by calling M-x cardano-tx-db-master-keys, which open a table view of the registered extended public keys. Likewise to the HD wallets, to derive and register the payment and staking verification keys you must first call M-x cardano-tx-address-hw-derive-key-files. There select which extended account key do you want to derive from and define the paths along which to derive these keys. In this case you can use the expansion syntax for paths with .. marking an inclusive range. For example

1852H/1815H/0H/0..1/0..3

Expands to

1852H/1815H/0H/0/0 1852H/1815H/0H/0/1 1852H/1815H/0H/0/2 1852H/1815H/0H/0/3 1852H/1815H/0H/1/0 1852H/1815H/0H/1/1 1852H/1815H/0H/1/2 1852H/1815H/0H/1/3

Don’t forget to derive the staking path which terminates in 2/0.

Once you have your verification keys registered it is time to create the corresponding addresses. In this case there is a special function that is account preserving for each of the extended public keys from the hardware device. Call M-x cardano-tx-address-hw-load and select an extended public key account. It will generate addresses for all registered keys in the database that belong to that account.

Registering key files

If you generated some key files previous to using cardano.el or from previous versions of it, before its use of a SQLite database you need to register those keys to the database. The easiest way is using dired to mark the files you want to register and then interactively calling cardano-tx-db-dired-load-files. You can also register Cardano native simple scripts (multisigs/timelocks) and Plutus script files.

To visualize the files registered in the database call the interactive function cardano-tx-db-typed-files. This opens a table view of all registered files. You may add annotations to each file. Annotations help you identify in the future their content more than the filename does. The available functions for this view are:

ShortcutFunctionDescription
ocardano-tx-db-file-openOpen file
acardano-tx-db-file-annotateAdd a note to the file
wcardano-tx-db-file-writeWrite the file to disk. This overwrites the file with your changes
ccardano-tx-db-file-name-copyCopy the file path into the kill-ring
dcardano-tx-db-file-deleteDelete file from the database. Optionally from disk too.

Manage addresses

cardano-tx-address-load calculates addresses from registered files and loads them on the address database. Call it after registering new files. This doesn’t work for files originating from the Hardware device as they produce extended keys. For those files use cardano-tx-address-hw-load.

To visualize addresses loaded into your database call cardano-tx-db-addresses. This opens a view with all registered addresses. You can toggle which ones to actively watch(query UTxO balance), copy the address to the keyboard or edit the annotation.

ShortcutFunctionDescription
acardano-tx-db-address-annotateAdd note to address
ccardano-tx-db-address-copyCopy address to kill-ring
wcardano-tx-db-address-toggle-watchQuery this address when looking for UTxOs
dcardano-tx-db-address-deleteDelete address from database

Crafting a transaction

The goal is to directly create the transaction in your editor instead of using the CLI commands when crafting of the transaction.

To launch the editor call M-x cardano-tx-new. It will list all the UTxOs that you control on your wallet for you to spend. This might take a while as it is an expensive query for the cardano-node [fn:1]. Select one or many, you can still include more into your transaction during the edit process later on. A new buffer opens with the basic spending transaction template you can directly edit.

Spending and sending funds to arbitrary addresses

Have a look at the next annotated example. It is a larger than usual transaction(2 inputs - 4 outputs), because the goal of this tool is to demonstrate that it doesn’t get cumbersome as the transaction scope grows. It is a simple and standard yaml file. The structure reflects intuitively what the transaction itself is about. I’m sure you can understand it just by reading it.

# These are the inputs for the transaction.
inputs:
  - utxo: a7c5d4ab42016fa2cbdcbdb03133a9c6826ad5432f2a30e4b5ed32c1ac4c86f0#1
  - utxo: bd61923ca80f4789a2a7eddbe57e200fcb3af84b7d990a2fb5bc30efc71ba440#1

# Outputs are defined in the same way.
outputs:
  # A simple payment output to this address
  - address: addr_test1qznwk2s30nyvtgn20z27kqlnezxn6gu3ud8f3zyrxfae3ymk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qt6aaad
    amount:
      lovelace: 10000000

  # Payment to a Plutus script. The AlwaysSucceeds script
  - address: addr_test1wpnlxv2xv9a9ucvnvzqakwepzl9ltx7jzgm53av2e9ncv4sysemm8
    amount:
      lovelace: 1234567
    # You must include the datum. This tool calculates the hash for you.
    datum: [2, "the always succeeds contract", {"with a": "mixed type datum"}]

  # Payment to another Plutus script
  - address: addr_test1wzxfj3l2es945szu8wd6mm9jnkj7wze2zwtagkhdmn62gxqnvz87d
    amount:
      lovelace: 20000000
    # This script requires a typed datum, because the script input is a 2-tuple of ints
    # In this case the input is the path to a file that has the typed specification
    # of the datum
    datumfile: "plutus-data/tuple_ints(-5,6)"

  # ALWAYS think about your change address
  - address: addr_test1qpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgnk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qmkmv4t
    change: true # The cardano-cli balances it. Only lovelaces for now

Not only is it readable, you get the advantages of syntax highlighting, indentation, auto-completion and more editing tools from the editor. You can of course write comments in between the lines, because yaml allows that. That is not possible within a bash script that uses long commands with line breaks. You only get to comment around the blocks of instructions.

When creating this transaction there are utility functions that help you with some input. For example:

  • cardano-tx-helm-utxos Pick from utxos that are in your wallet for easy input.
  • cardano-tx-address-pick Pick from all your registered addresses
  • cardano-tx-available-balance Calculates, displays and loads to kill-ring the balance not yet committed to transaction outputs.

The Plutus scripts we send funds in this transaction are contracts/AlwaysSucceeds.plutus and contracts/list-in-range.plutus. The first takes any datum, the second takes a two element tuple to define a range. That’s why the datum needs to be a tuple, and why we need to use the typed version for the datum, because tuples are not available as JSON values.

In this repository you can find the datum file used for this example in the path plutus-data/tuple_ints(-5,6), and it has this content.

{"constructor":0,"fields":[{"int":-5},{"int":6}]}

To send the transaction just use shortcut C-c C-c or call M-x cardano-tx-edit-finish. That will build the transaction, calculate the fees, sign it, submit it, close the editing window and copy the transaction id to the clipboard for you to look for it in your favorite explorer.

This transaction has the id 591d446e2ed8951e07cd9260df0eaec308e7b6eb75cae68124344bec09c9a75a, and is on the Preview Testnet.

Change address and fee

The editor uses in general the build command to craft the transaction, which requires a change address. Unfortunately, that change address only balances the transaction in lovelace and is a required field. However, if your change is exactly zero lovelace the transaction would still work(see IntersectMBO/cardano-node#3041). You can thus use than function cardano-tx-available-balance to balance the transaction and once you try to build it extract the minimum fee value from the error message. Then put that value as an extra field on the transaction description:

fee: 189432

Re-balance your transaction outputs and try again, the change address although required will not show up on the crafted transaction, and the fee field is only a help to balance the transaction, as the build command does not use it.

Currently, it only makes sense to pay the minimum fee in Cardano. Yet, if it one day implements a market for fees, where a higher fee would help you get ahead on the mempool and prioritize your transaction you can set your fee. For that use the fee field, but delete the change address output. That will use the build-raw command where you specify the fee.

Minting native tokens

Minting tokens is again simple and doable with a single specification. Again, exemplifying with a rather large transaction, where I’ll mint two kinds of tokens: a fungible token with unconstrained minting policy and a NFT policy. Additionally, the NFT metadata will include its metadata.

Launch the editor with M-x cardano-tx-new, and pick some UTxOs to fund the mint transaction. It is a big transaction, don’t get overwhelmed by the forest they are only trees. Follow the comments, a lot is going on in this transaction. To help you write the minting specification typing mint followed by <TAB> will use yasnippet to load minting template specification.

inputs:
  - utxo: bd61923ca80f4789a2a7eddbe57e200fcb3af84b7d990a2fb5bc30efc71ba440#0

# Minting policies are characterized by the policy-id, here you can name them,
# and use that name throughout the transaction. The editor will then replace the
# name for the policy-id when creating the transaction.

mint:
  # This first policy(reward-tokens) only requires one witness to mint. You can mint
  # anytime you want as long as you have the key. I can use them as reward points.
  # I can keep minting to reward users.
  reward-tokens: # This is my first policy name
    policy: # Declare the policy. A single signature is enough
      type: sig
      keyHash: 73a144c2762078541ac9d258714121da5044069dc442cc7fe1fb0471 # fourth
    assets: # Here is the amount of assets to mint. I name each of the tokens
      gold: 100
      platinum: 50
  # This second policy are two NFTs. It honors XKCD, and mints NFTs that link to
  # a particular comic. The minting policy requires 2 witnesses and has a time lock
  # to ensure that no more assets are minted under this policy after the slot passed
  xkcd: # this is the policy name
    policy:
      type: all
      scripts:
        - type: sig
          keyHash: a6eb2a117cc8c5a26a7895eb03f3c88d3d2391e34e988883327b9893 # second
        - type: sig
          keyHash: 9bcde05606b1fbd5f5390b3ebbba0f523bddba5822027c856ebc336a # third
        - type: before
          slot: 3979246 # this is the time lock
    assets: # Minting two unique NFTs
      networking: 1
      frustration: 1

# You need to help the tool when using scripts by enumerating which witnesses
# need to sign the transaction. These are the keys on your wallet. I commented
# in the previous scripts which keyHash maps to which key
# You don't need this hint on normal spending, because it can infer which key owns which UTxO.
witness:
  - second
  - third
  - fourth

# For Mary Era Timelocked NFTs don't forget to match the validity interval, with
# the one on the time lock policy
validity-interval:
  invalid-hereafter: 3979246
  # invalid before:

# The metadata here allows to describe the NFTs. You can then see them on an explorer
metadata:
  721:
    xkcd: # policy name
      networking: # token name
        id: 1
        name: "Networking"
        description: "Our company is agile and lean with a focus on the long tail."
        image: ipfs://Qmbu8L59m5YHxo7kSCnfZa9DLSApyLFXTpbcJo6tx8vzzq
      frustration: # token name
        id: 2
        name: "Frustration"
        description: "Don't worry, I can do it in under a minute."
        image: ipfs://QmdunoNVjXe8aLFHvPqWdjNZmSfQBnrhb1pPwLcEAJcVUR

# Finally the 4 output. I distribute the newly minted tokens across multiple addresses
outputs:
  - address: addr_test1vzdumczkq6clh4048y9nawa6pafrhhd6tq3qyly9d67rx6sq3zpq7 # third-enterprise
    amount:
      xkcd: # policy name
        networking: 1 # token name
      reward-tokens: # other policy name
        gold: 40 # corresponding token name
      lovelace: 2000000

  - address: addr_test1qznwk2s30nyvtgn20z27kqlnezxn6gu3ud8f3zyrxfae3ymk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qt6aaad # second
    amount:
      reward-tokens:
        gold: 60
        platinum: 15
      lovelace: 3678910

  - address: addr_test1qpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgnk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qmkmv4t
    amount:
      xkcd:
        frustration: 1
      reward-tokens:
        platinum: 35
      lovelace: 4002413

  # ALWAYS think about your change address
  - address: addr_test1qpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgnk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qmkmv4t
    change: true

Have a look at the transaction on an testnet explorer: b679f4aab00161e0e96b3b3b61611f849fb9f075aeff351fdf3c6cc1954496c7 Notice that the token names are still described by human readable strings. The editor translates those names to hexadecimal values when creating the transaction as required by the cardano-node>=1.33.

Registering stake address and delegating to a stakepool

The transaction to register and delegate at the same time looks like this:

inputs:
  - utxo: b679f4aab00161e0e96b3b3b61611f849fb9f075aeff351fdf3c6cc1954496c7#0

certificates:
  # Standard certificates
  - registration:
    # vkey-file:  # optionally pick the staking verification key file
    # deregistration: true
  - delegation:
      pool: pool1a7h89sr6ymj9g2a9tm6e6dddghl64tp39pj78f6cah5ewgd4px0
      # vkey-file:  # optionally pick the staking verification key file
  # Specify the certificate file
  # - file:

# You must sign with the stake key to authorize the certificate
witness:
  - stake

outputs:
  # ALWAYS think about your change address
  - address: addr_test1qpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgnk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qmkmv4t
    change: true

It is important to note, that you must register the stake address before you delegate your stake. If you are doing both actions in the same transaction, then make sure that the registration item is before the delegation item (like in this example) otherwise the transaction will fail. If you want to do this on separate transactions, it still holds to register before you delegate.

This sample transaction is also on the testnet under the txid: 649bc635b27d372f5274e439b70718732cea816483ab47c93ef6ec3d941fc0a0

Withdraw your staking rewards

Withdrawing is again just another element of your transaction.

input:
  - utxo: 8bdfcfa7faa87f32c624700d1bec7fb0cd3af0ed3fb9e7a5e1121bc52433e645#0

outputs:
  # ALWAYS think about your change address
  - address:  addr_test1qpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgnk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qmkmv4t
    change: true

withdrawals:
  # Specify from which staking address you withdraw the rewards
  - address: stake_test1urpklgzqsh9yqz8pkyuxcw9dlszpe5flnxjtl55epla6ftqktdyfz
    amount:
      lovelace: 315716

# You must sign with the stake key because you spend from the staking address
witness:
  - stake

The function cardano-tx-rewards receives as input the staking addresses and helps you with the total amount in the rewards.

Claiming from a Plutus script address

The Plutus script in this example has this validator script, and corresponds to the script in the file contracts/list-in-range.plutus.

{-# INLINABLE rangeContract #-}
rangeContract :: (Integer, Integer) -> [Integer] -> ScriptContext -> P.Bool
rangeContract (l,h) redeemer _ = P.all (\x -> l P.<= x P.&& (x P.<= h)) redeemer

data RangeContract
instance Scripts.ValidatorTypes RangeContract where
    type instance DatumType RangeContract = (Integer, Integer)
    type instance RedeemerType RangeContract = [Integer]

rangeContractInstance :: Scripts.TypedValidator RangeContract
rangeContractInstance = Scripts.mkTypedValidator @RangeContract
    $$(PlutusTx.compile [|| rangeContract ||])
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = Scripts.wrapValidator @(Integer, Integer) @[Integer]

As you see we needed a two element tuple for the datum to define a range. The redeemer must be a list of “arbitrary length”, but all elements must be integers within the range defined by the datum. This is exercise 4.d of the Alonzo-testnet exercises.

One transaction that solves this constraint is:

inputs:
  # This is the UTxO that created in the previous section
  # Because it is a Plutus script. To unclock it we need to provide extra
  # information like the Plutus script, datum and redeemer
  - utxo: 591d446e2ed8951e07cd9260df0eaec308e7b6eb75cae68124344bec09c9a75a#3
    # path to the script file
    script-file: "contracts/list-in-range.plutus"
    # path to the typed datum
    datumfile: "plutus-data/tuple_ints(-5,6)"
    # I can directly specify a JSON value. List are JSON values and thus
    # can be directly parsed. There is no need to write the typed version in a file.
    redeemer: [2, -5, -1, 4, 0, 3, 1, 6, -4]

collateral: 649bc635b27d372f5274e439b70718732cea816483ab47c93ef6ec3d941fc0a0#0

outputs:
  # ALWAYS think about your change address
  - address:  addr_test1qpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgnk2wgk4wl2rz04eaqmq9fnxhyn56az0c4d3unvcvg2yw4qmkmv4t
    change: true

C-c C-c or calling M-x cardano-tx-edit-finish, builds and submits the transaction. In this case the transaction is 76fd80c71c9e81cd68e2682a2a5da4ec83eff7beb2381714fb8aa85dc4056d3a and you can find it on the preview testnet explorer.

That’s it. This tool reflects the transaction crafting with a User Interface, that is the transaction itself and takes care of all the details about parsing the input, signing and submitting.

Native simple scripts (multisigs/timelocks)

The same scripts you used for minting policies are usable to secure funds. Those are simple multisig and timelock scripts. To create one of those scripts call the function cardano-tx-new-script. It will open an editor window where you can write the clauses of your script. The yasnippet shortcut ns expands into the clauses of a simple script. Simple scripts are recursive, thus you can go as deep as you want stating you spending clauses.

Press C-c C-c to save the script. This will convert the script from it’s YAML editing form to a JSON file and save it on your cardano-tx-db-keyring-dir for later use using the script hash as file name. Please understand that after that step you should never modify that file. If you need a new script with slight variations, make a new script and it to the database and keep that copy.

Visiting cardano-tx-db-typed-files you can see the newly created script. I advise you to also write a description of it using the annotation feature. Later you can call cardano-tx-address-load to calculate the address of this script and have it available for use.

Full wallet integration (Optional)

If you installed the cardano-wallet the main entry point is the interactive function cardano-wallet-balances, which opens a buffer with a table showing the balances of all your registered wallets. To register a wallet call cardano-wallet-create, it will ask for the name of the wallet, a file containing the seed phrase(use the previous section for that), and a password to lock up your wallet. Once registered cardano-wallet will scan the blockchain for transactions pertaining your wallet, that takes a fair amount of time the first time, then it stays in watch mode and keeps synchronizing with the latest state of the blockchain.

From the balances view you can interact with each wallet using this shortcut functions:

ShortcutFunctionDescription
RETcardano-wallet-describeShow the information about the wallet
scardano-wallet-tx-newCreate a new payment transaction
lcardano-wallet-addressesList all addresses associated to wallet
tcardano-wallet-tx-logList all the transactions from this wallet
dcardano-wallet-deleteRemove this wallet

cardano-wallet-helm-pick is the entry point to work with each of your wallets individually. Gives you the same functionality you have from the balances view. Its menu lets start a payment transaction, list all addresses, look at the transaction history, and show a description of the wallet.

You can register your hardware wallet public keys using the command cardano-wallet-hw-register. In this case you can create directly payment transaction from this interface. When opening this wallet from the address view it is also possible to instantiate their verification keys.

When creating transactions the editor is much more restricted, as only payments are possible, you can only specify outputs. The wallet takes care off the inputs through coin selection. If you have registered your hardware wallet it also takes care of calling the hardware device to witness the transaction and submit it.

Ouroboros mini-protocols

The file ouroboros.el contains a simple implementation of The Shelley Networking Protocol to connect to the node and query information. You can use it for the local state query mini-protocol, for example:

(progn
  (setq sock (ouroboros-connect "path/to/cardano-node.socket" 2))
  ;; After connection immediately engage in another mini protocol otherwise the server drops the connection
  (ouroboros-local sock 'acquire 'tip))
(ouroboros-local sock 'query 'chain-point)
(ouroboros-local sock 'query 'block-no)
(ouroboros-local sock 'query 'system-start)
(ouroboros-local sock 'query 'hard-fork-eras)
(ouroboros-local sock 'query 'current-era)

(ouroboros-local sock 'query '(shelley epoch-no))
(ouroboros-local sock 'query `(shelley non-myopic-member-rewards
                                       ,(ouroboros-non-myopic-stake '(123456 456789133))))
(ouroboros-local sock 'query '(shelley current-params))
(ouroboros-local sock 'query '(shelley proposed-params))
(ouroboros-local sock 'query '(shelley stake-distribution))
(ouroboros-local sock 'query `(shelley utxo-by-address
                                 ,(ouroboros-address-query
                                   '("addr_test1vpsfwsr4eqjfe49md9wpnyp3ws5emf4z3k6xqagvm880zgs2k5jvj"
                                     "addr_test1zqeh2kmcf3wlp8jjlzve75mmvnmyac730p8j33zkxdawy7xn5qmqcmgt2t5gzpygzpr3y2y72d9ftuydut8qr8tqvqvs06lg42"))))
(ouroboros-local sock 'query '(shelley utxo-whole))
(->
 (ouroboros-local sock 'query '(shelley cbor-wrap epoch-no))
 (cbor-tag-content)
 (cbor->elisp))
(ouroboros-local sock 'query `(shelley filtered-delegations-and-reward-accounts
                                 ,(ouroboros-reward-addresses
                                   '("stake_test17r9cs7pxyf2nzlwg64fkf646kwq0mq9ucjlscefdthyj33sy8f0js"
                                     "stake_test1upm98yt2h04p386u7sdsz5entjf6dw38u2kc7fkvxy9z82s5f2lrh"))))
(ouroboros-local sock 'query '(shelley genesis-config))
(ouroboros-local sock 'query '(shelley reward-provenance))
(ouroboros-local sock 'query `(shelley utxo-by-tx-in
                                 ,(ouroboros-utxo
                                   '("c6a1c03c473753c932277634a39e8a3bacf4ae792eac174ab1e1b272d142db1f#0"))))

(ouroboros-local sock 'query '(shelley stake-pools))
(ouroboros-local sock 'query `(shelley stake-pool-params
                                 ,(cbor-tag-create
                                   :number 258
                                   :content ["13ab5c2838adaf649eb7e974779b705bb2b997c3c8132c3700c78dfe"
                                             "96788607f51dfaf3d115594e09cc6b75740035b8da05891995434268"])))
(ouroboros-local sock 'query '(shelley reward-info-pools))
(ouroboros-local sock 'release)
(ouroboros-local sock 'done)

I published a written document about all available queries in https://arsmagna.xyz/docs/network-lsq/. A short video series teaching you about the node communication and the local state query is available on YouTube. https://www.youtube.com/watch?v=rAWPudH55D4&list=PLwRUn-ZyfKJx2sj5hgJqL68KCTq7aSvkpG

Extra info

This an awarded project of the Cardano Summit 2021 - Plutus Pioneer Capstone Challenge. You can read about it on the IOHK blog, and watch the interview with some of the winners. I hope it raises awareness of this tool and also to call attention to my Catalyst proposal to fund the further development of this tool.

Doom-Emacs interesting buffers

If you are a Doom-Emacs user, you might realize that it becomes extra cumbersome to find the buffers from this tool. That is because of Doom’s philosophy of what makes an interesting buffer. You can tell Doom that these buffers are interesting by including the following code on your configuration file.

(add-hook! 'doom-real-buffer-functions
  (defun cardano-interesting-buffer (b)
    "Whether the current buffer's major-mode is a cardano mode."
    (with-current-buffer b
      (memq major-mode '(cardano-tx-db-addresses-mode
                         cardano-tx-db-files-mode
                         cardano-tx-mode
                         cardano-wallet-tx-log-mode)))))

Footnotes

[fn:1] Finding the UTxOs takes a while and thus your editor blocks during that time. Since the cardano-node=1.33 the UTxO set moved from RAM to Disk and that makes this query even slower.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published