tx3-sdk (Rust)
The official Rust SDK for Tx3 — a DSL and protocol suite for defining and executing UTxO-based blockchain transactions declaratively. Load a compiled .tii protocol, bind parties and signers, and drive the full transaction lifecycle (resolve, sign, submit, confirm) via the Transaction Resolve Protocol (TRP).
This repository is organized as a monorepo. The publishable crate lives in sdk/.
What is Tx3
Tx3 is a domain-specific language and protocol suite for declarative, type-safe UTxO transactions. Authors write .tx3 files describing parties, environment, and transactions; the toolchain compiles them to .tii artifacts that this SDK loads at runtime to drive the resolve → sign → submit → wait lifecycle through a TRP server. See the Tx3 docs for project context.
Installation
Or in Cargo.toml:
[]
= "0.12"
= "1"
= { = "1", = ["full"] }
Quick start
use json;
use ;
async
All fallible validation — TRP endpoint present, profile declared, every bound
party declared — happens inside build(), which returns Error::MissingTrpEndpoint,
Error::UnknownProfile, or Error::UnknownParty. Optional setters never return
Result, so chains stay fluent up to build(). Profile selection is
builder-only: there is no profile-switching method on the built client.
Switching profiles requires a new builder.
Concepts
| SDK Type | Glossary Term | Description |
|---|---|---|
tii::Protocol |
TII / Protocol | Loaded .tii exposing transactions, parties, profiles. Protocol::client() returns a fresh Tx3ClientBuilder |
Tx3ClientBuilder |
Client builder | Fluent builder seeded by Protocol::client() or Tx3ClientBuilder::from_parts(...); absorbs all fallible validation in build() |
Tx3Client |
Facade | Output of Tx3ClientBuilder::build() — owns the deconstructed protocol parts, TRP client, profile, and party bindings |
TxBuilder |
Invocation builder | Source-agnostic; collects args, resolves via TRP |
Party |
Party | Party::address(...) (read-only) or Party::signer(...) (signing) |
Profile |
Profile | { environment, parties } value baked into the client; embedded by codegen plugins, decomposed from Protocol by from_protocol |
Signer |
Signer | Trait producing a TxWitness for a SignRequest |
SignRequest |
SignRequest | Input passed to Signer::sign: tx_hash_hex + tx_cbor_hex |
CardanoSigner |
Cardano Signer | BIP32-Ed25519 signer at m/1852'/1815'/0'/0/0 |
Ed25519Signer |
Ed25519 Signer | Generic raw-key Ed25519 signer |
ResolvedTx |
Resolved transaction | Output of resolve(), ready for signing |
SignedTx |
Signed transaction | Output of sign(), ready for submission |
SubmittedTx |
Submitted transaction | Output of submit(), pollable for status |
PollConfig |
Poll configuration | Controls wait_for_confirmed / wait_for_finalized polling |
Error::MissingTrpEndpoint / UnknownProfile / UnknownParty / UnknownTx |
Builder errors | Returned by build() and tx(name); named variants of the single tx3_sdk::Error enum |
Advanced usage
Skipping the runtime .tii (codegen flow)
If you've run trix codegen to generate typed bindings, your generated Client
embeds the per-transaction TIR envelopes and per-profile data at codegen time —
no .tii artifact at runtime. Under the hood it seeds the same builder via
Tx3ClientBuilder::from_parts(transactions, profiles, known_parties) and routes
typed per-party setters through with_party_unchecked. You can also call
from_parts directly from hand-written code:
use ;
use ;
let tx3 = from_parts
.trp_endpoint
.with_party_unchecked
.build?;
Adding TRP headers
with_header(key, value) attaches a header to every TRP request. Combine with
trp_endpoint (or trp(ClientOptions { ... })) — with_header does not supply
an endpoint on its own.
let tx3 = protocol
.client
.trp_endpoint
.with_header
.with_profile
.with_party
.build?;
One-off environment overrides
with_env_value(key, value) overlays a single environment value on top of the
selected profile's environment, merged at resolve time (override wins). Useful
for adjusting a network selector or other env without forking a new profile.
let tx3 = protocol
.client
.trp_endpoint
.with_profile
.with_env_value
.with_party
.build?;
Low-level TRP client
If you don't want the facade, drive TRP directly:
use ;
let client = new;
// build ResolveParams and call client.resolve(...).await
Custom Signer
Implement the Signer trait. sign receives a SignRequest carrying both the
tx hash and the full tx CBOR; hash-based signers read tx_hash_hex, tx-based
signers (e.g. wallet bridges) read tx_cbor_hex.
use ;
use TxWitness;
Manual witness attachment
When a witness is produced outside any registered Signer — for example by an
external wallet app or a remote signing service — resolve the transaction
first, hand the resolved hash (or full tx CBOR) to the wallet, then attach the
returned witness before sign():
let resolved = tx3
.tx?
.arg
.resolve
.await?;
// Hand `resolved.hash` (or `resolved.tx_hex`) to the external wallet
// and get back a witness. The wallet needs the resolved tx to sign.
let witness: TxWitness = /* sign resolved.hash with external wallet */;
let status = resolved
.add_witness
.sign?
.submit
.await?
.wait_for_confirmed
.await?;
add_witness may be called any number of times; manual witnesses are appended after registered-signer witnesses in attach order.
Tx3 protocol compatibility
- TRP protocol version: v1beta0
- TII schema version: v1beta0
Testing
- Unit tests are co-located with modules via
#[cfg(test)]. - End-to-end (e2e) tests live under
sdk/tests/and run as Cargo test targets.
# from rust-sdk/sdk
License
Apache-2.0