Crates.io | tx3-lang |
lib.rs | tx3-lang |
version | |
source | src |
created_at | 2025-04-13 16:29:24.984339+00 |
updated_at | 2025-04-18 17:51:16.581307+00 |
description | A DSL for defining protocols that run on UTxO blockchains |
homepage | https://github.com/tx3-lang/tx3 |
repository | https://github.com/tx3-lang/tx3 |
max_upload_size | |
id | 1631962 |
Cargo.toml error: | TOML parse error at line 19, column 1 | 19 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
A domain-specific language for describing protocols that run on UTxO-based blockchains, with a particular focus on Cardano.
In account-based blockchains, dapps are primarily defined by smart contracts with explicit function interfaces that represent user interactions and state mutations. These dapps have a clear API surface that can be used by different parties to interact with its business logic.
The deterministic nature of the UTxO approach is a great property, but it has a drawback: the interface of a dapp is not explicit, there's nothing describing how the different parties can interact with it. Dapps are defined by transaction patterns that represent deterministic "state transitions". A party interacting with an UTxO-based dapp has to understand the underlying business logic in order to construct transactions representing their intents.
This is why we need a strict but flexible mechanism to describe patterns of transactions (which we'll call transaction templates) that dapp authors can use to convey the interface of their dapp and dapp consumers can use to interact with it.
Tx3 is a purely functional language designed specifically for describing transaction templates in UTxO-based blockchains. Rather than trying to be a general-purpose language, it focuses exclusively on this narrow but important domain, allowing it to provide powerful and precise tools for working with blockchain transactions.
The language's narrow focus allows it to be highly opinionated and tightly integrated with core UTxO blockchain concepts. Instead of abstracting away blockchain-specific details, Tx3 embraces them - concepts fundamental to UTxO blockchains like inputs, outputs, datums, and redeemers are treated as first-class citizens in the language. This deep integration enables more natural and expressive ways to work with these concepts.
A key concept in Tx3 is the distinction between concrete transactions and transaction templates. While a transaction represents a specific state transition, a template is a function - it defines a pattern that can generate many different concrete transactions based on parameters provided at runtime. This parameterization is what makes templates so powerful for defining reusable transaction patterns.
Let's start with a very simple example: a transfer of funds from one party to another.
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,
}
}
Things to notice in the example:
tx
keyword is used to define a transaction template. You can think of it as a function that takes some parameters and returns a transaction.party
keyword is used to define a party. Parties are used to identify the participants in a transaction.Here's a more complex example: a vesting contract that allows a beneficiary to claim funds after a certain amount of time has passed.
party Owner;
party Beneficiary;
policy TimeLock = import(validators/vesting.ak);
record State {
lock_until: Int,
owner: Bytes,
beneficiary: Bytes,
}
tx lock(
quantity: Int,
until: Int
) {
input source {
from: Owner,
min_amount: quantity,
}
output target {
to: TimeLock,
amount: Ada(quantity),
datum: State {
lock_until: until,
owner: Owner,
beneficiary: Beneficiary,
}
}
output {
to: Owner,
amount: source - Ada(quantity) - fees,
}
}
tx unlock(
locked_utxo: UtxoRef
) {
input gas {
from: Beneficiary,
min_amount: fees,
}
input locked {
ref: locked_utxo,
redeemer: (),
}
output target {
to: Beneficiary,
amount: gas + locked - fees,
}
}
Things to notice in the example:
policy
keyword is used to define a policy, an onchain validation script of some sort. Policies can also act as parties in the transaction (by inferring a script address).record
keyword is used to define a record. Records are used to define the data structure that can be used as datums or redeemers.lock
and unlock
templates are part of the vesting
protocol.Tx3 provides three levels of transaction visualization (hence the name), inspired by the C4 model approach:
Interaction Level (L1)
Transaction Level (L2)
Validator Level (L3)