<h1 align="center">Soroban DevKit (<code>sdkt</code>)</h1>
<p align="center">
<a href="https://github.com/SaboLabs/soroban-devkit/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/SaboLabs/soroban-devkit/ci.yml?branch=main&label=CI" alt="CI"></a>
<a href="https://github.com/SaboLabs/soroban-devkit/actions/workflows/release.yml"><img src="https://img.shields.io/github/actions/workflow/status/SaboLabs/soroban-devkit/release.yml?branch=main&label=Release" alt="Release"></a>
<a href="https://img.shields.io/crates/v/sdkt-cli"><img src="https://img.shields.io/crates/v/sdkt-cli?label=crates.io" alt="crates.io"></a>
<a href="https://github.com/SaboLabs/soroban-devkit/releases"><img src="https://img.shields.io/github/v/release/SaboLabs/soroban-devkit?label=release" alt="release"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
</p>
<p align="center">
Release-assurance and operational verification toolkit for <strong>Stellar/Soroban</strong> smart contracts.<br>
Inspect, verify, audit, compare upgrades, and validate deployed contracts — with an aggregated release decision.
</p>
<p align="center">
<strong>Website:</strong> <a href="https://sabolabs.github.io/soroban-devkit/">sabolabs.github.io/soroban-devkit</a> — landing +
<a href="https://sabolabs.github.io/soroban-devkit/playground/">in-browser WASM inspector</a>
(contract bytes stay in the tab). Source: <a href="website/"><code>website/</code></a>.
</p>
---
`sdkt` is a release-assurance and operational verification toolkit for Soroban smart contracts. It consolidates the checks that answer "is this build safe to release?" — artifact inspection, static security audit, upgrade-safety diff, deployed-contract verification, and contract health — into a single CLI with an aggregated release decision, and covers the surrounding day-to-day work (XDR decoding, storage/TTL analysis, events, network profiles, build and deployment orchestration) so developers stop juggling 5+ separate tools.
## The Problem
Before shipping a contract upgrade, a developer has to answer several unrelated questions with unrelated tools: does the new WASM break the ABI callers depend on? Does the deployed contract actually match my build? Is the storage TTL about to expire? Did the source pass a security review? `sdkt` answers all of them from one CLI and aggregates the results into a single machine-readable release decision (`sdkt release-assurance`). It also spans the rest of the lifecycle — scaffold, build, deploy, invoke — with upgrade-safety guards applied on the write path.
## Capabilities
`sdkt` spans the full read-only **and** mutating contract lifecycle:
- **Release assurance** — one command aggregates artifact checks, static audit, upgrade-safety diff, deployed verification, and contract health into a single `PASS`/`REVIEW`/`FAIL` release decision (`sdkt release-assurance`); the same engine is available as a GitHub Action for CI and release gating.
- **Inspect & decode** — base64 XDR decoding, contract ABI + storage inspection, event exploration.
- **Analyze** — storage TTL / rent visibility, Instance / Persistent / Temporary classification, offline ABI/function/event/type WASM diffing.
- **Secure** — static analysis of contract source (`AUTH-001/002/003/004`, `MOVE-001`) and an upgrade-safety verdict for safe contract upgrades.
- **Verify deployed reality** — on-chain WASM hash vs local artifact (`sdkt verify`), unified contract posture (`sdkt health`).
- **Build & ship** — typed transaction envelope builder, simulate, **native transaction signing**, submit, identity/keystore management, multi-contract workspace topological deployments, and upgrade breaking-change guards.
Most commands are **offline**; only on-chain reads (`inspect`, `storage`, `tx`, `events`, `account`, `fee`, `wasm metadata`) need an RPC endpoint.
## Release assurance
`sdkt release-assurance` is the one command that answers the release question. It
is **read-only** — it never signs, submits, deploys, extends TTL, or mutates any
state — and it aggregates five checks on one candidate artifact into a single
release status.
Where it fits:
```
source → artifact → security → upgrade → deployed reality → health → release decision
```
| Section | What it checks | Source |
|---------|----------------|--------|
| Artifact | the candidate WASM's hash, size and spec; optional size policy | local file |
| Security | static audit of contract source (same engine as `sdkt audit`) | `--audit <path>` |
| Upgrade Safety | breaking-change verdict against the previous artifact | `--previous-wasm` |
| Verification | on-chain WASM hash vs the local artifact | `--contract` + RPC |
| Contract Health | storage/TTL posture and verdict | `--contract` + RPC |
Each section reports `PASS` / `REVIEW` / `FAIL` / `SKIPPED`, then aggregates
deterministically: any `FAIL`/`ERROR` makes `release_status` `FAIL` (exit 1),
otherwise a `REVIEW`/`SKIPPED` yields `REVIEW` (exit 0). On-chain sections are
**skipped** when `--contract` is omitted, and a skip is never flattened into
`PASS`. That aggregate status is what a CI step gates on.
```bash
# Candidate vs previous artifact: offline artifact + upgrade-safety checks:
sdkt release-assurance \
--wasm target/wasm32v1-none/release/my_contract.wasm \
--previous-wasm deployed/my_contract.wasm
# Machine-readable output, plus the on-chain sections once you pass --contract:
sdkt release-assurance \
--wasm target/wasm32v1-none/release/my_contract.wasm \
--previous-wasm deployed/my_contract.wasm \
--contract <CONTRACT_ID> \
--rpc-url https://soroban-testnet.stellar.org \
--format json
```
```text
Soroban Release Assurance
────────────────────────
Artifact PASS
Security SKIPPED
Upgrade Safety FAIL
Verification SKIPPED
Contract Health SKIPPED
RELEASE STATUS FAIL
Reasons:
- Upgrade Safety: FAIL
```
Add `--audit <path>` to include the source security section, `--contract <C…>`
(read-only) to include deployed verification and health, and `--max-size-bytes`
/ `--max-growth-pct` to enforce an operator-supplied size policy (a growth cap
requires `--previous-wasm`).
`sdkt` does not release, sign, or deploy anything on your behalf — the decision
is evidence for *your* release process. For CI, the same command is available as
a reusable GitHub Action: see [docs/ci-cd.md](docs/compatibility/ci-cd.md).
## Feature Highlights
| Capability | Command |
|------------|---------|
| **Aggregated release decision** (artifact + audit + upgrade + verification + health) | `sdkt release-assurance` |
| Decode base64 XDR (`ScVal`, `TransactionEnvelope`, `ContractEvent`) | `sdkt decode` |
| Inspect contract ABI + storage | `sdkt inspect`, `sdkt storage check` |
| Storage TTL / rent analysis | `sdkt storage analyze`, `sdkt storage estimate` |
| Transaction inspect / simulate / submit / build | `sdkt tx *` |
| Event explorer | `sdkt events` |
| Account balances + signers | `sdkt account` |
| Dynamic fee estimate | `sdkt fee estimate` |
| Multi-contract Orchestration | `sdkt build`, `sdkt project deploy` |
| WASM Operations | `sdkt wasm inspect`, `sdkt wasm metadata`, `sdkt wasm cache`, `sdkt verify`, `sdkt health` |
| Offline WASM diff + upgrade-safety verdict | `sdkt diff --upgrade-safety` |
| Static security audit | `sdkt audit` |
| ED25519 keystore | `sdkt identity` |
| Named network profiles | `sdkt network` |
| Project scaffolding | `sdkt init` |
| Deploy (with `--deny-breaking` guard) | `sdkt deploy` |
| Contract invocation (read-only) | `sdkt call` |
| Contract invocation (state-changing, end-to-end) | `sdkt invoke` |
## Quick Start
Running `sdkt` takes under five minutes. Pick an install method, verify, then
run your first command.
### 1. Install
Choose **one** of the following methods.
#### Recommended — install.sh (no Rust toolchain needed)
```bash
curl -fsSL https://raw.githubusercontent.com/SaboLabs/soroban-devkit/main/install.sh | bash
```
The script detects your OS/arch, downloads the matching release binary,
verifies its SHA-256 checksum, and installs `sdkt` to `~/.local/bin/sdkt`.
#### Alternative — Manual GitHub Release download
1. Open the [Releases](https://github.com/SaboLabs/soroban-devkit/releases)
page and download the latest release for your platform:
| Platform | Asset |
|----------|-------|
| Linux (x86_64) | `sdkt-x86_64-unknown-linux-gnu.tar.gz` |
| Linux (aarch64) | `sdkt-aarch64-unknown-linux-gnu.tar.gz` |
| macOS (Intel) | `sdkt-x86_64-apple-darwin.tar.gz` |
| macOS (Apple Silicon) | `sdkt-aarch64-apple-darwin.tar.gz` |
| Windows (x86_64) | `sdkt-x86_64-pc-windows-msvc.zip` |
2. Extract and run:
**Linux/macOS:**
```bash
tar -xzf sdkt-x86_64-unknown-linux-gnu.tar.gz # Linux x86_64
chmod +x sdkt
./sdkt --version
# Optional: make it available system-wide
sudo mv sdkt /usr/local/bin/
```
**Windows:** use `sdkt-x86_64-pc-windows-msvc.zip` from the
GitHub Release. Alternatively, install from crates.io or source:
```powershell
cargo install sdkt-cli
sdkt --version
```
> **Version note:** the GitHub Release carries the current repository
> release (v2.7.0). crates.io currently publishes **v2.5.0**, so
> `cargo install sdkt-cli` installs v2.5.0 — which lacks the WASM size
> policy, the `sdkt health` critical-exit fix, `sdkt-agent`, and the
> Windows zip. For v2.7.0 use the release binary, or build from source
> (below).
#### Alternative — Build from source (requires Rust 1.88.0+)
```bash
git clone https://github.com/SaboLabs/soroban-devkit
cd soroban-devkit
cargo install --path crates/sdkt-cli
sdkt --version
```
### 2. Verify and explore
```bash
sdkt --version
# sdkt <version>
sdkt --help
# Commands:
# decode Decode base64-encoded XDR to JSON
# wasm Manage WASM metadata and caching
# diff Offline diff of two contract WASM files
# audit Static security analysis of a Soroban contract source file
# init Initialize a new Soroban contract project
# deploy Deploy a contract (Upload WASM + Instantiate)
# ... (run `sdkt --help` to see all)
```
A successful `sdkt --version` means the binary is installed and on your `PATH`.
### Shell completions
Generate completion scripts for your shell and source them:
```bash
# bash
sdkt completions bash > ~/.local/share/bash-completion/completions/sdkt
# zsh
sdkt completions zsh > "${fpath[1]}/_sdkt"
# fish
sdkt completions fish > ~/.config/fish/completions/sdkt.fish
# powershell
sdkt completions powershell > sdkt.ps1
# then in your profile: . ./sdkt.ps1
```
Supported shells: `bash`, `zsh`, `fish`, `powershell` (also `elvish`).
### 3. Your first command (offline)
**No install:** drop a `.wasm` on the
[Web Playground](https://sabolabs.github.io/soroban-devkit/playground/)
(ContractSpec / exports / hash; bytes never leave the browser).
**CLI:** inspect a compiled contract WASM that ships with the repo:
```bash
sdkt wasm inspect crates/sdkt-cli/tests/fixtures/us_old.wasm
```
Then follow the guided walkthrough in
[docs/quick-start.md](docs/getting-started/quick-start.md) — it covers inspect, audit, and
upgrade-safety diff step by step.
## Use Cases
- **Decide whether a release is safe** — compare the candidate contract artifact
with its previous version, check upgrade compatibility and any release
constraints, and get evidence for the release decision in one aggregated report
(`sdkt release-assurance`). Read-only: it never signs or deploys.
- **Inspect Soroban WASM** — read ABI, functions, events, and metadata from any
compiled contract, offline (`sdkt wasm inspect`).
- **Verify deployed reality** — confirm a deployed contract matches your local
build, and check its health (`sdkt verify`, `sdkt health`).
- **Compare contract upgrades safely** — diff two WASM files and get a
breaking-change verdict before deploying (`sdkt diff --upgrade-safety`).
- **Audit contracts offline** — static security analysis of contract source with
no network or secrets (`sdkt audit`).
- **Scaffold new projects** — generate a ready-to-build Soroban contract
(`sdkt init`).
- **Deploy with upgrade protection** — upload and instantiate, aborting on a
non-backwards-compatible upgrade (`sdkt deploy --deny-breaking`).
### From scaffold to deployment
A typical first-contract workflow:
```bash
# 1. Create a new contract project
sdkt init my-contract --minimal
cd my-contract
# 2. Build the contract into a Soroban WASM
# Output: target/wasm32v1-none/release/<project>.wasm
sdkt build
# 3. Generate a local signing identity
sdkt identity generate my-deployer
# 4. Configure Testnet (one-time setup)
sdkt network add testnet \
--rpc-url https://soroban-testnet.stellar.org \
--passphrase "Test SDF Network ; September 2015" \
--friendbot https://friendbot.stellar.org
# 5. Fund your identity (Testnet only)
# Copy the public key from `sdkt identity show my-deployer` and paste it at:
# https://friendbot.stellar.org
# OR use the CLI directly:
sdkt identity fund my-deployer --network-profile testnet
# 6. Generate a 20-byte salt (40 hex characters)
openssl rand -hex 20
# 7. Deploy to Testnet
sdkt deploy \
--wasm target/wasm32v1-none/release/my_contract.wasm \
--salt <paste-hex-from-step-6> \
--identity my-deployer \
--network-profile testnet
# 8. Invoke a contract function (state-changing: sequence → simulate → sign → submit → poll)
sdkt invoke <CONTRACT_ID> increment --args u32:1 --identity my-deployer --network-profile testnet
```
For a detailed explanation of each step, see [Deploy a single contract](#deploy-a-single-contract).
## Installation (details)
Full options — including the `wasm-plugins` / `plugins` feature flags,
installing from crates.io, and updating — are in
[docs/installation.md](docs/getting-started/installation.md).
### Extensibility & Plugins
The `sdkt audit` static analysis engine supports third-party plugins.
- **`wasm-plugins` (Recommended):** Build with `cargo install --path crates/sdkt-cli --features wasm-plugins` to load platform-independent, sandboxed `.wasm` plugins.
- **`plugins`:** Build with `--features plugins` to load native shared libraries (`.so`, `.dylib`).
See [`docs/plugin-authoring.md`](docs/plugins/plugin-authoring.md) for how to build or use custom rules.
## Commands
| Command | Purpose |
|---------|---------|
| `sdkt release-assurance --wasm <file> [--previous-wasm <file>] [--audit <path>] [--contract <id>] [--format json]` | Aggregated read-only release decision: artifact + security + upgrade safety + deployed verification + health. Never signs or mutates. |
| `sdkt decode <xdr>` | Decode base64 XDR (`--type ScVal|TransactionEnvelope|ContractEvent`, `--file` for file input). |
| `sdkt inspect <contract-id>` | Inspect a contract's ABI and storage (`--abi <wasm>` for ABI-aware decode). |
| `sdkt storage check <contract-id>` | Storage TTL / rent visibility (`--abi <wasm>`). |
| `sdkt storage analyze <contract-id>` | Classify Instance / Persistent / Temporary storage entries + TTL summary. |
| `sdkt storage estimate <wasm-path>` | Estimate storage cost for a WASM. |
| `sdkt storage read <contract-id> --key-xdr <BASE64_XDR>` | Read a contract storage entry by its complete LedgerKey. ABI optional for ScVal formatting. |
| `sdkt storage extend <contract-id> --ledgers <N>` | Extend TTL of known footprint keys (`ExtendFootprintTtl`). Instance key is always included; extra keys via `--key`. Does not restore archived entries. |
| `sdkt storage restore --contract <id> --envelope <xdr>` | Restore archived entries (`RestoreFootprint`) using the `restorePreamble` from simulating the failed invocation. `--dry-run` shows the keys and fee without submitting. |
| `sdkt tx inspect <hash>` | Transaction status / ledger inclusion. |
| `sdkt tx validate --envelope <xdr>` | Offline pre-flight validation of an envelope (parses + structural checks). |
| `sdkt tx decode <xdr>` | Human-readable view of an envelope (source, fee, operations with decoded args, footprint, signatures) for review before signing. Offline; `--format json` for a structured breakdown. |
| `sdkt tx simulate <xdr>` | Offline pre-flight via `simulateTransaction` (RPC). `--abi <wasm>` decodes the invoke result via the contract spec. |
| `sdkt tx sign --input <xdr> --identity <name>` | Sign an envelope with a local ED25519 identity — fully offline. |
| `sdkt tx submit <xdr>` | Submit a transaction (with optional poll; RPC). |
| `sdkt tx build` | Typed envelope builder. |
| `sdkt events <contract-id>` | Emitted-contract event explorer (`--abi <wasm>`; `--topic <SYMBOL>` filters by event name server-side). |
| `sdkt account <address>` | Account balances (native + trustlines) and complete typed signers (Horizon-enriched with RPC fallback). |
| `sdkt call <contract> <function> [--args TYPE:VALUE...]` | Read-only contract invocation. No signing, no submission. Returns result + events. `--abi <wasm>` decodes the result via the contract spec; `--abi-contract <id>` fetches the deployed contract's on-chain WASM instead. |
| `sdkt diff` | Offline comparison of WASM binaries and API surfaces. |
| `sdkt diff --old-wasm <A> --new-wasm <B>` | Offline ABI/function/event/type diff of two WASM files. Add `--upgrade-safety` for a breaking-change verdict. |
| `sdkt build` | Compile workspace rust contracts into optimized WASMs. |
| `sdkt-agent "<request>"` | Read-only natural-language front end: plans a request against the capability registry, refuses anything mutating, runs the CLI and returns structured evidence. `--format json` for a machine-readable result. Not on crates.io — build from source. See [docs/agent.md](docs/reference/agent.md). |
| `sdkt deploy --wasm <file> [--salt <salt>] [--arg <type:value>...]` | Upload WASM + instantiate. Salt is auto-generated if omitted (see [Deploy a single contract](#deploy-a-single-contract) below). Pass constructor arguments via repeated `--arg type:value` flags (uses `CreateContractV2`). Add `--deny-breaking --old-wasm <deployed.wasm>` to abort on a non-backwards-compatible upgrade. |
| `sdkt project deploy` | Deploy multi-contract workspace orchestrating topological dependency sorting. |
| `sdkt verify --contract <ID> [--wasm <file>] [--network <net>]` | Verify a deployed contract matches a local WASM (offline hash vs on-chain hash). |
| `sdkt health --contract <ID> [--wasm <file>] [--network <net>]` | Unified read-only contract posture report (WASM, storage, TTL, health verdict). |
| `sdkt wasm inspect <file>` | Inspect offline WASM metadata, sections, and specifications. |
| `sdkt wasm metadata --contract <contract>` | WASM metadata for a deployed contract (cached). |
| `sdkt wasm cache` | Manage the WASM cache (`info` / `remove` / `clear`). |
|| `sdkt audit <path.rs>` | Static security analysis (AUTH-001/002/003/004, MOVE-001). `--disable <RULE_ID>` to skip a rule. `--rules <path|id>` (repeatable) to load external rule paths or resolve installed plugin IDs. |
| `sdkt identity <generate\|import\|list\|show\|delete\|default>` | ED25519 keystore management. |
| `sdkt identity fund <name> --network-profile <NAME>` | Fund an identity via Stellar Testnet Friendbot. |
| `sdkt network <add\|list\|show\|remove>` | Named network profiles (RPC URL + passphrase). Combine with `--network-profile <NAME>` on any RPC command to avoid repeating endpoints; `--rpc-url` / `--network-passphrase` override. |
| `sdkt network diagnose [--network <testnet>]` | Read-only network identity / protocol / resource-limit diagnosis. Reports passphrase identity, protocol agreement, and ledger limits. Never signs or mutates. |
| `sdkt deployment-verify --contract <ID>` | Read-only deployment verification: is the deployed contract the artifact I built? Compares local WASM SHA-256 against on-chain executable. |
|| `sdkt init <name>` | Scaffold a new Soroban project (`--minimal`, `--force`). |
| `sdkt lock generate` | Write `sdkt.lock` recording each built artifact's SHA-256 + deploy order (after `sdkt build`). |
| `sdkt lock verify` | Verify `sdkt.lock` against current on-disk artifacts **and** package dependencies (lock matches manifest, git commits, path existence). Advisory; never fails the build. Prints `✓ lock file verified` / `✓ package dependencies verified` or lists drift. |
| `sdkt lock show` | Print the current `sdkt.lock` contents. |
| `sdkt package validate` | Validate the local package manifest (`[package]` metadata + local/git `[dependencies]` graph). Offline; never touches the network or a registry. |
| `sdkt package fetch [--force]` | Fetch declared dependencies into `.sdkt-cache` (local path passthrough; git clone/checkout). Never builds. `--force` updates existing checkouts. |
| `sdkt package update [--check] [--dry-run] [--format pretty\|json]` | Synchronize dependencies: refresh git deps to the latest available commit, rewrite `sdkt.lock`. `rev` stays pinned; `tag`/`branch` update on drift. `--check` reports only; `--dry-run` previews without touching cache/lock. |
### Deploy a single contract
`sdkt deploy` uploads a Soroban WASM to the network and instantiates it as a
new contract instance. It is the single-contract counterpart to
`sdkt project deploy` (which orchestrates multi-contract workspaces).
#### Deploy a contract to Testnet (step by step)
A fresh deploy requires a built WASM, a funded signing identity, and a salt.
Follow these steps in order:
```bash
# 1. Build your contract into a Soroban WASM
# (from a project created with `sdkt init <name>`)
sdkt build
# 2. Generate a local ED25519 identity (used to sign the deploy transactions)
sdkt identity generate my-deployer
# 3. Configure the Testnet network profile
sdkt network add testnet \
--rpc-url https://soroban-testnet.stellar.org \
--passphrase "Test SDF Network ; September 2015" \
--friendbot https://friendbot.stellar.org
# 4. Fund your identity on Testnet
# Copy the public key from `sdkt identity show my-deployer` and paste it at:
# https://friendbot.stellar.org
# (Friendbot is a Testnet faucet — it does NOT work on Mainnet.)
# 5. Deploy (salt is auto-generated if omitted)
sdkt deploy \
--wasm target/wasm32v1-none/release/<project>.wasm \
--identity my-deployer \
--network-profile testnet
# Or with explicit salt for deterministic address:
# openssl rand -hex 20
# sdkt deploy --wasm ... --salt <40-hex-chars> --identity my-deployer --network-profile testnet
```
Replace `<project>` with your crate name (the `name` field in `Cargo.toml`).
The `--wasm` path follows the Cargo convention
`target/<profile>/<crate>.wasm` — adjust if your build profile or target
directory differs.
#### Options
- `--wasm` (required): Path to a compiled Soroban WASM (32kb+ after `stellar contract build`).
- `--salt` (optional): 40-character hex string (20 bytes). Auto-generated if omitted. It salts the contract
ID derivation so the same deployer + WASM + salt always yields the same contract
address across networks. Provide explicitly for deterministic/reproducible deployment.
- `--identity <name>`: ED25519 identity from `sdkt identity` used to sign both
transactions (upload + instantiate). Defaults to `default`.
- `--arg <type:value>`: Constructor argument in `type:value` format (e.g. `--arg u32:42`,
`--arg string:hello`, `--arg bool:true`, `--arg bytes:0a0b`, `--arg address:G...`,
`--arg symbol:init`). Pre-encoded base64 ScVal strings are also accepted as-is.
Can be repeated for multiple constructor arguments. Contracts deployed with arguments use
`CreateContractV2`.
- `--format <pretty|json>`: Output format (default `pretty`).
- `--deny-breaking`: Abort if the new WASM is not backwards-compatible with the
currently deployed contract. Requires `--old-wasm`.
- `--old-wasm <file>`: Path to the existing on-chain baseline WASM. Used only
with `--deny-breaking`.
#### Flow
1. Resolve the network (flag → profile → `.sdkt.toml` → built-in Testnet default).
2. Apply the mainnet-safety guard (mainnet requires explicit network selection).
3. Optionally run the `--deny-breaking` upgrade-safety check.
4. Load the signing identity and its key.
5. **Upload** — build an `UploadContractWasm` transaction, simulate, apply the
returned `SorobanTransactionData` and authorization entries, sign, submit,
and poll for confirmation.
6. **Instantiate** — build a `CreateContract` (or `CreateContractV2` when constructor
arguments are provided via `--arg`) transaction with the WASM hash from
the upload, the user-supplied salt, and any constructor arguments, simulate,
finalize, sign, submit, and poll for confirmation.
7. Derive the contract ID from `Hash(networkId || HashIdPreimage::ContractId{...})`
and report the deployment result.
#### Safety
- Mainnet deployments are refused unless the operator explicitly selects the
network (via `--rpc-url` + `--network-passphrase`, or `--network-profile` whose
passphrase is mainnet). Implicit Testnet defaults cannot touch mainnet.
- The salt must be exactly 40 hex characters; any other length or non-hex input
is rejected before any network call.
#### Output
```
Deployment Result:
WASM Hash: e71250b5...
Contract ID: 0bde4658...
Upload TX: c8599bb1...
Create TX: 1e934b4e...
Status: SUCCESS
```
### Multi-contract dependency graphs
A `.sdkt.toml` workspace declares contracts under `[contracts.<alias>]`. Each
contract may declare dependencies using either the canonical `depends_on`
or the legacy `deploy_after` field — both are merged during
resolution:
```toml
[contracts.token]
path = "contracts/token"
[contracts.router]
path = "contracts/router"
depends_on = ["token"]
```
`sdkt build`, `sdkt project deploy`, and `sdkt lock generate` all resolve the
same dependency graph via a single topological sort (Kahn's algorithm), so the
deploy order is deterministic and identical across commands. Invalid graphs are
rejected up front with a clear error:
- **Unknown dependency** — a `depends_on`/`deploy_after` entry that is not a
defined `[contracts.*]`.
- **Self-dependency** — a contract that lists itself as a dependency.
- **Duplicate dependency** — the same dependency declared more than once
(e.g. in both `depends_on` and `deploy_after`).
- **Circular dependency** — a cycle such as `a → b → a`.
- **Duplicate contract name** — two `[contracts.<alias>]` tables (TOML parse
error, surfaced instead of silently defaulting to an empty config).
### Local package manifests
`sdkt package validate` lays the groundwork for a future package registry
**without** introducing any network or remote-registry functionality. It checks
a local package manifest declared in `.sdkt.toml`:
```toml
[package]
name = "my-token"
version = "0.1.0"
description = "Example Soroban token"
[dependencies.math]
path = "../math"
[dependencies.auth]
path = "./auth"
```
Validation rules (all offline — never performs network or registry I/O):
- `[package]` must have a `name` and a `version`.
- `version` must be a valid `MAJOR.MINOR.PATCH` shape (with optional
pre-release/build metadata), matching the common semver form.
- Each `[dependencies.<name>]` entry is **exactly one source**: a local `path`
**or** a `git` URL (never both). `deny_unknown_fields` rejects unrecognized
keys so future source kinds (e.g. a registry) are explicit additions.
- For `git` deps, exactly one of `tag` / `branch` / `rev` must be set, and the
URL must use `https`/`http`/`git`/`ssh` (or the `git@host:org/repo` SCP form).
- No self-dependency (a dependency key equal to the package `name`).
- For `path` deps, the referenced directory must exist.
- The dependency graph is checked for cycles (reusing the same topological-sort
core as contract deploy-order resolution).
`sdkt package validate` exits non-zero on the first failure and prints a clear
message; with `--format json` it emits `{"valid": true}` or
`{"valid": false, "error": "..."}`.
### Fetching dependencies
`sdkt package fetch` materializes declared dependencies into a deterministic
local cache at `.sdkt-cache` (no registry, no authentication helpers, never
builds automatically):
```toml
[dependencies]
math = { path = "../math" }
token = { git = "https://github.com/org/token", tag = "v1.2.0" }
access = { git = "https://github.com/org/access", rev = "<commit>" }
utils = { git = "https://github.com/org/utils", branch = "main" }
```
- `path` deps are passed through (validated already by `validate`).
- `git` deps are cloned/checked out via the system `git` CLI into
`.sdkt-cache/git/<stable-key>/`, then pinned to the requested `tag` /
`branch` / `rev`. Re-running reuses an existing checkout unless `--force` is
passed. A future registry source plugs into the same `DependencyFetcher`
abstraction without touching callers.
The lock file (`sdkt.lock`) records each dependency's source, git URL,
requested reference, and resolved commit SHA (when available), so fetches are
reproducible. Local path deps remain unchanged in the lock.
### Network profiles
Save an RPC endpoint once and reference it from any RPC command instead of
repeating full URLs:
```bash
# Save a profile
sdkt network add testnet \
--rpc-url https://soroban-testnet.stellar.org \
--passphrase "Test SDF Network ; September 2015"
# Use it (any RPC command)
sdkt inspect <CONTRACT_ID> --network-profile testnet
sdkt account <ADDRESS> --network-profile testnet
```
Every RPC command (`inspect`, `verify`, `health`, `storage`, `events`, `account`,
`tx`, `fee`, `wasm`, `deploy`, `project deploy`) also accepts explicit
`--rpc-url <URL>` and `--network-passphrase <PASSPHRASE>` override flags.
**Precedence (highest wins):** explicit `--rpc-url` / `--network-passphrase` >
`--network-profile` > `.sdkt.toml` `[network]` > built-in testnet default.
Commands without these flags behave exactly as before. (`tx sign` is offline and
excluded.) See [docs/cli.md](docs/reference/cli.md) and [docs/examples.md](docs/getting-started/examples.md).
Most commands accept `--format json` for scripting / CI integration.
## Common Workflows
- **Audit every PR** — gate merges on `sdkt audit` via the
[reusable Action](docs/compatibility/ci-cd.md), whose `severity-threshold`
input fails the build on `critical` findings. The CLI itself reports findings
but does **not** encode severity into its exit code — `sdkt audit` exits 0
even when it prints critical findings, so gate on the Action (or parse
`--format json`'s `summary.critical`) rather than on the bare exit code. See
[docs/ci-cd.md](docs/compatibility/ci-cd.md).
- **Safe upgrades** — run `sdkt diff --upgrade-safety` in release CI to block
breaking contract changes.
- **Local analysis** — `decode`, `diff`, and `audit` need no RPC; run them in
CI or locally without secrets.
### End-to-end transaction signing (build → sign → submit)
`sdkt` can build, validate, simulate, **sign**, and submit a Soroban
transaction entirely from the CLI. Signing is **fully offline** — it uses a
local ED25519 identity from the keystore (`sdkt identity`); no RPC, no secret
ever leaves your machine.
```bash
# 1. Create a local signing identity (offline)
sdkt identity generate alice
# 2. Build an unsigned envelope (offline)
sdkt tx build \
--source <SOURCE_ACCOUNT> \
--sequence <SEQ> \
--contract <CONTRACT_ID> \
--function hello \
--output unsigned.xdr
# 3. Validate the envelope offline and review what it does
sdkt tx validate --envelope unsigned.xdr
sdkt tx decode unsigned.xdr
# 4. Simulate against the network (RPC) to catch failures early
sdkt tx simulate --envelope unsigned.xdr
# 5. Sign with the local identity (offline) — picks testnet by default
sdkt tx sign --input unsigned.xdr --output signed.xdr --identity alice --network testnet
# 6. Submit the signed envelope (RPC)
sdkt tx submit --envelope signed.xdr
```
Notes:
- `tx sign` takes `--network testnet|mainnet|futurenet|custom:<passphrase>`; the
network only affects the signature hash, so signing needs no RPC.
- `tx submit` / `tx simulate` read the network from `.sdkt.toml`
(`[network]` section) or fall back to the default testnet RPC.
- `--output` is optional; without it, the signed base64 envelope is printed to
stdout. Use `--format json` for scripting.
Copy-paste recipes for every subcommand are in
[docs/examples.md](docs/getting-started/examples.md).
## Upgrade Safety in CI
`sdkt` ships a reusable GitHub composite Action. See
[docs/ci-cd.md](docs/compatibility/ci-cd.md) for copy-paste workflows (audit-on-PR,
upgrade-safety-on-release).
## Documentation
- [docs/quick-start.md](docs/getting-started/quick-start.md) — five-minute first-time walkthrough (offline).
- [docs/agent.md](docs/reference/agent.md) — `sdkt-agent`: natural-language front end, capability surface, safety and refusal behaviour.
- [docs/testnet-walkthrough.md](docs/getting-started/testnet-walkthrough.md) — end-to-end Testnet loop: identity → fund → deploy → invoke → events / storage.
- [docs/getting-started.md](docs/getting-started/getting-started.md) — deeper offline `diff` and `audit` examples.
- [docs/examples.md](docs/getting-started/examples.md) — command recipes & CI gating.
- [docs/installation.md](docs/getting-started/installation.md) — build / install / features.
- [docs/compatibility.md](docs/compatibility/compatibility.md) — real-world contract compatibility matrix.
- [docs/ci-cd.md](docs/compatibility/ci-cd.md) — CI/CD with the reusable Action.
- [docs/adoption.md](docs/advanced/adoption.md) — ecosystem adoption and integration evidence.
- [SECURITY.md](SECURITY.md) — supported versions and vulnerability reporting.
- [CONTRIBUTING.md](CONTRIBUTING.md) — how to contribute.
Additional references: [docs/cli.md](docs/reference/cli.md) (full command reference),
[docs/faq.md](docs/getting-started/faq.md) (FAQ),
[docs/plugin-authoring.md](docs/plugins/plugin-authoring.md) (write your own audit
rules), and [ROADMAP.md](ROADMAP.md) · [CHANGELOG.md](CHANGELOG.md).
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). All contributions are welcome — docs,
tests, and small fixes are great first PRs. Please follow the
[Code of Conduct](CODE_OF_CONDUCT.md).
## License
[MIT](LICENSE).