Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ repository = "https://github.com/txpipe/cshell"
license = "Apache-2.0"
homepage = "https://docs.txpipe.io/cshell"

keywords = ["cardano", "blockchain", "wallet", "cardano"]
keywords = ["cardano", "blockchain", "wallet"]
categories = ["command-line-utilities", "blockchain", "cardano", "wallet"]

[dependencies]
tx3-lang = "0.11.1"
tx3-cardano = "0.11.1"
tx3-lang = "0.11.5"
tx3-cardano = "0.11.5"
tx3-sdk = "^0"

# tx3-lang = { git = "https://github.com/tx3-lang/tx3.git" }
Expand Down
72 changes: 72 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# TX3 Transaction Examples

This directory contains example TX3 files to execute through CShell invoke.

## Prerequisites

Before running TX3 files, ensure you have:

1. **CShell installed** - See the main [README](../README.md) for installation instructions
2. **A CShell configuration file** - Created using `cshell provider create` and `cshell wallet create`
3. **At least one provider configured** - For blockchain connectivity
4. **At least one wallet configured** - For signing transactions

## How to Execute TX3 Files

Use the following command pattern to execute a TX3 file:

```bash
cshell -s ./cshell.toml tx invoke --tx3-file ./<tx3-file>
```

### Command Breakdown

- `cshell` - Runs CShell
- `-s <config_file>` - Specifies the CShell configuration file path
- `tx invoke` - Invokes a transaction
- `--tx3-file <file_path>` - Path to the TX3 file to execute

### Configuration File

The `-s` flag points to your CShell configuration file (usually `cshell.toml`), which contains:
- Provider settings
- Wallet configurations

## Available Examples

### 1. `transfer.tx3` - Basic ADA Transfer

Transfers ADA from one party to another with change calculation.

**Parties**: `Sender`, `Receiver`
**Parameters**: `quantity` (amount to transfer in lovelace)

```bash
cshell -s ~/.tx3/tmp/devnet_756435378c8d3771/cshell.toml tx invoke --tx3-file ./transfer.tx3
```

### 2. `mint_token.tx3` - Token Minting

Creates new native tokens on Cardano.

**Parties**: `Minter`
**Parameters**:
- `token_policy` (policy ID in bytes)
- `token_name` (token name in bytes)
- `quantity` (amount to mint)

```bash
cshell -s ~/.tx3/tmp/devnet_756435378c8d3771/cshell.toml tx invoke --tx3-file ./mint_token.tx3
```

### 3. `mint_with_script.tx3` - Plutus Script Token Minting

Demonstrates token minting using a Plutus v3 script with a PIN-based vending machine mechanism. This example shows how to interact with smart contracts for token minting.

**Parties**: `Customer`
**Parameters**:
- `pin` (PIN code in bytes)

```bash
cshell -s ~/.tx3/tmp/devnet_756435378c8d3771/cshell.toml tx invoke --tx3-file ./mint_with_script.tx3
```
27 changes: 27 additions & 0 deletions examples/mint_token.tx3
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
party Minter;

tx mint_token (
token_policy: Bytes,
token_name: Bytes,
quantity: Int,
) {

locals {
token: AnyAsset(token_policy, token_name, quantity),
}

input source {
from: Minter,
min_amount: fees,
}

mint {
amount: token,
redeemer: (),
}

output destination {
to: Minter,
amount: source + token - fees,
}
}
34 changes: 34 additions & 0 deletions examples/mint_with_script.tx3
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
party Customer;

policy VendingMachine = 0x3f2e288b4a19ab51d1775d2c6e397b43fad17cc8c47b988603136d73;

asset COIN = 0x3f2e288b4a19ab51d1775d2c6e397b43fad17cc8c47b988603136d73."COIN";

tx claim_tokens(
pin: Bytes,
) {
input gas {
from: Customer,
min_amount: fees,
}

collateral {
from: Customer,
min_amount: fees,
}

mint {
amount: COIN(1),
redeemer: pin,
}

output {
to: Customer,
amount: gas - fees + COIN(1),
}

cardano::plutus_witness {
version: 3,
script: 0x5903e501010029800aba4aba2aba1aab9faab9eaab9dab9cab9a488888888c96600264653001300900198049805000cc0240092225980099b8748000c024dd500144c966002009007803c01e00f1323233223233225330103372c9210e70726f76696465642070696e3a20003732660046ea40052201001325330113372c92011370726f76696465642070696e20686173683a20003732660066ea400522010013371e0029111c4f43be03892183d6ea41480f616be43b58937aad2c7511e71be9f80d00379000260020026eb8024888c9660020071323233223300a00233714910101280059800800c4cdc52441035b5d2900006899b8a489035b5f20009800800ccdc52441025d2900006914c00402a00530070014029229800805400a002805100920305980099b880014803a266e0120f2010018acc004cdc4000a41000513370066e01208014001480362c80910121bac3015002375a60260026466ec0dd418098009ba73014001375400713259800800c4cdc52441027b7d00003899b8a489037b5f20003232330010010032259800800c400e264b30010018994c00402a6030003337149101023a200098008054c06400600a805100a180d00144ca6002015301800199b8a489023a200098008054c064006600e66008008004805100a180d0012032301a001406066e29220102207d0000340546eac00e264b3001001899b8a489025b5d00003899b8a489035b5f20009800800ccdc52441015d00003914c00401e0053004001401d229800803c00a0028039006202a3758007133006375a0060051323371491102682700329800800ccdc01b8d0024800666e292210127000044004444b3001337100049000440062646645300100699b800054800666e2ccdc00012cc004cdc40012402914818229037202e3371666e000056600266e2000520148a40c11481b9017002200c33706002901019b8600148080cdc70020012028375c00680b8dc5245022c2000223233001001003225980099b8700148002266e292210130000038acc004cdc4000a40011337149101012d0033002002337029000000c4cc014cdc2000a402866e2ccdc019b85001480512060003403880708888c8cc004004014896600200310058992cc004006266008602c00400d1330053016002330030030014054602c00280a0c0040048896600266e2400920008800c6600200733708004900a4cdc599b803370a004900a240c0002801900b201e375c601860146ea800a29410070c024004c014dd500545268a99801a4811856616c696461746f722072657475726e65642066616c7365001365640082a660049201206578706563742070696e3a20427974654172726179203d2072656465656d6572001601,
}
}
21 changes: 21 additions & 0 deletions examples/transfer.tx3
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
party Sender;
party Receiver;

tx transfer(
quantity: Int,
) {
input source {
from: Sender,
min_amount: Ada(quantity) + fees,
}

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

output {
to: Sender,
amount: source - Ada(quantity) - fees,
}
}
32 changes: 32 additions & 0 deletions src/tx/construct/add_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::{fs, path::PathBuf};

use anyhow::{Result, Context};
use clap::Parser;
use tracing::instrument;

#[derive(Parser, Clone)]
pub struct Args {
/// Path for tx3 file to create the transaction
#[arg(long)]
tx3_file: PathBuf,
}

#[instrument("add-input", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");
Comment on lines +14 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix invalid tracing::instrument usage

#[instrument("add-input", skip_all)] won’t compile—the attribute macro requires named parameters. Use the supported form instead.

-#[instrument("add-input", skip_all)]
+#[instrument(name = "add-input", skip_all)]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[instrument("add-input", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");
#[instrument(name = "add-input", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");
🤖 Prompt for AI Agents
In src/tx/construct/add_input.rs around lines 14 to 16, the attribute macro is
using positional parameters which won't compile; change the attribute to use
named parameters, e.g. replace #[instrument("add-input", skip_all)] with
#[instrument(name = "add-input", skip_all)] so the macro receives a named `name`
argument while retaining the `skip_all` flag.


let mut tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?;

tx_builder.collect_inputs(true)?;

let ast = tx_builder.ast.clone();

// Write to AST file
fs::write(&ast_path_buf, serde_json::to_string_pretty(&ast).unwrap())
.context("Failed to write tx3 AST file")?;

println!("\n✅ Input added successfully!");
println!("📄 File saved to: {}", ast_path_buf.display());

Ok(())
}
32 changes: 32 additions & 0 deletions src/tx/construct/add_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::{fs, path::PathBuf};

use anyhow::{Result, Context};
use clap::Parser;
use tracing::instrument;

#[derive(Parser, Clone)]
pub struct Args {
/// Path for tx3 file to create the transaction
#[arg(long)]
tx3_file: PathBuf,
}

#[instrument("add-output", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");
Comment on lines +14 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix invalid tracing::instrument usage

#[instrument("add-output", skip_all)] does not compile—the macro expects key/value pairs like name = "add-output" rather than a bare string literal. Please switch to the supported syntax so the module builds.

-#[instrument("add-output", skip_all)]
+#[instrument(name = "add-output", skip_all)]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[instrument("add-output", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");
#[instrument(name = "add-output", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");
🤖 Prompt for AI Agents
In src/tx/construct/add_output.rs around lines 14 to 16, the tracing attribute
uses an unsupported bare string literal (`#[instrument("add-output",
skip_all)]`); replace it with the proper key/value form so the macro compiles,
e.g. use `#[instrument(name = "add-output", skip_all)]`, preserving skip_all and
any other attributes.


let mut tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?;

tx_builder.collect_outputs(true)?;

let ast = tx_builder.ast.clone();

// Write to AST file
fs::write(&ast_path_buf, serde_json::to_string_pretty(&ast).unwrap())
.context("Failed to write tx3 AST file")?;

println!("\n✅ Output added successfully!");
println!("📄 File saved to: {}", ast_path_buf.display());

Ok(())
}
Comment on lines 1 to 33
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Search and fix similar unwraps across the PR.

There are identical patterns in sibling modules (e.g., add_input.rs). Run this to find them.


🏁 Script executed:

#!/bin/bash
rg -nP 'to_string_pretty\([^)]*\)\.unwrap\(\)' -S --glob '!target/**'

Length of output: 148


🏁 Script executed:

#!/bin/bash
# Search for serde_json::to_string_pretty(...).unwrap across Rust source (excluding target directory)
rg -nP --type=rs 'serde_json::to_string_pretty\([^)]*\)\.unwrap' --glob '!target/**'

Length of output: 26


🏁 Script executed:

#!/bin/bash
# Search for serde_json::to_string_pretty(...).unwrap across Rust source (excluding target directory)
rg -nP 'to_string_pretty\([^)]*\)\.unwrap\(\)' -g '*.rs' --glob '!target/**'

Length of output: 678


Remove .unwrap() on serde_json::to_string_pretty and propagate errors

  • In src/types.rs (lines 86, 127) and src/provider/types.rs (lines 355, 377): replace .unwrap() with ? or .context("failed to serialize").
  • In src/tx/construct/wizard.rs:46, add_input.rs:25, add_output.rs:25: apply the same error‐propagating change.
🤖 Prompt for AI Agents
In src/tx/construct/add_output.rs lines 1-32, remove the unwrap on
serde_json::to_string_pretty and propagate serialization errors: call
serde_json::to_string_pretty(&ast).context("Failed to serialize AST to JSON")?
to get the JSON string, then pass that string to fs::write(&ast_path_buf,
json).context("Failed to write tx3 AST file")? so both serialization and
file-write errors are properly returned.

31 changes: 31 additions & 0 deletions src/tx/construct/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::{fs, path::PathBuf};

use anyhow::{Result, Context};
use clap::Parser;
use tracing::instrument;

#[derive(Parser, Clone)]
pub struct Args {
/// Path for tx3 file to create the transaction
#[arg(long)]
tx3_file: PathBuf,
}

#[instrument("build", skip_all)]
pub async fn run(args: Args, _ctx: &crate::Context) -> Result<()> {
let ast_path_buf = args.tx3_file.with_extension("ast");

let tx_builder = super::common::TransactionBuilder::from_ast(&ast_path_buf)?;

// Generate the tx3 content
let tx3_content = tx_builder.generate_tx3_content();

// Write to file
fs::write(&args.tx3_file, tx3_content)
.context("Failed to write tx3 file")?;

println!("\n✅ Transaction created successfully!");
println!("📄 File saved to: {}", args.tx3_file.display());

Ok(())
}
Loading