Skip to content

Quick Start Guide

This guide will help you write your first Tx3 program. We’ll create a simple transfer program that allows one party to send ADA to another.

We’re assuming you have some experience building transactions for UTxO blockchains. If you need a refresher, here’s a good one.

Install the Toolchain

To start working with Tx3 you’ll need to install the toolchain. The fastest way to setup your environment is to run tx3up, which bundles everything you need in a single install experience:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/tx3-lang/up/releases/latest/download/tx3up-installer.sh | sh

Once you’ve installed tx3up, run the following command to execute the install of toolchain:

tx3up

You’ll see how the process downloads and install many components. By the end, you should have everything you need.

Run the following command to check the installed versions of each component:

tx3up show

The installer has a lot of advanced features, check our tx3up guide if you want to learn more.

Initialize a new Project

The next thing you need to do is prepare a project workspace. This is a directory in your file system that holds everything you need for developing your protocol.

Lets create a my-protocol folder for our tutorial:

mkdir my-protocol && cd my-protocol

Once you’re inside your protocol folder, you need to initialize the basic files using trix, the package manager for tx3.

trix init

The init command will command will ask you a few questions and then create a few files. Make sure to opt-in into the “Typescript” code generation option because we’ll need it for the tutorial.

By then end, your protocol folder should look like:

my-protocol/
├── main.tx3
└── trix.toml

Trix is to Tx3 what Npm is to NodeJS

Your First Tx3 Protocol

The trix init command generates a main.tx3 file with a very basic example. Open the file in your code editor of choice so that we can inspect the contents together.

TIP: if use VSCode, there’s a Tx3 extensions in the marketplace that provides many QoL features like syntax highlighting and error diagnostics.

party Sender;
party Receiver;
tx transfer(
quantity: Int
) {
input source {
from: Sender,
min_amount: Ada(quantity),
}
output {
to: Receiver,
amount: Ada(quantity),
}
output {
to: Sender,
amount: source - Ada(quantity) - fees,
}
}

The above code represent a basic protocol with only one operation that transfers ADA from one party o another.

Lets break it down to understand each part.

Party Definitions

party Sender;
party Receiver;

Defines two parties that will participate in the transaction. These are placeholder names that will be bound to actual addresses at runtime.

In this particular scenario, we have a Sender that is transferring some ADA to a Receiver party.

You’re not limited to only two parties, in more advanced scenarios you’ll learn how to define any number of parties to fully describe your protocol.

Transaction Template

tx transfer(quantity: Int)

This snippet defines a transaction template named transfer. You can think of these templates as functions that your code will call to build concrete transactions.

This template takes a single parameter name quantity of type Int. In this particular scenario, this params determines how much ADA to transfer.

Inside this template you’ll need to define how to connect inputs and outputs to fully describe your UTxO transaction.

Input Block

input source {
from: Sender,
min_amount: Ada(quantity),
}

This snippet defines an input block named source. An input block specifies the criteria that we need to use to query UTxO at runtime to fullfil the requirements of the transaction.

In this particular scenario we’re requiring the input to come from the address belonging to the Sender and must contain at least the quantity of ADA specified as a parameter of the transaction.

Notice that we specified the name source to identify this particular input. Templates can have multiple input blocks. The name will be useful to reference this particular input from other parts of the transaction.

The Ada(quantity) syntax is an asset constructor. In more advanced scenarios you’ll learn how to use other type of assets.

Output Block

output {
to: Receiver,
amount: Ada(quantity),
}

This snippet defines an output block. An output block describes how to construct UTxO that will be included at runtime as part of the concrete Tx.

In this particular scenario we’re specifying that the UTxO should be locked in the address of the Receiver party and that the amount it should contain the exact quantity of ADA specified as a parameter.

Another Output Block

output {
to: Sender,
amount: source - Ada(quantity) - fees,
}

This snippet contains another output block. This time it represent the “change” we need to give back to the Sender party to balance the transaction.

Notice that the amount is now a computed value that takes whatever values was found in the source input and then subtracts the transferred value and the fees for the transaction.

The fees keyword is a special placeholder that will be replaced by the computed at runtime to match the minimum fees required for the concrete transaction being built.

Checking for Errors

The above code should be work out-of-the-box, but if you are building your own protocol you might want to check that everything compiles correctly.

The Tx3 compilers comes with a parser and semantic analysis logic to ensure that there aren’t any errors in your code.

To execute these checks, run the following command from the root of your protocol folder:

trix check

TIP: The VSCode extension comes with a live error diagnostics that use the same logic.

Typescript Bindings

Ok, here’s where things get interesting. Now that we have our protocol interface, we’ll be generating concrete transactions just by calling the transaction templates as if they were functions.

Remember that we asked you to choose the “Typescript” option? We need it for the next step.

Bindings are just glue code that allows you to execute the transaction building logic by calling language-specific functions that represent the templates in your protocol.

Run the following command from your CLI:

trix bindgen

If things went well, you should see the following new files:

my-protocol/
└── gen/
└── typescript/
├── my-protocol.ts
├── test.ts
├── package.json
└── tsconfig.json

We won’t get into details of how to use the ts code, you can read more about it on the NodeJS bindings reference.

Running a Devnet

Tx3 tooling includes a mechanism to run a local ephemeral devnet. A devnet is a single-node network that runs inn your machine and mimics the behavior of a real blockchain.

The node will emulate the chain moving forward by generating new blocks every few seconds. Any valid transaction submitted to the network will be automatically added to the following block.

It’s ephemeral because any changes to the chain are reset after each restart, providing a nice deterministic workflow for testing transactions during development.

The config for you devnet lives inside your trix.toml as a devnet profile:

[profiles.devnet]
chain = "CardanoDevnet"
[[profiles.devnet.wallets]]
name = "alice"
random_key = true
initial_balance = 1000000000000000000
[[profiles.devnet.wallets]]
name = "bob"
random_key = true
initial_balance = 1000000000000000000

Notice that the config allows you to define test wallets that can be used as parties in your test transactions. When the devnet starts, these wallets will be configured automatically with the specified initial balances.

To start the devnet process, run the following command:

trix devnet

Once started, you should start seeing many logs in your temrinal. These logs describe the internal activity of the devnet.

TIP: the devnet mechanism is managed by Dolos a lightweight Cardano Data Node.

Now that your devnet process is running, you can see what’s happening by running the embedded chain explorer:

trix explore

What’s next

If you made it so far you should have a pretty good idea of what is Tx3 about, but this just barely scratched the surface.

Check the following section to continue your journey: