Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ Copy the `skills/` directory contents to your assistant's skills location.
skills/
├── smart-contracts/ # Stellar smart contracts — SKILL.md router + development/testing/security files
├── dapp/ # Frontend — SKILL.md router + react / data-fetching / smart-accounts files
├── assets/SKILL.md # Stellar Assets, trustlines, SAC bridge
├── assets/ # Stellar Assets, trustlines, SAC bridge — SKILL.md + pre-listing file
├── data/ # Stellar RPC (preferred) — SKILL.md router + horizon (legacy) file
├── agentic-payments/ # AI/machine payments — SKILL.md router + x402 / mpp files
├── zk-proofs/SKILL.md # ZK verification (BLS12-381/BN254 Groth16, UltraHonk), Circom/Noir/RISC Zero
├── standards/ # SEPs & CAPs — SKILL.md router + ecosystem / resources files
└── cross-chain/ # Cross-chain — SKILL.md router + cctp file
└── cross-chain/ # Cross-chain — SKILL.md router + cctp / axelar / layerzero files
```

Each sub-skill is a self-contained Agent Skill with its own frontmatter. Larger skills follow [Anthropic's progressive-disclosure guidance](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices): a sub-500-line `SKILL.md` router with a task-to-file table, plus companion files (one level deep) that load only when the task needs them. Cross-references link related skills (e.g., the `agentic-payments` skill points to `smart-contracts` for the SACs the protocols call, and to `assets` for USDC). The AI reads only the files relevant to the task at hand.
Expand Down Expand Up @@ -118,7 +118,7 @@ Contributions are welcome! Please ensure any updates reflect current Stellar eco

## Evaluations

[`evals/`](evals/README.md) holds ~3 task scenarios for each of seven skills (plus cross-skill routing checks and a negative control), each encoding a mistake agents actually make without the skill. Three grading tiers: machine-checkable compile checks, LLM-judged behavior assertions, and skill-trigger checks. Two gaps are open: `cross-chain` has no scenarios yet, and no baseline transcripts are committed, so the set is still unvalidated. See [evals/README.md](evals/README.md) for the format, how to run them, and what the missing baselines mean.
[`evals/`](evals/README.md) holds ~3 task scenarios for each of the eight skills (plus cross-skill routing checks and a negative control), each encoding a mistake agents actually make without the skill. Three grading tiers: machine-checkable compile checks, LLM-judged behavior assertions, and skill-trigger checks. One gap is open: no baseline transcripts are committed, so the set is still unvalidated. See [evals/README.md](evals/README.md) for the format, how to run them, and what the missing baselines mean.

## Resources

Expand Down
2 changes: 1 addition & 1 deletion evals/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Skill Evaluations

Representative task scenarios for seven of the eight skills in this repo, following [Anthropic's evaluation-driven skill authoring guidance](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#evaluation-and-iteration). `cross-chain` landed after this set was written and has no scenarios yet. Each scenario encodes a mistake an agent actually makes *without* the skill — several come from real failure modes (the #41 compile bugs, documented pitfalls in agentic-payments, the ZK curve trap), not imagined ones. Run them before publishing skill changes so regressions get caught here instead of by users.
Representative task scenarios for all eight skills in this repo, following [Anthropic's evaluation-driven skill authoring guidance](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#evaluation-and-iteration). `cross-chain` landed after this set was written; its scenarios arrived with the USDT0 rail. Each scenario encodes a mistake an agent actually makes *without* the skill — several come from real failure modes (the #41 compile bugs, documented pitfalls in agentic-payments, the ZK curve trap), not imagined ones. Run them before publishing skill changes so regressions get caught here instead of by users.

## Scenario format

Expand Down
13 changes: 13 additions & 0 deletions evals/scenarios/assets/04-sac-admin-handover.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"skills": [
"assets"
],
"query": "We want our Stellar token minted only by our contract, and the issuer account locked. What is the order of operations?",
"expected_behavior": [
"Calls `set_admin` on the SAC first, while the issuer can still sign, because the issuer is the SAC's initial admin",
"Locks the issuer (master key weight 0) only after that handover",
"Warns that locking the issuer first strands the SAC admin at the locked issuer forever, since nobody can authorize the first `set_admin`",
"Keeps the two controls apart: the issuer lock stops classic minting, the SAC admin decides who mints through the contract",
"Does not claim a locked issuer disables the SAC's `mint` under the new admin"
]
}
15 changes: 15 additions & 0 deletions evals/scenarios/cross-chain/01-usdt-arbitrum-to-stellar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"skills": [
"cross-chain"
],
"query": "Our users hold USDT on Arbitrum. Let them move it into their Stellar accounts.",
"expected_behavior": [
"Routes to USDT0 over LayerZero's OFT rail, not CCTP (which carries USDC only) and not a hand-rolled wrapped-asset bridge",
"Requires an account (`G…`) recipient's USDT0 trustline to exist before anything inbound is sent, and does not impose that trustline on a contract (`C…`) recipient, whose SAC balance lives in contract storage",
"Requires a `C…` recipient to be deployed before the source chain sends, because `resolve_address` falls back to a `G…` account when no contract with those 32 bytes exists, and that account can never be given a trustline",
"Checks the recipient contract's instance TTL as well, because delivery is asynchronous and an archived instance takes the same account fallback",
"Pins the asset by code and issuer and derives the SAC with `stellar contract id asset` instead of copying an address from a website",
"Names Stellar's LayerZero endpoint ID 30600 and encodes the recipient as the decoded 32-byte strkey payload (Ed25519 public key for `G…`, contract ID hash for `C…`), not the strkey string and not with its version byte or checksum",
"Does not treat the issuer's missing home_domain / stellar.toml as evidence the asset is fake"
]
}
13 changes: 13 additions & 0 deletions evals/scenarios/cross-chain/02-usdt0-send-loses-digit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"skills": [
"cross-chain"
],
"query": "When I send USDT0 off Stellar the last digit of my amount disappears. What is going wrong?",
"expected_behavior": [
"Explains the SAC's 7 local decimals against the OFT's shared_decimals of 6, so decimal_conversion_rate is 10 and the remainder below 6 decimals cannot cross",
"Says nothing is broken: the OFT removes that remainder before it builds the message",
"Makes the remainder's destination conditional on the route's OFT fee — it stays with the sender when effective_fee_bps(dst_eid) is 0, and is absorbed into the fee when the rate is above 0",
"Tells the user to trust quote_oft's OFTReceipt (amount_sent_ld and amount_received_ld) over their own input amount",
"Does not propose scaling the amount with floating-point arithmetic"
]
}
12 changes: 12 additions & 0 deletions evals/scenarios/cross-chain/03-usdt0-testnet-rehearsal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"skills": [
"cross-chain"
],
"query": "Before we ship, rehearse our USDT0 bridge integration end to end on Stellar testnet.",
"expected_behavior": [
"States that USDT0 publishes no Stellar testnet deployment, so a USDT0 testnet round trip is not available",
"Offers the real alternatives: read-only quote_oft and quote_send simulation, then a dust-sized mainnet transfer",
"Mentions that LayerZero's own testnet endpoint (EID 40600) can carry your own OApp or OFT, and says to confirm one delivered testnet message before trusting it as a rehearsal path",
"Does not invent a USDT0 testnet contract address or claim a testnet deployment exists"
]
}
15 changes: 15 additions & 0 deletions evals/scenarios/cross-chain/04-usdt0-stellar-to-ethereum.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"skills": [
"cross-chain"
],
"query": "Write up what happens to the tokens when our treasury moves USDT0 from Stellar to Ethereum, and then back.",
"expected_behavior": [
"Does not describe the route as burn-and-mint on both ends: the OFT mode is per leg",
"Says the Stellar leg is a MintBurn OFT, so `send` burns on the SAC and an inbound message mints through the SAC manager",
"Says the Ethereum leg is an OFT Adapter over canonical Tether USDT, so it unlocks USDT on arrival and locks USDT on the way back, with an ERC-20 approval to the adapter first",
"Tells the reader to confirm the mode per route — `oft_type()` on Stellar, and the `OFT` versus `OFT Adapter` entry on USDT0's deployments page",
"Quotes with `quote_oft` and `quote_send` rather than assuming the sent amount equals the received amount",
"Discovers the route with `min_amount_ld` set to 0, because both quotes enforce that floor and panic `SlippageExceeded`, then re-runs `quote_oft` and `quote_send` with the treasury's accepted minimum immediately before `send`",
"Keeps the two units apart: `min_amount_ld` is USDT0 in 7 decimals, while the messaging fee is XLM in stroops"
]
}
14 changes: 14 additions & 0 deletions evals/scenarios/cross-chain/05-oapp-fee-quote.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"skills": [
"cross-chain"
],
"query": "In our Stellar OApp, how do we quote and pay the LayerZero messaging fee?",
"expected_behavior": [
"Quotes with `__quote` and passes the returned `MessagingFee` to `__lz_send`, rather than guessing an amount",
"Names both fee fields: `native_fee` in XLM and `zro_fee` in the ZRO token",
"Says `__lz_send` pays ZRO whenever `zro_fee` is not 0",
"Separates the two no-ZRO failures: `__quote` with `pay_in_zro = true` fails in the endpoint with `EndpointError::ZroUnavailable`, while `__lz_send` fails earlier in `__pay_zro` with `OAppError::ZroTokenUnavailable` and never reaches the endpoint",
"Passes `pay_in_zro = false` unless a ZRO token is read on that endpoint",
"Re-quotes per send instead of reusing an earlier fee number"
]
}
20 changes: 20 additions & 0 deletions evals/scenarios/routing/04-usdt0-collateral.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"skills": [
"assets",
"cross-chain"
],
"query": "Is USDT0 safe to accept as collateral in our Stellar lending protocol?",
"expected_behavior": [
"Uses the assets pre-listing checks for the asset side and cross-chain/layerzero.md for the bridge side",
"Tests the issuer lock by the master key weight (the first byte of the account entry's thresholds), not by the signer list alone, and treats the extra signers' combined weight against the thresholds",
"Reports auth_revocable and auth_clawback_enabled as risks to model: balances can be frozen or clawed back",
"Derives the SAC from the asset rather than trusting a published address, and does not disqualify the asset for having no stellar.toml",
"Goes past oft_type's MintBurn address and enumerates the SAC admin contract's authority: get_existing_roles, then get_role_member for each role, plus get_role_admin and owner",
"Does not treat get_existing_roles as the role list: it returns only roles with a member today, so the answer queries MINTER_ROLE, CLAWBACK_ROLE, BLACKLISTER_ROLE and ADMIN_MANAGER_ROLE by name and reports each one's admin role, because an empty role's admin can still grant it",
"Enumerates the members of every admin role it finds, not only the members of the four roles themselves, and lists those accounts as holders of the authority they can grant",
"Reads the issuer's flags as a bitmask (10 = auth_revocable + auth_clawback_enabled) rather than expecting named boolean fields from the ledger entry",
"Says an empty role is not a safe role, because the owner can grant any role at any time, and models the owner (the OneSig contract) as holding every role",
"Does not stop at 'the owner is a multisig': reads the OneSig's own get_signers and threshold, reports the quorum (3 of 5 on 2026-08-28), and notes the signers are secp256k1 keys that can replace themselves",
"Marks ultimate control unresolved if an owner contract's governance cannot be read, rather than reporting the asset as reviewed"
]
}
4 changes: 2 additions & 2 deletions site/src/data/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ export const SKILL_CARD_SOURCES: readonly SkillCardSource[] = [
{
source: "skills/cross-chain/SKILL.md",
category: "Cross-Chain",
title: "Cross-Chain (CCTP, Axelar)",
title: "Cross-Chain (CCTP, Axelar, LayerZero)",
description:
"Bridge native USDC with Circle CCTP, pass messages and tokens with Axelar GMP/ITS, and route intent-based swaps with NEAR Intents.",
"Bridge native USDC with Circle CCTP and native USDT with USDT0, pass messages and tokens with Axelar GMP/ITS and LayerZero OApp/OFT, and route intent-based swaps with NEAR Intents.",
},
] as const;

Expand Down
55 changes: 54 additions & 1 deletion skills/assets/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: assets
description: Stellar Assets (classic) + trustlines + Stellar Asset Contract (SAC) bridge to smart contracts. Covers asset issuance, distribution, authorization flags, clawback, regulated assets, trustline management, and the SAC interop layer that exposes classic assets as SEP-41 contract tokens. Use when tokenizing real-world assets, issuing stablecoins, managing trustlines, or bridging classic assets to smart contracts.
description: Stellar Assets (classic) + trustlines + Stellar Asset Contract (SAC) bridge to smart contracts. Covers asset issuance, distribution, authorization flags, clawback, regulated assets, trustline management, the SAC interop layer that exposes classic assets as SEP-41 contract tokens, and read-only due diligence on an asset before listing it. Use when tokenizing real-world assets, issuing stablecoins, managing trustlines, bridging classic assets to smart contracts, or deciding whether to list, display or accept an asset as collateral.
user-invocable: true
argument-hint: "[asset task]"
---
Expand All @@ -15,6 +15,7 @@ Stellar's native token mechanism: classic asset issuance, trustlines, and the St
- Managing issuer flags (auth required, auth revocable, clawback)
- Bridging a classic asset into a smart contract via SAC
- Building regulated-asset flows (compliance, KYC, freeze)
- Reviewing an asset before you list it, display it, or take it as collateral → [pre-listing.md](pre-listing.md)

## Related skills
- Custom token contracts (when classic isn't enough) → `../smart-contracts/SKILL.md`
Expand Down Expand Up @@ -406,6 +407,26 @@ SAC implements the standard SEP-41 token interface:
> compatibility of a normal asset (DEX, anchors, wallets, trustlines) while
> still layering on custom logic. Prefer a custom contract token only when
> you need token behavior the SAC genuinely cannot express.
>
> **This runs in production today.** USDT0
> (`USDT0:GATISXX6BZ6NC7IKQBY37CJD4SOZL3CYZJWXEDG6JVIY4WBS6KXJHN6Q`) is a
> classic asset whose SAC admin is a contract: a role-gated manager that
> forwards `mint`, `clawback`, `set_authorized`, and `set_admin` to the SAC,
> with a cross-chain bridge holding only the minter role. See
> [setting a custom SAC admin](https://developers.stellar.org/docs/build/guides/tokens/custom-sac-admin)
> for the pattern and `../cross-chain/layerzero.md` for that deployment.
>
> One hard prerequisite: **lock the issuer** (master key weight `0`).
> Payments from a classic issuer are minting, so an unlocked issuer can mint
> outside the contract and bypass the role model entirely.
>
> **Do it in this order: `set_admin` first, then lock the issuer.** A SAC's
> admin starts as the issuer account, and only the *current* admin can
> authorize the first `set_admin`. Lock the issuer before that call and the
> admin stays the locked issuer forever, because nobody can sign the handover
> ([SAC admin guide](https://developers.stellar.org/docs/build/guides/tokens/custom-sac-admin)).
> After the handover the SAC still mints under the new admin, so lock the
> issuer then.

### Use SAC When:
- Need a Stellar asset inside a smart contract
Expand Down Expand Up @@ -460,6 +481,27 @@ const stats = await server
// - flags: issuer flags
```

### Pre-Listing Check (read-only)

Before you list an asset, display it, or accept it as collateral, answer seven
questions from the ledger itself: the issuer's lock and flags, the SAC
derivation, what the contract says it wraps, its admin, any bridge on top, that
admin's roles, and finally whoever controls the admin. Every step simulates
only, and none of them needs a key.

**The full recipe, with commands and a worked USDT0 example, is in
[pre-listing.md](pre-listing.md).** Read it before you sign off on an asset.

Two rules decide most reviews:

- **Walk the chain until it ends at keys.** A locked issuer with a contract
admin is a normal design, not a red flag. It moves the trust question to that
contract's roles, and then to whoever controls that contract. "The owner is a
multisig" is a governance layer, not an answer.
- **Read state, never reputation.** Derive the SAC yourself, decode the issuer's
`flags` bitmask, and treat role membership as live state. A missing
`stellar.toml` is not evidence of a fake asset.

## SEP Standards for Assets

### SEP-0001 (stellar.toml)
Expand Down Expand Up @@ -513,3 +555,14 @@ Standard contract interface for NFTs on Stellar. Reference implementations avail
- Be cautious of assets with clawback enabled
- Verify stellar.toml from authoritative source
- Use well-known asset lists for common tokens
- **Some live assets have no `stellar.toml` at all.** A missing `home_domain`
is not evidence of a scam — USDT0 ships without one. Validate by issuer
plus SAC derivation, never by the presence of `home_domain` or a
`[[CURRENCIES]]` entry
- **When `AUTH_REVOCABLE` and `AUTH_CLAWBACK_ENABLED` are both set, check the
issuer lock *and* the admin roles before listing the asset.** Those flags
mean balances can be frozen or clawed back. A contract SAC admin does not
contain that power on its own: an issuer whose master key still signs can
mint, freeze and claw back directly, whatever the admin contract allows. So
confirm the master key weight is `0` (see [pre-listing.md](pre-listing.md)),
then identify who holds the admin contract's roles
Loading
Loading