From 9c0fb646f9e4c3ee2327f707b2c18d1b68ff8884 Mon Sep 17 00:00:00 2001 From: SIDANPillow Date: Tue, 17 Mar 2026 18:24:32 +0800 Subject: [PATCH] add mdBook for m5 --- .github/workflows/static.yml | 22 ++- .gitignore | 5 +- .lychee.toml | 15 +- README.md | 4 +- docs/guide/book.toml | 13 ++ docs/guide/src/SUMMARY.md | 26 +++ .../guide/src/getting-started/installation.md | 60 +++++++ docs/guide/src/getting-started/quickstart.md | 86 ++++++++++ docs/guide/src/guides/dependency-injection.md | 64 ++++++++ docs/guide/src/guides/di/providers.md | 138 ++++++++++++++++ docs/guide/src/guides/di/serializers.md | 120 ++++++++++++++ .../src/guides/migration-csl-to-pallas.md | 142 ++++++++++++++++ docs/guide/src/guides/tx-builder.md | 80 +++++++++ docs/guide/src/guides/tx-builder/minting.md | 155 ++++++++++++++++++ docs/guide/src/guides/tx-builder/plutus.md | 129 +++++++++++++++ docs/guide/src/guides/tx-builder/simple.md | 114 +++++++++++++ docs/guide/src/guides/tx-builder/staking.md | 107 ++++++++++++ docs/guide/src/guides/tx-parser.md | 110 +++++++++++++ docs/guide/src/introduction.md | 42 +++++ docs/guide/src/reference/api-docs.md | 31 ++++ docs/guide/src/reference/examples-server.md | 67 ++++++++ package.json | 7 +- 22 files changed, 1526 insertions(+), 11 deletions(-) create mode 100644 docs/guide/book.toml create mode 100644 docs/guide/src/SUMMARY.md create mode 100644 docs/guide/src/getting-started/installation.md create mode 100644 docs/guide/src/getting-started/quickstart.md create mode 100644 docs/guide/src/guides/dependency-injection.md create mode 100644 docs/guide/src/guides/di/providers.md create mode 100644 docs/guide/src/guides/di/serializers.md create mode 100644 docs/guide/src/guides/migration-csl-to-pallas.md create mode 100644 docs/guide/src/guides/tx-builder.md create mode 100644 docs/guide/src/guides/tx-builder/minting.md create mode 100644 docs/guide/src/guides/tx-builder/plutus.md create mode 100644 docs/guide/src/guides/tx-builder/simple.md create mode 100644 docs/guide/src/guides/tx-builder/staking.md create mode 100644 docs/guide/src/guides/tx-parser.md create mode 100644 docs/guide/src/introduction.md create mode 100644 docs/guide/src/reference/api-docs.md create mode 100644 docs/guide/src/reference/examples-server.md diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 2bf68b6..92e4d26 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -5,7 +5,7 @@ on: push: branches: - master - - add-docs-for-m5 # temporary — remove after verification + - add-docs-for-m5 # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -34,18 +34,30 @@ jobs: uses: actions/checkout@v4 - name: Setup Pages uses: actions/configure-pages@v5 - - name: Build docs + - name: Install mdBook + uses: peaceiris/actions-mdbook@v2 + with: + mdbook-version: 'latest' + - name: Build API reference (cargo doc) run: | npm run rust:doc + - name: Build mdBook guide + run: | + mdbook build docs/guide + - name: Assemble site + run: | + mkdir -p _site + cp -r docs/guide/book/* _site/ + cp -r docs/ _site/api/ + rm -rf _site/api/guide - name: Link check uses: lycheeverse/lychee-action@v2 with: - args: --no-progress --config .lychee.toml ./docs + args: --no-progress --config .lychee.toml ./_site - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - # Upload entire repository - path: "./docs" + path: "./_site" - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 63ce4e3..9a84e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,12 @@ target */**/schemas */**/output rust/pkg -docs +docs/* +!docs/guide/ +docs/guide/book/ */**/.env publish +_site .claude \ No newline at end of file diff --git a/.lychee.toml b/.lychee.toml index c71990f..0ad06d8 100644 --- a/.lychee.toml +++ b/.lychee.toml @@ -15,9 +15,20 @@ exclude = [ "whisky_csl/core/builder/fn\\.js_serialize_tx_body", "whisky_js/builder/trait\\.ITxBuilderCore", "whisky_js/core/builder/fn\\.js_serialize_tx_body", + # mdBook relative ../api/ links resolve correctly over HTTP but not in lychee local file mode + "api/whisky/index\\.html", + "api/whisky_common/index\\.html", + "api/whisky_pallas/index\\.html", + "api/whisky_csl/index\\.html", + "api/whisky_provider/index\\.html", + "api/whisky_wallet/index\\.html", + "api/whisky_macros/index\\.html", ] -# Exclude generated static files from Rust docs +# Exclude generated static files from Rust docs and mdBook theme exclude_path = [ - "docs/static.files", + "_site/static.files", + "_site/api/static.files", + # mdBook 404 page has a root-relative "/" link that lychee can't resolve locally + "_site/404.html", ] diff --git a/README.md b/README.md index dcb9203..ea6d0c1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ [![Crates.io](https://img.shields.io/crates/v/whisky?style=for-the-badge)](https://crates.io/crates/whisky) [![NPM](https://img.shields.io/npm/v/%40sidan-lab%2Fwhisky-js-nodejs?style=for-the-badge)](https://www.npmjs.com/package/@sidan-lab/whisky-js-nodejs) +**[Read the Guide](https://sidan-lab.github.io/whisky/)** | **[API Reference](https://sidan-lab.github.io/whisky/api/whisky/index.html)** +
@@ -308,7 +310,7 @@ Make sure llvm is installed ## APIs -Please refer to the [hosted documentation](https://sidan-lab.github.io/whisky/whisky/index.html) for the list of endpoints. +Please refer to the [Guide](https://sidan-lab.github.io/whisky/) and [API Reference](https://sidan-lab.github.io/whisky/api/whisky/index.html) for full documentation. ![Alt](https://repobeats.axiom.co/api/embed/2e35716a9dd3250972c06ca2b4c7f1846ef7c51e.svg "Repobeats analytics image") diff --git a/docs/guide/book.toml b/docs/guide/book.toml new file mode 100644 index 0000000..5436149 --- /dev/null +++ b/docs/guide/book.toml @@ -0,0 +1,13 @@ +[book] +authors = ["SIDAN Lab"] +language = "en" +src = "src" +title = "Whisky - Cardano Rust SDK Guide" + +[build] +build-dir = "book" + +[output.html] +git-repository-url = "https://github.com/sidan-lab/whisky" +edit-url-template = "https://github.com/sidan-lab/whisky/edit/master/docs/guide/src/{path}" +no-section-label = false diff --git a/docs/guide/src/SUMMARY.md b/docs/guide/src/SUMMARY.md new file mode 100644 index 0000000..66e2288 --- /dev/null +++ b/docs/guide/src/SUMMARY.md @@ -0,0 +1,26 @@ +# Summary + +[Introduction](./introduction.md) + +# Getting Started + +- [Installation](./getting-started/installation.md) +- [Quick Start](./getting-started/quickstart.md) + +# Core Guides + +- [Transaction Builder](./guides/tx-builder.md) + - [Simple Transactions](./guides/tx-builder/simple.md) + - [Plutus Script Transactions](./guides/tx-builder/plutus.md) + - [Minting](./guides/tx-builder/minting.md) + - [Staking & Governance](./guides/tx-builder/staking.md) +- [Transaction Parser](./guides/tx-parser.md) +- [Dependency Injection](./guides/dependency-injection.md) + - [Serializer Backends](./guides/di/serializers.md) + - [Providers](./guides/di/providers.md) +- [Migration: CSL to Pallas](./guides/migration-csl-to-pallas.md) + +# Reference + +- [Examples Server](./reference/examples-server.md) +- [API Documentation](./reference/api-docs.md) diff --git a/docs/guide/src/getting-started/installation.md b/docs/guide/src/getting-started/installation.md new file mode 100644 index 0000000..584205a --- /dev/null +++ b/docs/guide/src/getting-started/installation.md @@ -0,0 +1,60 @@ +# Installation + +## Rust Library + +Add whisky to your project: + +```sh +cargo add whisky +``` + +Or add it directly to your `Cargo.toml`: + +```toml +[dependencies] +whisky = "1.0.28-beta.1" +``` + +### Feature Flags + +By default, all features are enabled (`full`). You can selectively enable only what you need: + +```toml +# Full (default) — includes wallet + provider +whisky = "1.0.28-beta.1" + +# Just common types (minimal, no serializer backends) +whisky = { version = "1.0.28-beta.1", default-features = false } + +# Wallet only (signing + key management) +whisky = { version = "1.0.28-beta.1", default-features = false, features = ["wallet"] } + +# Provider only (Blockfrost/Maestro integrations) +whisky = { version = "1.0.28-beta.1", default-features = false, features = ["provider"] } +``` + +| Feature | Includes | Use Case | +|---------|----------|----------| +| `full` (default) | wallet + provider | Full DApp backend | +| `wallet` | Signing, key encryption | Transaction signing only | +| `provider` | Blockfrost, Maestro | Blockchain data fetching | + +## JS / TS WASM Library + +For JavaScript or TypeScript projects, whisky is available as a WASM package: + +```sh +# For Node.js +yarn add @sidan-lab/whisky-js-nodejs + +# For browser +yarn add @sidan-lab/whisky-js-browser +``` + +## Prerequisites + +For building from source, make sure LLVM is installed on your system: + +- **macOS**: `brew install llvm` +- **Ubuntu/Debian**: `apt install llvm-dev libclang-dev` +- **Windows**: Install via [LLVM releases](https://releases.llvm.org/) diff --git a/docs/guide/src/getting-started/quickstart.md b/docs/guide/src/getting-started/quickstart.md new file mode 100644 index 0000000..c1d9c5e --- /dev/null +++ b/docs/guide/src/getting-started/quickstart.md @@ -0,0 +1,86 @@ +# Quick Start + +This guide shows you how to build your first Cardano transaction with whisky. + +## Your First Transaction + +The simplest transaction sends lovelace from one address to another. Here's the complete example: + +```rust,ignore +use whisky::*; + +pub fn send_lovelace( + recipient_address: &str, + my_address: &str, + inputs: &[UTxO], +) -> Result { + let mut tx_builder = TxBuilder::new_core(); + tx_builder + .tx_out( + recipient_address, + &[Asset::new_from_str("lovelace", "1000000")], + ) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; + + Ok(tx_builder.tx_hex()) +} +``` + +Let's break this down: + +1. **`TxBuilder::new_core()`** — Creates a new transaction builder with the default Pallas serializer +2. **`.tx_out(address, assets)`** — Adds an output sending 1 ADA (1,000,000 lovelace) to the recipient +3. **`.change_address(address)`** — Sets where leftover funds go after paying fees +4. **`.select_utxos_from(inputs, threshold)`** — Automatically selects UTxOs from the provided set to cover outputs + fees. The threshold (5,000,000 lovelace) is extra headroom for fees and min UTxO +5. **`.complete_sync(None)`** — Balances the transaction, calculates fees, and serializes to CBOR +6. **`.tx_hex()`** — Returns the unsigned transaction as a hex-encoded CBOR string + +## Sync vs Async + +Whisky offers both synchronous and asynchronous completion: + +```rust,ignore +// Synchronous — no script evaluation, no provider calls +tx_builder.complete_sync(None)?; + +// Asynchronous — evaluates Plutus scripts, can fetch data from providers +tx_builder.complete(None).await?; +``` + +Use `complete_sync` for simple transactions without scripts. Use `complete` (async) when your transaction includes Plutus scripts that need execution unit evaluation. + +## Signing + +After building, sign the transaction with a private key: + +```rust,ignore +let signed_tx = tx_builder + .signing_key("your_signing_key_hex") + .complete_sync(None)? + .complete_signing()?; +``` + +The `signed_tx` string is ready for submission to the Cardano network. + +## Running the Tests + +Whisky includes comprehensive integration tests you can run to see these patterns in action: + +```sh +# Run all tests +cargo test + +# Run Pallas integration tests specifically +cargo test --package whisky --test pallas_integration_tests + +# Run a specific test with output +cargo test --package whisky --test pallas_integration_tests test_simple_spend -- --nocapture +``` + +## Next Steps + +- [Transaction Builder](../guides/tx-builder.md) — Explore all transaction building patterns +- [Transaction Parser](../guides/tx-parser.md) — Parse and edit existing transactions +- [Dependency Injection](../guides/dependency-injection.md) — Customize serializers and providers diff --git a/docs/guide/src/guides/dependency-injection.md b/docs/guide/src/guides/dependency-injection.md new file mode 100644 index 0000000..d6022d6 --- /dev/null +++ b/docs/guide/src/guides/dependency-injection.md @@ -0,0 +1,64 @@ +# Dependency Injection + +Whisky uses a trait-based dependency injection pattern that lets you swap out core components: the serializer backend, blockchain data fetcher, script evaluator, and transaction submitter. + +## TxBuilderParam + +When creating a `TxBuilder`, you can inject dependencies via `TxBuilderParam`: + +```rust,ignore +use whisky::*; +use whisky_pallas::WhiskyPallas; + +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyPallas::new(None)), // Required + evaluator: None, // Optional — defaults to OfflineTxEvaluator + fetcher: None, // Optional — for blockchain data + submitter: None, // Optional — for tx submission + params: None, // Optional — protocol parameters +}); +``` + +Or use the convenience constructor with all defaults: + +```rust,ignore +let mut tx_builder = TxBuilder::new_core(); +// Equivalent to: WhiskyPallas serializer, offline evaluator, no fetcher/submitter +``` + +## The TxBuilder Struct + +```rust,ignore +pub struct TxBuilder { + pub serializer: Box, // Serializes tx body to CBOR + pub fetcher: Option>, // Fetches blockchain data + pub evaluator: Option>, // Evaluates Plutus scripts + pub submitter: Option>, // Submits transactions + pub protocol_params: Option, // Network parameters + // ... internal state fields +} +``` + +## Why Dependency Injection? + +This design enables: + +- **Swappable serializers**: Use Pallas (recommended) or CSL backend without changing transaction logic +- **Testing**: Mock fetchers and evaluators in unit tests +- **Custom providers**: Implement your own blockchain data source +- **Offline mode**: Build transactions without any network dependency (the default) +- **Full pipeline**: Wire up fetcher + evaluator + submitter for end-to-end transaction handling + +## Trait Overview + +| Trait | Purpose | Built-in Implementations | +|-------|---------|------------------------| +| `TxBuildable` | Serialize transaction body to CBOR | `WhiskyPallas`, `WhiskyCSL` | +| `Fetcher` | Fetch UTxOs, protocol params, block info | `MaestroProvider`, `BlockfrostProvider` | +| `Evaluator` | Evaluate Plutus script execution units | `OfflineTxEvaluator` | +| `Submitter` | Submit signed transactions | `MaestroProvider`, `BlockfrostProvider` | + +## Chapters + +- [Serializer Backends](./di/serializers.md) — `TxBuildable` trait, WhiskyPallas vs WhiskyCSL +- [Providers](./di/providers.md) — Fetcher, Evaluator, Submitter traits and implementations diff --git a/docs/guide/src/guides/di/providers.md b/docs/guide/src/guides/di/providers.md new file mode 100644 index 0000000..6ecd46f --- /dev/null +++ b/docs/guide/src/guides/di/providers.md @@ -0,0 +1,138 @@ +# Providers + +Providers implement the `Fetcher`, `Evaluator`, and `Submitter` traits to connect whisky to the Cardano blockchain. + +## Fetcher + +The `Fetcher` trait provides blockchain data: + +```rust,ignore +#[async_trait] +pub trait Fetcher: Send + Sync { + async fn fetch_account_info(&self, address: &str) -> Result; + async fn fetch_address_utxos( + &self, + address: &str, + asset: Option<&str>, + ) -> Result, WError>; + async fn fetch_asset_addresses(&self, asset: &str) -> Result, WError>; + async fn fetch_asset_metadata( + &self, + asset: &str, + ) -> Result>, WError>; + async fn fetch_block_info(&self, hash: &str) -> Result; + async fn fetch_collection_assets( + &self, + policy_id: &str, + cursor: Option, + ) -> Result<(Vec<(String, String)>, Option), WError>; + async fn fetch_protocol_parameters(&self, epoch: Option) -> Result; + async fn fetch_tx_info(&self, hash: &str) -> Result; + async fn fetch_utxos(&self, hash: &str, index: Option) -> Result, WError>; + async fn get(&self, url: &str) -> Result; +} +``` + +## Evaluator + +The `Evaluator` trait runs Plutus scripts off-chain to determine execution units: + +```rust,ignore +#[async_trait] +pub trait Evaluator: Send { + async fn evaluate_tx( + &self, + tx_hex: &str, + inputs: &[UTxO], + additional_txs: &[String], + network: &Network, + slot_config: &SlotConfig, + ) -> Result, WError>; +} +``` + +By default, `TxBuilder` uses `OfflineTxEvaluator`, which evaluates scripts locally using TxPipe's `uplc` library — no network calls needed. + +## Submitter + +The `Submitter` trait submits signed transactions: + +```rust,ignore +#[async_trait] +pub trait Submitter: Send + Sync { + async fn submit_tx(&self, tx_hex: &str) -> Result; +} +``` + +Returns the transaction hash on success. + +## Built-in Providers + +### Maestro + +```rust,ignore +use whisky_provider::MaestroProvider; + +let provider = MaestroProvider::new("your_api_key", "preprod"); // or "mainnet" + +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyPallas::new(None)), + evaluator: None, + fetcher: Some(Box::new(provider.clone())), + submitter: Some(Box::new(provider)), + params: None, +}); +``` + +### Blockfrost + +```rust,ignore +use whisky_provider::BlockfrostProvider; + +let provider = BlockfrostProvider::new("your_project_id", "preprod"); // or "mainnet" + +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyPallas::new(None)), + evaluator: None, + fetcher: Some(Box::new(provider.clone())), + submitter: Some(Box::new(provider)), + params: None, +}); +``` + +> **Note**: Using providers requires the `provider` feature flag (enabled by default). + +## Wiring It All Together + +A fully-wired `TxBuilder` can fetch UTxOs, evaluate scripts, and submit — all in one flow: + +```rust,ignore +use whisky::*; +use whisky_pallas::WhiskyPallas; +use whisky_provider::MaestroProvider; + +let provider = MaestroProvider::new("api_key", "preprod"); + +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyPallas::new(None)), + evaluator: None, // Uses OfflineTxEvaluator by default + fetcher: Some(Box::new(provider.clone())), + submitter: Some(Box::new(provider)), + params: None, +}); + +// Build, evaluate, sign, and submit +tx_builder + .tx_out(recipient, &[Asset::new_from_str("lovelace", "5000000")]) + .change_address(my_address) + .select_utxos_from(&utxos, 5000000) + .signing_key(skey_hex) + .complete(None) + .await? + .complete_signing()?; + +// Submit +let tx_hash = tx_builder + .submit_tx(&tx_builder.tx_hex()) + .await?; +``` diff --git a/docs/guide/src/guides/di/serializers.md b/docs/guide/src/guides/di/serializers.md new file mode 100644 index 0000000..482a964 --- /dev/null +++ b/docs/guide/src/guides/di/serializers.md @@ -0,0 +1,120 @@ +# Serializer Backends + +The `TxBuildable` trait abstracts transaction serialization. Whisky ships with two implementations: **WhiskyPallas** (recommended) and **WhiskyCSL** (legacy). + +## TxBuildable Trait + +```rust,ignore +pub trait TxBuildable: Debug + Send + Sync { + fn set_protocol_params(&mut self, protocol_params: Protocol); + fn set_tx_builder_body(&mut self, tx_builder: TxBuilderBody); + fn reset_builder(&mut self); + + fn serialize_tx_body(&mut self) -> Result; + fn unbalanced_serialize_tx_body(&mut self) -> Result; + fn complete_signing(&mut self) -> Result; + fn set_tx_hex(&mut self, tx_hex: String); + fn tx_hex(&mut self) -> String; + fn tx_evaluation_multiplier_percentage(&self) -> u64; + + fn add_tx_in(&mut self, input: PubKeyTxIn) -> Result<(), WError>; +} +``` + +The `TxBuilder` calls these methods internally — you interact with the high-level builder API, not the trait directly. + +## WhiskyPallas (Recommended) + +The Pallas-based serializer is the default and recommended backend. It uses [TxPipe's Pallas](https://github.com/txpipe/pallas) library for CBOR serialization. + +```rust,ignore +use whisky_pallas::WhiskyPallas; + +// With default protocol parameters +let serializer = WhiskyPallas::new(None); + +// With custom protocol parameters +let serializer = WhiskyPallas::new(Some(protocol_params)); +``` + +Use it with `TxBuilder`: + +```rust,ignore +use whisky::*; +use whisky_pallas::WhiskyPallas; + +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyPallas::new(None)), + evaluator: None, + fetcher: None, + submitter: None, + params: None, +}); +``` + +Or simply: + +```rust,ignore +let mut tx_builder = TxBuilder::new_core(); +// new_core() uses WhiskyPallas by default +``` + +**Why Pallas?** +- Pure Rust implementation — no C dependencies +- Actively maintained and updated for hard forks +- Better alignment with the Cardano Rust ecosystem + +## WhiskyCSL (Legacy) + +The CSL-based serializer uses `cardano-serialization-lib`. It's available for backward compatibility. + +```rust,ignore +use whisky_csl::WhiskyCSL; + +let serializer = WhiskyCSL::new(None); +``` + +> **Note**: The main `whisky` crate no longer includes CSL by default. To use it, add `whisky-csl` directly: +> +> ```toml +> [dependencies] +> whisky-csl = "1.0.28-beta.1" +> ``` + +## Implementing a Custom Serializer + +You can implement `TxBuildable` for your own serializer: + +```rust,ignore +use whisky_common::*; + +#[derive(Debug)] +struct MySerializer { + // your fields +} + +impl TxBuildable for MySerializer { + fn set_protocol_params(&mut self, protocol_params: Protocol) { /* ... */ } + fn set_tx_builder_body(&mut self, tx_builder: TxBuilderBody) { /* ... */ } + fn reset_builder(&mut self) { /* ... */ } + fn serialize_tx_body(&mut self) -> Result { /* ... */ } + fn unbalanced_serialize_tx_body(&mut self) -> Result { /* ... */ } + fn complete_signing(&mut self) -> Result { /* ... */ } + fn set_tx_hex(&mut self, tx_hex: String) { /* ... */ } + fn tx_hex(&mut self) -> String { /* ... */ } + fn tx_evaluation_multiplier_percentage(&self) -> u64 { 110 } + fn add_tx_in(&mut self, input: PubKeyTxIn) -> Result<(), WError> { /* ... */ } +} +``` + +Then inject it into `TxBuilder`: + +```rust,ignore +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(MySerializer { /* ... */ }), + evaluator: None, + fetcher: None, + submitter: None, + params: None, +}); +``` diff --git a/docs/guide/src/guides/migration-csl-to-pallas.md b/docs/guide/src/guides/migration-csl-to-pallas.md new file mode 100644 index 0000000..6e5323d --- /dev/null +++ b/docs/guide/src/guides/migration-csl-to-pallas.md @@ -0,0 +1,142 @@ +# Migration: CSL to Pallas + +This guide covers migrating from the legacy `cardano-serialization-lib` (CSL) backend to the `pallas`-based backend. + +## Why Migrate? + +Both serialization libraries have similar functionality, but **Pallas** offers: + +- **Better maintenance** — actively updated for Cardano hard forks +- **Pure Rust** — no C/WASM dependencies +- **Ecosystem alignment** — used widely in the Cardano Rust ecosystem + +The `whisky` main crate now defaults to Pallas. CSL has been removed from the default feature set. + +## Transaction Building + +### Before (CSL) + +```rust,ignore +use whisky::*; +use whisky_csl::WhiskyCSL; + +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyCSL::new(None)), + evaluator: None, + fetcher: None, + submitter: None, + params: None, +}); +``` + +### After (Pallas) + +```rust,ignore +use whisky::*; +use whisky_pallas::WhiskyPallas; + +// Option 1: Explicit +let mut tx_builder = TxBuilder::new(TxBuilderParam { + serializer: Box::new(WhiskyPallas::new(None)), + evaluator: None, + fetcher: None, + submitter: None, + params: None, +}); + +// Option 2: Use the convenience constructor (defaults to Pallas) +let mut tx_builder = TxBuilder::new_core(); +``` + +The transaction building API remains **identical** — only the serializer instantiation changes: + +```rust,ignore +let signed_tx = tx_builder + .tx_in(tx_hash, tx_index, amount, address) + .change_address(my_address) + .signing_key(skey_hex) + .complete_sync(None)? + .complete_signing()?; +``` + +## Transaction Parsing + +### Before (CSL) + +```rust,ignore +use whisky_csl::CSLParser; + +let mut parser = CSLParser::new(); +parser.parse(tx_hex, &utxos)?; +let body = parser.get_builder_body(); +``` + +### After (Pallas) + +```rust,ignore +use whisky_pallas::tx_parser::parse; + +let body = parse(tx_hex, &utxos)?; +``` + +Or using the trait-based approach: + +```rust,ignore +use whisky_pallas::tx_parser::PallasParser; +use whisky_common::TxParsable; + +let mut parser = PallasParser::new(); +parser.parse(tx_hex, &utxos)?; +let body = parser.get_builder_body(); +``` + +## Transaction Evaluation + +```rust,ignore +use uplc::tx::script_context::SlotConfig; +use whisky_common::{Network, UTxO}; +use whisky_pallas::utils::evaluate_tx_scripts; + +let result = evaluate_tx_scripts( + tx_hex, + &utxos, + &[], // additional chained transactions + &Network::Mainnet, + &SlotConfig::default(), +); +``` + +## Dependency Changes + +If you were depending on `whisky-csl` directly, update your `Cargo.toml`: + +### Before + +```toml +[dependencies] +whisky = "1.0.17" +# CSL was included by default +``` + +### After + +```toml +[dependencies] +whisky = "1.0.28-beta.1" +# Pallas is now the default — no extra dependency needed + +# Only if you still need CSL: +# whisky-csl = "1.0.28-beta.1" +``` + +## Summary of Changes + +| Component | CSL | Pallas | +|-----------|-----|--------| +| Serializer | `WhiskyCSL::new(None)` | `WhiskyPallas::new(None)` | +| Default constructor | N/A | `TxBuilder::new_core()` | +| Parser | `CSLParser::new()` | `parse(tx_hex, &utxos)` | +| Crate | `whisky-csl` | `whisky-pallas` (included via `whisky`) | +| Feature flag | `features = ["csl"]` | Included by default | + +The transaction building API (`tx_in`, `tx_out`, `change_address`, `complete`, etc.) is **unchanged** — migration only requires swapping the serializer backend. diff --git a/docs/guide/src/guides/tx-builder.md b/docs/guide/src/guides/tx-builder.md new file mode 100644 index 0000000..8d24ffa --- /dev/null +++ b/docs/guide/src/guides/tx-builder.md @@ -0,0 +1,80 @@ +# Transaction Builder + +The `TxBuilder` is the core API for constructing Cardano transactions in whisky. It uses a chainable builder pattern where you compose a transaction step by step, then finalize it. + +## Overview + +```rust,ignore +use whisky::*; + +let mut tx_builder = TxBuilder::new_core(); +tx_builder + .tx_in(tx_hash, tx_index, amount, address) // Add inputs + .tx_out(address, assets) // Add outputs + .change_address(my_address) // Set change address + .complete_sync(None)?; // Balance and serialize + +let tx_hex = tx_builder.tx_hex(); +``` + +## Key Concepts + +### Builder Pattern + +Every method returns `&mut Self`, allowing you to chain calls fluently. The builder accumulates state until you call `complete_sync()` or `complete()`. + +### Inputs and UTxO Selection + +You can specify inputs explicitly with `.tx_in()` or let whisky select them automatically: + +```rust,ignore +// Explicit input +tx_builder.tx_in(tx_hash, tx_index, amount, address); + +// Automatic selection from a pool of UTxOs +tx_builder.select_utxos_from(&available_utxos, 5000000); +``` + +The `select_utxos_from` threshold (e.g., 5,000,000 lovelace) tells the selector to pick enough UTxOs to cover all outputs plus this extra amount for fees and change output min UTxO. + +### Outputs + +```rust,ignore +// Send lovelace +tx_builder.tx_out(address, &[Asset::new_from_str("lovelace", "2000000")]); + +// Send native tokens +tx_builder.tx_out(address, &[ + Asset::new_from_str("lovelace", "2000000"), + Asset::new("policy_id_hex".to_string() + "token_name_hex", "1".to_string()), +]); +``` + +### Completion + +| Method | Sync/Async | Script Evaluation | Use Case | +|--------|-----------|-------------------|----------| +| `complete_sync(None)` | Sync | No | Simple transactions | +| `complete(None).await` | Async | Yes (offline) | Plutus script transactions | + +### Common Methods + +| Method | Purpose | +|--------|---------| +| `.tx_in()` | Add a specific UTxO as input | +| `.tx_out()` | Add an output | +| `.change_address()` | Set the change address | +| `.select_utxos_from()` | Auto-select UTxOs from a pool | +| `.signing_key()` | Add a signing key | +| `.required_signer_hash()` | Add a required signer | +| `.invalid_before()` | Set validity start slot | +| `.invalid_hereafter()` | Set validity end slot | +| `.metadata_value()` | Attach transaction metadata | +| `.complete_signing()` | Sign and return the final tx hex | + +## Chapters + +- [Simple Transactions](./tx-builder/simple.md) — Send lovelace, lock funds, delegate stake +- [Plutus Script Transactions](./tx-builder/plutus.md) — Unlock funds from scripts, handle datums and redeemers +- [Minting](./tx-builder/minting.md) — Mint and burn native tokens with Plutus scripts +- [Staking & Governance](./tx-builder/staking.md) — Stake registration, delegation, withdrawals, governance diff --git a/docs/guide/src/guides/tx-builder/minting.md b/docs/guide/src/guides/tx-builder/minting.md new file mode 100644 index 0000000..ff89f0e --- /dev/null +++ b/docs/guide/src/guides/tx-builder/minting.md @@ -0,0 +1,155 @@ +# Minting + +This chapter covers minting and burning native tokens using Plutus minting policies. + +## Mint Tokens + +Mint tokens using a Plutus V3 minting policy: + +```rust,ignore +use whisky::*; + +pub async fn mint_tokens( + to_mint_asset: &Asset, + redeemer: &str, + script: &ProvidedScriptSource, + my_address: &str, + inputs: &[UTxO], + collateral: &UTxO, +) -> Result { + let mut tx_builder = TxBuilder::new_core(); + + tx_builder + .mint_plutus_script_v3() + .mint( + to_mint_asset.quantity_i128(), + &to_mint_asset.policy(), + &to_mint_asset.name(), + ) + .minting_script(&script.script_cbor) + .mint_redeemer_value(&WRedeemer { + data: WData::JSON(redeemer.to_string()), + ex_units: Budget { mem: 0, steps: 0 }, + }) + .change_address(my_address) + .tx_in_collateral( + &collateral.input.tx_hash, + collateral.input.output_index, + &collateral.output.amount, + &collateral.output.address, + ) + .select_utxos_from(inputs, 5000000) + .complete(None) + .await?; + + Ok(tx_builder.tx_hex()) +} +``` + +## The Minting Pattern + +Every Plutus mint follows this sequence: + +1. **Declare the script version**: `.mint_plutus_script_v3()` (or `_v2()`, `_v1()`) +2. **Specify the mint**: `.mint(quantity, policy_id, asset_name)` +3. **Provide the script**: `.minting_script(&script_cbor)` or use a reference script +4. **Provide the redeemer**: `.mint_redeemer_value(&redeemer)` + +## Reference Script Minting + +Instead of embedding the script, reference one already on-chain: + +```rust,ignore +tx_builder + .mint_plutus_script_v2() + .mint(1, policy_id, token_name_hex) + .mint_tx_in_reference( + "reference_tx_hash", + 0, // reference tx index + policy_id, // script hash to validate against + 100, // script size in bytes + ) + .mint_redeemer_value(&WRedeemer { + data: WData::JSON(r#"{"constructor": 0, "fields": []}"#.to_string()), + ex_units: Budget { mem: 3386819, steps: 1048170931 }, + }) +``` + +## Burning Tokens + +To burn tokens, use a negative quantity: + +```rust,ignore +tx_builder + .mint_plutus_script_v3() + .mint(-1, policy_id, token_name_hex) // Negative = burn + .minting_script(&script.script_cbor) + .mint_redeemer_value(&redeemer) +``` + +## Multiple Mints in One Transaction + +You can mint tokens from multiple policies in a single transaction by chaining mint blocks: + +```rust,ignore +use whisky::*; + +tx_builder + // First mint + .mint_plutus_script_v2() + .mint( + to_mint_asset_1.quantity_i128(), + &to_mint_asset_1.policy(), + &to_mint_asset_1.name(), + ) + .mint_redeemer_value(&WRedeemer { + data: WData::JSON(redeemer_1.to_string()), + ex_units: Budget { mem: 0, steps: 0 }, + }) + .minting_script(&script_1.script_cbor) + // Second mint + .mint_plutus_script_v2() + .mint( + to_mint_asset_2.quantity_i128(), + &to_mint_asset_2.policy(), + &to_mint_asset_2.name(), + ) + .mint_redeemer_value(&WRedeemer { + data: WData::JSON(redeemer_2.to_string()), + ex_units: Budget { mem: 0, steps: 0 }, + }) + .minting_script(&script_2.script_cbor) + .change_address(my_address) + .tx_in_collateral(/* ... */) + .select_utxos_from(inputs, 5000000) + .complete(None) + .await?; +``` + +Each mint block starts with `.mint_plutus_script_vN()` and is independent — you can mix V1, V2, and V3 policies in the same transaction. + +## Complex Transaction: Spend + Mint + +You can combine script spending and minting in one transaction: + +```rust,ignore +tx_builder + // Script spend + .spending_plutus_script_v2() + .tx_in(/* script UTxO */) + .tx_in_inline_datum_present() + .tx_in_redeemer_value(&spend_redeemer) + .tx_in_script(&spend_script_cbor) + // Mint + .mint_plutus_script_v2() + .mint(1, policy_id, token_name) + .mint_redeemer_value(&mint_redeemer) + .minting_script(&mint_script_cbor) + // Finalize + .change_address(my_address) + .tx_in_collateral(/* ... */) + .input_for_evaluation(script_utxo) + .select_utxos_from(inputs, 5000000) + .complete(None) + .await?; +``` diff --git a/docs/guide/src/guides/tx-builder/plutus.md b/docs/guide/src/guides/tx-builder/plutus.md new file mode 100644 index 0000000..581dfa6 --- /dev/null +++ b/docs/guide/src/guides/tx-builder/plutus.md @@ -0,0 +1,129 @@ +# Plutus Script Transactions + +This chapter covers spending from Plutus script addresses — unlocking funds guarded by validators. + +## Unlock Funds from a Script + +To spend a UTxO locked at a Plutus script address, you must provide the script, datum, and redeemer: + +```rust,ignore +use whisky::*; + +pub async fn unlock_fund( + script_utxo: &UTxO, + redeemer: &str, + script: &ProvidedScriptSource, + my_address: &str, + inputs: &[UTxO], + collateral: &UTxO, +) -> Result { + let mut tx_builder = TxBuilder::new_core(); + let pub_key_hash = deserialize_address(my_address)?.pub_key_hash; + + tx_builder + .spending_plutus_script_v3() + .tx_in( + &script_utxo.input.tx_hash, + script_utxo.input.output_index, + &script_utxo.output.amount, + &script_utxo.output.address, + ) + .tx_in_inline_datum_present() + .tx_in_redeemer_value(&WRedeemer { + data: WData::JSON(redeemer.to_string()), + ex_units: Budget { mem: 0, steps: 0 }, + }) + .tx_in_script(&script.script_cbor) + .change_address(my_address) + .required_signer_hash(&pub_key_hash) + .tx_in_collateral( + &collateral.input.tx_hash, + collateral.input.output_index, + &collateral.output.amount, + &collateral.output.address, + ) + .input_for_evaluation(script_utxo) + .select_utxos_from(inputs, 5000000) + .complete(None) + .await?; + + Ok(tx_builder.tx_hex()) +} +``` + +## The Script Spending Pattern + +Every Plutus spend follows the same sequence: + +1. **Declare the script version**: `.spending_plutus_script_v3()` (or `_v2()`, `_v1()`) +2. **Add the script input**: `.tx_in(hash, index, amount, address)` +3. **Provide the datum**: `.tx_in_inline_datum_present()` or `.tx_in_datum_value(&datum)` +4. **Provide the redeemer**: `.tx_in_redeemer_value(&redeemer)` +5. **Provide the script**: `.tx_in_script(&script_cbor)` or use a reference script + +## Datum Handling + +Whisky supports two datum modes: + +```rust,ignore +// The UTxO already has an inline datum — just declare it's present +.tx_in_inline_datum_present() + +// Provide the datum value explicitly (e.g., when only the datum hash is on-chain) +.tx_in_datum_value(&WData::JSON(datum_json.to_string())) +``` + +## Redeemer Values + +Redeemers are Plutus data values passed to the validator. Set execution units to `0` and let the evaluator calculate them: + +```rust,ignore +.tx_in_redeemer_value(&WRedeemer { + data: WData::JSON(r#"{"constructor": 0, "fields": []}"#.to_string()), + ex_units: Budget { mem: 0, steps: 0 }, +}) +``` + +When you call `.complete(None).await`, the built-in offline evaluator runs the script and fills in the actual execution units. + +## Script Sources + +You can provide the script in two ways: + +```rust,ignore +// Embed the script CBOR directly in the transaction +.tx_in_script(&script_cbor) + +// Reference a script already on-chain (more efficient — saves tx size) +.spending_tx_in_reference(tx_hash, tx_index, script_hash, script_size) +``` + +## Collateral + +Plutus transactions require collateral — a UTxO that gets consumed if the script fails: + +```rust,ignore +.tx_in_collateral( + &collateral.input.tx_hash, + collateral.input.output_index, + &collateral.output.amount, + &collateral.output.address, +) +``` + +You can also set a specific total collateral amount: + +```rust,ignore +.tx_in_collateral(tx_hash, tx_index, amount, address) +.set_total_collateral("5000000") +``` + +## Input for Evaluation + +When using offline evaluation, provide the script UTxO context so the evaluator can resolve inputs: + +```rust,ignore +.input_for_evaluation(script_utxo) +``` + +This is required for the offline evaluator to correctly simulate script execution. diff --git a/docs/guide/src/guides/tx-builder/simple.md b/docs/guide/src/guides/tx-builder/simple.md new file mode 100644 index 0000000..0748422 --- /dev/null +++ b/docs/guide/src/guides/tx-builder/simple.md @@ -0,0 +1,114 @@ +# Simple Transactions + +These examples cover basic transaction patterns that don't involve Plutus scripts. + +## Send Lovelace + +The most basic transaction: send ADA from one address to another. + +```rust,ignore +use whisky::*; + +pub fn send_lovelace( + recipient_address: &str, + my_address: &str, + inputs: &[UTxO], +) -> Result { + let mut tx_builder = TxBuilder::new_core(); + tx_builder + .tx_out( + recipient_address, + &[Asset::new_from_str("lovelace", "1000000")], + ) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; + + Ok(tx_builder.tx_hex()) +} +``` + +> **Note**: You don't need to manually add inputs — `select_utxos_from` automatically picks UTxOs to cover the output amount plus the threshold for fees. + +## Lock Funds at a Script Address + +Send funds to a script address with an inline datum attached: + +```rust,ignore +use whisky::*; + +pub fn lock_fund( + script_address: &str, + datum: &str, + my_address: &str, + inputs: &[UTxO], +) -> Result { + let mut tx_builder = TxBuilder::new_core(); + tx_builder + .tx_out(script_address, &[]) + .tx_out_inline_datum_value(&WData::JSON(datum.to_string())) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; + + Ok(tx_builder.tx_hex()) +} +``` + +Key points: +- **`tx_out_inline_datum_value`** attaches an inline datum (stored on-chain) to the output +- The datum is provided as a JSON-encoded Plutus data string (e.g., `{"constructor": 0, "fields": []}`) +- Use `tx_out_datum_hash_value` instead if you only want to store the datum hash on-chain + +## Delegate Stake + +Register a stake key and delegate to a pool in a single transaction: + +```rust,ignore +use whisky::*; + +pub fn delegate_stake( + stake_key_hash: &str, + pool_id: &str, // e.g., "pool1..." + my_address: &str, + inputs: &[UTxO], +) -> Result { + let mut tx_builder = TxBuilder::new_core(); + tx_builder + .register_stake_certificate(stake_key_hash) + .delegate_stake_certificate(stake_key_hash, pool_id) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; + + Ok(tx_builder.tx_hex()) +} +``` + +## Validity Ranges and Metadata + +You can set time bounds and attach metadata to any transaction: + +```rust,ignore +tx_builder + .tx_out(address, &[Asset::new_from_str("lovelace", "2000000")]) + .invalid_before(100) // Transaction valid from slot 100 + .invalid_hereafter(200) // Transaction invalid after slot 200 + .metadata_value("674", "{\"msg\": [\"Hello, Cardano!\"]}") + .change_address(my_address) + .complete_sync(None)?; +``` + +## Signing and Submitting + +After building, sign with one or more keys: + +```rust,ignore +let signed_tx = tx_builder + .signing_key("ed25519_sk_hex_key_1") + .signing_key("ed25519_sk_hex_key_2") // Multiple signers + .complete_sync(None)? + .complete_signing()?; + +// signed_tx is ready for submission +``` diff --git a/docs/guide/src/guides/tx-builder/staking.md b/docs/guide/src/guides/tx-builder/staking.md new file mode 100644 index 0000000..fa088b8 --- /dev/null +++ b/docs/guide/src/guides/tx-builder/staking.md @@ -0,0 +1,107 @@ +# Staking & Governance + +This chapter covers stake operations and Conway-era governance actions. + +## Stake Registration + +Register a stake key on-chain: + +```rust,ignore +use whisky::*; + +let mut tx_builder = TxBuilder::new_core(); +tx_builder + .register_stake_certificate(stake_key_hash) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; +``` + +## Stake Delegation + +Delegate to a stake pool (can be combined with registration): + +```rust,ignore +tx_builder + .register_stake_certificate(stake_key_hash) + .delegate_stake_certificate(stake_key_hash, pool_id) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; +``` + +## Stake Deregistration + +Deregister a stake key to reclaim the deposit: + +```rust,ignore +tx_builder + .deregister_stake_certificate(stake_key_hash) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; +``` + +## Withdrawals + +Withdraw staking rewards: + +```rust,ignore +tx_builder + .tx_in(tx_hash, tx_index, amount, address) + .change_address(my_address) + .withdrawal(stake_address, 0) // stake_address e.g., "stake_test1ur..." + .required_signer_hash(pub_key_hash) + .signing_key(signing_key_hex) + .complete_sync(None)? + .complete_signing()?; +``` + +## Governance: DRep Registration + +Register as a Delegated Representative (Conway era): + +```rust,ignore +tx_builder + .drep_registration(drep_id, deposit_amount) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; +``` + +## Governance: Vote Delegation + +Delegate your voting power to a DRep: + +```rust,ignore +tx_builder + .vote_delegation(stake_key_hash, drep) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; +``` + +## Governance: Voting + +Cast a governance vote: + +```rust,ignore +tx_builder + .vote(voter, ref_tx_hash, ref_tx_index, vote_kind) + .change_address(my_address) + .select_utxos_from(inputs, 5000000) + .complete_sync(None)?; +``` + +For script-based voting, use the Plutus vote pattern: + +```rust,ignore +tx_builder + .vote_plutus_script_v3() + .vote(voter, ref_tx_hash, ref_tx_index, vote_kind) + .vote_script(&script_cbor) + .vote_redeemer_value(&redeemer) + .tx_in_collateral(/* ... */) + .complete(None) + .await?; +``` diff --git a/docs/guide/src/guides/tx-parser.md b/docs/guide/src/guides/tx-parser.md new file mode 100644 index 0000000..642a1ea --- /dev/null +++ b/docs/guide/src/guides/tx-parser.md @@ -0,0 +1,110 @@ +# Transaction Parser + +The transaction parser lets you deserialize a raw CBOR transaction hex back into a `TxBuilderBody`, inspect it, edit it, and rebuild it into a new transaction. + +## Parsing a Transaction + +Use the `parse` function to deserialize a transaction: + +```rust,ignore +use whisky::*; +use whisky_pallas::tx_parser::parse; + +let tx_hex = "84a700d90102..."; // Raw transaction CBOR hex +let utxos = vec![/* resolved UTxOs referenced by the transaction */]; + +let body = parse(tx_hex, &utxos).unwrap(); +``` + +The `parse` function returns a `TxBuilderBody` containing all the transaction's inputs, outputs, mints, certificates, withdrawals, and metadata. + +> **Important**: You must provide the resolved UTxOs that the transaction references as inputs. The parser needs these to reconstruct the full input context. + +## The Parse-Edit-Rebuild Pattern + +A powerful pattern is to parse an existing transaction, modify it, and rebuild: + +```rust,ignore +use whisky::*; +use whisky_pallas::tx_parser::parse; + +// 1. Parse the original transaction +let utxos = vec![utxo_1, utxo_2, utxo_3]; +let tx_hex = "84a700d90102..."; +let mut body = parse(tx_hex, &utxos).unwrap(); + +// 2. Edit the body +body.outputs.pop(); // Remove last output +body.reference_inputs.pop(); // Remove a reference input + +// 3. Rebuild with a new TxBuilder +let mut tx_builder = TxBuilder::new_core(); +tx_builder.tx_builder_body = body; + +// 4. Add new elements and rebalance +let new_tx_hex = tx_builder + .tx_out( + "addr_test1zp...", + &[Asset::new_from_str("lovelace", "5000000")], + ) + .invalid_before(100) + .invalid_hereafter(200) + .required_signer_hash("3f1b5974f4f09f0974be655e4ce94f8a2d087df378b79ef3916c26b2") + .complete_sync(None) + .unwrap() + .tx_hex(); +``` + +The resulting transaction is automatically rebalanced with proper fee calculation and a new change output. + +## TxParsable Trait + +The parser implements the `TxParsable` trait, which provides: + +```rust,ignore +pub trait TxParsable { + fn parse(&mut self, tx_hex: &str, resolved_utxos: &[UTxO]) -> Result<(), WError>; + fn get_required_inputs(&mut self, tx_hex: &str) -> Result, WError>; + fn get_builder_body(&self) -> TxBuilderBody; + fn get_builder_body_without_change(&self) -> TxBuilderBody; + fn to_tester(&self) -> TxTester; +} +``` + +| Method | Purpose | +|--------|---------| +| `parse` | Deserialize tx hex into internal state | +| `get_required_inputs` | Extract input references without full parsing | +| `get_builder_body` | Get the full `TxBuilderBody` from parsed state | +| `get_builder_body_without_change` | Get the body excluding the change output | +| `to_tester` | Convert to a `TxTester` for making assertions | + +## Checking Required Signers + +You can also inspect a transaction's required signers: + +```rust,ignore +use whisky_pallas::tx_parser::check_tx_required_signers; + +let signers = check_tx_required_signers(tx_hex); +``` + +## Transaction Evaluation + +For parsed transactions that include Plutus scripts, you can evaluate execution units: + +```rust,ignore +use uplc::tx::script_context::SlotConfig; +use whisky_common::{Network, UTxO}; +use whisky_pallas::utils::evaluate_tx_scripts; + +let result = evaluate_tx_scripts( + tx_hex, + &utxos, + &[], // additional chained transactions + &Network::Mainnet, + &SlotConfig::default(), +); +``` + +This returns execution units (memory and CPU steps) for each script in the transaction. diff --git a/docs/guide/src/introduction.md b/docs/guide/src/introduction.md new file mode 100644 index 0000000..cd3ff00 --- /dev/null +++ b/docs/guide/src/introduction.md @@ -0,0 +1,42 @@ +# Introduction + +Whisky is an open-source Cardano Rust SDK built by [SIDAN Lab](https://github.com/sidan-lab). It provides a comprehensive set of tools for building Cardano DApps in Rust, with a chainable builder API inspired by [MeshJS](https://meshjs.dev/). + +## Modules + +Whisky is organized as a Rust workspace with the following crates: + +| Crate | Description | +|-------|-------------| +| **whisky** | The main crate — re-exports everything you need for DApp development | +| **whisky-common** | Shared types, interfaces, and utilities used across all crates | +| **whisky-pallas** | Transaction serializer built on [TxPipe's Pallas](https://github.com/txpipe/pallas) (recommended) | +| **whisky-csl** | Legacy serializer built on `cardano-serialization-lib` | +| **whisky-provider** | Provider integrations for Blockfrost and Maestro | +| **whisky-wallet** | Wallet signing and key management utilities | +| **whisky-macros** | Procedural macros for Plutus data encoding | +| **whisky-js** | WASM bindings for JavaScript/TypeScript usage | + +## What You Can Do + +With whisky, you can: + +- **Build transactions** with a chainable, cardano-cli-like API supporting complex DApp backends +- **Parse and edit transactions** from raw CBOR hex +- **Sign transactions** with key-based signing in Rust +- **Interact with the blockchain** via Maestro and Blockfrost providers +- **Evaluate scripts off-chain** using TxPipe's `uplc` for execution unit estimation +- **Swap serializer backends** between Pallas and CSL via dependency injection + +## Guide Overview + +This guide walks you through: + +1. **[Installation](./getting-started/installation.md)** — Adding whisky to your project +2. **[Quick Start](./getting-started/quickstart.md)** — Building your first transaction +3. **[Transaction Builder](./guides/tx-builder.md)** — Simple sends, Plutus scripts, minting, staking +4. **[Transaction Parser](./guides/tx-parser.md)** — Parsing and editing existing transactions +5. **[Dependency Injection](./guides/dependency-injection.md)** — Pluggable serializers and providers +6. **[Migration: CSL to Pallas](./guides/migration-csl-to-pallas.md)** — Upgrading from the legacy backend + +For full API reference, see the [generated Rust docs](../api/whisky/index.html). diff --git a/docs/guide/src/reference/api-docs.md b/docs/guide/src/reference/api-docs.md new file mode 100644 index 0000000..3ed696a --- /dev/null +++ b/docs/guide/src/reference/api-docs.md @@ -0,0 +1,31 @@ +# API Documentation + +Full API reference documentation is auto-generated from Rust doc comments using `cargo doc`. + +## Browse the API Docs + +**[Open API Reference](../api/whisky/index.html)** + +## Key Entry Points + +| Crate | Description | Link | +|-------|-------------|------| +| **whisky** | Main crate — re-exports all public APIs | [docs](../api/whisky/index.html) | +| **whisky-common** | Shared types, traits, and utilities | [docs](../api/whisky_common/index.html) | +| **whisky-pallas** | Pallas-based serializer | [docs](../api/whisky_pallas/index.html) | +| **whisky-csl** | Legacy CSL-based serializer | [docs](../api/whisky_csl/index.html) | +| **whisky-provider** | Blockfrost and Maestro integrations | [docs](../api/whisky_provider/index.html) | +| **whisky-wallet** | Wallet signing and key management | [docs](../api/whisky_wallet/index.html) | +| **whisky-macros** | Procedural macros for Plutus data | [docs](../api/whisky_macros/index.html) | + +## Building Docs Locally + +```sh +# Generate API reference +npm run rust:doc + +# Serve locally +npx http-server ./docs +``` + +The docs are also published automatically to GitHub Pages on every push to the deployment branch. diff --git a/docs/guide/src/reference/examples-server.md b/docs/guide/src/reference/examples-server.md new file mode 100644 index 0000000..611b73b --- /dev/null +++ b/docs/guide/src/reference/examples-server.md @@ -0,0 +1,67 @@ +# Examples Server + +The `whisky-examples` crate provides runnable transaction examples and an HTTP server that exposes them as API endpoints. + +## Running the Server + +```sh +cargo run --package whisky-examples +``` + +The server starts on `http://127.0.0.1:8080` with CORS enabled. + +## Available Endpoints + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/send_lovelace` | POST | Send ADA to a recipient | +| `/lock_fund` | POST | Lock funds at a script address with datum | +| `/unlock_fund` | POST | Unlock funds from a Plutus script | +| `/mint_tokens` | POST | Mint tokens with a Plutus minting policy | + +## Example: Send Lovelace + +```sh +curl -X POST http://127.0.0.1:8080/send_lovelace \ + -H "Content-Type: application/json" \ + -d '{ + "recipientAddress": "addr_test1...", + "myAddress": "addr_test1...", + "inputs": [ + { + "input": { + "txHash": "abcdef...", + "outputIndex": 0 + }, + "output": { + "address": "addr_test1...", + "amount": [{"unit": "lovelace", "quantity": "10000000"}] + } + } + ] + }' +``` + +Response: + +```json +{ + "txHex": "84a400..." +} +``` + +## Example Functions + +The transaction functions are in `packages/whisky-examples/src/tx/`: + +| File | Function | Type | +|------|----------|------| +| `send_lovelace.rs` | `send_lovelace` | Sync | +| `lock_fund.rs` | `lock_fund` | Sync | +| `unlock_fund.rs` | `unlock_fund` | Async | +| `mint_tokens.rs` | `mint_tokens` | Async | +| `delegate_stake.rs` | `delegate_stake` | Sync | +| `complex_transaction.rs` | `complex_transaction` | Async | +| `collateral_return.rs` | `collateral_return` | Async | + +These examples serve as both documentation and testable reference implementations. See the [Transaction Builder](../guides/tx-builder.md) guide for detailed explanations of each pattern. diff --git a/package.json b/package.json index 050e8d9..b19de09 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,12 @@ "js:publish-browser": "npm run core:build-browser && npm run js:prepublish && node ./scripts/publish-helper -browser && cd publish && npm publish --access public", "js:publish-asm": "npm run core:build-asm && npm run js:prepublish && node ./scripts/publish-helper -asmjs && cd publish && npm publish --access public", "js:ts-json-gen": "cd packages/whisky-js/json-gen && cargo +stable run && cd ../../.. && node ./scripts/run-json2ts.js && node ./scripts/json-ts-types.js", - "rust:doc-clear": "rm -rf ./docs && mkdir docs && echo '' > docs/index.html", + "rust:doc-clear": "find ./docs -maxdepth 1 -not -name guide -not -name docs -not -name '.' -exec rm -rf {} + && echo '' > docs/index.html", "rust:doc": "npm run rust:doc-clear && RUSTDOCFLAGS=\"--cfg docsrs\" cargo doc --manifest-path packages/Cargo.toml --no-deps -p whisky -p whisky-pallas -p whisky-common -p whisky-macros -p whisky-provider -p whisky-wallet -p whisky-csl && cp -r ./packages/target/doc/* ./docs", - "start-doc": "npm run rust:doc && npx http-server ./docs", + "guide:build": "mdbook build docs/guide", + "guide:serve": "mdbook serve docs/guide --open", + "docs:build": "npm run rust:doc && npm run guide:build && mkdir -p _site && cp -r docs/guide/book/* _site/ && cp -r docs/ _site/api/ && rm -rf _site/api/guide", + "start-doc": "npm run docs:build && npx http-server ./_site", "sh:bump-version": "./scripts/bump-version.sh", "sh:run-example": "./scripts/run-example.sh" },