{
  "slug": "stellar",
  "title": "Stellar",
  "lede": "A Soroban spend policy that refuses an over-limit payment with a typed error, deployed on MAINNET as well as testnet and holding real USDC: an agent spent exactly its 1 USDC daily budget there and the next payment was refused by the contract. The x402 facilitator we wrote for this chain now sells on BOTH networks: the first mainnet sale settled 2026-08-27 through our own broadcaster, at the fee market's own rate. OpenZeppelin Channels got to a Stellar facilitator first and is kept as a fallback; what is ours is that no payment counts until we have read the transfer ourselves. On testnet, owners whose keys we never held have since acted on vaults of their own: a key generated inside Freighter froze its vault and withdrew on 2026-10-03, and a device passkey froze another on 2026-10-04.",
  "networks": [
    {
      "chain": "stellar",
      "summary": "The same Soroban spend policy as the testnet rail, deployed to Stellar mainnet and funded with real USDC. An agent spent exactly its daily budget and not one unit more: four payments settled inside the policy, the fifth was refused with the contract's own DailyCapExceeded, and the human override paid through a freeze that had already stopped the agent. Small money on purpose, and the cap is the reason. Since 2026-08-27 the Soroban x402 rail also SELLS here: the first mainnet sale settled through our own facilitator, the buyer signing an authorization entry and paying no fee, and the sale counted only once we read the SEP-41 transfer event bound to its nonce.",
      "contracts": [
        {
          "name": "AgentSpendPolicy (Soroban, pubnet)",
          "address": "CB5LYXFKKTKDDSCM6JO6C4GNRQUFBGSLYDET6Q56JNFJQSMBKH6KWSYP",
          "note": "Ours. The wasm hash is 155eb31c1867254eacbf1b7a4755164d15cc6b6f939644705ab6b8df61579239, byte for byte the hash the testnet vault carries, so mainnet runs the code that has been under test since 2026-08-15 rather than a rebuild of it. No upgrade entrypoint and no initialize: the constructor ran atomically at deploy and its arguments are permanent. Policy: 1 USDC per UTC day, 0.25 USDC per payment."
        },
        {
          "name": "USDC (Stellar Asset Contract, pubnet)",
          "address": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
          "note": "Circle's mainnet USDC as a SEP-41 contract. The issuer was checked before the derivation, which is the step that matters here: Horizon lists dozens of assets called USDC because anyone may issue one, and this issuer's home_domain is circle.com. The SAC id was then derived from that asset plus the pubnet passphrase rather than pasted, and read back live for symbol, decimals and name."
        }
      ],
      "artifacts": [
        {
          "kind": "funding",
          "label": "The payee opens a USDC trustline",
          "txHash": "f10c27d98a07c386c975bfeb3168947acab5e13e63536bc14093eb700a97c662",
          "onChain": "stellar",
          "blockNumber": 64103407,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "A Stellar prerequisite with no EVM analogue, and one that is easy to learn the hard way: paying an account that holds no USDC trustline fails with op_no_trust, which a buyer reads as our bug rather than as their missing setup. The vault itself needs none, because it holds the token in contract storage rather than through a trustline."
        },
        {
          "kind": "deploy",
          "label": "The spend policy, uploaded to mainnet",
          "txHash": "4230a328bf063cc005e8fea00c45a9d38af57968b8ee166cbb5a11fb92b51fba",
          "onChain": "stellar",
          "blockNumber": 64103416,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "The code entry alone cost 12.2319214 XLM, which is almost the whole bill for this deploy: a Soroban wasm entry pays rent for its size and this one is 11,625 bytes. The binary is deliberately not committed, because Rust wasm is not bit-reproducible across machines by default. Pull it with `stellar contract fetch` and sha256 it against the hash above."
        },
        {
          "kind": "deploy",
          "label": "Instantiated with a policy that can never be changed",
          "txHash": "847dc7e99e73f6c0062e5aed29599f41226998053fe7b6c35e48e9cf64a6ee2d",
          "onChain": "stellar",
          "blockNumber": 64103418,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "Instantiating on top of the uploaded hash cost 0.0992122 XLM. The constructor read decimals() off the token itself, which is how the deploy proves the address really implements SEP-41; it read 7, not the 6 every EVM USDC uses."
        },
        {
          "kind": "funding",
          "label": "1 USDC bought on Stellar's own order book",
          "txHash": "b3ad997d83f578edf7583ef8c59dc5ec5db4091955b603e77aca1b939f5e9b41",
          "onChain": "stellar",
          "blockNumber": 64103437,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "A strict-receive path payment, XLM in and exactly 1.0000000 USDC out at 0.1949500 USDC per XLM. No bridge and no exchange. It is also where the USD figures in this repo come from: a price read off the same ledger the rail settles on, rather than from an API we cannot show you."
        },
        {
          "kind": "funding",
          "label": "1 USDC moved into the vault",
          "txHash": "e558baf97bb8dde87cc585245df430e72667e21bd2cb78fee62418cd04692344",
          "onChain": "stellar",
          "blockNumber": 64103469,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "Submitted twice, and the reason is worth recording rather than hiding. The first attempt returned a submission timeout, which is not a failure: a Stellar transaction stays valid for its whole timeout window. Horizon was checked first and showed the hash absent with no fee charged, so the retry was a resubmission of the same envelope and not a second payment. It landed under the same hash."
        },
        {
          "kind": "settlement",
          "label": "An under-limit agent payment, in real USDC",
          "txHash": "c4a884c306ee0cd76b7fb4fa245176618897687ad7fee724e2d43b72d20f3733",
          "onChain": "stellar",
          "blockNumber": 64103478,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "The operator paid 0.20 USDC, inside both the 0.25 ceiling and the 1 USDC cap. Two events fired: the SAC transfer out of the vault, and the vault's own Paid event carrying by_owner:false, which is what marks this as the agent path rather than the human one."
        },
        {
          "kind": "settlement",
          "label": "Three payments at exactly the ceiling, walking the cap to its edge",
          "txHash": "d2386d419a2d546627b4b7247bb152e70b314e5f84a9d76a60f752cc81f95c80",
          "onChain": "stellar",
          "blockNumber": 64103495,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "0.25 USDC, the largest single payment the policy auto-approves. Two more followed at ledgers 64103499 (f514ac178bd4aba60d53cc3980f5517bb1bd93d53d7f69d227a798632251aefb) and 64103501 (ebf3cb627c18ec226be9e2790054c4de43d0da2b524f27fb499ab0af6a477d80), taking spent_today to 0.95 of a 1 USDC cap. The cap is cumulative across payments, which is what made the next one refusable."
        },
        {
          "kind": "settlement",
          "label": "A fifth agent payment, 0.01 USDC, just before the freeze",
          "txHash": "db886f90d2edf82f9e885a6147589732175f18cdb0dfe41be5afc35fa3740291",
          "onChain": "stellar",
          "blockNumber": 64103518,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "pay(owner, 100000) by the operator, taking spent_today from 0.95 to 0.96 USDC. Missing from the first version of the release record and found on 2026-09-15 by reconciling the operator account on Horizon: without it the 1 USDC that went in and the payments recorded coming out did not add up to the zero balance and the full cap the record ends on. The same amount was then refused with Frozen once the freeze was on."
        },
        {
          "kind": "owner-action",
          "label": "The kill switch, thrown on mainnet",
          "txHash": "c003e3fed6d39d820da51ea281b6d17fc910961bee88163ef8fb6fa084e059cf",
          "onChain": "stellar",
          "blockNumber": 64103526,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "set_frozen(true), event FrozenSet. With the vault frozen the operator's next payment was refused with error 1, Frozen, and that refusal has no hash of its own for the reason every Soroban refusal here has none. Lifted again at ledger 64103532 by 8bccb734a624cb6165cdd74da5c2d196c3b67dd8a0ed92e3435df1ffd2ae9f9a, because the other half of a kill switch is that it turns back off: a freeze you cannot lift is a loss rather than a control."
        },
        {
          "kind": "owner-action",
          "label": "The owner overrides a freeze and pays anyway",
          "txHash": "58c118ee659b65875efe5e916f7bb332bc896b62537fa8dd030e2c225defa1cf",
          "onChain": "stellar",
          "blockNumber": 64103531,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "owner_pay while the vault was frozen. It settles, because the human path is meant to work exactly when the agent path does not, and its Paid event carries by_owner:true. It was still CHARGED to the daily cap, but note what that does and does not mean: owner_pay increments the day accumulator and is NOT limited by it. `check_owner_pay` in policy.rs has no cap comparison. The override bypasses the budget as well as the gates; what it does not bypass is the accounting. An earlier version of this note said the budget still bound it, which was wrong. The freeze went on at ledger 64103526 (c003e3fed6d39d820da51ea281b6d17fc910961bee88163ef8fb6fa084e059cf) and came off at 64103532 (8bccb734a624cb6165cdd74da5c2d196c3b67dd8a0ed92e3435df1ffd2ae9f9a), because a freeze you cannot lift is a loss rather than a control."
        },
        {
          "kind": "funding",
          "label": "A buyer wallet funded with 0.05 USDC for the first x402 sale",
          "txHash": "2f47f4fe2f003e8cf65f13d9c8ce62eb2c56319bda2812d93564f5c083d3a12e",
          "onChain": "stellar",
          "blockNumber": 64155317,
          "date": "2026-08-27",
          "deliverable": "self-funded",
          "note": "The owner account (now 2-of-3 multisig, so the payment carries two signatures) moved 0.05 USDC to a burner that already held a USDC trustline. The buyer needs USDC and a trustline and nothing else: it signs authorization entries and never pays a network fee."
        },
        {
          "kind": "settlement",
          "label": "First x402 sale on Stellar mainnet (verify_agent, 0.001 USDC)",
          "txHash": "f213371c1241968ee78170923d8c5a3bd9b32950e73bb9c563d800ab2c70ec9e",
          "onChain": "stellar",
          "blockNumber": 64155370,
          "date": "2026-08-27",
          "deliverable": "self-funded",
          "note": "The buyer signed a Soroban authorization entry for transfer on the USDC SAC and paid nothing; we assembled, BID 34035 stroops and were CHARGED 23479 (Horizon fee_charged, read 2026-09-15), and the sale counted only once the SEP-41 transfer event bound to the authorization's nonce was read back. The two fee numbers are not the same claim and an earlier version of this note reported the bid as what we paid: Stellar runs a fee auction and charges the clearing fee, so the envelope fee is a ceiling we offer and the charge is what the ledger took. Recorded honestly: the first two attempts never landed, because the transaction bid the 100-stroop minimum inclusion fee that testnet always accepts while pubnet's auction was clearing at 200 across every percentile. The fix bids the fee market's own p90 with headroom, and this settlement is the measurement."
        },
        {
          "kind": "funding",
          "label": "The pubnet vault refilled after a read found it empty",
          "txHash": "c91aaa824b84ee33a8b328514fcb415554626d824e443a2c338e318c99e4042c",
          "onChain": "stellar",
          "blockNumber": 64458213,
          "date": "2026-09-16",
          "deliverable": "self-funded",
          "note": "0.04 USDC transferred into the vault through the USDC SAC on 2026-09-16 by mcp/scripts/stellar-vault-fund.mjs. A third-party review read the contract that day and found balance 0: the dust it was funded with had been spent by the payments recorded above, so \"holds real USDC\" had stopped being true without anything failing. Read back from the contract after the transfer: balance 0.04, daily_cap 1 USDC, auto_approve_max 0.25 USDC, the policy unchanged since construction."
        }
      ],
      "accounts": [
        {
          "role": "Owner of the pubnet vault CB5LYXFK..., a 2-of-3 multisig since 2026-08-25",
          "address": "GARC7OFBBQCZJ5N3LCI7HTTYJ2MMPDAFDNGIHSQMZ7EPJ5EAWQJ5R6I5",
          "network": "stellar",
          "custody": "ours: local CLI keystore",
          "usedFor": "The vault's deploy, its funding, and every owner action on it (set_frozen, owner_pay). Permanent, because the contract has no set_owner. Its three signers are listed in soroban/releases/pubnet-v0.1.0.json and are all held in one keystore, which SECURITY.md states as an open weakness.",
          "publishedAt": "2026-08-24"
        },
        {
          "role": "Operator of the pubnet vault CB5LYXFK...",
          "address": "GDLAJM25YQRTIZOVZPVEM2GJ6L2I4OTZGY3HAWX3HGMPV7SM3QZONO4S",
          "network": "stellar",
          "custody": "ours: local CLI keystore",
          "usedFor": "pay() inside the policy, 1 USDC per UTC day and 0.25 per payment, and nothing else. It also broadcast the first two pubnet x402 sales, on 2026-08-27 and 2026-08-28, before the fee payer below was split off.",
          "publishedAt": "2026-08-24"
        },
        {
          "role": "x402 pubnet fee payer",
          "address": "GAFVDEN6BC52WWPRPINOVENMXW3FU4LCSVVVA5C67RLPG4GAK6BE4SXY",
          "network": "stellar",
          "custody": "ours: backend environment key",
          "usedFor": "Assembling, broadcasting and paying the network fee for pubnet x402 settlements since 2026-09-15. XLM only: no USDC, no trustline and no role on any vault.",
          "publishedAt": "2026-09-15"
        }
      ],
      "caveats": [
        "Real money, but small money. The cap is 1 USDC per UTC day and the vault was funded with 1 USDC, then refilled with 0.04 USDC on 2026-09-16, which is all it holds: read at pubnet ledger 64890848 on 2026-10-11, balance 0.04 USDC, not frozen, nothing spent since the refill. Nothing here shows behaviour at a size anyone would mind losing, and that is the deliberate trade for an unaudited contract holding value.",
        "The two refusals have no transaction to link, and that is Soroban rather than evasion. A payment the contract refuses fails in SIMULATION, so nothing is submitted and no hash exists. The 0.50 USDC attempt returned AboveAutoApprove (error 4) and the over-cap attempt returned DailyCapExceeded (error 5). Anyone can reproduce both against the live contract in seconds, and it costs nothing precisely because they are refused.",
        "The over-cap refusal is worth reading closely. The vault held only 0.05 USDC at that moment, so an InsufficientBalance refusal was also available, and the contract returned DailyCapExceeded instead because the cap gate fires before the balance gate. The ORDER is the product: the agent is told its budget is spent, not that the account is short, and those call for different human responses.",
        "Not audited. Free tooling we can re-run, an adversarial review that found and fixed real defects, and a negative-control runner that deletes each guard in turn and requires the suite to go red. That is not an audit and we will not call it one.",
        "The operator is a single burner key in a local CLI keystore, not an HSM. The owner account has since been raised to 2-of-3 multisig (thresholds 2/2/2, read live 2026-08-28 and again 2026-10-11: three signers of weight 1), which an earlier version of this caveat predated; losing two of its three keys still makes the balance unrecoverable, which is the trade a capped vault is meant to make survivable.",
        "Payer and payee are both ours: the owner account funded the vault and received every payment, including the first x402 sale. Evidence the rail works, not evidence of demand.",
        "Three x402 sales have settled on pubnet, and every one is internal: 0.001 USDC each, from our own buyer burner GAHWB3OF... to the owner account GARC7OFB.... The one recorded here was settled from an operator machine on 2026-08-27. The production deployment settled the other two, on 2026-08-28 (546bfa8d..., ledger 64155975) and 2026-09-15 (43a97d67..., ledger 64432240), and the live settlement log on this page lists them; it sells on pubnet with its own fee payer, GAFVDEN6..., since 2026-09-15. Read off Horizon on 2026-10-11, no payment has reached the owner account since 2026-09-15.",
        "No identity. ERC-8004 is EVM-only and no Soroban identity registry exists to point at, so a Stellar agent's passport is bridged from an EVM chain rather than anchored here. KYA cannot be verified on this chain."
      ],
      "name": "Stellar",
      "caip2": "stellar:pubnet",
      "status": "live",
      "ecosystem": "stellar",
      "explorer": "https://stellar.expert/explorer/public",
      "contractsLinked": [
        {
          "name": "AgentSpendPolicy (Soroban, pubnet)",
          "address": "CB5LYXFKKTKDDSCM6JO6C4GNRQUFBGSLYDET6Q56JNFJQSMBKH6KWSYP",
          "note": "Ours. The wasm hash is 155eb31c1867254eacbf1b7a4755164d15cc6b6f939644705ab6b8df61579239, byte for byte the hash the testnet vault carries, so mainnet runs the code that has been under test since 2026-08-15 rather than a rebuild of it. No upgrade entrypoint and no initialize: the constructor ran atomically at deploy and its arguments are permanent. Policy: 1 USDC per UTC day, 0.25 USDC per payment.",
          "explorerUrl": "https://stellar.expert/explorer/public/contract/CB5LYXFKKTKDDSCM6JO6C4GNRQUFBGSLYDET6Q56JNFJQSMBKH6KWSYP"
        },
        {
          "name": "USDC (Stellar Asset Contract, pubnet)",
          "address": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
          "note": "Circle's mainnet USDC as a SEP-41 contract. The issuer was checked before the derivation, which is the step that matters here: Horizon lists dozens of assets called USDC because anyone may issue one, and this issuer's home_domain is circle.com. The SAC id was then derived from that asset plus the pubnet passphrase rather than pasted, and read back live for symbol, decimals and name.",
          "explorerUrl": "https://stellar.expert/explorer/public/contract/CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"
        }
      ],
      "artifactsLinked": [
        {
          "kind": "funding",
          "label": "The payee opens a USDC trustline",
          "txHash": "f10c27d98a07c386c975bfeb3168947acab5e13e63536bc14093eb700a97c662",
          "onChain": "stellar",
          "blockNumber": 64103407,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "A Stellar prerequisite with no EVM analogue, and one that is easy to learn the hard way: paying an account that holds no USDC trustline fails with op_no_trust, which a buyer reads as our bug rather than as their missing setup. The vault itself needs none, because it holds the token in contract storage rather than through a trustline.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/f10c27d98a07c386c975bfeb3168947acab5e13e63536bc14093eb700a97c662"
        },
        {
          "kind": "deploy",
          "label": "The spend policy, uploaded to mainnet",
          "txHash": "4230a328bf063cc005e8fea00c45a9d38af57968b8ee166cbb5a11fb92b51fba",
          "onChain": "stellar",
          "blockNumber": 64103416,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "The code entry alone cost 12.2319214 XLM, which is almost the whole bill for this deploy: a Soroban wasm entry pays rent for its size and this one is 11,625 bytes. The binary is deliberately not committed, because Rust wasm is not bit-reproducible across machines by default. Pull it with `stellar contract fetch` and sha256 it against the hash above.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/4230a328bf063cc005e8fea00c45a9d38af57968b8ee166cbb5a11fb92b51fba"
        },
        {
          "kind": "deploy",
          "label": "Instantiated with a policy that can never be changed",
          "txHash": "847dc7e99e73f6c0062e5aed29599f41226998053fe7b6c35e48e9cf64a6ee2d",
          "onChain": "stellar",
          "blockNumber": 64103418,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "Instantiating on top of the uploaded hash cost 0.0992122 XLM. The constructor read decimals() off the token itself, which is how the deploy proves the address really implements SEP-41; it read 7, not the 6 every EVM USDC uses.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/847dc7e99e73f6c0062e5aed29599f41226998053fe7b6c35e48e9cf64a6ee2d"
        },
        {
          "kind": "funding",
          "label": "1 USDC bought on Stellar's own order book",
          "txHash": "b3ad997d83f578edf7583ef8c59dc5ec5db4091955b603e77aca1b939f5e9b41",
          "onChain": "stellar",
          "blockNumber": 64103437,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "A strict-receive path payment, XLM in and exactly 1.0000000 USDC out at 0.1949500 USDC per XLM. No bridge and no exchange. It is also where the USD figures in this repo come from: a price read off the same ledger the rail settles on, rather than from an API we cannot show you.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/b3ad997d83f578edf7583ef8c59dc5ec5db4091955b603e77aca1b939f5e9b41"
        },
        {
          "kind": "funding",
          "label": "1 USDC moved into the vault",
          "txHash": "e558baf97bb8dde87cc585245df430e72667e21bd2cb78fee62418cd04692344",
          "onChain": "stellar",
          "blockNumber": 64103469,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "Submitted twice, and the reason is worth recording rather than hiding. The first attempt returned a submission timeout, which is not a failure: a Stellar transaction stays valid for its whole timeout window. Horizon was checked first and showed the hash absent with no fee charged, so the retry was a resubmission of the same envelope and not a second payment. It landed under the same hash.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/e558baf97bb8dde87cc585245df430e72667e21bd2cb78fee62418cd04692344"
        },
        {
          "kind": "settlement",
          "label": "An under-limit agent payment, in real USDC",
          "txHash": "c4a884c306ee0cd76b7fb4fa245176618897687ad7fee724e2d43b72d20f3733",
          "onChain": "stellar",
          "blockNumber": 64103478,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "The operator paid 0.20 USDC, inside both the 0.25 ceiling and the 1 USDC cap. Two events fired: the SAC transfer out of the vault, and the vault's own Paid event carrying by_owner:false, which is what marks this as the agent path rather than the human one.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/c4a884c306ee0cd76b7fb4fa245176618897687ad7fee724e2d43b72d20f3733"
        },
        {
          "kind": "settlement",
          "label": "Three payments at exactly the ceiling, walking the cap to its edge",
          "txHash": "d2386d419a2d546627b4b7247bb152e70b314e5f84a9d76a60f752cc81f95c80",
          "onChain": "stellar",
          "blockNumber": 64103495,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "0.25 USDC, the largest single payment the policy auto-approves. Two more followed at ledgers 64103499 (f514ac178bd4aba60d53cc3980f5517bb1bd93d53d7f69d227a798632251aefb) and 64103501 (ebf3cb627c18ec226be9e2790054c4de43d0da2b524f27fb499ab0af6a477d80), taking spent_today to 0.95 of a 1 USDC cap. The cap is cumulative across payments, which is what made the next one refusable.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/d2386d419a2d546627b4b7247bb152e70b314e5f84a9d76a60f752cc81f95c80"
        },
        {
          "kind": "settlement",
          "label": "A fifth agent payment, 0.01 USDC, just before the freeze",
          "txHash": "db886f90d2edf82f9e885a6147589732175f18cdb0dfe41be5afc35fa3740291",
          "onChain": "stellar",
          "blockNumber": 64103518,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "pay(owner, 100000) by the operator, taking spent_today from 0.95 to 0.96 USDC. Missing from the first version of the release record and found on 2026-09-15 by reconciling the operator account on Horizon: without it the 1 USDC that went in and the payments recorded coming out did not add up to the zero balance and the full cap the record ends on. The same amount was then refused with Frozen once the freeze was on.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/db886f90d2edf82f9e885a6147589732175f18cdb0dfe41be5afc35fa3740291"
        },
        {
          "kind": "owner-action",
          "label": "The kill switch, thrown on mainnet",
          "txHash": "c003e3fed6d39d820da51ea281b6d17fc910961bee88163ef8fb6fa084e059cf",
          "onChain": "stellar",
          "blockNumber": 64103526,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "set_frozen(true), event FrozenSet. With the vault frozen the operator's next payment was refused with error 1, Frozen, and that refusal has no hash of its own for the reason every Soroban refusal here has none. Lifted again at ledger 64103532 by 8bccb734a624cb6165cdd74da5c2d196c3b67dd8a0ed92e3435df1ffd2ae9f9a, because the other half of a kill switch is that it turns back off: a freeze you cannot lift is a loss rather than a control.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/c003e3fed6d39d820da51ea281b6d17fc910961bee88163ef8fb6fa084e059cf"
        },
        {
          "kind": "owner-action",
          "label": "The owner overrides a freeze and pays anyway",
          "txHash": "58c118ee659b65875efe5e916f7bb332bc896b62537fa8dd030e2c225defa1cf",
          "onChain": "stellar",
          "blockNumber": 64103531,
          "date": "2026-08-24",
          "deliverable": "self-funded",
          "note": "owner_pay while the vault was frozen. It settles, because the human path is meant to work exactly when the agent path does not, and its Paid event carries by_owner:true. It was still CHARGED to the daily cap, but note what that does and does not mean: owner_pay increments the day accumulator and is NOT limited by it. `check_owner_pay` in policy.rs has no cap comparison. The override bypasses the budget as well as the gates; what it does not bypass is the accounting. An earlier version of this note said the budget still bound it, which was wrong. The freeze went on at ledger 64103526 (c003e3fed6d39d820da51ea281b6d17fc910961bee88163ef8fb6fa084e059cf) and came off at 64103532 (8bccb734a624cb6165cdd74da5c2d196c3b67dd8a0ed92e3435df1ffd2ae9f9a), because a freeze you cannot lift is a loss rather than a control.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/58c118ee659b65875efe5e916f7bb332bc896b62537fa8dd030e2c225defa1cf"
        },
        {
          "kind": "funding",
          "label": "A buyer wallet funded with 0.05 USDC for the first x402 sale",
          "txHash": "2f47f4fe2f003e8cf65f13d9c8ce62eb2c56319bda2812d93564f5c083d3a12e",
          "onChain": "stellar",
          "blockNumber": 64155317,
          "date": "2026-08-27",
          "deliverable": "self-funded",
          "note": "The owner account (now 2-of-3 multisig, so the payment carries two signatures) moved 0.05 USDC to a burner that already held a USDC trustline. The buyer needs USDC and a trustline and nothing else: it signs authorization entries and never pays a network fee.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/2f47f4fe2f003e8cf65f13d9c8ce62eb2c56319bda2812d93564f5c083d3a12e"
        },
        {
          "kind": "settlement",
          "label": "First x402 sale on Stellar mainnet (verify_agent, 0.001 USDC)",
          "txHash": "f213371c1241968ee78170923d8c5a3bd9b32950e73bb9c563d800ab2c70ec9e",
          "onChain": "stellar",
          "blockNumber": 64155370,
          "date": "2026-08-27",
          "deliverable": "self-funded",
          "note": "The buyer signed a Soroban authorization entry for transfer on the USDC SAC and paid nothing; we assembled, BID 34035 stroops and were CHARGED 23479 (Horizon fee_charged, read 2026-09-15), and the sale counted only once the SEP-41 transfer event bound to the authorization's nonce was read back. The two fee numbers are not the same claim and an earlier version of this note reported the bid as what we paid: Stellar runs a fee auction and charges the clearing fee, so the envelope fee is a ceiling we offer and the charge is what the ledger took. Recorded honestly: the first two attempts never landed, because the transaction bid the 100-stroop minimum inclusion fee that testnet always accepts while pubnet's auction was clearing at 200 across every percentile. The fix bids the fee market's own p90 with headroom, and this settlement is the measurement.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/f213371c1241968ee78170923d8c5a3bd9b32950e73bb9c563d800ab2c70ec9e"
        },
        {
          "kind": "funding",
          "label": "The pubnet vault refilled after a read found it empty",
          "txHash": "c91aaa824b84ee33a8b328514fcb415554626d824e443a2c338e318c99e4042c",
          "onChain": "stellar",
          "blockNumber": 64458213,
          "date": "2026-09-16",
          "deliverable": "self-funded",
          "note": "0.04 USDC transferred into the vault through the USDC SAC on 2026-09-16 by mcp/scripts/stellar-vault-fund.mjs. A third-party review read the contract that day and found balance 0: the dust it was funded with had been spent by the payments recorded above, so \"holds real USDC\" had stopped being true without anything failing. Read back from the contract after the transfer: balance 0.04, daily_cap 1 USDC, auto_approve_max 0.25 USDC, the policy unchanged since construction.",
          "explorerUrl": "https://stellar.expert/explorer/public/tx/c91aaa824b84ee33a8b328514fcb415554626d824e443a2c338e318c99e4042c"
        }
      ],
      "accountsLinked": [
        {
          "role": "Owner of the pubnet vault CB5LYXFK..., a 2-of-3 multisig since 2026-08-25",
          "address": "GARC7OFBBQCZJ5N3LCI7HTTYJ2MMPDAFDNGIHSQMZ7EPJ5EAWQJ5R6I5",
          "network": "stellar",
          "custody": "ours: local CLI keystore",
          "usedFor": "The vault's deploy, its funding, and every owner action on it (set_frozen, owner_pay). Permanent, because the contract has no set_owner. Its three signers are listed in soroban/releases/pubnet-v0.1.0.json and are all held in one keystore, which SECURITY.md states as an open weakness.",
          "publishedAt": "2026-08-24",
          "explorerUrl": "https://stellar.expert/explorer/public/account/GARC7OFBBQCZJ5N3LCI7HTTYJ2MMPDAFDNGIHSQMZ7EPJ5EAWQJ5R6I5"
        },
        {
          "role": "Operator of the pubnet vault CB5LYXFK...",
          "address": "GDLAJM25YQRTIZOVZPVEM2GJ6L2I4OTZGY3HAWX3HGMPV7SM3QZONO4S",
          "network": "stellar",
          "custody": "ours: local CLI keystore",
          "usedFor": "pay() inside the policy, 1 USDC per UTC day and 0.25 per payment, and nothing else. It also broadcast the first two pubnet x402 sales, on 2026-08-27 and 2026-08-28, before the fee payer below was split off.",
          "publishedAt": "2026-08-24",
          "explorerUrl": "https://stellar.expert/explorer/public/account/GDLAJM25YQRTIZOVZPVEM2GJ6L2I4OTZGY3HAWX3HGMPV7SM3QZONO4S"
        },
        {
          "role": "x402 pubnet fee payer",
          "address": "GAFVDEN6BC52WWPRPINOVENMXW3FU4LCSVVVA5C67RLPG4GAK6BE4SXY",
          "network": "stellar",
          "custody": "ours: backend environment key",
          "usedFor": "Assembling, broadcasting and paying the network fee for pubnet x402 settlements since 2026-09-15. XLM only: no USDC, no trustline and no role on any vault.",
          "publishedAt": "2026-09-15",
          "explorerUrl": "https://stellar.expert/explorer/public/account/GAFVDEN6BC52WWPRPINOVENMXW3FU4LCSVVVA5C67RLPG4GAK6BE4SXY"
        }
      ],
      "live": {
        "reachable": true,
        "checkedAt": "2026-10-22T21:18:52.185Z",
        "blockNumber": "65083629",
        "contracts": [
          {
            "name": "AgentSpendPolicy (Soroban, pubnet)",
            "address": "CB5LYXFKKTKDDSCM6JO6C4GNRQUFBGSLYDET6Q56JNFJQSMBKH6KWSYP",
            "deployed": true
          },
          {
            "name": "USDC (Stellar Asset Contract, pubnet)",
            "address": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
            "deployed": true
          }
        ]
      }
    },
    {
      "chain": "stellar-testnet",
      "summary": "The first non-EVM rail here, and the only one where the spending limit is enforced by a contract before the payment exists. A Soroban spend policy holds the money, the agent asks it to pay, and the policy answers with a typed error or a transfer. Paid calls settle in SEP-41 USDC through the Soroban x402 facilitator we run ourselves, and every settlement is confirmed by reading the transfer event, whoever broadcast it.",
      "contracts": [
        {
          "name": "AgentSpendPolicy (Soroban)",
          "address": "CAIL6ECRAB5FUURQ54R7OTZPXRRCDO2S353YT6N6UZUWIBDG2ZOEB4UI",
          "note": "Ours, written in Rust for this chain rather than translated from the Solidity original: Soroban has no msg.sender, so the whole authorization surface collapses onto one require_auth line, and the test suite proves it would notice if that line went missing. Immutable by design, with no upgrade entrypoint."
        },
        {
          "name": "AgentSpendPolicy, passkey-owned (Soroban)",
          "address": "CBGTXWFBYAOZBR6EN3UK4PTLUAY6BRV2C36D3DPOTE5JSOLQXANS6J6U",
          "note": "Ours, and the same wasm as the vault above, byte for byte: instantiated against the code entry already on the ledger rather than uploaded again, which is the difference between about 0.1 XLM and about 12 XLM. What is new is the owner. It is not an account but a CONTRACT, the smart account below, so `owner.require_auth()` dispatches to that contract's `__check_auth` and a passkey signature is what satisfies it. A separate vault rather than a migration because the contract has `set_operator` and deliberately no `set_owner`: the owner is permanent, so proving a passkey can own a vault meant deploying one that a passkey owned from its first ledger. Policy 5 USDC a day, 1 USDC a payment, allowlist on. Recorded in soroban/releases/testnet-passkey-owner-2026-09-19.json. A rehearsal: every owner call it has received was signed by a software P-256 key in our own script, so it is not SOW 2 D3 evidence."
        },
        {
          "name": "OpenZeppelin smart account (third party)",
          "address": "CC5RNXNHKKPAHFP5YEOTZDFOQDQVC6AQKX3EH3W6QKFKGVBAXPVM3RWA",
          "note": "The instance is ours, the code is not. OpenZeppelin's Stellar smart account, deployed through the `smart-account-kit` npm package 0.8.0 (stellar/smart-account-kit, formerly kalepail) against account wasm hash 1b5f4534..., with OpenZeppelin's testnet WebAuthn verifier CC7EKIHQ... as its one signer's verifier. Both of those are third-party testnet deployments read out of the kit's deployment manifest, not built or verified by us. The kit says of itself that it is unaudited and that the contracts under it were audited at rc-v0.7.0 with a different scope; we repeat that rather than improve on it."
        },
        {
          "name": "USDC (Stellar Asset Contract)",
          "address": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
          "note": "Circle's testnet USDC as a SEP-41 contract. Derived with `stellar contract id asset` and matched against the literal rather than pasted, and read back live: the contract reports USDC with 7 decimals, which is what the registry declares. Seven, not the six every EVM USDC uses."
        }
      ],
      "artifacts": [
        {
          "kind": "bridge",
          "label": "CCTP inbound: 0.2 USDC burned on Arc testnet, minted here through the CctpForwarder in one call",
          "txHash": "32a09568d56bb0f0eeda54b6529f8756cc1e7e60e0bc235e914aec0898dd1fa2",
          "onChain": "stellar-testnet",
          "blockNumber": 4607724,
          "date": "2026-09-10",
          "deliverable": "self-funded",
          "note": "mint_and_forward(message, attestation) on Circle's CctpForwarder CA66Q2WF..., 2026-09-10, ledger 4607724. The recipient G... account rode in the hook data of the Arc burn (tx 0x09d6a77e, block 61433933) with the forwarder in both address slots, which is the only way a Stellar account can receive a CCTP mint; Iris attested in seconds and the whole leg took 16 s. Driven by mcp/src/cctp-stellar.ts, not Bridge Kit, which has no Stellar adapter."
        },
        {
          "kind": "bridge",
          "label": "CCTP outbound: 0.15 USDC burned here for the Arc testnet signer",
          "txHash": "b5766784c5409a877ae28039182824978dd306c147a30d469b7f3fdc204dd458",
          "onChain": "stellar-testnet",
          "blockNumber": 4607728,
          "date": "2026-09-10",
          "deliverable": "self-funded",
          "note": "deposit_for_burn on Circle's TokenMessengerMinter CDNG7HXA..., 2026-09-10, ledger 4607728, after a SAC approve with a 100-ledger expiry (tx ec96149d). Amount passed as 1500000 seven-decimal subunits for a 150000-unit message; the mint landed on Arc as receiveMessage tx 0x072be2ef (block 61434003) 21 s after the burn. The round trip closes the NEAR Intents caveat for test money: USDC now crosses between Stellar and an EVM chain natively."
        },
        {
          "kind": "deploy",
          "label": "The spend policy wasm, uploaded",
          "txHash": "242c4ec6291e31348c0dc6a92ab016aa042ca467eb522abc287d69e6a9e9e644",
          "onChain": "stellar-testnet",
          "blockNumber": 4147601,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The first of the two deploy transactions: an UploadContractWasm host function sourced by the owner account GBLHNAL5..., one ledger before the instance was created. Read off Horizon on 2026-10-02 (the account's transaction list and this transaction's operation). An earlier version of this ledger called the deploy one transaction and listed only the create below; soroban/releases/testnet-v0.1.0.json still omits this upload."
        },
        {
          "kind": "deploy",
          "label": "The spend policy, instantiated",
          "txHash": "718f050b962b6e645d8cca5cc053d9f1c11a7264d3ddc266f7e36661bd82c68c",
          "onChain": "stellar-testnet",
          "blockNumber": 4147602,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The second deploy transaction: CreateContractV2 against the code entry uploaded one ledger earlier, with the five constructor arguments. The wasm sha256 is 155eb31c1867254eacbf1b7a4755164d15cc6b6f939644705ab6b8df61579239, recorded in soroban/releases/testnet-v0.1.0.json and confirmed by Stellar Expert as the code this contract carries. The binary itself is deliberately not committed: Rust wasm is not bit-reproducible across machines by default, so shipping one would invite a reproducibility claim we cannot honour. Pull it with `stellar contract fetch` and compare."
        },
        {
          "kind": "settlement",
          "label": "An under-limit payment the policy allowed",
          "txHash": "3da7463422c7d122202b009bb27442199ffc3b6da87da12a7112963bf4bcc999",
          "onChain": "stellar-testnet",
          "blockNumber": 4147945,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The first half of the pair the SoW measures. The operator paid 1 USDC inside a 2 USDC per-payment ceiling and a 10 USDC daily cap; the payee went to 1.0000000, the vault from 15 to 14, and spent_today to 1 USDC."
        },
        {
          "kind": "settlement",
          "label": "An over-limit payment the policy refused, with a typed error",
          "txHash": "12df418f21d329f606f412b1aee498714f1178d68fd0db0a97c64f0de6f209d3",
          "onChain": "stellar-testnet",
          "blockNumber": 4147972,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The other half, and the one that took work to produce. On Soroban a refused call normally leaves NO transaction at all, because the contract says no during simulation and nothing is ever submitted. To get a hash a reviewer can open, the policy was tightened while this payment was in flight, so it failed at apply time and the ledger recorded error #5, DailyCapExceeded."
        },
        {
          "kind": "funding",
          "label": "15 USDC into the vault, through the SAC",
          "txHash": "bec1b68be5861fdf7cc71b50ce7c8a5b5cb311326a240ca8e1f6a6af99e2a400",
          "onChain": "stellar-testnet",
          "blockNumber": 4147942,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The vault holds the token in contract storage rather than through a trustline, so it needs none. Both classic accounts do, and that is easy to learn the hard way: paying an account with no USDC trustline fails with op_no_trust, which a buyer reads as our bug."
        },
        {
          "kind": "settlement",
          "label": "A gasless x402 purchase: the buyer signed, we paid the fee",
          "txHash": "6d87799242b9fb36a26ac6f2d2fb11c5e7fb8bdd52bc6cf0471dcc8a8caba09c",
          "onChain": "stellar-testnet",
          "blockNumber": 4149194,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "A buyer agent answered a 402 with a signed Soroban authorization entry and got the tool back. Horizon records the fee as charged to our operator account, not to the buyer, which is the gasless claim as a number somebody else can look up."
        },
        {
          "kind": "owner-action",
          "label": "The owner freezes the vault, and the agent stops",
          "txHash": "fd0fb958923c5e5e70bedae6451cc9a492b250d3cec3750313814b7e4ccdf117",
          "onChain": "stellar-testnet",
          "blockNumber": 4259182,
          "date": "2026-08-21",
          "deliverable": "SOW1",
          "note": "Signed by the owner account GBLHNAL5..., whose key is ours, in a local CLI keystore: this vault was never meant to show an owner we do not hold. The kill switch, exercised rather than described. With the vault frozen the operator's next payment was refused with error #1, Frozen. That refusal has no hash of its own, for the reason every Soroban refusal here has none: the contract answers during simulation and nothing is submitted."
        },
        {
          "kind": "owner-action",
          "label": "The owner overrides: a payment past the freeze AND past the allowlist",
          "txHash": "f05c2f5be029d7403c6241c85f894160fe83f5866f1993de6ba1c3be7911b3eb",
          "onChain": "stellar-testnet",
          "blockNumber": 4259183,
          "date": "2026-08-21",
          "deliverable": "SOW1",
          "note": "owner_pay to an account that is NOT on the allowlist while the vault is frozen. It settles, because the human path is meant to work exactly when the agent path does not. It was still CHARGED to the daily cap, which is the Solidity original's behaviour ported deliberately. Note the exact claim, because an earlier version of this note overstated it: owner_pay increments the day accumulator, but it is not LIMITED by the cap. `check_owner_pay` in policy.rs runs the amount, arithmetic and balance guards and no cap comparison, so the override bypasses the budget as well as the gates. What it does not bypass is the accounting: the outflow is recorded."
        },
        {
          "kind": "owner-action",
          "label": "The owner unfreezes, and the agent spends again",
          "txHash": "e92fcd5ff1c02b812419891da8a8c915d1d67e5f6d97d1d4da12f516bb227115",
          "onChain": "stellar-testnet",
          "blockNumber": 4259184,
          "date": "2026-08-21",
          "deliverable": "SOW1",
          "note": "The other half of a kill switch is that it turns back off. A freeze you cannot lift is a loss, not a control."
        },
        {
          "kind": "settlement",
          "label": "The same purchase through the on-chain policy",
          "txHash": "fab5c864939da4165c21384afb24d690662c58ec17d46e36f7bc35ddf60b321f",
          "onChain": "stellar-testnet",
          "blockNumber": 4149294,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The agent paid from the vault instead of from a wallet, so the allowlist, the ceiling and the daily cap all ran on chain before the transaction existed. The same call to an unlisted payee was refused by the contract with error #3, PayeeNotAllowed, and produced no transaction at all, which is why that refusal has no hash here. The passkey vault below does have one, for a reason its own note gives."
        },
        {
          "kind": "deploy",
          "label": "Rehearsal: a passkey smart account, deployed as an owner that is not a key",
          "txHash": "dcd3c4227b0a773bf3d825a8fb0c5d37196b9cb7366377bf8a2c76162d3d914c",
          "onChain": "stellar-testnet",
          "blockNumber": 4760408,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "OpenZeppelin's Stellar smart account, deployed through smart-account-kit 0.8.0 with one WebAuthn P-256 signer and no recovery signer. Third-party code, our instance. The \"passkey\" was a SOFTWARE P-256 key generated inside our own script (mcp/scripts/stellar-passkey-proof.mjs), standing in for a platform authenticator: the same verifier contract and the same WebAuthn signature format, but the private key lived in a process of ours, not on anyone's device. Fee paid by our dedicated testnet deployer GDNRET2G... over direct RPC."
        },
        {
          "kind": "deploy",
          "label": "Rehearsal: a second spend vault, owned by that smart account from its first ledger",
          "txHash": "ccac0b30612a216deea7d84035cac3e3acbb5884c827f60065ed33ff61729fd2",
          "onChain": "stellar-testnet",
          "blockNumber": 4760409,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "The same wasm 155eb31c..., instantiated against the existing code entry with no upload, with the smart account as owner and our usual testnet operator as operator, which also paid the fee. The daily cap is 5 USDC and the per-payment ceiling 1 USDC. The vault above keeps its plain account owner, because there is no `set_owner` to move it."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: set_policy signed by a software P-256 key, and the vault accepts it",
          "txHash": "994b5cb92c5dee9ce733109e9b7cecd35625aeb3b3edc35903a22cc93a0dd758",
          "onChain": "stellar-testnet",
          "blockNumber": 4760411,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "set_policy(5 USDC, 1 USDC, allowlist on), delivered through the smart account's `execute`. The chain of custody on the ledger: a P-256 signature over the authorization digest, verified by OpenZeppelin's WebAuthn verifier in the account's `__check_auth`, which satisfies the vault's `owner.require_auth()`. The signature came from a software key in our own script and the fee from our deployer GDNRET2G..., so this proves the contract path and does NOT prove that a key outside our systems authorized anything."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: the software key allowlists a payee, which is what a KYA ALLOW writes",
          "txHash": "e371b1b38cb1f31aca91709d7ace18fe974f5673a8eafc00012df442dc15ef47",
          "onChain": "stellar-testnet",
          "blockNumber": 4760413,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "Signed by the same software P-256 key, fee paid by our deployer. The on-chain allowlist is binary and the KYA verdict has three states, so the mapping is stated rather than implied: ALLOW writes set_allowed(payee, true), WARN is a server-side flag that writes nothing on chain, and DENY writes set_allowed(payee, false). WARN never reaches the ledger, and nothing here should be read as if it did."
        },
        {
          "kind": "funding",
          "label": "Rehearsal: 3 USDC into the passkey vault, through the SAC",
          "txHash": "b84b70de3a087a316bf2267c9bdccb9c191fd9be1ac5b0a741bdbd73aa238faf",
          "onChain": "stellar-testnet",
          "blockNumber": 4760414,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "A plain SEP-41 transfer into contract storage, so this vault needs no trustline either. Sent from the older vault's owner account, which is the only role these two deployments share."
        },
        {
          "kind": "settlement",
          "label": "Rehearsal: the agent pays an allowed payee under a policy the software key set",
          "txHash": "bf375df0b03b7e4a9644676cd4d157df0fe4c4139d870ec2706fcdbe56fb7e4f",
          "onChain": "stellar-testnet",
          "blockNumber": 4760415,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "0.5 USDC, inside the 1 USDC ceiling and the 5 USDC daily cap, to the payee the owner allowed. The vault went to 2.5 USDC and spent_today to 0.5. The operator key that paid is ours and can spend only inside these limits."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: the owner allows an untrusted payee, on purpose, to arm the race",
          "txHash": "b7ea4c33b19b487b6ee2aadcd6e5486b9917d08325a0e8444e2ac7c643707c33",
          "onChain": "stellar-testnet",
          "blockNumber": 4760419,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "Signed by the software P-256 key, fee paid by our deployer. The payee here is a fresh account nobody has vouched for. Asked to pay it before this, the vault refused in simulation with error #3 and no transaction was ever created, which is the normal and unlinkable shape of a Soroban refusal. Allowing it is step one of forcing a refusal that a reviewer can open."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: the owner revokes while the agent's payment is already signed",
          "txHash": "9a3aece13d12279be23864a8131b0cf96d18801bd6eb01e966b74f330d22ca88",
          "onChain": "stellar-testnet",
          "blockNumber": 4760420,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "set_allowed(payee, false), signed by the software P-256 key, which is what a KYA DENY writes. The agent had already simulated, built and signed its payment and was holding it. This is not a contrivance: it is the race a real agent hits when a human, or a KYA verdict, changes the allowlist mid-flight."
        },
        {
          "kind": "settlement",
          "label": "Rehearsal: the held payment lands and the contract refuses it on chain",
          "txHash": "22b33018c807946df066365bde2a72293372bf7768ab96688acb623c290357a0",
          "onChain": "stellar-testnet",
          "blockNumber": 4760421,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "Included in the ledger and refused by the contract: Horizon reports it unsuccessful with the fee charged, and the result carries Error(Contract, #3), PayeeNotAllowed. spent_today stayed at 0.5 USDC and is_allowed read false afterwards, so the revoke cost the agent its fee and nothing else. This is the one refusal on this network with a hash a reviewer can open, and it exists only because the policy was tightened between build and apply."
        },
        {
          "kind": "deploy",
          "label": "Rehearsal, sponsored: a smart account deployed with its fee paid by OpenZeppelin Channels",
          "txHash": "9df1bbb1d29e623bcdce1dc8919f0f8add4941e148e390d789d80a755b795b32",
          "onChain": "stellar-testnet",
          "blockNumber": 4764131,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "The artifacts above were paid by our own testnet deployer over direct RPC, which proved the contract path and not the fee path the public /stellar page uses. This run exercised that fee path, and it was OUR run, not a visitor's: our own script drove the smart-account kit, which posted { func, auth } to our relay; the relay decoded the XDR, refused everything outside the three shapes it allows, and forwarded the rest to OpenZeppelin Channels, whose channel account supplied the source and sequence while a Channels account (GCNJB6V5..., read off Horizon as this transaction's fee account) paid the fee. The P-256 key was again a software key in our process."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, sponsored: set_policy signed by a software key, fee paid by Channels",
          "txHash": "fb2b59a05f5f5988d5ec0e625212d7af8e6c5067a945c9544e146f5180c5982e",
          "onChain": "stellar-testnet",
          "blockNumber": 4764136,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "set_policy on a second vault (CCV2MMK4WFJJVYITOWAH6Z3OW5RW7MYOYB3WGOZJ54NEL4PIJHV3KA7T), sponsored through the same relay. What this shows is that an owner call can land with the fee paid by a third party and no XLM in the owner's hands. What it does not show is a person holding the key: the signer was a software P-256 key in our own run."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, sponsored: the owner overrides a DENY, and the override is itself on chain",
          "txHash": "6b083e8340d8585aa800b022bba843c74e03547ee4cf360243029b8a81c0b86a",
          "onChain": "stellar-testnet",
          "blockNumber": 4764142,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "risk_check answered DENY for this payee, correctly: the agent id it was given did not resolve to an on-chain identity, so there was no reputation or tenure to score. The owner allowed it anyway, which the /stellar page offers as its own button; in this run the \"owner\" pressing it was our own script with a software key. Worth stating plainly because it cuts against the pitch: the guardrail is a bound on the AGENT, not on the owner, and an owner who overrides it leaves an owner-signed transaction behind rather than a silent exception."
        },
        {
          "kind": "settlement",
          "label": "Rehearsal, sponsored: one payment allowed, one refused",
          "txHash": "8590694194da891361734f541042870e1a297f829a0fc701c82b988c34a23410",
          "onChain": "stellar-testnet",
          "blockNumber": 4764146,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "0.05 USDC to the allowed payee, paid by our operator, settled. The same call to the payee the owner had revoked at ledger 4764144 answered contract error #3, PayeeNotAllowed, in simulation, so it has no hash of its own. That pairing, a settlement and a typed refusal under a policy an owner call set, is the 90-second demonstration the /stellar page rehearses."
        },
        {
          "kind": "owner-action",
          "label": "The flagship vault's owner withdraws 5 test USDC to our operator",
          "txHash": "9536bd1a7fefcb516c9dc67ed71f304a9f9a86362e5401836143cbd09c7ef0b3",
          "onChain": "stellar-testnet",
          "blockNumber": 4760510,
          "date": "2026-09-19",
          "deliverable": "self-funded",
          "note": "withdraw(GDZXSO4A..., 5 USDC) on CAIL6ECR..., sourced, paid and signed by the owner GBLHNAL5..., a key of ours in a local CLI keystore: test money moved between two of our own accounts. Recorded on 2026-10-03, when a ledger read showed the vault at 8.988 USDC rather than the 13.988 read on 2026-09-16. It is the last owner or operator transaction on this vault, read off Horizon on 2026-10-03."
        },
        {
          "kind": "deploy",
          "label": "The v0.1.1 vault code, uploaded: the A3-02 fix every SoW 2 vault runs",
          "txHash": "09d041ab3c0dbae95b902b0c22be8f6587f43542798701db98a09df948119e02",
          "onChain": "stellar-testnet",
          "blockNumber": 4974389,
          "date": "2026-10-01",
          "deliverable": "SOW2-D2",
          "note": "UploadContractWasm for sha256 353e4264..., 11605 bytes, the v0.1.1 build in which settle checks the amount before the payee (finding A3-02), sourced by our deployer GDNRET2G.... Uploading code creates no vault: the D2 and D3 vaults are instantiated against this code entry, and the flagship testnet vault stays on v0.1.0 because a vault cannot change its code."
        },
        {
          "kind": "deploy",
          "label": "Our WebAuthn verifier instance, OpenZeppelin v0.7.2 code",
          "txHash": "8c6894a8bc0ee1aa8168a49f1de0c4dbdc7f7bf3e86b731277754b81d8242005",
          "onChain": "stellar-testnet",
          "blockNumber": 4974910,
          "date": "2026-10-01",
          "deliverable": "SOW2-D3",
          "note": "Instance CABPDJH4... of wasm e63a030d..., which we built from OpenZeppelin/stellar-contracts v0.7.2 (soroban/third-party/openzeppelin-smart-account). It is the verifier every D3 passkey signature passes through. The code is OpenZeppelin's and was already on testnet; this instance is ours, with a salt derived from the source commit."
        },
        {
          "kind": "deploy",
          "label": "Our Ed25519 verifier instance, OpenZeppelin v0.7.2 code",
          "txHash": "33642444e71dbda544e61e728019ac728d10a38f9ebfce65ed955bf29fb06a4b",
          "onChain": "stellar-testnet",
          "blockNumber": 4974913,
          "date": "2026-10-01",
          "deliverable": "SOW2-D3",
          "note": "Instance CCKPFIAA... of wasm 60e8798d..., built the same way. The smart-account kit requires an Ed25519 verifier in its configuration; a D3 passkey wallet has no Ed25519 signer, and the vault deploy refuses an owner account that carries one."
        },
        {
          "kind": "deploy",
          "label": "The v0.1.1 vault code, its rent extended past the 2026-12-16 testnet reset",
          "txHash": "5106db1d74522efa9b5b89d7db9d672ebd204b1ed74a78b4ab45e668e55d21ea",
          "onChain": "stellar-testnet",
          "blockNumber": 4981800,
          "date": "2026-10-02",
          "deliverable": "SOW2-D2",
          "note": "A newly uploaded code entry gets the network minimum TTL, about seven days, and every SoW 2 vault instantiates against this one, so it was extended to ledger 6281800 by our deployer GDNRET2G... before any vault needed it."
        },
        {
          "kind": "funding",
          "label": "The D2 owner account, created by Friendbot rather than by any account of ours",
          "txHash": "ebd666aacdbcbee7ebcf1723c4c29b86f4449134b7d0be86495edd213c5ba69d",
          "onChain": "stellar-testnet",
          "blockNumber": 5000410,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "GDIZE6XJ... was generated inside Freighter by the user and did not exist on the testnet ledger until the public testnet Friendbot (source GCG75HSV..., not ours) created and funded it with test XLM. That is the account that sources, pays for and signs the D2 owner actions."
        },
        {
          "kind": "deploy",
          "label": "The D2 vault, deployed from v0.1.1, owner = a key generated inside Freighter",
          "txHash": "c57f0bf6ba1dad27d23a42612cd11a396fc0af08957b2353ff80a36fe64768c0",
          "onChain": "stellar-testnet",
          "blockNumber": 5001000,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "Vault CDEU2D4T... instantiated against the v0.1.1 code entry 353e4264... with a recorded salt (soroban/releases/stellar-testnet-v0.1.1-2026-10-03.json), sourced and paid by our deployer GDNRET2G.... Constructor: owner GDIZE6XJ..., operator GAFVKKMD..., daily cap 5 USDC, auto-approve 1 USDC. owner(), operator() and the code hash were read back from the ledger after the deploy. The deployer cannot act on the vault: only the owner can call set_policy, set_frozen and withdraw."
        },
        {
          "kind": "funding",
          "label": "The D2 vault funded with 1 test USDC",
          "txHash": "4c715d7b34d59a2479098ded4f8b542d094de96a12974fcbd80ab3e9014c2221",
          "onChain": "stellar-testnet",
          "blockNumber": 5001017,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "A plain SAC transfer from GBLHNAL5... (ours) to the vault; it is not an owner action and it touches no other vault. The vault read its balance back as 1 USDC."
        },
        {
          "kind": "owner-action",
          "label": "The D2 owner freezes its vault from the panel, signed in Freighter",
          "txHash": "60a7dd67cf5c999a74129a7201289402b51373d481e79b1e979273ff4abb4c6e",
          "onChain": "stellar-testnet",
          "blockNumber": 5006288,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "set_frozen(true) on CDEU2D4T..., the first owner action on this vault, landed 19:17:07 UTC. GDIZE6XJ... is the transaction source and the fee payer (0.0007196 XLM), its signature is the only one on the envelope, and the authorization entry is a source-account credential: the wallet signature over the whole transaction is the authorization, and nothing our backend holds could produce it. Our backend built and simulated the unsigned call for the signed-in session; Freighter showed the owner account, the network and the call before the user approved it."
        },
        {
          "kind": "owner-action",
          "label": "The D2 owner withdraws 0.5 test USDC to its own account, signed in Freighter",
          "txHash": "b59f6ed844c511d6e4fce4f8385235da6a009dcc0ca6dcb424891b10f9eb61c4",
          "onChain": "stellar-testnet",
          "blockNumber": 5006299,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "withdraw(GDIZE6XJ..., 5000000) on CDEU2D4T..., 0.5 test USDC at seven decimals, landed 19:18:02 UTC while the vault was frozen: the freeze stops the agent, not the owner. Same shape as the freeze: GDIZE6XJ... sources it, pays the fee (0.0014252 XLM) and signs the whole transaction in Freighter, after the panel restated the amount, the destination and the vault on a review screen. Read back afterwards: the vault frozen with 0.5 USDC, the owner account holding 0.5 USDC."
        },
        {
          "kind": "deploy",
          "label": "The D3 smart account, created from the owner's device passkey on the production site",
          "txHash": "5af017bda75de876508400dc9e973467608a151d49d402d9cb0df662fac3ff9b",
          "onChain": "stellar-testnet",
          "blockNumber": 5019008,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "Smart account CBII2K5R... on the account wasm a12747ff... (our OpenZeppelin v0.7.2 build), created at 12:57:07 UTC when the owner made a passkey on /stellar?network=testnet in a browser. Read back off the ledger: one context rule (Default, no policy, no expiry) holding exactly one signer, External under the WebAuthn verifier CABPDJH4... with the device public key 04560be2...; no Ed25519 and no Delegated signer. The page reported a platform passkey synced in Apple Passwords (backup eligible, backed up, user verified); that report is the browser's, not the ledger's. The kit posted the deploy to our relay, which forwarded it to OpenZeppelin Channels: a Channels channel account sourced it and the Channels account GCNJB6V5... paid the fee."
        },
        {
          "kind": "deploy",
          "label": "The D3 vault, deployed from v0.1.1, owner = that smart account",
          "txHash": "fa1080f6787f82bf3ca2b9c41828cd2ee16ee20bb78ee65818cdad5801f82c38",
          "onChain": "stellar-testnet",
          "blockNumber": 5019022,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "Vault CCTYM23I... on the v0.1.1 code 353e4264..., deployed at 12:58:17 UTC by POST /api/stellar/passkey/vault/deploy after the route read the smart account's code and its one passkey signer off the ledger. Sourced and paid (0.6559942 XLM) by GDZXSO4A..., which is the vault's operator and cannot call an owner entrypoint. Constructor: owner CBII2K5R..., daily cap 10 USDC, auto-approve 2 USDC. owner(), operator() and the code hash were read back from the ledger after the deploy."
        },
        {
          "kind": "funding",
          "label": "The D3 vault seeded with 0.2 test USDC",
          "txHash": "62dc830950ba3322019c928fa35a47a509bac886a52c4a316cb31666236bbf10",
          "onChain": "stellar-testnet",
          "blockNumber": 5019023,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "A plain SAC transfer of 0.2 test USDC from GDZXSO4A... into CCTYM23I..., made by the same deploy route at 12:58:22 UTC; it is not an owner action. The vault read its balance back as 0.2 USDC."
        },
        {
          "kind": "owner-action",
          "label": "The D3 owner freezes its vault with the device passkey, from the page",
          "txHash": "2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6",
          "onChain": "stellar-testnet",
          "blockNumber": 5019748,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "set_frozen(true) on CCTYM23I..., the first owner action on this vault, landed 13:58:47 UTC, called through execute on the smart account CBII2K5R.... Decoded off the ledger (archive soroban/releases/tx-archive/stellar-testnet/2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6.json): the one authorization entry is an address credential for the smart account, signed by a webauthn-secp256r1 signer under the WebAuthn verifier CABPDJH4... with the device public key 04560be2..., on context rule 0; flags UP, UV, BE and BS; the origin is the a-identity.xyz site; the challenge is the authorization digest and the signature re-verifies. A Channels channel account sourced it and the Channels account GCNJB6V5... paid the fee (0.1048712 XLM) through a fee bump; the smart account paid nothing. The owner approved it with Touch ID in a recorded browser session. The chain itself cannot tell a device authenticator from a software key; the recording and the enrolment are what show the device."
        },
        {
          "kind": "deploy",
          "label": "Rehearsal, v0.7.2: a smart account on our own OpenZeppelin build, deployed through our relay",
          "txHash": "ac287daf11b3b9bd8219d57582dc92c0dada49bf3474a8f7ecbe00ef57873027",
          "onChain": "stellar-testnet",
          "blockNumber": 5001527,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "Smart account CD5WPJ5O..., the first instance of the account wasm a12747ff... we built from OpenZeppelin v0.7.2, with one WebAuthn signer under our verifier CABPDJH4.... The kit was configured as the /stellar page configures it and posted { func, auth } to our relay, which forwarded it to OpenZeppelin Channels; Channels sourced it and its account GCNJB6V5... paid the fee. The \"passkey\" was a software P-256 key in our own script, so this proves the path, not a device."
        },
        {
          "kind": "deploy",
          "label": "Rehearsal, v0.7.2: a v0.1.1 vault owned by that smart account, from the deploy route",
          "txHash": "d5b44ad8c0abdfce90f1a3f3aaf2903dd26b4a26e9be5cd6bf5c458d4e7b0b40",
          "onChain": "stellar-testnet",
          "blockNumber": 5001529,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "Vault CCFQEMTY... on the v0.1.1 code 353e4264..., deployed by POST /api/stellar/passkey/vault/deploy after the route read the smart account's code and its one passkey signer off the ledger. Sourced and paid by our operator GDZXSO4A..., which is also its operator; daily cap 10 USDC, ceiling 2 USDC."
        },
        {
          "kind": "funding",
          "label": "Rehearsal, v0.7.2: 0.2 test USDC seeded by the deploy route",
          "txHash": "66433fb8251b2213147dce36c1c49dbba7b64188def7ec4cde3601c5615ded3d",
          "onChain": "stellar-testnet",
          "blockNumber": 5001530,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "A SAC transfer from our operator into the new vault, so the agent has something to pay with. Every unit of it came back to the operator by the end of the run (one agent payment and two withdrawals)."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: set_policy signed by a software key through our verifier",
          "txHash": "68971bde0327080686e76bff3a8df01ddef90162de19d255782ebc6fb9d7913f",
          "onChain": "stellar-testnet",
          "blockNumber": 5001532,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "set_policy(10 USDC, 2 USDC, allowlist on) through the account's execute, relayed and fee-bumped by Channels. Decoded off the ledger: a webauthn-secp256r1 signer under CABPDJH4..., bound to context rule 0, its challenge the entry's auth digest and its signature re-verifying. A software key signed it."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: set_allowed for the payee, signed by the software key",
          "txHash": "5d78975e422627055438e06477c3476054b9fd35973e2de7d2beb890ccbd1bd7",
          "onChain": "stellar-testnet",
          "blockNumber": 5001535,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "The payee was our operator account, which holds a USDC trustline, so the run needed no second funded account. Relayed and fee-bumped by Channels."
        },
        {
          "kind": "settlement",
          "label": "Rehearsal, v0.7.2: the agent pays the allowed payee, through the agent-pay route",
          "txHash": "40753e65ed63e31c2583a06e628cda91bd11513b3fa72975c38b2ba3267f55fb",
          "onChain": "stellar-testnet",
          "blockNumber": 5001538,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "0.1 USDC by POST /api/stellar/passkey/agent-pay, signed and paid by our operator inside the policy. The same call to a payee nobody allowed was refused with PayeeNotAllowed (#3) in simulation, so that refusal has no hash."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: the software key freezes the vault, and the agent stops",
          "txHash": "6176ed231dc5f3442eba125ba8143bb27fc3057fd81849c61b0899297b0057e3",
          "onChain": "stellar-testnet",
          "blockNumber": 5001540,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "set_frozen(true), the button the D3 recording will press. With the vault frozen, agent-pay was refused with Frozen (#1) in simulation, so that refusal has no hash. Relayed and fee-bumped by Channels; signed by a software key."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: the software key unfreezes the vault",
          "txHash": "ac4a2f8f0fc4c198924cf2caf2c08d4818408ce5a7bb525f0a0422228eda8019",
          "onChain": "stellar-testnet",
          "blockNumber": 5001543,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "set_frozen(false), read back as not frozen right after."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: withdraw to a G account, its trustline checked first",
          "txHash": "d946a1ff310281e2e79ba8017af4b2ee5c5f9cc744ce5e8f4994015126bc4a2c",
          "onChain": "stellar-testnet",
          "blockNumber": 5001545,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "withdraw(GDZXSO4A..., 0.05 USDC), after Horizon confirmed the destination holds an authorized USDC trustline; the destination's balance rose by exactly 0.05. Signed by the software key under rule 0, relayed and fee-bumped by Channels."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: a second passkey added as its own context rule, never rule 0",
          "txHash": "b57f931d874bb4d53ed8ec1d8e52bd53cfb2e7f1e1ede026989c0467d0cc85aa",
          "onChain": "stellar-testnet",
          "blockNumber": 5001548,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "add_context_rule on the smart account itself: a Default rule, id 1, holding one new WebAuthn signer under CABPDJH4... and no policy, approved by the first passkey, the way the page's \"Add another device\" builds it. Read back afterwards: rule 0 still holds the first passkey alone and rule 1 the second alone, so either can act. An action on the account, not on the vault; both keys were software keys."
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: signed in with the second passkey alone, it withdraws the rest",
          "txHash": "741ad16c32d84dfe226eb25a4c0571665ac8c815fbe0bb8de77fb6b38c1bae16",
          "onChain": "stellar-testnet",
          "blockNumber": 5001551,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "After signing out and back in with the second credential, withdraw(GDZXSO4A..., 0.05 USDC) emptied the vault. Decoded off the ledger: the webauthn-secp256r1 signature is bound to context rule 1, so the second device authorized it on its own. What the recovery page promises for a second device, shown on the contract path with software keys; a device enrolment is still to be shown."
        }
      ],
      "accounts": [
        {
          "role": "Operator of the flagship testnet vault CAIL6ECR..., the x402 testnet fee payer, and since 2026-10-03 the hosted backend's testnet signer",
          "address": "GDZXSO4AOKPSHMQZMBNEEBQNYOIF7TWDPD7K2U5VAPKFN3QIAIELTAN6",
          "network": "stellar-testnet",
          "custody": "ours: backend environment key",
          "usedFor": "pay() inside the vault policy (it can never call an owner entrypoint), broadcasting and paying the fee for every testnet x402 settlement, and the operator of the 2026-09-19 rehearsal vaults and of the 2026-10-03 rehearsal vaults CCFQEMTY... and CDE5P5QX..., which it deployed and seeded. Since 2026-10-03 it is also the testnet signer of the hosted backend, set on Render by the maintainer: it deploys, seeds and operates every vault /stellar?network=testnet creates, the SoW 2 D3 vault CCTYM23I... among them, which it deployed and seeded on 2026-10-04, and it can never sign that vault's owner calls, which only the owner's passkey can. One key in several roles on testnet, which mcp/scripts/stellar-key-roles.mjs reports as a warning.",
          "publishedAt": "2026-08-15"
        },
        {
          "role": "Owner of the flagship testnet vault CAIL6ECR...",
          "address": "GBLHNAL57WLA5GKTIGPBHCJTQDNEZFX2CVH53EDUOGWIERNKECRENHQ5",
          "network": "stellar-testnet",
          "custody": "ours: local CLI keystore",
          "usedFor": "The vault's deploy (upload and create), its funding, and every owner action on it: set_policy, set_allowed, set_frozen, owner_pay and, on 2026-09-19, a withdraw of 5 test USDC to our operator GDZXSO4A.... Permanent, because the contract has no set_owner. It also funded the 2026-09-19 rehearsal vault and, on 2026-10-03, the SoW 2 D2 vault CDEU2D4T... with 1 test USDC: a token transfer, not an owner action on either.",
          "publishedAt": "2026-08-15"
        },
        {
          "role": "Deployer and fee payer of the 2026-09-19 passkey rehearsal",
          "address": "GDNRET2G5WNC25QQ43ODLGAZ42X74DQDGRHWHSLKC6FCVF7C6JYLHAJA",
          "network": "stellar-testnet",
          "custody": "ours: local CLI keystore",
          "usedFor": "Paid the fee for the rehearsal smart account deploy and for every software-key owner call in the first 2026-09-19 run, over direct RPC. On 2026-10-01 it uploaded the v0.1.1 vault code and deployed our own OpenZeppelin verifier instances; on 2026-10-02 it extended the v0.1.1 code entry, and on 2026-10-03 it deployed the SoW 2 D2 vault CDEU2D4T.... It holds no vault role and cannot authorize an owner call; it only sources and pays for transactions.",
          "publishedAt": "2026-09-19"
        },
        {
          "role": "OpenZeppelin Channels fee-bump account in the 2026-09-19 sponsored rehearsal",
          "address": "GCNJB6V5YIODDSSCWXZ2VOKMRPRVZ2V723RRQS6STXE6NWTGVOJY35CN",
          "network": "stellar-testnet",
          "custody": "third party: OpenZeppelin Channels",
          "usedFor": "Fee-bumped the four owner-side transactions of the sponsored rehearsal run (ledgers 4764131, 4764136, 4764142 and 4764144), relayed through our endpoint with our API key, and the eight owner-side transactions of the 2026-10-03 rehearsal on our v0.7.2 build (ledgers 5001527 to 5001551). On 2026-10-04 it fee-bumped the deploy of the SoW 2 D3 smart account CBII2K5R... (ledger 5019008), the owner's own passkey enrolment relayed through our endpoint. We do not hold its key. Read off Horizon as the fee_account of those transactions and recorded in soroban/releases/testnet-passkey-owner-2026-09-19.json, testnet-passkey-rehearsal-v072-2026-10-03.json and testnet-passkey-d3-2026-10-04.json.",
          "publishedAt": "2026-10-02"
        },
        {
          "role": "Owner of the SoW 2 D2 vault CDEU2D4T...",
          "address": "GDIZE6XJ36EDO4G2G674DCHMNRQLHOQN3JH7EZDBIQENOJABPSYL44EQ",
          "network": "stellar-testnet",
          "custody": "owner: generated inside a browser wallet, secret never on our systems",
          "usedFor": "set_policy, set_frozen and withdraw on the D2 vault, each in a transaction this account sources, pays for and signs whole in Freighter. The key was generated inside Freighter by the user; the public Friendbot created its testnet account, and the account added its testnet USDC trustline itself in Freighter on 2026-10-03 (tx 870cf65d...). Published here on the day the vault was deployed and before its first owner action, the freeze 60a7dd67... later that day, followed by the withdraw b59f6ed8....",
          "publishedAt": "2026-10-03"
        },
        {
          "role": "Operator (agent key) of the SoW 2 D2 vault CDEU2D4T...",
          "address": "GAFVKKMDZKMV7GTODASFCS222QEUGKTFXOH5XXGIJN2ZCYVRZCKQCWZ2",
          "network": "stellar-testnet",
          "custody": "ours: local CLI keystore",
          "usedFor": "pay() inside the D2 vault policy and nothing else: it can never call an owner entrypoint. The public Friendbot created the account on 2026-10-03 (tx 02290d96..., test XLM only) so its explorer page resolves; it has never called pay() and is not used during the SoW 2 sprint.",
          "publishedAt": "2026-10-03"
        },
        {
          "role": "Owner of the SoW 2 D3 vault CCTYM23I...: an OpenZeppelin smart account behind a device passkey",
          "address": "CBII2K5RHXA7QTBXXUG6O3EMR25NOVOL73KMVGWKWGH7PHO7QXDTHMUD",
          "network": "stellar-testnet",
          "custody": "owner: passkey smart account",
          "usedFor": "set_policy, set_frozen and withdraw on the D3 vault, each authorized only by a WebAuthn signature from the passkey the owner created on 2026-10-04 in a browser on the production site: the account's one signer, on rule 0, under the WebAuthn verifier CABPDJH4.... It holds no XLM and pays no fee; a relayer or the vault operator pays, and the page names which. Published here on the day the vault was deployed and before its first owner action, the freeze 2d4cb917... later that day. Read on 2026-10-11 at testnet ledger 5143315: still one context rule holding one signer, so the second device the owner tried to add on 2026-10-04 never reached the ledger. At ledger 5143331 the account's own instance entry had outlived its rent and was archived (the vault's is not): a simulated read marks it for restoration, which the ledger performs inside the next transaction that touches it, at that transaction's fee payer's cost.",
          "publishedAt": "2026-10-04"
        }
      ],
      "caveats": [
        "Test money. This is the rehearsal rail: every number on this network is test USDC and none of it is worth anything. It used to add that nothing of value had moved on Stellar mainnet, which stopped being true on 2026-08-24 when the same vault was deployed to pubnet and a real USDC budget was spent through it. That network has its own section on this page, with its own caveats.",
        "No identity. ERC-8004 is EVM-only and no Soroban identity registry exists to point at, so a Stellar agent's passport is bridged from an EVM chain rather than anchored here. KYA cannot be verified on this chain.",
        "Not audited. The contract has been reviewed with the free tooling we could actually run, named, with output committed, plus an adversarial review that found and fixed real defects. That is not an audit and we will not call it one.",
        "No vault here has a second owner. The flagship vault and the SoW 2 D2 vault are each owned by a single key, not a multisig; the two 2026-09-19 rehearsal vaults (CBGTXWFB... and CCV2MMK4...) and the SoW 2 D3 vault are each owned by a smart account with a single WebAuthn signer and no recovery signer, which moves the failure from a lost key to a lost passkey without reducing it. Only the two 2026-10-03 rehearsal accounts, run with software keys, carry a second signer, each on its own rule. The D3 owner tried to add a second device on 2026-10-04 and it did not reach the ledger: read on 2026-10-11, its account still holds one context rule with one signer. In every case the owner is permanent, because the contract has `set_operator` and deliberately no `set_owner`, so losing it makes the balance unrecoverable. That is a deliberate trade against a capped balance, written up in soroban/README.md rather than discovered, and on the passkey side the mitigation that was NOT applied is adding a recovery signer to the smart account.",
        "The 2026-09-19 passkey runs are a rehearsal, not SOW 2 D3 evidence. Both runs were driven by our own script, and the P-256 key that signed every owner call in them was generated in that process rather than held by a platform authenticator on anyone's device: same verifier, same signature format, custody ours. No passkey-owned vault exists on pubnet. Two fee payers appear above and they are separate claims: the first run was paid by our dedicated testnet deployer GDNRET2G... over direct RPC; in the second, the four owner-side transactions at ledgers 4764131 to 4764144 were sourced by OpenZeppelin Channels channel accounts and fee-bumped by the Channels account GCNJB6V5... through our own relay, while the vault deploy at 4764133 and the agent payment at 4764146 were sourced and paid by our operator. Full record and caveats in soroban/releases/testnet-passkey-owner-2026-09-19.json.",
        "Until 2026-10-03 every owner action on this network was signed by a key we hold: the flagship vault's owner GBLHNAL5... is ours, in a local CLI keystore, and the passkey vaults' owner calls, the 2026-10-03 rehearsal on our v0.7.2 build included, came from software keys in our script. Owner actions signed inside a wallet or on a device we do not control are what SOW 2 D2 and D3 added, and three are recorded above: the D2 owner's freeze and withdraw, signed in Freighter on 2026-10-03, and the D3 owner's freeze, signed with a device passkey on 2026-10-04. Read on 2026-10-11 at testnet ledger 5143290, neither vault's state has changed since: both are still frozen, holding 0.5 and 0.2 test USDC.",
        "On the `settled` scheme, where an agent pays from the vault and hands us the hash, the binding is the transaction rather than an authorization nonce. We can prove the payment happened and was not redeemed here before. We cannot prove it was made for that particular purchase rather than another of the same price, and we cannot prove the party presenting the hash is the party that made the payment: a landed transaction is public, so whoever presents it first is served. The scheme is restricted to contract payers for this reason, since an account can sign an authorization entry and get the stronger binding for free.",
        "One payment is one sale, and that took a fix. The two schemes keyed their replay guards in disjoint namespaces, so a purchase we had already broadcast, served and been paid for could be re-presented as a hash and sell the tool a second time. Found by an adversarial review, reproduced live against e1b0097a, and closed by burning both keys on every settlement plus refusing account payers on the hash path.",
        "A refused payment usually has no transaction to link. That is Soroban, not evasion: the contract answers during simulation and nothing is submitted, so most of our proofs of refusal are typed error codes rather than hashes."
      ],
      "name": "Stellar Testnet",
      "caip2": "stellar:testnet",
      "status": "beta",
      "ecosystem": "stellar",
      "explorer": "https://stellar.expert/explorer/testnet",
      "contractsLinked": [
        {
          "name": "AgentSpendPolicy (Soroban)",
          "address": "CAIL6ECRAB5FUURQ54R7OTZPXRRCDO2S353YT6N6UZUWIBDG2ZOEB4UI",
          "note": "Ours, written in Rust for this chain rather than translated from the Solidity original: Soroban has no msg.sender, so the whole authorization surface collapses onto one require_auth line, and the test suite proves it would notice if that line went missing. Immutable by design, with no upgrade entrypoint.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/contract/CAIL6ECRAB5FUURQ54R7OTZPXRRCDO2S353YT6N6UZUWIBDG2ZOEB4UI"
        },
        {
          "name": "AgentSpendPolicy, passkey-owned (Soroban)",
          "address": "CBGTXWFBYAOZBR6EN3UK4PTLUAY6BRV2C36D3DPOTE5JSOLQXANS6J6U",
          "note": "Ours, and the same wasm as the vault above, byte for byte: instantiated against the code entry already on the ledger rather than uploaded again, which is the difference between about 0.1 XLM and about 12 XLM. What is new is the owner. It is not an account but a CONTRACT, the smart account below, so `owner.require_auth()` dispatches to that contract's `__check_auth` and a passkey signature is what satisfies it. A separate vault rather than a migration because the contract has `set_operator` and deliberately no `set_owner`: the owner is permanent, so proving a passkey can own a vault meant deploying one that a passkey owned from its first ledger. Policy 5 USDC a day, 1 USDC a payment, allowlist on. Recorded in soroban/releases/testnet-passkey-owner-2026-09-19.json. A rehearsal: every owner call it has received was signed by a software P-256 key in our own script, so it is not SOW 2 D3 evidence.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/contract/CBGTXWFBYAOZBR6EN3UK4PTLUAY6BRV2C36D3DPOTE5JSOLQXANS6J6U"
        },
        {
          "name": "OpenZeppelin smart account (third party)",
          "address": "CC5RNXNHKKPAHFP5YEOTZDFOQDQVC6AQKX3EH3W6QKFKGVBAXPVM3RWA",
          "note": "The instance is ours, the code is not. OpenZeppelin's Stellar smart account, deployed through the `smart-account-kit` npm package 0.8.0 (stellar/smart-account-kit, formerly kalepail) against account wasm hash 1b5f4534..., with OpenZeppelin's testnet WebAuthn verifier CC7EKIHQ... as its one signer's verifier. Both of those are third-party testnet deployments read out of the kit's deployment manifest, not built or verified by us. The kit says of itself that it is unaudited and that the contracts under it were audited at rc-v0.7.0 with a different scope; we repeat that rather than improve on it.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/contract/CC5RNXNHKKPAHFP5YEOTZDFOQDQVC6AQKX3EH3W6QKFKGVBAXPVM3RWA"
        },
        {
          "name": "USDC (Stellar Asset Contract)",
          "address": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
          "note": "Circle's testnet USDC as a SEP-41 contract. Derived with `stellar contract id asset` and matched against the literal rather than pasted, and read back live: the contract reports USDC with 7 decimals, which is what the registry declares. Seven, not the six every EVM USDC uses.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/contract/CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA"
        }
      ],
      "artifactsLinked": [
        {
          "kind": "bridge",
          "label": "CCTP inbound: 0.2 USDC burned on Arc testnet, minted here through the CctpForwarder in one call",
          "txHash": "32a09568d56bb0f0eeda54b6529f8756cc1e7e60e0bc235e914aec0898dd1fa2",
          "onChain": "stellar-testnet",
          "blockNumber": 4607724,
          "date": "2026-09-10",
          "deliverable": "self-funded",
          "note": "mint_and_forward(message, attestation) on Circle's CctpForwarder CA66Q2WF..., 2026-09-10, ledger 4607724. The recipient G... account rode in the hook data of the Arc burn (tx 0x09d6a77e, block 61433933) with the forwarder in both address slots, which is the only way a Stellar account can receive a CCTP mint; Iris attested in seconds and the whole leg took 16 s. Driven by mcp/src/cctp-stellar.ts, not Bridge Kit, which has no Stellar adapter.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/32a09568d56bb0f0eeda54b6529f8756cc1e7e60e0bc235e914aec0898dd1fa2"
        },
        {
          "kind": "bridge",
          "label": "CCTP outbound: 0.15 USDC burned here for the Arc testnet signer",
          "txHash": "b5766784c5409a877ae28039182824978dd306c147a30d469b7f3fdc204dd458",
          "onChain": "stellar-testnet",
          "blockNumber": 4607728,
          "date": "2026-09-10",
          "deliverable": "self-funded",
          "note": "deposit_for_burn on Circle's TokenMessengerMinter CDNG7HXA..., 2026-09-10, ledger 4607728, after a SAC approve with a 100-ledger expiry (tx ec96149d). Amount passed as 1500000 seven-decimal subunits for a 150000-unit message; the mint landed on Arc as receiveMessage tx 0x072be2ef (block 61434003) 21 s after the burn. The round trip closes the NEAR Intents caveat for test money: USDC now crosses between Stellar and an EVM chain natively.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/b5766784c5409a877ae28039182824978dd306c147a30d469b7f3fdc204dd458"
        },
        {
          "kind": "deploy",
          "label": "The spend policy wasm, uploaded",
          "txHash": "242c4ec6291e31348c0dc6a92ab016aa042ca467eb522abc287d69e6a9e9e644",
          "onChain": "stellar-testnet",
          "blockNumber": 4147601,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The first of the two deploy transactions: an UploadContractWasm host function sourced by the owner account GBLHNAL5..., one ledger before the instance was created. Read off Horizon on 2026-10-02 (the account's transaction list and this transaction's operation). An earlier version of this ledger called the deploy one transaction and listed only the create below; soroban/releases/testnet-v0.1.0.json still omits this upload.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/242c4ec6291e31348c0dc6a92ab016aa042ca467eb522abc287d69e6a9e9e644"
        },
        {
          "kind": "deploy",
          "label": "The spend policy, instantiated",
          "txHash": "718f050b962b6e645d8cca5cc053d9f1c11a7264d3ddc266f7e36661bd82c68c",
          "onChain": "stellar-testnet",
          "blockNumber": 4147602,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The second deploy transaction: CreateContractV2 against the code entry uploaded one ledger earlier, with the five constructor arguments. The wasm sha256 is 155eb31c1867254eacbf1b7a4755164d15cc6b6f939644705ab6b8df61579239, recorded in soroban/releases/testnet-v0.1.0.json and confirmed by Stellar Expert as the code this contract carries. The binary itself is deliberately not committed: Rust wasm is not bit-reproducible across machines by default, so shipping one would invite a reproducibility claim we cannot honour. Pull it with `stellar contract fetch` and compare.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/718f050b962b6e645d8cca5cc053d9f1c11a7264d3ddc266f7e36661bd82c68c"
        },
        {
          "kind": "settlement",
          "label": "An under-limit payment the policy allowed",
          "txHash": "3da7463422c7d122202b009bb27442199ffc3b6da87da12a7112963bf4bcc999",
          "onChain": "stellar-testnet",
          "blockNumber": 4147945,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The first half of the pair the SoW measures. The operator paid 1 USDC inside a 2 USDC per-payment ceiling and a 10 USDC daily cap; the payee went to 1.0000000, the vault from 15 to 14, and spent_today to 1 USDC.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/3da7463422c7d122202b009bb27442199ffc3b6da87da12a7112963bf4bcc999"
        },
        {
          "kind": "settlement",
          "label": "An over-limit payment the policy refused, with a typed error",
          "txHash": "12df418f21d329f606f412b1aee498714f1178d68fd0db0a97c64f0de6f209d3",
          "onChain": "stellar-testnet",
          "blockNumber": 4147972,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The other half, and the one that took work to produce. On Soroban a refused call normally leaves NO transaction at all, because the contract says no during simulation and nothing is ever submitted. To get a hash a reviewer can open, the policy was tightened while this payment was in flight, so it failed at apply time and the ledger recorded error #5, DailyCapExceeded.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/12df418f21d329f606f412b1aee498714f1178d68fd0db0a97c64f0de6f209d3"
        },
        {
          "kind": "funding",
          "label": "15 USDC into the vault, through the SAC",
          "txHash": "bec1b68be5861fdf7cc71b50ce7c8a5b5cb311326a240ca8e1f6a6af99e2a400",
          "onChain": "stellar-testnet",
          "blockNumber": 4147942,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The vault holds the token in contract storage rather than through a trustline, so it needs none. Both classic accounts do, and that is easy to learn the hard way: paying an account with no USDC trustline fails with op_no_trust, which a buyer reads as our bug.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/bec1b68be5861fdf7cc71b50ce7c8a5b5cb311326a240ca8e1f6a6af99e2a400"
        },
        {
          "kind": "settlement",
          "label": "A gasless x402 purchase: the buyer signed, we paid the fee",
          "txHash": "6d87799242b9fb36a26ac6f2d2fb11c5e7fb8bdd52bc6cf0471dcc8a8caba09c",
          "onChain": "stellar-testnet",
          "blockNumber": 4149194,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "A buyer agent answered a 402 with a signed Soroban authorization entry and got the tool back. Horizon records the fee as charged to our operator account, not to the buyer, which is the gasless claim as a number somebody else can look up.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/6d87799242b9fb36a26ac6f2d2fb11c5e7fb8bdd52bc6cf0471dcc8a8caba09c"
        },
        {
          "kind": "owner-action",
          "label": "The owner freezes the vault, and the agent stops",
          "txHash": "fd0fb958923c5e5e70bedae6451cc9a492b250d3cec3750313814b7e4ccdf117",
          "onChain": "stellar-testnet",
          "blockNumber": 4259182,
          "date": "2026-08-21",
          "deliverable": "SOW1",
          "note": "Signed by the owner account GBLHNAL5..., whose key is ours, in a local CLI keystore: this vault was never meant to show an owner we do not hold. The kill switch, exercised rather than described. With the vault frozen the operator's next payment was refused with error #1, Frozen. That refusal has no hash of its own, for the reason every Soroban refusal here has none: the contract answers during simulation and nothing is submitted.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/fd0fb958923c5e5e70bedae6451cc9a492b250d3cec3750313814b7e4ccdf117"
        },
        {
          "kind": "owner-action",
          "label": "The owner overrides: a payment past the freeze AND past the allowlist",
          "txHash": "f05c2f5be029d7403c6241c85f894160fe83f5866f1993de6ba1c3be7911b3eb",
          "onChain": "stellar-testnet",
          "blockNumber": 4259183,
          "date": "2026-08-21",
          "deliverable": "SOW1",
          "note": "owner_pay to an account that is NOT on the allowlist while the vault is frozen. It settles, because the human path is meant to work exactly when the agent path does not. It was still CHARGED to the daily cap, which is the Solidity original's behaviour ported deliberately. Note the exact claim, because an earlier version of this note overstated it: owner_pay increments the day accumulator, but it is not LIMITED by the cap. `check_owner_pay` in policy.rs runs the amount, arithmetic and balance guards and no cap comparison, so the override bypasses the budget as well as the gates. What it does not bypass is the accounting: the outflow is recorded.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/f05c2f5be029d7403c6241c85f894160fe83f5866f1993de6ba1c3be7911b3eb"
        },
        {
          "kind": "owner-action",
          "label": "The owner unfreezes, and the agent spends again",
          "txHash": "e92fcd5ff1c02b812419891da8a8c915d1d67e5f6d97d1d4da12f516bb227115",
          "onChain": "stellar-testnet",
          "blockNumber": 4259184,
          "date": "2026-08-21",
          "deliverable": "SOW1",
          "note": "The other half of a kill switch is that it turns back off. A freeze you cannot lift is a loss, not a control.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/e92fcd5ff1c02b812419891da8a8c915d1d67e5f6d97d1d4da12f516bb227115"
        },
        {
          "kind": "settlement",
          "label": "The same purchase through the on-chain policy",
          "txHash": "fab5c864939da4165c21384afb24d690662c58ec17d46e36f7bc35ddf60b321f",
          "onChain": "stellar-testnet",
          "blockNumber": 4149294,
          "date": "2026-08-15",
          "deliverable": "SOW1",
          "note": "The agent paid from the vault instead of from a wallet, so the allowlist, the ceiling and the daily cap all ran on chain before the transaction existed. The same call to an unlisted payee was refused by the contract with error #3, PayeeNotAllowed, and produced no transaction at all, which is why that refusal has no hash here. The passkey vault below does have one, for a reason its own note gives.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/fab5c864939da4165c21384afb24d690662c58ec17d46e36f7bc35ddf60b321f"
        },
        {
          "kind": "deploy",
          "label": "Rehearsal: a passkey smart account, deployed as an owner that is not a key",
          "txHash": "dcd3c4227b0a773bf3d825a8fb0c5d37196b9cb7366377bf8a2c76162d3d914c",
          "onChain": "stellar-testnet",
          "blockNumber": 4760408,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "OpenZeppelin's Stellar smart account, deployed through smart-account-kit 0.8.0 with one WebAuthn P-256 signer and no recovery signer. Third-party code, our instance. The \"passkey\" was a SOFTWARE P-256 key generated inside our own script (mcp/scripts/stellar-passkey-proof.mjs), standing in for a platform authenticator: the same verifier contract and the same WebAuthn signature format, but the private key lived in a process of ours, not on anyone's device. Fee paid by our dedicated testnet deployer GDNRET2G... over direct RPC.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/dcd3c4227b0a773bf3d825a8fb0c5d37196b9cb7366377bf8a2c76162d3d914c"
        },
        {
          "kind": "deploy",
          "label": "Rehearsal: a second spend vault, owned by that smart account from its first ledger",
          "txHash": "ccac0b30612a216deea7d84035cac3e3acbb5884c827f60065ed33ff61729fd2",
          "onChain": "stellar-testnet",
          "blockNumber": 4760409,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "The same wasm 155eb31c..., instantiated against the existing code entry with no upload, with the smart account as owner and our usual testnet operator as operator, which also paid the fee. The daily cap is 5 USDC and the per-payment ceiling 1 USDC. The vault above keeps its plain account owner, because there is no `set_owner` to move it.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/ccac0b30612a216deea7d84035cac3e3acbb5884c827f60065ed33ff61729fd2"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: set_policy signed by a software P-256 key, and the vault accepts it",
          "txHash": "994b5cb92c5dee9ce733109e9b7cecd35625aeb3b3edc35903a22cc93a0dd758",
          "onChain": "stellar-testnet",
          "blockNumber": 4760411,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "set_policy(5 USDC, 1 USDC, allowlist on), delivered through the smart account's `execute`. The chain of custody on the ledger: a P-256 signature over the authorization digest, verified by OpenZeppelin's WebAuthn verifier in the account's `__check_auth`, which satisfies the vault's `owner.require_auth()`. The signature came from a software key in our own script and the fee from our deployer GDNRET2G..., so this proves the contract path and does NOT prove that a key outside our systems authorized anything.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/994b5cb92c5dee9ce733109e9b7cecd35625aeb3b3edc35903a22cc93a0dd758"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: the software key allowlists a payee, which is what a KYA ALLOW writes",
          "txHash": "e371b1b38cb1f31aca91709d7ace18fe974f5673a8eafc00012df442dc15ef47",
          "onChain": "stellar-testnet",
          "blockNumber": 4760413,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "Signed by the same software P-256 key, fee paid by our deployer. The on-chain allowlist is binary and the KYA verdict has three states, so the mapping is stated rather than implied: ALLOW writes set_allowed(payee, true), WARN is a server-side flag that writes nothing on chain, and DENY writes set_allowed(payee, false). WARN never reaches the ledger, and nothing here should be read as if it did.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/e371b1b38cb1f31aca91709d7ace18fe974f5673a8eafc00012df442dc15ef47"
        },
        {
          "kind": "funding",
          "label": "Rehearsal: 3 USDC into the passkey vault, through the SAC",
          "txHash": "b84b70de3a087a316bf2267c9bdccb9c191fd9be1ac5b0a741bdbd73aa238faf",
          "onChain": "stellar-testnet",
          "blockNumber": 4760414,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "A plain SEP-41 transfer into contract storage, so this vault needs no trustline either. Sent from the older vault's owner account, which is the only role these two deployments share.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/b84b70de3a087a316bf2267c9bdccb9c191fd9be1ac5b0a741bdbd73aa238faf"
        },
        {
          "kind": "settlement",
          "label": "Rehearsal: the agent pays an allowed payee under a policy the software key set",
          "txHash": "bf375df0b03b7e4a9644676cd4d157df0fe4c4139d870ec2706fcdbe56fb7e4f",
          "onChain": "stellar-testnet",
          "blockNumber": 4760415,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "0.5 USDC, inside the 1 USDC ceiling and the 5 USDC daily cap, to the payee the owner allowed. The vault went to 2.5 USDC and spent_today to 0.5. The operator key that paid is ours and can spend only inside these limits.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/bf375df0b03b7e4a9644676cd4d157df0fe4c4139d870ec2706fcdbe56fb7e4f"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: the owner allows an untrusted payee, on purpose, to arm the race",
          "txHash": "b7ea4c33b19b487b6ee2aadcd6e5486b9917d08325a0e8444e2ac7c643707c33",
          "onChain": "stellar-testnet",
          "blockNumber": 4760419,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "Signed by the software P-256 key, fee paid by our deployer. The payee here is a fresh account nobody has vouched for. Asked to pay it before this, the vault refused in simulation with error #3 and no transaction was ever created, which is the normal and unlinkable shape of a Soroban refusal. Allowing it is step one of forcing a refusal that a reviewer can open.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/b7ea4c33b19b487b6ee2aadcd6e5486b9917d08325a0e8444e2ac7c643707c33"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal: the owner revokes while the agent's payment is already signed",
          "txHash": "9a3aece13d12279be23864a8131b0cf96d18801bd6eb01e966b74f330d22ca88",
          "onChain": "stellar-testnet",
          "blockNumber": 4760420,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "set_allowed(payee, false), signed by the software P-256 key, which is what a KYA DENY writes. The agent had already simulated, built and signed its payment and was holding it. This is not a contrivance: it is the race a real agent hits when a human, or a KYA verdict, changes the allowlist mid-flight.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/9a3aece13d12279be23864a8131b0cf96d18801bd6eb01e966b74f330d22ca88"
        },
        {
          "kind": "settlement",
          "label": "Rehearsal: the held payment lands and the contract refuses it on chain",
          "txHash": "22b33018c807946df066365bde2a72293372bf7768ab96688acb623c290357a0",
          "onChain": "stellar-testnet",
          "blockNumber": 4760421,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "Included in the ledger and refused by the contract: Horizon reports it unsuccessful with the fee charged, and the result carries Error(Contract, #3), PayeeNotAllowed. spent_today stayed at 0.5 USDC and is_allowed read false afterwards, so the revoke cost the agent its fee and nothing else. This is the one refusal on this network with a hash a reviewer can open, and it exists only because the policy was tightened between build and apply.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/22b33018c807946df066365bde2a72293372bf7768ab96688acb623c290357a0"
        },
        {
          "kind": "deploy",
          "label": "Rehearsal, sponsored: a smart account deployed with its fee paid by OpenZeppelin Channels",
          "txHash": "9df1bbb1d29e623bcdce1dc8919f0f8add4941e148e390d789d80a755b795b32",
          "onChain": "stellar-testnet",
          "blockNumber": 4764131,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "The artifacts above were paid by our own testnet deployer over direct RPC, which proved the contract path and not the fee path the public /stellar page uses. This run exercised that fee path, and it was OUR run, not a visitor's: our own script drove the smart-account kit, which posted { func, auth } to our relay; the relay decoded the XDR, refused everything outside the three shapes it allows, and forwarded the rest to OpenZeppelin Channels, whose channel account supplied the source and sequence while a Channels account (GCNJB6V5..., read off Horizon as this transaction's fee account) paid the fee. The P-256 key was again a software key in our process.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/9df1bbb1d29e623bcdce1dc8919f0f8add4941e148e390d789d80a755b795b32"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, sponsored: set_policy signed by a software key, fee paid by Channels",
          "txHash": "fb2b59a05f5f5988d5ec0e625212d7af8e6c5067a945c9544e146f5180c5982e",
          "onChain": "stellar-testnet",
          "blockNumber": 4764136,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "set_policy on a second vault (CCV2MMK4WFJJVYITOWAH6Z3OW5RW7MYOYB3WGOZJ54NEL4PIJHV3KA7T), sponsored through the same relay. What this shows is that an owner call can land with the fee paid by a third party and no XLM in the owner's hands. What it does not show is a person holding the key: the signer was a software P-256 key in our own run.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/fb2b59a05f5f5988d5ec0e625212d7af8e6c5067a945c9544e146f5180c5982e"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, sponsored: the owner overrides a DENY, and the override is itself on chain",
          "txHash": "6b083e8340d8585aa800b022bba843c74e03547ee4cf360243029b8a81c0b86a",
          "onChain": "stellar-testnet",
          "blockNumber": 4764142,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "risk_check answered DENY for this payee, correctly: the agent id it was given did not resolve to an on-chain identity, so there was no reputation or tenure to score. The owner allowed it anyway, which the /stellar page offers as its own button; in this run the \"owner\" pressing it was our own script with a software key. Worth stating plainly because it cuts against the pitch: the guardrail is a bound on the AGENT, not on the owner, and an owner who overrides it leaves an owner-signed transaction behind rather than a silent exception.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/6b083e8340d8585aa800b022bba843c74e03547ee4cf360243029b8a81c0b86a"
        },
        {
          "kind": "settlement",
          "label": "Rehearsal, sponsored: one payment allowed, one refused",
          "txHash": "8590694194da891361734f541042870e1a297f829a0fc701c82b988c34a23410",
          "onChain": "stellar-testnet",
          "blockNumber": 4764146,
          "date": "2026-09-19",
          "deliverable": "rehearsal",
          "note": "0.05 USDC to the allowed payee, paid by our operator, settled. The same call to the payee the owner had revoked at ledger 4764144 answered contract error #3, PayeeNotAllowed, in simulation, so it has no hash of its own. That pairing, a settlement and a typed refusal under a policy an owner call set, is the 90-second demonstration the /stellar page rehearses.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/8590694194da891361734f541042870e1a297f829a0fc701c82b988c34a23410"
        },
        {
          "kind": "owner-action",
          "label": "The flagship vault's owner withdraws 5 test USDC to our operator",
          "txHash": "9536bd1a7fefcb516c9dc67ed71f304a9f9a86362e5401836143cbd09c7ef0b3",
          "onChain": "stellar-testnet",
          "blockNumber": 4760510,
          "date": "2026-09-19",
          "deliverable": "self-funded",
          "note": "withdraw(GDZXSO4A..., 5 USDC) on CAIL6ECR..., sourced, paid and signed by the owner GBLHNAL5..., a key of ours in a local CLI keystore: test money moved between two of our own accounts. Recorded on 2026-10-03, when a ledger read showed the vault at 8.988 USDC rather than the 13.988 read on 2026-09-16. It is the last owner or operator transaction on this vault, read off Horizon on 2026-10-03.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/9536bd1a7fefcb516c9dc67ed71f304a9f9a86362e5401836143cbd09c7ef0b3"
        },
        {
          "kind": "deploy",
          "label": "The v0.1.1 vault code, uploaded: the A3-02 fix every SoW 2 vault runs",
          "txHash": "09d041ab3c0dbae95b902b0c22be8f6587f43542798701db98a09df948119e02",
          "onChain": "stellar-testnet",
          "blockNumber": 4974389,
          "date": "2026-10-01",
          "deliverable": "SOW2-D2",
          "note": "UploadContractWasm for sha256 353e4264..., 11605 bytes, the v0.1.1 build in which settle checks the amount before the payee (finding A3-02), sourced by our deployer GDNRET2G.... Uploading code creates no vault: the D2 and D3 vaults are instantiated against this code entry, and the flagship testnet vault stays on v0.1.0 because a vault cannot change its code.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/09d041ab3c0dbae95b902b0c22be8f6587f43542798701db98a09df948119e02"
        },
        {
          "kind": "deploy",
          "label": "Our WebAuthn verifier instance, OpenZeppelin v0.7.2 code",
          "txHash": "8c6894a8bc0ee1aa8168a49f1de0c4dbdc7f7bf3e86b731277754b81d8242005",
          "onChain": "stellar-testnet",
          "blockNumber": 4974910,
          "date": "2026-10-01",
          "deliverable": "SOW2-D3",
          "note": "Instance CABPDJH4... of wasm e63a030d..., which we built from OpenZeppelin/stellar-contracts v0.7.2 (soroban/third-party/openzeppelin-smart-account). It is the verifier every D3 passkey signature passes through. The code is OpenZeppelin's and was already on testnet; this instance is ours, with a salt derived from the source commit.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/8c6894a8bc0ee1aa8168a49f1de0c4dbdc7f7bf3e86b731277754b81d8242005"
        },
        {
          "kind": "deploy",
          "label": "Our Ed25519 verifier instance, OpenZeppelin v0.7.2 code",
          "txHash": "33642444e71dbda544e61e728019ac728d10a38f9ebfce65ed955bf29fb06a4b",
          "onChain": "stellar-testnet",
          "blockNumber": 4974913,
          "date": "2026-10-01",
          "deliverable": "SOW2-D3",
          "note": "Instance CCKPFIAA... of wasm 60e8798d..., built the same way. The smart-account kit requires an Ed25519 verifier in its configuration; a D3 passkey wallet has no Ed25519 signer, and the vault deploy refuses an owner account that carries one.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/33642444e71dbda544e61e728019ac728d10a38f9ebfce65ed955bf29fb06a4b"
        },
        {
          "kind": "deploy",
          "label": "The v0.1.1 vault code, its rent extended past the 2026-12-16 testnet reset",
          "txHash": "5106db1d74522efa9b5b89d7db9d672ebd204b1ed74a78b4ab45e668e55d21ea",
          "onChain": "stellar-testnet",
          "blockNumber": 4981800,
          "date": "2026-10-02",
          "deliverable": "SOW2-D2",
          "note": "A newly uploaded code entry gets the network minimum TTL, about seven days, and every SoW 2 vault instantiates against this one, so it was extended to ledger 6281800 by our deployer GDNRET2G... before any vault needed it.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/5106db1d74522efa9b5b89d7db9d672ebd204b1ed74a78b4ab45e668e55d21ea"
        },
        {
          "kind": "funding",
          "label": "The D2 owner account, created by Friendbot rather than by any account of ours",
          "txHash": "ebd666aacdbcbee7ebcf1723c4c29b86f4449134b7d0be86495edd213c5ba69d",
          "onChain": "stellar-testnet",
          "blockNumber": 5000410,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "GDIZE6XJ... was generated inside Freighter by the user and did not exist on the testnet ledger until the public testnet Friendbot (source GCG75HSV..., not ours) created and funded it with test XLM. That is the account that sources, pays for and signs the D2 owner actions.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/ebd666aacdbcbee7ebcf1723c4c29b86f4449134b7d0be86495edd213c5ba69d"
        },
        {
          "kind": "deploy",
          "label": "The D2 vault, deployed from v0.1.1, owner = a key generated inside Freighter",
          "txHash": "c57f0bf6ba1dad27d23a42612cd11a396fc0af08957b2353ff80a36fe64768c0",
          "onChain": "stellar-testnet",
          "blockNumber": 5001000,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "Vault CDEU2D4T... instantiated against the v0.1.1 code entry 353e4264... with a recorded salt (soroban/releases/stellar-testnet-v0.1.1-2026-10-03.json), sourced and paid by our deployer GDNRET2G.... Constructor: owner GDIZE6XJ..., operator GAFVKKMD..., daily cap 5 USDC, auto-approve 1 USDC. owner(), operator() and the code hash were read back from the ledger after the deploy. The deployer cannot act on the vault: only the owner can call set_policy, set_frozen and withdraw.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/c57f0bf6ba1dad27d23a42612cd11a396fc0af08957b2353ff80a36fe64768c0"
        },
        {
          "kind": "funding",
          "label": "The D2 vault funded with 1 test USDC",
          "txHash": "4c715d7b34d59a2479098ded4f8b542d094de96a12974fcbd80ab3e9014c2221",
          "onChain": "stellar-testnet",
          "blockNumber": 5001017,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "A plain SAC transfer from GBLHNAL5... (ours) to the vault; it is not an owner action and it touches no other vault. The vault read its balance back as 1 USDC.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/4c715d7b34d59a2479098ded4f8b542d094de96a12974fcbd80ab3e9014c2221"
        },
        {
          "kind": "owner-action",
          "label": "The D2 owner freezes its vault from the panel, signed in Freighter",
          "txHash": "60a7dd67cf5c999a74129a7201289402b51373d481e79b1e979273ff4abb4c6e",
          "onChain": "stellar-testnet",
          "blockNumber": 5006288,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "set_frozen(true) on CDEU2D4T..., the first owner action on this vault, landed 19:17:07 UTC. GDIZE6XJ... is the transaction source and the fee payer (0.0007196 XLM), its signature is the only one on the envelope, and the authorization entry is a source-account credential: the wallet signature over the whole transaction is the authorization, and nothing our backend holds could produce it. Our backend built and simulated the unsigned call for the signed-in session; Freighter showed the owner account, the network and the call before the user approved it.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/60a7dd67cf5c999a74129a7201289402b51373d481e79b1e979273ff4abb4c6e"
        },
        {
          "kind": "owner-action",
          "label": "The D2 owner withdraws 0.5 test USDC to its own account, signed in Freighter",
          "txHash": "b59f6ed844c511d6e4fce4f8385235da6a009dcc0ca6dcb424891b10f9eb61c4",
          "onChain": "stellar-testnet",
          "blockNumber": 5006299,
          "date": "2026-10-03",
          "deliverable": "SOW2-D2",
          "note": "withdraw(GDIZE6XJ..., 5000000) on CDEU2D4T..., 0.5 test USDC at seven decimals, landed 19:18:02 UTC while the vault was frozen: the freeze stops the agent, not the owner. Same shape as the freeze: GDIZE6XJ... sources it, pays the fee (0.0014252 XLM) and signs the whole transaction in Freighter, after the panel restated the amount, the destination and the vault on a review screen. Read back afterwards: the vault frozen with 0.5 USDC, the owner account holding 0.5 USDC.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/b59f6ed844c511d6e4fce4f8385235da6a009dcc0ca6dcb424891b10f9eb61c4"
        },
        {
          "kind": "deploy",
          "label": "The D3 smart account, created from the owner's device passkey on the production site",
          "txHash": "5af017bda75de876508400dc9e973467608a151d49d402d9cb0df662fac3ff9b",
          "onChain": "stellar-testnet",
          "blockNumber": 5019008,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "Smart account CBII2K5R... on the account wasm a12747ff... (our OpenZeppelin v0.7.2 build), created at 12:57:07 UTC when the owner made a passkey on /stellar?network=testnet in a browser. Read back off the ledger: one context rule (Default, no policy, no expiry) holding exactly one signer, External under the WebAuthn verifier CABPDJH4... with the device public key 04560be2...; no Ed25519 and no Delegated signer. The page reported a platform passkey synced in Apple Passwords (backup eligible, backed up, user verified); that report is the browser's, not the ledger's. The kit posted the deploy to our relay, which forwarded it to OpenZeppelin Channels: a Channels channel account sourced it and the Channels account GCNJB6V5... paid the fee.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/5af017bda75de876508400dc9e973467608a151d49d402d9cb0df662fac3ff9b"
        },
        {
          "kind": "deploy",
          "label": "The D3 vault, deployed from v0.1.1, owner = that smart account",
          "txHash": "fa1080f6787f82bf3ca2b9c41828cd2ee16ee20bb78ee65818cdad5801f82c38",
          "onChain": "stellar-testnet",
          "blockNumber": 5019022,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "Vault CCTYM23I... on the v0.1.1 code 353e4264..., deployed at 12:58:17 UTC by POST /api/stellar/passkey/vault/deploy after the route read the smart account's code and its one passkey signer off the ledger. Sourced and paid (0.6559942 XLM) by GDZXSO4A..., which is the vault's operator and cannot call an owner entrypoint. Constructor: owner CBII2K5R..., daily cap 10 USDC, auto-approve 2 USDC. owner(), operator() and the code hash were read back from the ledger after the deploy.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/fa1080f6787f82bf3ca2b9c41828cd2ee16ee20bb78ee65818cdad5801f82c38"
        },
        {
          "kind": "funding",
          "label": "The D3 vault seeded with 0.2 test USDC",
          "txHash": "62dc830950ba3322019c928fa35a47a509bac886a52c4a316cb31666236bbf10",
          "onChain": "stellar-testnet",
          "blockNumber": 5019023,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "A plain SAC transfer of 0.2 test USDC from GDZXSO4A... into CCTYM23I..., made by the same deploy route at 12:58:22 UTC; it is not an owner action. The vault read its balance back as 0.2 USDC.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/62dc830950ba3322019c928fa35a47a509bac886a52c4a316cb31666236bbf10"
        },
        {
          "kind": "owner-action",
          "label": "The D3 owner freezes its vault with the device passkey, from the page",
          "txHash": "2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6",
          "onChain": "stellar-testnet",
          "blockNumber": 5019748,
          "date": "2026-10-04",
          "deliverable": "SOW2-D3",
          "note": "set_frozen(true) on CCTYM23I..., the first owner action on this vault, landed 13:58:47 UTC, called through execute on the smart account CBII2K5R.... Decoded off the ledger (archive soroban/releases/tx-archive/stellar-testnet/2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6.json): the one authorization entry is an address credential for the smart account, signed by a webauthn-secp256r1 signer under the WebAuthn verifier CABPDJH4... with the device public key 04560be2..., on context rule 0; flags UP, UV, BE and BS; the origin is the a-identity.xyz site; the challenge is the authorization digest and the signature re-verifies. A Channels channel account sourced it and the Channels account GCNJB6V5... paid the fee (0.1048712 XLM) through a fee bump; the smart account paid nothing. The owner approved it with Touch ID in a recorded browser session. The chain itself cannot tell a device authenticator from a software key; the recording and the enrolment are what show the device.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6"
        },
        {
          "kind": "deploy",
          "label": "Rehearsal, v0.7.2: a smart account on our own OpenZeppelin build, deployed through our relay",
          "txHash": "ac287daf11b3b9bd8219d57582dc92c0dada49bf3474a8f7ecbe00ef57873027",
          "onChain": "stellar-testnet",
          "blockNumber": 5001527,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "Smart account CD5WPJ5O..., the first instance of the account wasm a12747ff... we built from OpenZeppelin v0.7.2, with one WebAuthn signer under our verifier CABPDJH4.... The kit was configured as the /stellar page configures it and posted { func, auth } to our relay, which forwarded it to OpenZeppelin Channels; Channels sourced it and its account GCNJB6V5... paid the fee. The \"passkey\" was a software P-256 key in our own script, so this proves the path, not a device.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/ac287daf11b3b9bd8219d57582dc92c0dada49bf3474a8f7ecbe00ef57873027"
        },
        {
          "kind": "deploy",
          "label": "Rehearsal, v0.7.2: a v0.1.1 vault owned by that smart account, from the deploy route",
          "txHash": "d5b44ad8c0abdfce90f1a3f3aaf2903dd26b4a26e9be5cd6bf5c458d4e7b0b40",
          "onChain": "stellar-testnet",
          "blockNumber": 5001529,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "Vault CCFQEMTY... on the v0.1.1 code 353e4264..., deployed by POST /api/stellar/passkey/vault/deploy after the route read the smart account's code and its one passkey signer off the ledger. Sourced and paid by our operator GDZXSO4A..., which is also its operator; daily cap 10 USDC, ceiling 2 USDC.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/d5b44ad8c0abdfce90f1a3f3aaf2903dd26b4a26e9be5cd6bf5c458d4e7b0b40"
        },
        {
          "kind": "funding",
          "label": "Rehearsal, v0.7.2: 0.2 test USDC seeded by the deploy route",
          "txHash": "66433fb8251b2213147dce36c1c49dbba7b64188def7ec4cde3601c5615ded3d",
          "onChain": "stellar-testnet",
          "blockNumber": 5001530,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "A SAC transfer from our operator into the new vault, so the agent has something to pay with. Every unit of it came back to the operator by the end of the run (one agent payment and two withdrawals).",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/66433fb8251b2213147dce36c1c49dbba7b64188def7ec4cde3601c5615ded3d"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: set_policy signed by a software key through our verifier",
          "txHash": "68971bde0327080686e76bff3a8df01ddef90162de19d255782ebc6fb9d7913f",
          "onChain": "stellar-testnet",
          "blockNumber": 5001532,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "set_policy(10 USDC, 2 USDC, allowlist on) through the account's execute, relayed and fee-bumped by Channels. Decoded off the ledger: a webauthn-secp256r1 signer under CABPDJH4..., bound to context rule 0, its challenge the entry's auth digest and its signature re-verifying. A software key signed it.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/68971bde0327080686e76bff3a8df01ddef90162de19d255782ebc6fb9d7913f"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: set_allowed for the payee, signed by the software key",
          "txHash": "5d78975e422627055438e06477c3476054b9fd35973e2de7d2beb890ccbd1bd7",
          "onChain": "stellar-testnet",
          "blockNumber": 5001535,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "The payee was our operator account, which holds a USDC trustline, so the run needed no second funded account. Relayed and fee-bumped by Channels.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/5d78975e422627055438e06477c3476054b9fd35973e2de7d2beb890ccbd1bd7"
        },
        {
          "kind": "settlement",
          "label": "Rehearsal, v0.7.2: the agent pays the allowed payee, through the agent-pay route",
          "txHash": "40753e65ed63e31c2583a06e628cda91bd11513b3fa72975c38b2ba3267f55fb",
          "onChain": "stellar-testnet",
          "blockNumber": 5001538,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "0.1 USDC by POST /api/stellar/passkey/agent-pay, signed and paid by our operator inside the policy. The same call to a payee nobody allowed was refused with PayeeNotAllowed (#3) in simulation, so that refusal has no hash.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/40753e65ed63e31c2583a06e628cda91bd11513b3fa72975c38b2ba3267f55fb"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: the software key freezes the vault, and the agent stops",
          "txHash": "6176ed231dc5f3442eba125ba8143bb27fc3057fd81849c61b0899297b0057e3",
          "onChain": "stellar-testnet",
          "blockNumber": 5001540,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "set_frozen(true), the button the D3 recording will press. With the vault frozen, agent-pay was refused with Frozen (#1) in simulation, so that refusal has no hash. Relayed and fee-bumped by Channels; signed by a software key.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/6176ed231dc5f3442eba125ba8143bb27fc3057fd81849c61b0899297b0057e3"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: the software key unfreezes the vault",
          "txHash": "ac4a2f8f0fc4c198924cf2caf2c08d4818408ce5a7bb525f0a0422228eda8019",
          "onChain": "stellar-testnet",
          "blockNumber": 5001543,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "set_frozen(false), read back as not frozen right after.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/ac4a2f8f0fc4c198924cf2caf2c08d4818408ce5a7bb525f0a0422228eda8019"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: withdraw to a G account, its trustline checked first",
          "txHash": "d946a1ff310281e2e79ba8017af4b2ee5c5f9cc744ce5e8f4994015126bc4a2c",
          "onChain": "stellar-testnet",
          "blockNumber": 5001545,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "withdraw(GDZXSO4A..., 0.05 USDC), after Horizon confirmed the destination holds an authorized USDC trustline; the destination's balance rose by exactly 0.05. Signed by the software key under rule 0, relayed and fee-bumped by Channels.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/d946a1ff310281e2e79ba8017af4b2ee5c5f9cc744ce5e8f4994015126bc4a2c"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: a second passkey added as its own context rule, never rule 0",
          "txHash": "b57f931d874bb4d53ed8ec1d8e52bd53cfb2e7f1e1ede026989c0467d0cc85aa",
          "onChain": "stellar-testnet",
          "blockNumber": 5001548,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "add_context_rule on the smart account itself: a Default rule, id 1, holding one new WebAuthn signer under CABPDJH4... and no policy, approved by the first passkey, the way the page's \"Add another device\" builds it. Read back afterwards: rule 0 still holds the first passkey alone and rule 1 the second alone, so either can act. An action on the account, not on the vault; both keys were software keys.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/b57f931d874bb4d53ed8ec1d8e52bd53cfb2e7f1e1ede026989c0467d0cc85aa"
        },
        {
          "kind": "owner-action",
          "label": "Rehearsal, v0.7.2: signed in with the second passkey alone, it withdraws the rest",
          "txHash": "741ad16c32d84dfe226eb25a4c0571665ac8c815fbe0bb8de77fb6b38c1bae16",
          "onChain": "stellar-testnet",
          "blockNumber": 5001551,
          "date": "2026-10-03",
          "deliverable": "rehearsal",
          "note": "After signing out and back in with the second credential, withdraw(GDZXSO4A..., 0.05 USDC) emptied the vault. Decoded off the ledger: the webauthn-secp256r1 signature is bound to context rule 1, so the second device authorized it on its own. What the recovery page promises for a second device, shown on the contract path with software keys; a device enrolment is still to be shown.",
          "explorerUrl": "https://stellar.expert/explorer/testnet/tx/741ad16c32d84dfe226eb25a4c0571665ac8c815fbe0bb8de77fb6b38c1bae16"
        }
      ],
      "accountsLinked": [
        {
          "role": "Operator of the flagship testnet vault CAIL6ECR..., the x402 testnet fee payer, and since 2026-10-03 the hosted backend's testnet signer",
          "address": "GDZXSO4AOKPSHMQZMBNEEBQNYOIF7TWDPD7K2U5VAPKFN3QIAIELTAN6",
          "network": "stellar-testnet",
          "custody": "ours: backend environment key",
          "usedFor": "pay() inside the vault policy (it can never call an owner entrypoint), broadcasting and paying the fee for every testnet x402 settlement, and the operator of the 2026-09-19 rehearsal vaults and of the 2026-10-03 rehearsal vaults CCFQEMTY... and CDE5P5QX..., which it deployed and seeded. Since 2026-10-03 it is also the testnet signer of the hosted backend, set on Render by the maintainer: it deploys, seeds and operates every vault /stellar?network=testnet creates, the SoW 2 D3 vault CCTYM23I... among them, which it deployed and seeded on 2026-10-04, and it can never sign that vault's owner calls, which only the owner's passkey can. One key in several roles on testnet, which mcp/scripts/stellar-key-roles.mjs reports as a warning.",
          "publishedAt": "2026-08-15",
          "explorerUrl": "https://stellar.expert/explorer/testnet/account/GDZXSO4AOKPSHMQZMBNEEBQNYOIF7TWDPD7K2U5VAPKFN3QIAIELTAN6"
        },
        {
          "role": "Owner of the flagship testnet vault CAIL6ECR...",
          "address": "GBLHNAL57WLA5GKTIGPBHCJTQDNEZFX2CVH53EDUOGWIERNKECRENHQ5",
          "network": "stellar-testnet",
          "custody": "ours: local CLI keystore",
          "usedFor": "The vault's deploy (upload and create), its funding, and every owner action on it: set_policy, set_allowed, set_frozen, owner_pay and, on 2026-09-19, a withdraw of 5 test USDC to our operator GDZXSO4A.... Permanent, because the contract has no set_owner. It also funded the 2026-09-19 rehearsal vault and, on 2026-10-03, the SoW 2 D2 vault CDEU2D4T... with 1 test USDC: a token transfer, not an owner action on either.",
          "publishedAt": "2026-08-15",
          "explorerUrl": "https://stellar.expert/explorer/testnet/account/GBLHNAL57WLA5GKTIGPBHCJTQDNEZFX2CVH53EDUOGWIERNKECRENHQ5"
        },
        {
          "role": "Deployer and fee payer of the 2026-09-19 passkey rehearsal",
          "address": "GDNRET2G5WNC25QQ43ODLGAZ42X74DQDGRHWHSLKC6FCVF7C6JYLHAJA",
          "network": "stellar-testnet",
          "custody": "ours: local CLI keystore",
          "usedFor": "Paid the fee for the rehearsal smart account deploy and for every software-key owner call in the first 2026-09-19 run, over direct RPC. On 2026-10-01 it uploaded the v0.1.1 vault code and deployed our own OpenZeppelin verifier instances; on 2026-10-02 it extended the v0.1.1 code entry, and on 2026-10-03 it deployed the SoW 2 D2 vault CDEU2D4T.... It holds no vault role and cannot authorize an owner call; it only sources and pays for transactions.",
          "publishedAt": "2026-09-19",
          "explorerUrl": "https://stellar.expert/explorer/testnet/account/GDNRET2G5WNC25QQ43ODLGAZ42X74DQDGRHWHSLKC6FCVF7C6JYLHAJA"
        },
        {
          "role": "OpenZeppelin Channels fee-bump account in the 2026-09-19 sponsored rehearsal",
          "address": "GCNJB6V5YIODDSSCWXZ2VOKMRPRVZ2V723RRQS6STXE6NWTGVOJY35CN",
          "network": "stellar-testnet",
          "custody": "third party: OpenZeppelin Channels",
          "usedFor": "Fee-bumped the four owner-side transactions of the sponsored rehearsal run (ledgers 4764131, 4764136, 4764142 and 4764144), relayed through our endpoint with our API key, and the eight owner-side transactions of the 2026-10-03 rehearsal on our v0.7.2 build (ledgers 5001527 to 5001551). On 2026-10-04 it fee-bumped the deploy of the SoW 2 D3 smart account CBII2K5R... (ledger 5019008), the owner's own passkey enrolment relayed through our endpoint. We do not hold its key. Read off Horizon as the fee_account of those transactions and recorded in soroban/releases/testnet-passkey-owner-2026-09-19.json, testnet-passkey-rehearsal-v072-2026-10-03.json and testnet-passkey-d3-2026-10-04.json.",
          "publishedAt": "2026-10-02",
          "explorerUrl": "https://stellar.expert/explorer/testnet/account/GCNJB6V5YIODDSSCWXZ2VOKMRPRVZ2V723RRQS6STXE6NWTGVOJY35CN"
        },
        {
          "role": "Owner of the SoW 2 D2 vault CDEU2D4T...",
          "address": "GDIZE6XJ36EDO4G2G674DCHMNRQLHOQN3JH7EZDBIQENOJABPSYL44EQ",
          "network": "stellar-testnet",
          "custody": "owner: generated inside a browser wallet, secret never on our systems",
          "usedFor": "set_policy, set_frozen and withdraw on the D2 vault, each in a transaction this account sources, pays for and signs whole in Freighter. The key was generated inside Freighter by the user; the public Friendbot created its testnet account, and the account added its testnet USDC trustline itself in Freighter on 2026-10-03 (tx 870cf65d...). Published here on the day the vault was deployed and before its first owner action, the freeze 60a7dd67... later that day, followed by the withdraw b59f6ed8....",
          "publishedAt": "2026-10-03",
          "explorerUrl": "https://stellar.expert/explorer/testnet/account/GDIZE6XJ36EDO4G2G674DCHMNRQLHOQN3JH7EZDBIQENOJABPSYL44EQ"
        },
        {
          "role": "Operator (agent key) of the SoW 2 D2 vault CDEU2D4T...",
          "address": "GAFVKKMDZKMV7GTODASFCS222QEUGKTFXOH5XXGIJN2ZCYVRZCKQCWZ2",
          "network": "stellar-testnet",
          "custody": "ours: local CLI keystore",
          "usedFor": "pay() inside the D2 vault policy and nothing else: it can never call an owner entrypoint. The public Friendbot created the account on 2026-10-03 (tx 02290d96..., test XLM only) so its explorer page resolves; it has never called pay() and is not used during the SoW 2 sprint.",
          "publishedAt": "2026-10-03",
          "explorerUrl": "https://stellar.expert/explorer/testnet/account/GAFVKKMDZKMV7GTODASFCS222QEUGKTFXOH5XXGIJN2ZCYVRZCKQCWZ2"
        },
        {
          "role": "Owner of the SoW 2 D3 vault CCTYM23I...: an OpenZeppelin smart account behind a device passkey",
          "address": "CBII2K5RHXA7QTBXXUG6O3EMR25NOVOL73KMVGWKWGH7PHO7QXDTHMUD",
          "network": "stellar-testnet",
          "custody": "owner: passkey smart account",
          "usedFor": "set_policy, set_frozen and withdraw on the D3 vault, each authorized only by a WebAuthn signature from the passkey the owner created on 2026-10-04 in a browser on the production site: the account's one signer, on rule 0, under the WebAuthn verifier CABPDJH4.... It holds no XLM and pays no fee; a relayer or the vault operator pays, and the page names which. Published here on the day the vault was deployed and before its first owner action, the freeze 2d4cb917... later that day. Read on 2026-10-11 at testnet ledger 5143315: still one context rule holding one signer, so the second device the owner tried to add on 2026-10-04 never reached the ledger. At ledger 5143331 the account's own instance entry had outlived its rent and was archived (the vault's is not): a simulated read marks it for restoration, which the ledger performs inside the next transaction that touches it, at that transaction's fee payer's cost.",
          "publishedAt": "2026-10-04",
          "explorerUrl": "https://stellar.expert/explorer/testnet/contract/CBII2K5RHXA7QTBXXUG6O3EMR25NOVOL73KMVGWKWGH7PHO7QXDTHMUD"
        }
      ],
      "live": {
        "reachable": true,
        "checkedAt": "2026-10-22T21:18:52.186Z",
        "blockNumber": "5336069",
        "contracts": [
          {
            "name": "AgentSpendPolicy (Soroban)",
            "address": "CAIL6ECRAB5FUURQ54R7OTZPXRRCDO2S353YT6N6UZUWIBDG2ZOEB4UI",
            "deployed": true
          },
          {
            "name": "AgentSpendPolicy, passkey-owned (Soroban)",
            "address": "CBGTXWFBYAOZBR6EN3UK4PTLUAY6BRV2C36D3DPOTE5JSOLQXANS6J6U",
            "deployed": true
          },
          {
            "name": "OpenZeppelin smart account (third party)",
            "address": "CC5RNXNHKKPAHFP5YEOTZDFOQDQVC6AQKX3EH3W6QKFKGVBAXPVM3RWA",
            "deployed": true,
            "archived": true
          },
          {
            "name": "USDC (Stellar Asset Contract)",
            "address": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
            "deployed": true
          }
        ]
      }
    }
  ],
  "howToVerify": [
    "Open any transaction link below: each is a real transaction in the ledger named, on the chain named.",
    "A refused payment usually has NO transaction to open, and that is Soroban rather than evasion: the contract answers during simulation and nothing is ever submitted. Where a refusal IS linked here, it exists because the limit moved while the payment was in flight, so it failed at apply time and the ledger recorded the typed error. Everywhere else the typed error code is the artifact, and you can reproduce it against the live contract for free precisely because it is refused.",
    "The contract is unverified on Stellar Expert by design, because Rust wasm is not bit-reproducible across machines. Check it the direct way instead, by fetching its bytes and comparing their sha256 with the hash in soroban/releases/. On Stellar, `stellar contract fetch --id <contract> --rpc-url https://mainnet.sorobanrpc.com --network-passphrase \"Public Global Stellar Network ; September 2015\"` (the CLI's built-in mainnet entry ships with no RPC, so name one; any mainnet Soroban RPC will do); on Stellar Testnet, `stellar contract fetch --id <contract> --network testnet`.",
    "Settlements are proven by our own read of the SEP-41 transfer event, never by a broadcaster reporting success. A payment we or OpenZeppelin Channels broadcast is matched to the buyer's authorization nonce; one the buyer broadcast is bound to its transaction hash alone, and the log says which is which. See GET /api/x402/stellar/proof: byBroadcaster counts who moved each payment, and a payment from an account we control is labeled internal, not hidden."
  ],
  "sow2": {
    "sprintStart": "2026-09-15",
    "deliverables": [
      {
        "id": "D1",
        "title": "Wallet connection and a live, read-only vault panel",
        "status": "live",
        "date": "2026-10-03",
        "caption": "Live at /app/vault/stellar since 2026-10-03: a Stellar Wallets Kit connection and a panel that reads any AgentSpendPolicy vault by contract address with no wallet, every value stamped with its ledger. Checked the same day against the raw ledger storage of CAIL6ECR... and the D2 vault CDEU2D4T... (testnet ledger 5001932): every policy field and both balances matched.",
        "links": [
          {
            "label": "Open the live vault panel",
            "url": "/app/vault/stellar"
          }
        ],
        "artifacts": [],
        "artifactsLinked": []
      },
      {
        "id": "D2",
        "title": "Owner actions from a browser wallet, on testnet",
        "status": "live",
        "date": "2026-10-03",
        "caption": "Live since 2026-10-03. The D2 vault CDEU2D4T... runs the fixed v0.1.1 code; its owner GDIZE6XJ..., a key generated inside Freighter, was published in the accounts table below on the day of the deploy, before any owner action. The same day the owner froze the vault (ledger 5006288) and then withdrew 0.5 test USDC to its own account (ledger 5006299), both from the live panel, each a transaction the owner account sources, pays for and signs whole in Freighter. Neither carries a signature or an authorization from any system of ours.",
        "links": [
          {
            "label": "Open the D2 vault in the live panel",
            "url": "/app/vault/stellar?network=stellar:testnet&contract=CDEU2D4TFDA5XMFI7QMCOGR2O6HWLV2QMOHYVEQDC4Z6REG73HNF2MKT"
          }
        ],
        "artifacts": [
          "09d041ab3c0dbae95b902b0c22be8f6587f43542798701db98a09df948119e02",
          "5106db1d74522efa9b5b89d7db9d672ebd204b1ed74a78b4ab45e668e55d21ea",
          "ebd666aacdbcbee7ebcf1723c4c29b86f4449134b7d0be86495edd213c5ba69d",
          "c57f0bf6ba1dad27d23a42612cd11a396fc0af08957b2353ff80a36fe64768c0",
          "4c715d7b34d59a2479098ded4f8b542d094de96a12974fcbd80ab3e9014c2221",
          "60a7dd67cf5c999a74129a7201289402b51373d481e79b1e979273ff4abb4c6e",
          "b59f6ed844c511d6e4fce4f8385235da6a009dcc0ca6dcb424891b10f9eb61c4"
        ],
        "artifactsLinked": [
          {
            "txHash": "09d041ab3c0dbae95b902b0c22be8f6587f43542798701db98a09df948119e02",
            "label": "The v0.1.1 vault code, uploaded: the A3-02 fix every SoW 2 vault runs",
            "date": "2026-10-01",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/09d041ab3c0dbae95b902b0c22be8f6587f43542798701db98a09df948119e02"
          },
          {
            "txHash": "5106db1d74522efa9b5b89d7db9d672ebd204b1ed74a78b4ab45e668e55d21ea",
            "label": "The v0.1.1 vault code, its rent extended past the 2026-12-16 testnet reset",
            "date": "2026-10-02",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/5106db1d74522efa9b5b89d7db9d672ebd204b1ed74a78b4ab45e668e55d21ea"
          },
          {
            "txHash": "ebd666aacdbcbee7ebcf1723c4c29b86f4449134b7d0be86495edd213c5ba69d",
            "label": "The D2 owner account, created by Friendbot rather than by any account of ours",
            "date": "2026-10-03",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/ebd666aacdbcbee7ebcf1723c4c29b86f4449134b7d0be86495edd213c5ba69d"
          },
          {
            "txHash": "c57f0bf6ba1dad27d23a42612cd11a396fc0af08957b2353ff80a36fe64768c0",
            "label": "The D2 vault, deployed from v0.1.1, owner = a key generated inside Freighter",
            "date": "2026-10-03",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/c57f0bf6ba1dad27d23a42612cd11a396fc0af08957b2353ff80a36fe64768c0"
          },
          {
            "txHash": "4c715d7b34d59a2479098ded4f8b542d094de96a12974fcbd80ab3e9014c2221",
            "label": "The D2 vault funded with 1 test USDC",
            "date": "2026-10-03",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/4c715d7b34d59a2479098ded4f8b542d094de96a12974fcbd80ab3e9014c2221"
          },
          {
            "txHash": "60a7dd67cf5c999a74129a7201289402b51373d481e79b1e979273ff4abb4c6e",
            "label": "The D2 owner freezes its vault from the panel, signed in Freighter",
            "date": "2026-10-03",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/60a7dd67cf5c999a74129a7201289402b51373d481e79b1e979273ff4abb4c6e"
          },
          {
            "txHash": "b59f6ed844c511d6e4fce4f8385235da6a009dcc0ca6dcb424891b10f9eb61c4",
            "label": "The D2 owner withdraws 0.5 test USDC to its own account, signed in Freighter",
            "date": "2026-10-03",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/b59f6ed844c511d6e4fce4f8385235da6a009dcc0ca6dcb424891b10f9eb61c4"
          }
        ]
      },
      {
        "id": "D3",
        "title": "An owner action signed by a device passkey, on testnet",
        "status": "live",
        "date": "2026-10-04",
        "caption": "Live since 2026-10-04. The owner created a passkey on /stellar?network=testnet in a browser; it is the one signer of the smart account CBII2K5R..., under our verifier instance of OpenZeppelin's audited v0.7.2 code, and that account owns the vault CCTYM23I... on the fixed v0.1.1 code. Both were deployed and published in the accounts table below that day, before any owner action. The same day the owner froze the vault with the passkey (ledger 5019748): the only authorization on that transaction is a WebAuthn (secp256r1) signature from the device, on the account's rule 0, and OpenZeppelin Channels paid the fee, not the passkey. The decoded authorization is linked below. The 2026-09-19 runs further down, and the 2026-10-03 run that took the whole owner path once on our own v0.7.2 build through our relay (a second passkey on its own rule included), are rehearsals with software keys and are not this deliverable.",
        "links": [
          {
            "label": "The passkey vault page, on testnet",
            "url": "/stellar?network=testnet"
          },
          {
            "label": "Open the D3 vault in the live panel",
            "url": "/app/vault/stellar?network=stellar:testnet&contract=CCTYM23I6UCKKFWHBUWU2GFUSDY6WJEJ3FYSS7WI33DTI5P5HARB72EH"
          },
          {
            "label": "Decoded authorization of the passkey owner action",
            "url": "/api/stellar/tx/2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6?network=stellar:testnet"
          }
        ],
        "artifacts": [
          "8c6894a8bc0ee1aa8168a49f1de0c4dbdc7f7bf3e86b731277754b81d8242005",
          "33642444e71dbda544e61e728019ac728d10a38f9ebfce65ed955bf29fb06a4b",
          "5af017bda75de876508400dc9e973467608a151d49d402d9cb0df662fac3ff9b",
          "fa1080f6787f82bf3ca2b9c41828cd2ee16ee20bb78ee65818cdad5801f82c38",
          "62dc830950ba3322019c928fa35a47a509bac886a52c4a316cb31666236bbf10",
          "2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6"
        ],
        "artifactsLinked": [
          {
            "txHash": "8c6894a8bc0ee1aa8168a49f1de0c4dbdc7f7bf3e86b731277754b81d8242005",
            "label": "Our WebAuthn verifier instance, OpenZeppelin v0.7.2 code",
            "date": "2026-10-01",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/8c6894a8bc0ee1aa8168a49f1de0c4dbdc7f7bf3e86b731277754b81d8242005"
          },
          {
            "txHash": "33642444e71dbda544e61e728019ac728d10a38f9ebfce65ed955bf29fb06a4b",
            "label": "Our Ed25519 verifier instance, OpenZeppelin v0.7.2 code",
            "date": "2026-10-01",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/33642444e71dbda544e61e728019ac728d10a38f9ebfce65ed955bf29fb06a4b"
          },
          {
            "txHash": "5af017bda75de876508400dc9e973467608a151d49d402d9cb0df662fac3ff9b",
            "label": "The D3 smart account, created from the owner's device passkey on the production site",
            "date": "2026-10-04",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/5af017bda75de876508400dc9e973467608a151d49d402d9cb0df662fac3ff9b"
          },
          {
            "txHash": "fa1080f6787f82bf3ca2b9c41828cd2ee16ee20bb78ee65818cdad5801f82c38",
            "label": "The D3 vault, deployed from v0.1.1, owner = that smart account",
            "date": "2026-10-04",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/fa1080f6787f82bf3ca2b9c41828cd2ee16ee20bb78ee65818cdad5801f82c38"
          },
          {
            "txHash": "62dc830950ba3322019c928fa35a47a509bac886a52c4a316cb31666236bbf10",
            "label": "The D3 vault seeded with 0.2 test USDC",
            "date": "2026-10-04",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/62dc830950ba3322019c928fa35a47a509bac886a52c4a316cb31666236bbf10"
          },
          {
            "txHash": "2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6",
            "label": "The D3 owner freezes its vault with the device passkey, from the page",
            "date": "2026-10-04",
            "onChain": "stellar-testnet",
            "explorerUrl": "https://stellar.expert/explorer/testnet/tx/2d4cb917c415c68b2c9eb14079d6634f9b9f65432c7558a6e5d152231f2d6fe6"
          }
        ]
      }
    ],
    "trustModel": "Owner authority (set_policy, set_frozen, withdraw, owner_pay) is never ours on the SOW 2 D2 and D3 vaults: the contract checks owner.require_auth() against the owner address fixed at deploy, there is no set_owner, and we never hold that wallet key or that passkey. Our backend may build the unsigned owner call and relay what the owner signed; it can withhold that, but it cannot alter what was signed or produce the signature. Operator authority (pay, inside the policy: the daily cap, the auto-approve ceiling, the allowlist, the freeze and the session expiry) IS ours on every vault where our backend is the operator, and the policy is what bounds it. The older vaults are a different case and are labeled as such: the owners of CAIL6ECR... on testnet and CB5LYXFK... on pubnet are keys we hold, and the 2026-09-19 passkey rehearsal was signed by a software key in our own script.",
    "caveats": [
      "The 2026-09-19 passkey runs on testnet are a rehearsal, not SOW 2 D3 evidence. Every owner call in them was signed by a software P-256 key generated inside our own script, and the first run's fees were paid by our own deployer key. The 2026-10-03 run on our own v0.7.2 build is the same kind of rehearsal: software keys in our script, labeled as such, recorded in soroban/releases/testnet-passkey-rehearsal-v072-2026-10-03.json.",
      "Every owner action recorded on this page before SOW 2 was signed by a key we hold. Those artifacts prove the contract enforces its policy; they do not prove an owner outside our systems, which is the point of D2 and D3.",
      "One account the 2026-09-19 sponsored run touched is not in the accounts table: the smart-account kit's public deployer. No receipt of ours records its full address, and this table publishes only addresses a receipt does.",
      "Testnet resets periodically. A D2 or D3 vault is evidence that the flow works on the ledger at the time shown, not a permanent record; the hashes and dates here are what survive a reset.",
      "This section reads from the live backend. A page saved without it, or rendered before the backend answered, shows no evidence rather than stale evidence."
    ]
  }
}