Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
84196c0
Add USDT0 (LayerZero OFT) to the cross-chain and assets skills
kaankacar Aug 27, 2026
9028152
Address review: drop unverified claims, add the OFT read steps
kaankacar Aug 27, 2026
525add7
fix: separate the two USDT0 fees and tighten the issuer-lock check
kaankacar Aug 28, 2026
093c751
Merge branch 'main' into issue-agent/115-usdt0-layerzero
kaankacar Aug 28, 2026
aef2fd8
fix: add the cross-chain evals and the missing OFT command shapes
kaankacar Aug 28, 2026
38325cd
fix: scope the USDT0 OFT mode and the trustline rule per leg
kaankacar Aug 28, 2026
79a81c1
fix: order the SAC admin handover and cover the ZRO fee path
kaankacar Aug 28, 2026
e8a0fd7
fix: separate the two ZRO failures and pin the recipient encoding
kaankacar Aug 28, 2026
e85680e
fix: say what an M address costs on the OFT rail
kaankacar Aug 28, 2026
8186d4c
style: unfold the recipient decode into plain branches
kaankacar Aug 28, 2026
b03d077
style: flatten the step 6 notes into plain bullets
kaankacar Aug 28, 2026
46b9a05
fix: require a deployed C… recipient and resolve the OneSig quorum
kaankacar Aug 28, 2026
de8ffe1
fix: quote with a zero floor and ask about the empty roles by name
kaankacar Aug 28, 2026
48148d7
fix: decode the issuer flags and walk the admin roles' members
kaankacar Aug 28, 2026
54485c0
refactor: move the pre-listing recipe into a companion file
kaankacar Aug 28, 2026
69e472a
Remove the pre-listing recipe and its references
kaankacar Sep 4, 2026
6b7b53a
Record the verified skeleton build and the testnet send result
kaankacar Sep 4, 2026
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ skills/
├── 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"
]
}
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
31 changes: 31 additions & 0 deletions skills/assets/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,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 @@ -513,3 +533,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`, then identify who holds the admin
contract's roles
Loading
Loading