Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion Cargo.lock

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

75 changes: 73 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ To add a wallet, you can do the following:

```sh
cargo run -- wallet create

```

This will prompt you for a a name and a password. Keep in mind that losing the
Expand All @@ -102,8 +101,80 @@ cargo run -- provider create

This will prompt you for a name, a kind (only UTxORPC supported), whether it is for mainnet or testnet, a URL and the possibility to add headers.

>>> If you have a [Demeter](https://demeter.run) port you would have to set the URL as `https://{host}` and on put `dmtr-api-key:YOUR_API_KEY` on the headers.
> If you have a [Demeter](https://demeter.run) port you would have to set the URL as `https://{host}` and on put `dmtr-api-key:YOUR_API_KEY` on the headers.

# Examples

In the `examples` folder you can find scripts demonstrating advanced capabilities.

## Batch transactions

This example shows how to send transactions to multiple recipients in a batch.

**Location:** `examples/batch-transactions/`

**Usage:**
```sh
./transfer.sh <sender_wallet> <receiver_wallets_list> <lovelace_amount>
```

**Arguments:**
- `sender_wallet`: Name of the wallet sending the funds (e.g., `alice`)
- `receiver_wallets_list`: Comma-separated list of recipient wallet names (e.g., `bob,charlie,mark`)
- `lovelace_amount`: Amount in lovelaces to send to each recipient (e.g., `1000000`)

**Example:**
```sh
./transfer.sh alice bob,charlie,mark 1000000
```

This will send 1,000,000 lovelaces from Alice's wallet to Bob, Charlie, and Mark individually.

## Scheduled tasks

This example demonstrates how to schedule recurring transactions using cron expressions.

**Location:** `examples/scheduled-tasks/`

**Usage:**
```sh
./transfer.sh <sender_wallet> <receiver_wallet> <lovelace_amount> <cron_string>
```

**Arguments:**
- `sender_wallet`: Name of the wallet sending the funds (e.g., `alice`)
- `receiver_wallet`: Name of the recipient wallet (e.g., `bob`)
- `lovelace_amount`: Amount in lovelaces to send (e.g., `1000000`)
- `cron_string`: Cron schedule expression in the format `'minute hour day month weekday'`

**Example:**
```sh
./transfer.sh alice bob 1000000 '0 */2 * * *'
```

This will schedule a transfer of 1,000,000 lovelaces from Alice to Bob every 2 hours.

## Complex transaction

This example shows how to interact with a protocol that requires several parameters, specifically creating a ship in [Asteria](https://asteria.txpipe.io).

**Location:** `examples/complex-transaction/`

**Usage:**
```sh
./create-ship.sh <player_wallet> <pos_x> <pos_y>
```

**Arguments:**
- `player_wallet`: Name of the player's wallet (e.g., `alice`)
- `pos_x`: X coordinate for the ship position (integer)
- `pos_y`: Y coordinate for the ship position (integer)

**Example:**
```sh
./create-ship.sh alice 25 25
```

This will create a new ship for Alice at coordinates (25, 25) in [Asteria](https://asteria.txpipe.io).

> Note: you need to use a provider with the Cardano preview testnet in order to submit this transaction
4 changes: 2 additions & 2 deletions dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ cargo-dist-version = "0.29.0"
# CI backends to support
ci = "github"
# The installers to generate for each app
installers = ["shell", "npm", "homebrew"]
installers = ["shell", "powershell", "npm", "homebrew"]
# A GitHub repo to push Homebrew formulas to
tap = "txpipe/homebrew-tap"
# Target platforms to build apps for (Rust target-triple syntax)
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
# Publish jobs to run in CI
publish-jobs = ["homebrew"]
# Which actions to run on pull requests
Expand Down
61 changes: 61 additions & 0 deletions examples/batch-transactions/transfer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash

# Validate arguments
if [ $# -ne 3 ]; then
echo "Error: exactly 3 arguments are required"
echo "Usage: $0 <sender_wallet> <receiver_wallets_list> <lovelace_amount>"
echo "Example: $0 alice bob,charlie,mark 1000000"
exit 1
fi

# Get arguments
SENDER_WALLET=$1
RECEIVER_WALLETS=$2
AMOUNT=$3

# Validate sender wallet name is not empty
if [ -z "$SENDER_WALLET" ]; then
echo "Error: sender wallet name cannot be empty"
exit 1
fi

# Validate receiver wallets list is not empty
if [ -z "$RECEIVER_WALLETS" ]; then
echo "Error: receiver wallets list cannot be empty"
exit 1
fi

# Validate amount is a positive integer
if ! [[ "$AMOUNT" =~ ^[0-9]+$ ]]; then
echo "Error: amount must be a positive integer"
exit 1
fi

# Get sender wallet info
SENDER_INFO=$(cshell wallet info --name $SENDER_WALLET 2>&1)
if [ $? -ne 0 ]; then
echo "Error: sender wallet '$SENDER_WALLET' does not exist"
exit 1
fi

SENDER_ADDRESS=$(echo "$SENDER_INFO" | grep "Address (testnet)" | awk '{print $5}')

for RECEIVER_WALLET in ${RECEIVER_WALLETS//,/ }; do

echo "Sending $AMOUNT lovelaces from $SENDER_WALLET to $RECEIVER_WALLET"

RECEIVER_INFO=$(cshell wallet info --name $RECEIVER_WALLET 2>&1)
if [ $? -ne 0 ]; then
echo "Error: receiver wallet '$RECEIVER_WALLET' does not exist"
exit 1
fi

RECEIVER_ADDRESS=$(echo "$RECEIVER_INFO" | grep "Address (testnet)" | awk '{print $5}')

cshell tx invoke \
--tx3-file ./transfer.tx3 --signers $SENDER_WALLET --unsafe \
--tx3-args-json "{\"sender\":\"$SENDER_ADDRESS\",\"receiver\":\"$RECEIVER_ADDRESS\",\"quantity\":$AMOUNT}"

echo ""

done
22 changes: 22 additions & 0 deletions examples/batch-transactions/transfer.tx3
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
party Sender;

party Receiver;

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

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

output {
to: Sender,
amount: source - Ada(quantity) - fees,
}
}
135 changes: 135 additions & 0 deletions examples/complex-transaction/asteria.tx3
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
party Player;

policy SpacetimePolicy {
hash: 0xb6c5e14f31af0c92515ce156625afc4749e30ceef178cfae1f929fff,
ref: 0x81667fe89e20c352a8428f68efd0c9db1fef6cd15aa36ad4423797bb2c401431#1,
}

policy AsteriaPolicy {
hash: 0xb16a0775a5e045b482ab2a98e241c9347f8ffe265bb6acd10452a6cc,
ref: 0x81667fe89e20c352a8428f68efd0c9db1fef6cd15aa36ad4423797bb2c401431#0,
}

asset Fuel = 0x98b1c97b219c102dd0e9ba014481272d6ec069ec3ff47c63e291f1b7."FUEL";
asset AdminToken = 0x516238dd0a79bac4bebe041c44bad8bf880d74720733d2fc0d255d28."asteriaAdmin";

type ShipDatum {
pos_x: Int,
pos_y: Int,
ship_token_name: Bytes,
pilot_token_name: Bytes,
last_move_latest_time: Int,
}

type AsteriaDatum {
ship_counter: Int,
shipyard_policy: Bytes,
}

type AsteriaRedeemer {
AddNewShip,
Mine,
ConsumeAsteria,
}

type ShipyardRedeemer {
MintShip,
BurnShip,
}

type FuelRedeemer {
MintFuel,
BurnFuel,
}

tx create_ship(
p_pos_x: Int, // Ship Position X
p_pos_y: Int, // Ship Position Y
ship_name: Bytes, // Name of the ship
pilot_name: Bytes, // Name of the pilot
tip_slot: Int, // TODO: remove when tip_slot() implemented
last_move_timestamp: Int,
) {
locals {
initial_fuel: 5, // Should be taken from spaceTime datum
ship_mint_lovelace_fee: 1000000, // Should be taken from asteria script datum
spacetime_policy_hash: 0xb6c5e14f31af0c92515ce156625afc4749e30ceef178cfae1f929fff,
spacetime_policy_ref: 0x81667fe89e20c352a8428f68efd0c9db1fef6cd15aa36ad4423797bb2c401431#1,
asteria_policy_ref: 0x81667fe89e20c352a8428f68efd0c9db1fef6cd15aa36ad4423797bb2c401431#0,
pellet_policy_ref: 0x81667fe89e20c352a8428f68efd0c9db1fef6cd15aa36ad4423797bb2c401431#2,
}

validity {
until_slot: tip_slot, // tip_slot() + 300
}

reference SpacetimeRef {
ref: spacetime_policy_ref,
}

reference AsteriaRef {
ref: asteria_policy_ref,
}

reference PelletRef {
ref: pellet_policy_ref,
}

input* gas {
from: Player,
min_amount: fees + Ada(ship_mint_lovelace_fee) + min_utxo(pilot_token) + min_utxo(new_ship) + min_utxo(gas_change),
}

input asteria {
from: AsteriaPolicy,
min_amount: AdminToken(1),
datum_is: AsteriaDatum,
redeemer: AsteriaRedeemer::AddNewShip {},
}

mint {
amount: AnyAsset(spacetime_policy_hash, pilot_name, 1) + AnyAsset(spacetime_policy_hash, ship_name, 1),
redeemer: ShipyardRedeemer::MintShip {},
}

mint {
amount: Fuel(initial_fuel),
redeemer: FuelRedeemer::MintFuel {},
}

output pilot_token {
to: Player,
amount: AnyAsset(spacetime_policy_hash, pilot_name, 1) + min_utxo(pilot_token),
}

output updated_asteria {
to: AsteriaPolicy,
amount: asteria + Ada(ship_mint_lovelace_fee),
datum: AsteriaDatum {
ship_counter: asteria.ship_counter + 1,
shipyard_policy: asteria.shipyard_policy,
},
}

output new_ship {
to: SpacetimePolicy,
amount: AnyAsset(spacetime_policy_hash, ship_name, 1) + Fuel(initial_fuel) + min_utxo(new_ship),
datum: ShipDatum {
pos_x: p_pos_x,
pos_y: p_pos_y,
ship_token_name: ship_name,
pilot_token_name: pilot_name,
last_move_latest_time: last_move_timestamp,
},
}

output gas_change {
to: Player,
amount: gas - fees - Ada(ship_mint_lovelace_fee) - min_utxo(pilot_token) - min_utxo(new_ship),
}

collateral {
from: Player,
min_amount: fees,
}
}
Loading
Loading