npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mutants/cardano-tx-builder

v1.20.0

Published

A package that provides utility functions to build and destructure a cardano transaction

Downloads

428

Readme

Cardano Tx Builder (By Mutants)

example workflow

Cardano Tx Builder is a library that helps building your Cardano transaction without the need for WebAssembly or any rust libraries, like cardano-serialization-lib. The goal is to provide an alternative for those that prefer the use of Typescript libraries and have more knowledge with this programming language.

This library also has no dependency from Blockfrost API, but you must provide the protocol parameters in order to build a transaction.

The code is open source and also makes use of a small open-source library also created by Mutants team: @mutants/cardano-utils

Warning

The code here is already being used in our production apps but is far from being as robust as cardano-serialization-lib. There are several options in the cardano transaction spec that are not implemented yet (contributions are welcome!).

How to use (Step by step)

The core of this library is the TransactionBuilder class, which we can use to describe our transaction using Typescript.

Step 1: Creating the builder

import { TransactionBuilder } from "@mutants/cardano-tx-builder";

// Here you must implement your own way to fetch the protocol parameters of the current epoch.
// These parameters are dynamic so it's easier to have an API that provides them.
// If you are new to Cardano development, we suggest using Blockfrost to fetch those values:
// https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1latest~1parameters/get
const currentProtocolParameters = await fetchProtocolParameters();

const transactionBuilder = new TransactionBuilder(currentProtocolParameters);

Step 2: Setting up our inputs and outputs

Once you have your transaction builder created the most common operation would be to setup the transaction inputs. This information you would usually get from the Wallet API, which is where you can get the available UTxOs from the connected user.

Since this is not the kind of problem this library aims to solve, let's say we already have the two UTxOs and they have 2 ADA each:

import { toLovelace } from "@mutants/cardano-utils";

transactionBuilder.setInputs([{
  txHash: '037546cba8a7f352c5d9802b2aeb17395776a6c5b60253a75d3a1a90fbc6e3b7',
  txIndex: 0,
  address: 'addr1qxn93q92eatt544gu9fytkkddlr3m87hm2ly280692w45zcrdquesr9ddx2uarwu8dasltwd7986dzkw95tgv3hvqxxqmemh6s';
  value: {
    coin: toLovelace(2)
  }
}, {
  txHash: 'fc9020aa87eb00e25d819c930968ff3e0d227f853fc3cd5f121de268c94938e8',
  txIndex: 3,
  address: 'addr1qxn93q92eatt544gu9fytkkddlr3m87hm2ly280692w45zcrdquesr9ddx2uarwu8dasltwd7986dzkw95tgv3hvqxxqmemh6s';
  value: {
    coin: toLovelace(2)
  }
}])

Now let's say our connected user wants to send 1 ADA to another wallet with payment address addr1qx25trx4q5rmrkwx853suyk2dvpv93fytuv67qpc6kgzaqyw90fc7d6ehwz992ffmccptm4crsfvfs5qfd5z4hfpt55s5sfljx

In that case we have to set an output specific for this wallet:

transactionBuilder.setOutputs([{
  address: paymentAddress,
  value: {
    coin: toLovelace(1)
  }
}])

Step 3: The change

After we have our operation set, we must also tell our TransactionBuilder what to do with the 3 ADA that will be left from those 2 inputs.

In that case we have the setChangeAddress method, which tells where all the remaining assets that weren't specific in the setOutputs must go after this transaction:

transactionBuilder.setChangeAddress('addr1qxn93q92eatt544gu9fytkkddlr3m87hm2ly280692w45zcrdquesr9ddx2uarwu8dasltwd7986dzkw95tgv3hvqxxqmemh6s');

Most of the times the change address will be the connected user address, to make sure all the remaining assets from their input will go back to them.

Step 4: The transaction fee

Once we have everything set up we can tell the transaction builder to calculate the fee. This is the step where the protocol parameters will be used, so make sure to provide them correctly or the fee calculated will be incorrect.

transactionBuilder.calculateFee();

Step 5: Getting the signature

In order to spend inputs, we must have authorization from the input owner. Again, to do that, we usually rely on a connected Cardano wallet API.

To ask for a signature we must provide a valid transaction, so let's serialize our builder's transaction!

const unsignedTx = transactionBuilder.serialize();

Now that we have our transaction serialized, we can ask for user's signature. We will simulate the use of a connected Cardano wallet api:

const signature = await walletApi.signTx(unsignedTx);

Step 6: Adding the witness

In order to submit the transaction we have to provide witnesses and that's why we need the signature from the inputs' owner. The wallet api will return the signature encoded in CBOR so it's ready to be used by our TransactionBuilder.

transactionBuilder.setEncodedVKeyWitnesses(signature);

Step 7: Submit

We have inputs, outputs, permission to spend the inputs and the fee is calculated, now the only thing that is left is.. submit! To do that we must first serialize our tx and then we can submit the result through the connected wallet api:

const signedTx = transactionBuilder.serialize();

try {
  const txHash = await walletApi.submitTx(signedTx);

  if (tx) {
    // celebrate
  } else {
    throw new Error('Unexpected error'); // Wallet API gave us an unexpected result
  }
} catch (e) {
  // Something went wrong :(
  // Transaction submission can throw errors in case you provided invalid inputs, for example.
  // You can check the wallet error for more details.
}

Advanced usage

This library also supports more complex operations, like using validators. You can setup PlutusV2 scripts and collateral inputs, for example:

transactionBuilder.setCollateralInputs(collateralInputs); // Same format of regular inputs, change is also calculated automatically

// Inline PlutusV2 script
transactionBuilder.setPlutusV2Scripts(['REPLACE_FULL_CBOR_SCRIPT']);

// OR you can use PlutusV2 script with reference inputs
// Make sure to send hasScript as true for the reference input to be setup properly
transactionBuilder.setReferenceInputs([
  {
    txHash: 'REPLACE_TX_HASH',
    txIndex: 0,
    hasScript: true,
  }
]);

// Setting up redeemers
builder.setRedeemers([
  [
    RedeemerTag.Spend,
    {
      txHash: 'REPLACE_VALIDATOR_INPUT_TX_HASH',
      txIndex: REPLACE_VALIDATOR_INPUT_TX_INDEX,
    },
    { constructor: 0, fields: [] },
    [0, 0], // Evaluation can be calculated after
  ],
]);

// After evaluating the transaction you can set the exact cpu/mem values
builder.setRedeemerEvaluations([{
  tag: RedeemerTag.Spend,
  index: 0, // replace with proper input index considering your transaction
  memory: 18237,
  steps: 328742
}]);