From 532d5aeed5a48e2fa96f01214db1d787019fab22 Mon Sep 17 00:00:00 2001 From: Aristides Staffieri Date: Wed, 8 Jul 2026 09:46:07 -0600 Subject: [PATCH 1/5] Add wallet skills package (stellar-wallet-skills) Add a `wallet` skill that documents using the Stellar CLI as a wallet by composing existing commands, closing the protocol/usability gap called for in the Agentic Wallet CLI epic (stellar/stellar-cli#2628, #2624). The skill is a SKILL.md entry plus three task-focused companions: - SKILL.md: composition map (wallet operation -> command), prerequisites (install, RPC/relayer config), and the structured output/error contract - keys.md: key lifecycle, private-key security, funding, selection - accounts-and-tx.md: balances/readiness, trustlines, tx diagnosis, sign + submit, and account draining - tokens.md: the stellar token client (SEP-41/SAC), trusted token lists, error remediation, and asset anatomy Wire it into the site: new "Wallets" filter category and a SKILL_CARD_SOURCES entry so it renders on skills.stellar.org and in llms.txt. Commands verified against stellar-cli 25.1.0 on testnet. Surface still gated on in-flight work is documented as forthcoming: the `stellar token` client (#2620), structured JSON output and the {status,result,error} receipt (#2622), and relayer submission (#2623). --- site/src/data/skills.ts | 9 +++ skills/wallet/SKILL.md | 124 +++++++++++++++++++++++++++++++ skills/wallet/accounts-and-tx.md | 103 +++++++++++++++++++++++++ skills/wallet/keys.md | 85 +++++++++++++++++++++ skills/wallet/tokens.md | 102 +++++++++++++++++++++++++ 5 files changed, 423 insertions(+) create mode 100644 skills/wallet/SKILL.md create mode 100644 skills/wallet/accounts-and-tx.md create mode 100644 skills/wallet/keys.md create mode 100644 skills/wallet/tokens.md diff --git a/site/src/data/skills.ts b/site/src/data/skills.ts index e45da66..d000487 100644 --- a/site/src/data/skills.ts +++ b/site/src/data/skills.ts @@ -22,6 +22,7 @@ type FilterType = | "Assets" | "APIs" | "ZK" + | "Wallets" | "Ecosystem"; /** @@ -36,6 +37,7 @@ export const FILTERS: readonly FilterType[] = [ "Assets", "APIs", "ZK", + "Wallets", "Ecosystem", ] as const; @@ -113,6 +115,13 @@ export const SKILL_CARD_SOURCES: readonly SkillCardSource[] = [ description: "Charge AI agents for API calls with x402 paywalls or MPP payment channels.", }, + { + source: "skills/wallet/SKILL.md", + category: "Wallets", + title: "CLI Wallet", + description: + "Use the Stellar CLI as a wallet: manage keys, fund accounts, check balances, transfer tokens, handle trustlines, and diagnose transactions.", + }, { source: "skills/zk-proofs/SKILL.md", category: "ZK", diff --git a/skills/wallet/SKILL.md b/skills/wallet/SKILL.md new file mode 100644 index 0000000..ba9605f --- /dev/null +++ b/skills/wallet/SKILL.md @@ -0,0 +1,124 @@ +--- +name: wallet +description: Use the Stellar CLI (`stellar`) as a wallet. Covers install and RPC/relayer configuration, key lifecycle and private-key security, funding, balances and account readiness, trustlines, value transfer, the `stellar token` client (SEP-41 / SAC), and transaction diagnosis, composed from existing commands with structured JSON output. Use when holding funds, moving value, managing tokens, checking balances, or transacting on Stellar from the command line. +user-invocable: true +argument-hint: "[wallet task]" +--- + +# Wallet: the Stellar CLI as a wallet + +There is no `stellar wallet` command. The "wallet" is a set of composed CLI commands: `keys` for custody and selection, `ledger` for reads, `tx` for building and submitting, `token` for SEP-41 / SAC value transfer, and `contract` for contract interactions. This skill maps each wallet operation to the command that performs it, when to reach for it, and how to read the errors it returns. + +Two habits apply everywhere: + +1. **Pass `--output json`** on any command that supports it. You get a machine-readable object instead of formatted text, so the next step can parse it instead of scraping. +2. **Discover before you guess.** `stellar --help` prints the exact args for any command. Do not hardcode contract IDs, fees, or sequence numbers — the pipeline resolves them. + +## Read the file that matches the task + +| Task | File | +|------|------| +| Create / import / export / list / select keys, private-key security, fund an account | [keys.md](keys.md) | +| Check balances and account readiness, trustlines, diagnose a transaction, sign + submit a prepared XDR, drain an account | [accounts-and-tx.md](accounts-and-tx.md) | +| Transfer / approve / burn tokens, read token metadata, SAC admin ops, pull a token list, asset anatomy | [tokens.md](tokens.md) | + +## Composition map + +| Wallet operation | Composed from | Covered in | +|------------------|---------------|------------| +| create a key | `keys generate` | [keys.md](keys.md) | +| import a key | `keys add` | [keys.md](keys.md) | +| export a secret | `keys secret` | [keys.md](keys.md) | +| fund an account | `keys fund` | [keys.md](keys.md) | +| list keys | `keys ls` | [keys.md](keys.md) | +| select the default key | `keys use` | [keys.md](keys.md) | +| check XLM balance and reserves | `ledger entry fetch account` | [accounts-and-tx.md](accounts-and-tx.md) | +| check a trustline | `ledger entry fetch trustline` | [accounts-and-tx.md](accounts-and-tx.md) | +| check a token balance | `token balance` | [tokens.md](tokens.md) | +| add or change a trustline | `tx new change-trust` | [accounts-and-tx.md](accounts-and-tx.md) | +| transfer value | `token transfer` | [tokens.md](tokens.md) | +| diagnose a transaction | `tx fetch --hash` | [accounts-and-tx.md](accounts-and-tx.md) | +| sign and submit a prepared XDR | `tx sign` + `tx send` | [accounts-and-tx.md](accounts-and-tx.md) | +| drain an account (sweep + close) | `token transfer` + `tx new account-merge` | [accounts-and-tx.md](accounts-and-tx.md) | + +## Prerequisites + +### Install the CLI + +Install `stellar` (the Stellar CLI, package `stellar-cli`). Pick one: + +```bash +brew install stellar-cli # macOS / Linux (Homebrew) +cargo install --locked stellar-cli # any platform with a Rust toolchain +winget install --id Stellar.StellarCLI # Windows +npm install --global @stellar/cli # via npm +``` + +Verify: `stellar --version`. Full matrix and latest instructions: . + +### Configure the network (RPC) + +The CLI uses a [Stellar RPC](https://developers.stellar.org/docs/build/guides/rpc) in order to read ledger entries, simulate transactions, and submit them. The default is the public testnet RPC at `https://soroban-testnet.stellar.org`. You can also configure a named network for mainnet or a private network. + +You can find a list of provicers at . + +```bash +# Save a named network once, then reference it with --network / -n +stellar network add testnet \ + --rpc-url https://soroban-testnet.stellar.org \ + --network-passphrase "Test SDF Network ; September 2015" +stellar network use testnet # set the default so you can omit --network + +stellar network ls # list configured networks +stellar network health # confirm the RPC is reachable +``` + +You can also pass `--rpc-url` / `STELLAR_RPC_URL` and `--network-passphrase` / `STELLAR_NETWORK_PASSPHRASE` per command instead of saving a network. + +### Configure a relayer (optional) + +A relayer wraps your transaction in a fee-bump and signs + submits it, so the wallet key needs no XLM for fees. Configuration is `--relayer-url` / `STELLAR_RELAYER_URL` (plus `--relayer-header` for auth). Without a relayer, transactions are self-funded from the source account. + +Learn more about the Relayer service at . + +## Structured output and errors + +The CLI is designed for progressive disclosure and programmatic recovery: + +- **Structured output.** `--output json` returns predictable keys. A state-changing command returns a *receipt* — result, tx hash, fee, decoded events. A read returns the decoded value. + + ```jsonc + // stellar token balance --id native --of alice --output json + { "status": "ok", "result": "9999999500", "error": null } + ``` + +- **Structured errors.** On failure the object carries a code you can branch on and a remediation path: + + ```jsonc + { + "status": "error", + "result": null, + "error": { + "code": "tx_simulation_failed", + "domain": "tx", + "message": "host invocation failed: Error(Contract, #2)", + "details": { "error_name": "InsufficientBalance", "contract_id": "C…" } + } + } + ``` + + Read `error.code` / `error.details.error_name`, not the human message. The named-error → next-command table lives in [tokens.md](tokens.md#error-remediation). + +## Related skills + +- Classic assets, trustlines, authorization flags, and the SAC bridge → [`../assets/SKILL.md`](../assets/SKILL.md) +- The SEP-41 token contracts and SACs these commands call → [`../smart-contracts/SKILL.md`](../smart-contracts/SKILL.md) +- Querying chain data over RPC / Horizon → [`../data/SKILL.md`](../data/SKILL.md) +- SEP-41 and other standards → [`../standards/SKILL.md`](../standards/SKILL.md) +- Paying x402 / MPP services → [`../agentic-payments/SKILL.md`](../agentic-payments/SKILL.md) +- DeFi playbooks → [`../defi/SKILL.md`](../defi/SKILL.md) +## Documentation + +- [Stellar CLI manual](https://developers.stellar.org/docs/tools/cli/stellar-cli) +- [Anatomy of an asset](https://developers.stellar.org/docs/tokens/anatomy-of-an-asset) +- [Agentic Wallet CLI epic](https://github.com/stellar/stellar-cli/issues/2628) diff --git a/skills/wallet/accounts-and-tx.md b/skills/wallet/accounts-and-tx.md new file mode 100644 index 0000000..3efef59 --- /dev/null +++ b/skills/wallet/accounts-and-tx.md @@ -0,0 +1,103 @@ +# Accounts & transactions: read, provision, submit, diagnose + +Back to the [wallet overview](SKILL.md). + +## Balances and readiness + +Before a state-changing command, confirm the account exists and holds what the operation needs. + +```bash +# Account entry: XLM balance, subentry count, sequence number, reserves +stellar ledger entry fetch account --account alice --output json + +# A specific trustline: does alice hold this asset, and up to what limit / authorization? +stellar ledger entry fetch trustline --account alice --asset USDC:GA5Z…ISSUER --output json + +# A SEP-41 / SAC token balance (decimal-aware), including the native SAC +stellar token balance --id native --of alice --output json # (via #2620) +``` + +Readiness checklist to run first: + +1. **Account funded?** `ledger entry fetch account` succeeds and XLM balance covers the base reserve plus one reserve per subentry (trustlines, offers, signers). If the fetch reports the account as missing, it is unfunded — see [keys.md](keys.md#fund-an-account). +2. **Trustline present + authorized?** For any issued (non-native) asset, `ledger entry fetch trustline` must return an authorized line before a transfer can settle. If not, provision it (below). +3. **Enough balance?** Compare the decimal balance against the amount you intend to move. + +## Trustlines + +An issued asset can only be held by an account with an authorized trustline to it. Provision one before receiving or transferring that asset. + +```bash +# Create / update a trustline from alice to USDC (limit defaults to max) +stellar tx new change-trust \ + --source alice \ + --line USDC:GA5Z…ISSUER \ + --network testnet + +# Remove a trustline by setting the limit to 0 (balance must be 0 first) +stellar tx new change-trust --source alice --line USDC:GA5Z…ISSUER --limit 0 +``` + +`tx new` commands build, sign (with `--source`), submit, and poll to inclusion in one call. Add `--build-only` to emit unsigned XDR instead (see [sign + submit](#sign-submit)). + +Missing or unauthorized trustlines are the most common transfer failure. `token transfer` surfaces a named error pointing back here — see [tokens.md](tokens.md#error-remediation). + +## Move value + +`token transfer` is the primary path for all value transfer — native XLM, a classic asset, or a custom SEP-41 token — because every classic asset is reachable through its SAC ([tokens.md](tokens.md)). + +`tx new payment` remains available as a pure classic payment operation. Reach for it when you want a classic-only payment that does not depend on the asset's SAC being deployed: + +```bash +stellar tx new payment \ + --source alice \ + --destination GBOB…DEST \ + --asset USDC:GA5Z…ISSUER \ + --amount 100 \ + --network testnet --output json +``` + +## Diagnose a transaction + +Given a tx hash, `tx fetch` explains what happened. Sub-commands narrow the projection. + +```bash +stellar tx fetch --hash --output json # full envelope + result +stellar tx fetch result --hash --output json # just the result code +stellar tx fetch meta --hash --output json # ledger meta / state changes +stellar tx fetch fee --hash --output json # charged fee / fee-bump info +stellar tx fetch events --hash --output json # decoded contract events +``` + +`--output` here also accepts `json-formatted` (multiline) and `xdr` (raw RPC). To turn a failed step into a diagnosis: fetch the hash, read the result code, and act on it. + +## Sign and submit a prepared XDR + + +When you have an unsigned transaction envelope (from `--build-only`, an offline flow, or another tool), sign it then send it. Both read the XDR from an argument, a file, or stdin. + +```bash +# Build without signing +stellar tx new payment --source alice --destination GBOB… --asset native --amount 10 \ + --build-only > tx.xdr + +# Sign with a key, then submit; piping chains the two +stellar tx sign --sign-with-key alice tx.xdr | stellar tx send --network testnet --output json +``` + +## Drain an account (sweep + close) + +To empty and close an account, move every asset out, then merge the XLM balance and delete the account. Order matters — `account-merge` fails while the account still holds non-XLM balances or subentries. + +1. **Sweep each non-native asset** with `token transfer` ([tokens.md](tokens.md)) until every issued balance is 0. +2. **Remove trustlines** you no longer need (`tx new change-trust --limit 0`) so no subentries block the merge. +3. **Merge XLM and close:** + + ```bash + stellar tx new account-merge \ + --source alice \ + --account GDEST…KEEP \ + --network testnet --output json + ``` + +`account-merge` transfers the remaining XLM (minus fee) to `--account` and removes the source account. Double-check the destination — this is irreversible. diff --git a/skills/wallet/keys.md b/skills/wallet/keys.md new file mode 100644 index 0000000..70a5a04 --- /dev/null +++ b/skills/wallet/keys.md @@ -0,0 +1,85 @@ +# Keys: custody, funding, and selection + +An identity in the CLI is a named key. Custody lives here — every signing operation resolves a `--source` / `--sign-with-key` to one of these identities. Manage them with `stellar keys`. + +Back to the [wallet overview](SKILL.md). + +## Lifecycle at a glance + +| Operation | Command | +|-----------|---------| +| create a new key | `stellar keys generate ` | +| import an existing key (secret or seed phrase) | `stellar keys add ` | +| reveal a secret (dangerous, see below) | `stellar keys secret ` | +| get the public address | `stellar keys public-key ` (alias `address`) | +| list keys | `stellar keys ls` | +| select the default key | `stellar keys use ` | +| remove a key | `stellar keys rm ` | + +## Create a key + +```bash +# Generate a new 24-word-seed identity named "alice" +stellar keys generate alice + +# Generate and fund it in one step on a test network (Friendbot) +stellar keys generate alice --network testnet --fund + +# Store the key in the OS secure store (Keychain / Windows Credential store / Secret Service) +# instead of a plaintext config file +stellar keys generate alice --secure-store +``` + +`--fund` only works on test networks. On pubnet, fund the address externally (see below). + +## Import a key + +```bash +# Prompts for a secret (S…) key or a 12–24 word seed phrase, saved to the secure store +stellar keys add alice --secure-store +``` + +`stellar keys add` reads the secret from an interactive prompt, never from a command-line argument — a secret on the command line lands in shell history and the process table. + +## List and select + +```bash +stellar keys ls # list identity names (add --long for addresses) +stellar keys use alice # set alice as the default source for all commands +``` + +Once `keys use` is set, you can omit `--source alice` on subsequent commands. When juggling multiple wallets, pass `--source ` explicitly per command rather than relying on the mutable default. + +## Get an address + +```bash +stellar keys public-key alice +``` + +Use this to resolve a name to a `G…` address for `--to`, `--of`, or a trustline account, without ever touching the secret. + +## Fund an account + +**Test networks (testnet / futurenet):** Friendbot creates and funds the account with XLM. + +```bash +stellar keys fund alice --network testnet +``` + +**Pubnet:** there is no faucet. Fund the address (`stellar keys public-key alice`) from an exchange, an existing account via `tx new payment`, or `tx new create-account`. An account does not exist on-chain until it holds the minimum XLM reserve — reads and transfers against an unfunded account fail until then (see [accounts-and-tx.md](accounts-and-tx.md#readiness)). + +## Private-key security: dos and don'ts + +Custody is inherited from `stellar keys`; there is no separate wallet key store. Treat these keys as live funds. + +**Do:** +- Prefer `--secure-store` so the secret lives in the OS credential store, not a plaintext file under `~/.config/stellar/identity/`. +- Reference keys by **name** (`--source alice`), never by pasting the `S…` secret into a command. +- Use a dedicated, low-value key for automation; keep high-value keys out of any automated flow's reach. +- Verify the active network (`stellar network ls`) before any state-changing command — a pubnet mistake spends real value. + +**Don't:** +- Don't run `stellar keys secret ` anywhere the output is captured (a shared transcript, a CI log) — it prints the raw secret to stdout. Reserve it for interactive export, and treat any log that captured it as compromised. +- Don't pass secrets as command-line arguments (they persist in shell history and `ps` output). The CLI takes them via prompt or key name for this reason. +- Don't commit `~/.config/stellar/` or any exported secret / seed phrase to version control. +- Don't reuse the same key across testnet experiments and pubnet funds. diff --git a/skills/wallet/tokens.md b/skills/wallet/tokens.md new file mode 100644 index 0000000..d409f73 --- /dev/null +++ b/skills/wallet/tokens.md @@ -0,0 +1,102 @@ +# Tokens: the `stellar token` client + +`stellar token` is a typed client for any SEP-41 token or Stellar Asset Contract (SAC). Each subcommand is a thin wrapper over `contract invoke` with token-aware argument parsing, asset/contract resolution, and decimal-aware amounts. Every state-changing subcommand inherits the full pipeline — simulate, sign auth entries, sign the transaction, fee-bump if needed, submit, poll — and returns a decoded JSON receipt. No sequence number or fee is requested from you. + +Back to the [wallet overview](SKILL.md). + +## Target resolution + +A subcommand targets a contract with `--id`: + +- `--id native` — the XLM SAC (special-cased). +- `--id C…` — any SEP-41 / SAC contract address directly. +- `--id ` — a saved contract alias. +- `--id CODE:ISSUER` — a classic asset; resolves to its deterministic SAC id. + +Get a classic asset's SAC id (or deploy the SAC) without transferring: + +```bash +stellar contract id asset --asset USDC:GA5Z…ISSUER --network testnet # compute the SAC id +stellar contract asset deploy --asset USDC:GA5Z…ISSUER --source alice --network testnet +``` + +## Subcommand reference + +| Group | Subcommand | Key args | Purpose | +|-------|-----------|----------|---------| +| Transfer | `transfer` | `--id --to ` | Move tokens. The primary value-transfer command. | +| Transfer | `transfer-from` | `--id --from --to ` | Spend an allowance on behalf of another holder. | +| Read | `balance` | `--id --of ` | Decimal-aware balance. | +| Read | `allowance` | `--id --from --spender ` | Read an allowance. | +| Read | `name` / `symbol` / `decimals` | `--id ` | Token metadata. | +| Allowance | `approve` | `--id --spender --expires ` | Set an allowance. | +| Supply | `burn` | `--id ` | Burn from the caller's balance. | +| Supply | `burn-from` | `--id --from ` | Burn from an allowance. | +| SAC admin | `mint` | `--id --to ` | Mint (admin only). | +| SAC admin | `set-admin` | `--id --new-admin ` | Transfer admin. | +| SAC admin | `clawback` | `--id --from ` | Claw back (admin only). | +| SAC admin | `set-authorized` | `--id --addr --authorized ` | Set trustline authorization. | + +## Transfer example + +```bash +# Transfer 100 XLM through the native SAC — resolves, simulates, signs, submits, polls +stellar token transfer \ + --id native \ + --to GBOB…DEST \ + --source alice \ + --network testnet \ + --output json \ + 100 +``` + +The receipt carries `status`, the decoded `result`, the tx hash, the charged fee, and decoded events. For an issued asset, pass `--id USDC:GA5Z…ISSUER` (or its SAC `C…` id); the destination must hold an authorized trustline. + +Amounts are **decimal-aware**: pass human units (`100`), not stroops or base units. `token decimals --id ` tells you the scale. + +## Reads + +```bash +stellar token balance --id USDC:GA5Z…ISSUER --of alice --output json +stellar token decimals --id USDC:GA5Z…ISSUER --output json +stellar token symbol --id USDC:GA5Z…ISSUER --output json +``` + +Reads never sign or submit; they simulate and return the decoded value. + +## Error remediation + + +State-changing token calls return a structured error with a `code` you branch on. The recurring ones and their next command: + +| Error | Meaning | Next step | +|-------|---------|-----------| +| SAC not deployed | The classic asset's SAC does not exist on-chain yet | `stellar contract asset deploy --asset CODE:ISSUER --source ` | +| missing / unauthorized trustline | Destination (or source) has no authorized trustline for the asset | `stellar tx new change-trust --source --line CODE:ISSUER` — see [accounts-and-tx.md](accounts-and-tx.md#trustlines) | +| insufficient balance | Source balance below the amount | Check `token balance`; reduce the amount or fund the account | +| insufficient allowance | `transfer-from` / `burn-from` exceeds the approved amount | Have the owner call `token approve` with a higher amount and a future `--expires` ledger | +| not authorized (admin) | Caller is not the SAC admin | Use the admin key, or `set-admin` first | + +Read `error.code` / `error.details.error_name` from the JSON, not the human message. The full error-object shape is in the [wallet overview](SKILL.md#structured-output-and-errors). + +## Pull a trusted token list + +Don't hardcode contract IDs. Resolve assets from a published, trusted list so you target the right issuer. Stellar's convention is [SEP-1 `stellar.toml`](https://developers.stellar.org/docs/tokens/publishing-asset-information) `[[CURRENCIES]]`, and asset directories publish JSON. + +```bash +# Fetch a home domain's stellar.toml and list its declared assets (code:issuer) +curl -s https:///.well-known/stellar.toml \ + | grep -E '^(code|issuer)\s*=' + +# Example: a JSON asset list (e.g. an ecosystem token list), extract code + issuer +curl -s https:///list.json \ + | jq -r '.assets[] | "\(.code):\(.issuer)"' +``` + +Then resolve each `CODE:ISSUER` to a SAC id with `stellar contract id asset --asset CODE:ISSUER` before transferring. Prefer issuers whose `stellar.toml` is served from the same home domain declared on the issuing account (the SEP-1 linkage is what makes the asset "trusted"). + +You can learn more about Stellar Asset Lists here: , scroll to the bottom to find a few of the most commonly used asset lists. + +## Asset anatomy + +A Stellar asset is `CODE:ISSUER` (a `G…` issuing account plus a 1–12 char code); `native` is XLM. The SAC wraps that classic asset behind the SEP-41 contract interface so contracts — and `stellar token` — can move it. USDC therefore has two addresses: the classic issuer (`G…`, used for trustlines) and the SAC (`C…`, the contract `transfer` targets). Deep dive: [Anatomy of an asset](https://developers.stellar.org/docs/tokens/anatomy-of-an-asset), and the classic-asset + SAC bridge in [`../assets/SKILL.md`](../assets/SKILL.md). From ad44cca73c1a2c1cf559cbd37df86ff9aec0b0d9 Mon Sep 17 00:00:00 2001 From: Aristides Staffieri Date: Wed, 8 Jul 2026 10:17:13 -0600 Subject: [PATCH 2/5] Document Stellar account & transaction model in wallet skill Add an inline "Stellar account & transaction model" section to accounts-and-tx.md covering the mechanics the command pipeline handles by default, so readers can diagnose and recover when a default isn't enough. Closes a gap against design-doc goal #1 ("sane defaults for fees, sequences, retry, error handling") and its Idempotency row: - minimum balance & reserves (why you can't spend to zero) - sequence numbers & idempotency (txBAD_SEQ; check inclusion before retry) - fees, surge pricing & fee-bumps (max-bid model, CAP-15, relayer link) - transaction lifecycle: time bounds, poll-to-inclusion, safe retries Wire cross-links: readiness checklist and drain ordering -> reserves; tokens.md insufficient-balance row -> reserves; fee-bump -> relayer section; lifecycle -> tx diagnosis. Also fix a deprecated command surfaced during testnet verification: `stellar contract asset id` -> `stellar contract id asset`. --- skills/wallet/accounts-and-tx.md | 35 ++++++++++++++++++++++++++++++-- skills/wallet/tokens.md | 2 +- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/skills/wallet/accounts-and-tx.md b/skills/wallet/accounts-and-tx.md index 3efef59..e37cc59 100644 --- a/skills/wallet/accounts-and-tx.md +++ b/skills/wallet/accounts-and-tx.md @@ -2,6 +2,36 @@ Back to the [wallet overview](SKILL.md). +## Stellar account & transaction model + +The command pipeline applies sane defaults for the mechanics below — it picks the sequence number, sets a fee, fee-bumps on surge, submits, and polls to inclusion. You do not set these by hand. This section explains what they are so you can diagnose and recover when a default is not enough and a command surfaces one of the named errors. + +### Minimum balance & reserves + + +An account must always hold a minimum XLM balance and **cannot spend below it**. The minimum is `(2 + number_of_subentries) × base_reserve`, where each trustline, offer, signer, and data entry is one subentry. Base reserve is currently **0.5 XLM** (a ledger parameter, so 1 XLM base minimum for a bare account, +0.5 per subentry). + +Consequences you will hit: +- A transfer or fee that would drop XLM below the reserve fails even though the raw balance "looks" sufficient. Fund more, or move less. +- Draining requires ordering (see [drain](#drain)): each trustline is a subentry, so you remove trustlines before `account-merge`. + +### Sequence numbers & idempotency + +Every account has one **strictly-increasing sequence number**. Each transaction is valid only at `current_seq + 1` and consumes it on inclusion. This is the double-spend guard: a transaction that already landed **cannot be resubmitted** — a resubmit fails with `txBAD_SEQ`. + +Operational rule: **on a timeout, do not blindly rebuild and resend.** First run `tx fetch --hash ` ([diagnose](#diagnose-a-transaction)) to check whether the original landed. Resending the *same signed envelope* is safe (same sequence, so it either lands once or is already included); building a *new* transaction after the first may have landed is the double-spend risk. + +### Fees, surge pricing & fee-bumps + +The base fee is **100 stroops per operation** (1 stroop = 0.0000001 XLM). The fee you set is a **maximum bid**, not a fixed price — you are charged the market rate up to your bid. When the network is congested (surge pricing), a transaction that bid too low fails with `txINSUFFICIENT_FEE` (or is dropped as `tx_too_late` once its time bound passes). + +- Raise the bid with `--inclusion-fee ` on `tx new …`. +- A **fee-bump** (CAP-15) wraps an already-signed inner transaction in an outer envelope with a *new fee source*, so a different account pays the fee. The pipeline applies one automatically on surge, and it is the exact mechanism a [relayer](SKILL.md#configure-a-relayer-optional) uses to sponsor fees so the wallet key needs no XLM. + +### Transaction lifecycle: timeouts & safe retries + +A transaction carries **time bounds** (`setTimeout`); past the upper bound it can no longer be included and returns `tx_too_late`. The CLI submits and then **polls to inclusion**, so a successful command already confirms the transaction landed. Transient RPC responses like `TRY_AGAIN_LATER` mean not-yet-included, not failed — retry the same envelope. Combine with the sequence rule above: safe retry = resend the same signed transaction; never rebuild-and-resend without checking inclusion first. + ## Balances and readiness Before a state-changing command, confirm the account exists and holds what the operation needs. @@ -19,7 +49,7 @@ stellar token balance --id native --of alice --output json # (via #2620 Readiness checklist to run first: -1. **Account funded?** `ledger entry fetch account` succeeds and XLM balance covers the base reserve plus one reserve per subentry (trustlines, offers, signers). If the fetch reports the account as missing, it is unfunded — see [keys.md](keys.md#fund-an-account). +1. **Account funded?** `ledger entry fetch account` succeeds and XLM balance covers the [minimum balance and reserves](#reserves). If the fetch reports the account as missing, it is unfunded — see [keys.md](keys.md#fund-an-account). 2. **Trustline present + authorized?** For any issued (non-native) asset, `ledger entry fetch trustline` must return an authorized line before a transfer can settle. If not, provision it (below). 3. **Enough balance?** Compare the decimal balance against the amount you intend to move. @@ -86,8 +116,9 @@ stellar tx sign --sign-with-key alice tx.xdr | stellar tx send --network testnet ``` ## Drain an account (sweep + close) + -To empty and close an account, move every asset out, then merge the XLM balance and delete the account. Order matters — `account-merge` fails while the account still holds non-XLM balances or subentries. +To empty and close an account, move every asset out, then merge the XLM balance and delete the account. Order matters — `account-merge` fails while the account still holds non-XLM balances or [subentries](#reserves). 1. **Sweep each non-native asset** with `token transfer` ([tokens.md](tokens.md)) until every issued balance is 0. 2. **Remove trustlines** you no longer need (`tx new change-trust --limit 0`) so no subentries block the merge. diff --git a/skills/wallet/tokens.md b/skills/wallet/tokens.md index d409f73..86d421e 100644 --- a/skills/wallet/tokens.md +++ b/skills/wallet/tokens.md @@ -73,7 +73,7 @@ State-changing token calls return a structured error with a `code` you branch on |-------|---------|-----------| | SAC not deployed | The classic asset's SAC does not exist on-chain yet | `stellar contract asset deploy --asset CODE:ISSUER --source ` | | missing / unauthorized trustline | Destination (or source) has no authorized trustline for the asset | `stellar tx new change-trust --source --line CODE:ISSUER` — see [accounts-and-tx.md](accounts-and-tx.md#trustlines) | -| insufficient balance | Source balance below the amount | Check `token balance`; reduce the amount or fund the account | +| insufficient balance | Source balance below the amount (remember XLM must stay above the [reserve](accounts-and-tx.md#reserves)) | Check `token balance`; reduce the amount or fund the account | | insufficient allowance | `transfer-from` / `burn-from` exceeds the approved amount | Have the owner call `token approve` with a higher amount and a future `--expires` ledger | | not authorized (admin) | Caller is not the SAC admin | Use the admin key, or `set-admin` first | From d975c382875ef9f4a2064934773d798b29725cf2 Mon Sep 17 00:00:00 2001 From: Aristides Staffieri Date: Wed, 8 Jul 2026 10:55:44 -0600 Subject: [PATCH 3/5] Route to DeFi skills for Soroban protocol interactions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a "Working with Soroban protocols (DeFi)" section to the wallet SKILL.md that draws the boundary — this skill covers wallet primitives (value transfer, trustlines, tx mechanics), not protocol-specific logic — and points readers to the DeFi skills when they need to understand how a Soroban protocol works or craft the transaction(s) to act on it (swap, lend/borrow, vault deposit/withdraw, provide liquidity). Link the section from Related skills and point at the forthcoming ../defi/ playbooks. Supports design-doc goal #2 (skills to discover and interact with on-chain protocols). --- skills/wallet/SKILL.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/skills/wallet/SKILL.md b/skills/wallet/SKILL.md index ba9605f..1223db2 100644 --- a/skills/wallet/SKILL.md +++ b/skills/wallet/SKILL.md @@ -109,6 +109,17 @@ The CLI is designed for progressive disclosure and programmatic recovery: Read `error.code` / `error.details.error_name`, not the human message. The named-error → next-command table lives in [tokens.md](tokens.md#error-remediation). +## Working with Soroban protocols (DeFi) + +This skill covers wallet primitives — moving value, trustlines, and transaction mechanics. It does **not** teach how any specific Soroban protocol works. Reference the DeFi skills when you need to: + +1. **Understand how a protocol works** — its architecture, contracts, and on-chain addresses. +2. **Craft the transaction (or sequence of transactions)** to perform a protocol action — swap or quote, lend / borrow / repay, deposit / withdraw from a vault, provide liquidity. + +The DeFi playbooks map each protocol's operations to concrete `contract invoke` / `stellar token` calls and carry the current contract references, so you act on the protocol instead of reverse-engineering it from raw ledger data. + +Find them under [`../defi/SKILL.md`](../defi/SKILL.md) + ## Related skills - Classic assets, trustlines, authorization flags, and the SAC bridge → [`../assets/SKILL.md`](../assets/SKILL.md) @@ -116,7 +127,8 @@ The CLI is designed for progressive disclosure and programmatic recovery: - Querying chain data over RPC / Horizon → [`../data/SKILL.md`](../data/SKILL.md) - SEP-41 and other standards → [`../standards/SKILL.md`](../standards/SKILL.md) - Paying x402 / MPP services → [`../agentic-payments/SKILL.md`](../agentic-payments/SKILL.md) -- DeFi playbooks → [`../defi/SKILL.md`](../defi/SKILL.md) +- Acting on Soroban protocols (swap, lend, vaults) → [Working with Soroban protocols](#working-with-soroban-protocols-defi) + ## Documentation - [Stellar CLI manual](https://developers.stellar.org/docs/tools/cli/stellar-cli) From b6ecf5ea9cfc27e34ad65f93348949bbcbd4c46c Mon Sep 17 00:00:00 2001 From: Aristides Staffieri Date: Wed, 8 Jul 2026 11:57:33 -0600 Subject: [PATCH 4/5] Address Copilot review comments - site/src/app/styles.scss: add "Wallets" to the filter whitelist so the category actually shows its cards when selected (the @each list mirrors FILTERS minus "All" and was missing the new entry) - skills/wallet/SKILL.md: fix typo "provicers" -> "providers" - skills/wallet/accounts-and-tx.md: move the "readiness" anchor onto its own line to match the other anchors Co-Authored-By: Claude Opus 4.8 (1M context) --- site/src/app/styles.scss | 2 +- skills/wallet/SKILL.md | 2 +- skills/wallet/accounts-and-tx.md | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/site/src/app/styles.scss b/site/src/app/styles.scss index 58d6aa4..0fc30cf 100644 --- a/site/src/app/styles.scss +++ b/site/src/app/styles.scss @@ -314,7 +314,7 @@ } @each $filter - in ("Smart Contracts", "Agentic Payments", Frontend, Assets, APIs, ZK, Ecosystem) + in ("Smart Contracts", "Agentic Payments", Frontend, Assets, APIs, ZK, Wallets, Ecosystem) { .SkillsLanding__filterPanel[data-active-filter="#{$filter}"] .SkillsLanding__filterItem[data-category="#{$filter}"] { diff --git a/skills/wallet/SKILL.md b/skills/wallet/SKILL.md index 1223db2..1003d12 100644 --- a/skills/wallet/SKILL.md +++ b/skills/wallet/SKILL.md @@ -60,7 +60,7 @@ Verify: `stellar --version`. Full matrix and latest instructions: . +You can find a list of providers at . ```bash # Save a named network once, then reference it with --network / -n diff --git a/skills/wallet/accounts-and-tx.md b/skills/wallet/accounts-and-tx.md index e37cc59..fc2d13b 100644 --- a/skills/wallet/accounts-and-tx.md +++ b/skills/wallet/accounts-and-tx.md @@ -34,7 +34,9 @@ A transaction carries **time bounds** (`setTimeout`); past the upper bound it ca ## Balances and readiness -Before a state-changing command, confirm the account exists and holds what the operation needs. + + +Before a state-changing command, confirm the account exists and holds what the operation needs. ```bash # Account entry: XLM balance, subentry count, sequence number, reserves From 2f3dd634849225a81dbbd720b356bc6e5dec9e59 Mon Sep 17 00:00:00 2001 From: Aristides Staffieri Date: Thu, 9 Jul 2026 09:36:59 -0600 Subject: [PATCH 5/5] Fix wallet skill docs against real CLI behavior Fresh agents given only the wallet SKILL.md, real tasks, and --help completed every flow but had to escape into --help to do it, and hit a silent 10^7 amount-units error. Reconcile the docs with observed CLI 26.0.0 behavior (verified on-chain on testnet), and settle two framing decisions: amounts are raw base units everywhere, and state-changing commands are documented against the target CLI that returns --output json receipts. accounts-and-tx.md: - Label every --amount / --starting-balance as stroops with realistic values; call out the silent 10^7 trap. - Add a create-account example; note payment to a non-existent account fails with NoDestination. - Add a Named errors section (TxFailed(VecM([OpInner(...)])) dumps) for NoDestination, NoTrust, Underfunded, InvalidLimit, HasSubEntries, and note failed txs still charge the fee. - Fix readiness: fetch returns raw stroops; a missing account succeeds with entries:[], not an error. - Distinguish classic assets (always 7-decimal) from SEP-41 tokens (variable decimals, look up via decimals()). keys.md: - Document the stdin pipe for keys add --secure-store (no TTY). - Note keys rm needs --force non-interactively. - Correct secure-store: seed-phrase only, never exportable (one-way door). - Fix keys ls --long (config-file paths, not addresses) and the pubnet funding note (payment can't fund a new address; use create-account). SKILL.md: - Correct the network section: testnet/pubnet/etc. are built-in; reserve network add for custom/private RPCs. tokens.md: - Reframe amounts as raw base units (10^decimals, not always 7; read decimals() first), consistent with the rest of the CLI. - Add an interim contract-invoke path until `stellar token` ships. - Fix the 404 publishing-asset-info link; note the burn-to-issuer i64::MAX sentinel; point to ../assets for acquiring an issued asset. --- skills/wallet/SKILL.md | 25 ++++++++------- skills/wallet/accounts-and-tx.md | 53 +++++++++++++++++++++++++++----- skills/wallet/keys.md | 21 +++++++++---- skills/wallet/tokens.md | 21 ++++++++++--- 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/skills/wallet/SKILL.md b/skills/wallet/SKILL.md index 1003d12..8e6d8e3 100644 --- a/skills/wallet/SKILL.md +++ b/skills/wallet/SKILL.md @@ -58,22 +58,26 @@ Verify: `stellar --version`. Full matrix and latest instructions: . +```bash +stellar network ls # list networks (built-ins are already present) +stellar network use testnet # set the default so you can omit --network / -n +stellar network health # confirm the RPC is reachable + +# …or select a network per command instead of setting a default +stellar --network testnet # (or -n testnet) +``` + +`stellar network add` is only for a **custom or private** RPC (or to override a built-in's endpoint): ```bash -# Save a named network once, then reference it with --network / -n -stellar network add testnet \ - --rpc-url https://soroban-testnet.stellar.org \ +stellar network add my-rpc \ + --rpc-url https://my-private-rpc.example.com \ --network-passphrase "Test SDF Network ; September 2015" -stellar network use testnet # set the default so you can omit --network - -stellar network ls # list configured networks -stellar network health # confirm the RPC is reachable ``` -You can also pass `--rpc-url` / `STELLAR_RPC_URL` and `--network-passphrase` / `STELLAR_NETWORK_PASSPHRASE` per command instead of saving a network. +You can also pass `--rpc-url` / `STELLAR_RPC_URL` and `--network-passphrase` / `STELLAR_NETWORK_PASSPHRASE` per command instead of saving a network. A provider list is at . ### Configure a relayer (optional) @@ -133,4 +137,3 @@ Find them under [`../defi/SKILL.md`](../defi/SKILL.md) - [Stellar CLI manual](https://developers.stellar.org/docs/tools/cli/stellar-cli) - [Anatomy of an asset](https://developers.stellar.org/docs/tokens/anatomy-of-an-asset) -- [Agentic Wallet CLI epic](https://github.com/stellar/stellar-cli/issues/2628) diff --git a/skills/wallet/accounts-and-tx.md b/skills/wallet/accounts-and-tx.md index fc2d13b..f8d0af3 100644 --- a/skills/wallet/accounts-and-tx.md +++ b/skills/wallet/accounts-and-tx.md @@ -45,15 +45,15 @@ stellar ledger entry fetch account --account alice --output json # A specific trustline: does alice hold this asset, and up to what limit / authorization? stellar ledger entry fetch trustline --account alice --asset USDC:GA5Z…ISSUER --output json -# A SEP-41 / SAC token balance (decimal-aware), including the native SAC -stellar token balance --id native --of alice --output json # (via #2620) +# A SEP-41 / SAC token balance (raw base units), including the native SAC +stellar token balance --id native --of alice --output json ``` Readiness checklist to run first: -1. **Account funded?** `ledger entry fetch account` succeeds and XLM balance covers the [minimum balance and reserves](#reserves). If the fetch reports the account as missing, it is unfunded — see [keys.md](keys.md#fund-an-account). +1. **Account funded?** `ledger entry fetch account` returns an `entries` array. An **unfunded / non-existent account is not an error** — the call succeeds with `"entries":[]`, so test for the empty array, not a failure. When the account is present, confirm its XLM balance covers the [minimum balance and reserves](#reserves). To fund, see [keys.md](keys.md#fund-an-account). 2. **Trustline present + authorized?** For any issued (non-native) asset, `ledger entry fetch trustline` must return an authorized line before a transfer can settle. If not, provision it (below). -3. **Enough balance?** Compare the decimal balance against the amount you intend to move. +3. **Enough balance?** Balances come back as **raw stroops** (e.g. `"balance":"110043500001"`), not decimal XLM — divide by `10_000_000` to compare against a human amount, and remember the amount you pass to move it is also in stroops. ## Trustlines @@ -78,17 +78,54 @@ Missing or unauthorized trustlines are the most common transfer failure. `token `token transfer` is the primary path for all value transfer — native XLM, a classic asset, or a custom SEP-41 token — because every classic asset is reachable through its SAC ([tokens.md](tokens.md)). -`tx new payment` remains available as a pure classic payment operation. Reach for it when you want a classic-only payment that does not depend on the asset's SAC being deployed: +`tx new payment` remains available as a pure classic payment operation. Reach for it when you want a classic-only payment that does not depend on the asset's SAC being deployed. **`--amount` is in stroops** (1 XLM = `10_000_000` stroops), *not* human units — passing `100` sends 100 stroops (0.00001 XLM), and it succeeds silently, so this is an easy 10⁷ mistake. All classic assets (native XLM and any `CODE:ISSUER`) are 7-decimal, so this stroop scale always applies here; SEP-41 tokens moved via `stellar token` can declare a different `decimals` — look it up ([tokens.md](tokens.md#amounts)): ```bash stellar tx new payment \ --source alice \ --destination GBOB…DEST \ --asset USDC:GA5Z…ISSUER \ - --amount 100 \ + --amount 100000000 \ # 10 units, in stroops (1 unit = 10_000_000) --network testnet --output json ``` +`tx new payment` fails with `NoDestination` if the destination account does not exist on-chain yet (see [named errors](#errors)). To send value to a brand-new address, first create and fund it with `create-account` — `--starting-balance` is also in **stroops** (default `10_000_000` = 1 XLM): + +```bash +stellar tx new create-account \ + --source alice \ + --destination GNEW…ADDR \ + --starting-balance 10000000 \ # 1 XLM, in stroops + --network testnet --output json +``` + +With `--output json` these return a decoded *receipt* — result, tx hash, charged fee, and decoded events (see [structured output and errors](SKILL.md#structured-output-and-errors)). To diagnose a transaction you already submitted, look its hash up with [`tx fetch`](#diagnose-a-transaction). + +## Named errors + + +A failed on-chain transaction is not printed as a tidy message — it is a Rust debug dump. The name that tells you what went wrong is the innermost one: + +```text +❌ error: transaction submission failed: Some(TransactionResult { + fee_charged: 100, // the fee is charged even though the tx failed + result: TxFailed(VecM([OpInner(Payment(NoDestination))])), + ext: V0, +}) +``` + +Read the `()` at the center. The ones you will actually hit: + +| Error name | Seen on | Meaning | Fix | +|------------|---------|---------|-----| +| `NoDestination` | `payment` | Destination account does not exist on-chain | Create it first with `create-account` ([move value](#move-value)) | +| `NoTrust` | `payment` | Destination has no authorized trustline for the (non-native) asset | Add the trustline ([trustlines](#trustlines)) before paying | +| `Underfunded` | `payment` | Source cannot cover the amount **and** stay above its [reserve](#reserves) | Reduce the amount, or fund the source | +| `InvalidLimit` | `change-trust` | New limit is below the current balance — including `--limit 0` while the balance is non-zero | Move the balance out to 0 first, *then* set `--limit 0` | +| `HasSubEntries` | `account-merge` | Account still holds subentries (trustlines, offers, …) | Remove every subentry first ([drain](#drain)) | + +Failed transactions **still charge the fee** (`fee_charged` above), so a loop that retries a doomed transaction burns XLM each attempt. + ## Diagnose a transaction Given a tx hash, `tx fetch` explains what happened. Sub-commands narrow the projection. @@ -109,8 +146,8 @@ stellar tx fetch events --hash --output json # decoded contract eve When you have an unsigned transaction envelope (from `--build-only`, an offline flow, or another tool), sign it then send it. Both read the XDR from an argument, a file, or stdin. ```bash -# Build without signing -stellar tx new payment --source alice --destination GBOB… --asset native --amount 10 \ +# Build without signing (--amount in stroops: this is 10 XLM) +stellar tx new payment --source alice --destination GBOB… --asset native --amount 100000000 \ --build-only > tx.xdr # Sign with a key, then submit; piping chains the two diff --git a/skills/wallet/keys.md b/skills/wallet/keys.md index 70a5a04..27c1487 100644 --- a/skills/wallet/keys.md +++ b/skills/wallet/keys.md @@ -14,7 +14,9 @@ Back to the [wallet overview](SKILL.md). | get the public address | `stellar keys public-key ` (alias `address`) | | list keys | `stellar keys ls` | | select the default key | `stellar keys use ` | -| remove a key | `stellar keys rm ` | +| remove a key | `stellar keys rm ` (add `--force` to skip the confirmation prompt) | + +Removing a key asks for confirmation. With no TTY (piped or scripted), a bare `stellar keys rm ` fails with `removal cancelled by user` — pass `--force` to remove it non-interactively. ## Create a key @@ -34,17 +36,24 @@ stellar keys generate alice --secure-store ## Import a key +`--secure-store` accepts a **12–24 word seed phrase only** (not an `S…` secret key) and saves it to the OS credential store. + ```bash -# Prompts for a secret (S…) key or a 12–24 word seed phrase, saved to the secure store +# Interactive: prompts for the seed phrase stellar keys add alice --secure-store + +# Non-interactive (automation / no TTY): pipe the seed phrase on stdin +echo "$SEED_PHRASE" | stellar keys add alice --secure-store ``` -`stellar keys add` reads the secret from an interactive prompt, never from a command-line argument — a secret on the command line lands in shell history and the process table. +`stellar keys add` never takes the secret as a command-line argument — a secret on the command line lands in shell history and the process table. It reads from the interactive prompt or from stdin. + +> **One-way door.** A secure-store key can never be exported — `stellar keys secret ` on it fails with `Secure Store does not reveal secret key`. Back up the original seed phrase elsewhere *before* you rely on `--secure-store`; the CLI will not hand it back. ## List and select ```bash -stellar keys ls # list identity names (add --long for addresses) +stellar keys ls # list identity names (--long adds each key's config-file path, not its address) stellar keys use alice # set alice as the default source for all commands ``` @@ -66,7 +75,7 @@ Use this to resolve a name to a `G…` address for `--to`, `--of`, or a trustlin stellar keys fund alice --network testnet ``` -**Pubnet:** there is no faucet. Fund the address (`stellar keys public-key alice`) from an exchange, an existing account via `tx new payment`, or `tx new create-account`. An account does not exist on-chain until it holds the minimum XLM reserve — reads and transfers against an unfunded account fail until then (see [accounts-and-tx.md](accounts-and-tx.md#readiness)). +**Pubnet:** there is no faucet. Fund the address (`stellar keys public-key alice`) from an exchange, or from an existing account with `tx new create-account`. A plain `tx new payment` **cannot** fund a brand-new address — it fails with `NoDestination` against an account that does not exist on-chain yet. Until an account holds the minimum XLM reserve it does not exist on-chain: `ledger entry fetch account` returns `"entries":[]` and transfers against it fail (see [accounts-and-tx.md](accounts-and-tx.md#readiness)). ## Private-key security: dos and don'ts @@ -79,7 +88,7 @@ Custody is inherited from `stellar keys`; there is no separate wallet key store. - Verify the active network (`stellar network ls`) before any state-changing command — a pubnet mistake spends real value. **Don't:** -- Don't run `stellar keys secret ` anywhere the output is captured (a shared transcript, a CI log) — it prints the raw secret to stdout. Reserve it for interactive export, and treat any log that captured it as compromised. +- Don't run `stellar keys secret ` anywhere the output is captured (a shared transcript, a CI log) — for a file-based key it prints the raw secret to stdout (secure-store keys refuse to export). Reserve it for interactive export, and treat any log that captured it as compromised. - Don't pass secrets as command-line arguments (they persist in shell history and `ps` output). The CLI takes them via prompt or key name for this reason. - Don't commit `~/.config/stellar/` or any exported secret / seed phrase to version control. - Don't reuse the same key across testnet experiments and pubnet funds. diff --git a/skills/wallet/tokens.md b/skills/wallet/tokens.md index 86d421e..1adeee5 100644 --- a/skills/wallet/tokens.md +++ b/skills/wallet/tokens.md @@ -1,9 +1,11 @@ # Tokens: the `stellar token` client -`stellar token` is a typed client for any SEP-41 token or Stellar Asset Contract (SAC). Each subcommand is a thin wrapper over `contract invoke` with token-aware argument parsing, asset/contract resolution, and decimal-aware amounts. Every state-changing subcommand inherits the full pipeline — simulate, sign auth entries, sign the transaction, fee-bump if needed, submit, poll — and returns a decoded JSON receipt. No sequence number or fee is requested from you. +`stellar token` is a typed client for any SEP-41 token or Stellar Asset Contract (SAC). Each subcommand is a thin wrapper over `contract invoke` with token-aware argument parsing and asset/contract resolution. Amounts are **raw base units** (`10^decimals`, which you look up per token with `decimals` — not always 7), like the rest of the CLI — see [amounts below](#amounts). Every state-changing subcommand inherits the full pipeline — simulate, sign auth entries, sign the transaction, fee-bump if needed, submit, poll — and returns a decoded JSON receipt. No sequence number or fee is requested from you. Back to the [wallet overview](SKILL.md). +> **Lower-level access.** `stellar contract invoke` calls a token's contract functions directly — reach for it for anything `stellar token` does not wrap. Discover a token's functions with `stellar contract invoke --id --network testnet -- --help`. Amounts are **base units** here too, exactly as with `stellar token` — read the token's `decimals` first (`stellar contract invoke --id --network testnet -- decimals`) and scale by `10^decimals`. It is **not always 7** (SAC-wrapped classic assets are 7, but a SEP-41 token can declare 6, 18, …) — see [amounts](#amounts). + ## Target resolution A subcommand targets a contract with `--id`: @@ -26,7 +28,7 @@ stellar contract asset deploy --asset USDC:GA5Z…ISSUER --source alice --networ |-------|-----------|----------|---------| | Transfer | `transfer` | `--id --to ` | Move tokens. The primary value-transfer command. | | Transfer | `transfer-from` | `--id --from --to ` | Spend an allowance on behalf of another holder. | -| Read | `balance` | `--id --of ` | Decimal-aware balance. | +| Read | `balance` | `--id --of ` | Balance, returned in raw base units. | | Read | `allowance` | `--id --from --spender ` | Read an allowance. | | Read | `name` / `symbol` / `decimals` | `--id ` | Token metadata. | | Allowance | `approve` | `--id --spender --expires ` | Set an allowance. | @@ -47,12 +49,21 @@ stellar token transfer \ --source alice \ --network testnet \ --output json \ - 100 + 1000000000 # 100 XLM in base units (native SAC has 7 decimals) ``` The receipt carries `status`, the decoded `result`, the tx hash, the charged fee, and decoded events. For an issued asset, pass `--id USDC:GA5Z…ISSUER` (or its SAC `C…` id); the destination must hold an authorized trustline. -Amounts are **decimal-aware**: pass human units (`100`), not stroops or base units. `token decimals --id ` tells you the scale. + +The amount is in **raw base units**, not human units — like `tx new payment --amount`, the whole CLI works this way. The scale is `10^decimals`, and **a SEP-41 token declares its own `decimals` — it is not always 7.** Read it before computing any amount, never assume: + +```bash +stellar token decimals --id --output json +``` + +Then `1 unit = 10^decimals` base units. The native SAC and any SAC-wrapped classic asset are 7 (so 1 XLM = `10_000_000`), but a native Soroban token can declare anything — a 6-decimal token means `1 unit = 1_000_000`, an 18-decimal token means `1 unit = 1_000_000_000_000_000_000`. Passing `100` without scaling moves 100 base units — a silent off-by-`10^decimals` mistake. + +> **Transferring to the issuer burns.** Sending a SAC-wrapped classic asset *to its own issuer* address emits a `Burn` event and the issuer's balance reads back as the `i64::MAX` sentinel (`9223372036854775807`) rather than going up — so verifying the transfer by checking the issuer's destination balance looks like a failure even though it succeeded. Confirm by the `Burn` event or the sender's decreased balance instead. ## Reads @@ -81,7 +92,7 @@ Read `error.code` / `error.details.error_name` from the JSON, not the human mess ## Pull a trusted token list -Don't hardcode contract IDs. Resolve assets from a published, trusted list so you target the right issuer. Stellar's convention is [SEP-1 `stellar.toml`](https://developers.stellar.org/docs/tokens/publishing-asset-information) `[[CURRENCIES]]`, and asset directories publish JSON. +Don't hardcode contract IDs. Resolve assets from a published, trusted list so you target the right issuer. Stellar's convention is [SEP-1 `stellar.toml`](https://developers.stellar.org/docs/tokens/publishing-asset-info) `[[CURRENCIES]]`, and asset directories publish JSON. ```bash # Fetch a home domain's stellar.toml and list its declared assets (code:issuer)