Seedelf-Wallet

Chunk 24 · dApp additions: more DEXes through Minswap’s router

Branch web-wallet/dapp-additions, from main. One long branch for all of it (the owner, 2026-10-06), with a PR at the end.

Status: built and run live (2026-10-06 and 07). SundaeSwap V3 and Danogo are routed, routes are direct, and Stop cancels every order itself. The owner ran every DEX the wallet routes on mainnet but Splash and Spectrum, and two Stops there cancelled, and the stuck preprod V3 order cancelled live (Mainnet runs, Step 3). It goes out in 1.3.0 (the owner, 2026-10-07). What’s still open is in post-release-roadmap.md’s Owed (O2, O4) and Kept in mind.

The owner’s calls (2026-10-06)

What the research found (2026-10-06)

Checked against live chain data, APIs and repos.

Step 0 · SplashStable out

Remove SplashStable from MAINNET_PROTOCOLS so mainnet routing leaves it out (excludedProtocols). Preprod already leaves it out (PREPROD_BROKEN).

Foundation 1 · SundaeSwap V3 orders

What Minswap builds. Seen on chain, 25 open orders at V3’s order script, 2026-10-06:

What the foundation adds:

  1. The route rule. V3 only as a path of its own, one leg. A path where SundaeSwapV3 sits beside another leg is refused at the quote, and again when the order is placed, the same way an unchecked DEX is (uncheckedProtocols).
  2. checkOrder reads a V3 order exactly. An output at the V3 order script counts as the session’s order only if all of these hold:
    • It sits under the session’s staking part, none, or Minswap’s pinned f217f435…. That pinned part is accepted at this script alone.
    • Its datum’s owner is Signature of the session’s stake key hash.
    • Its destination is Fixed{the session's address, NoDatum}. Anything else at that script is refused, whatever names would say.
  3. Stop’s cancel may be signed by the session’s stake key too. Only when the cancel spends a V3 order (an input at the V3 order script) and the session has its own stake key (ownStake). Otherwise 0/i alone, as now. Everything else refuseOddities refuses still stands: certificates, withdrawals, votes, mints, other people’s signatures. So a stake signature only meets a required signer.
    • inspectSessionTx already names the stake key as a signer when a required signer is its hash.
    • signSessionTx already signs with 2/i (stakeIndex).
    • So no Rust change.
  4. A session from before ownStake carries the shared Seedelf stake key, which is never signed with. A V3 order for such a session is refused.

Foundation 2 · Direct swaps (Danogo CLMM)

Danogo has no order: Minswap’s transaction swaps against its pools in the same transaction. On preprod in chunk 15b that meant:

The session refuses all of it today. Chunk 15b listed what allowing it takes (archive). To be designed in detail from a real Minswap-built Danogo transaction recorded first (mainnet, read from chain):

The swap parts (after the foundation)

  1. SundaeSwapV3 onto MAINNET_PROTOCOLS. Owner: one small mainnet swap that routes through it, then a Stop on a second one. Preprod may have no V3 pools.
  2. WingRiders’ smoke test (owner).
  3. DanogoCLMMV1 routed on mainnet, once Foundation 2 is in. Owner: one small swap.
  4. Candidates, not committed:
    • SundaeSwapV4: when Minswap routes it (the owner, 2026-10-07). On 2026-10-07 Minswap’s router didn’t name it on either network. Sundae’s SDK 3.0.0 builds its orders: owner and a destination as V3’s, plus a service budget (3 ₳), partial fills (max_per_execution) and its batcher’s own two-pool routes. Partial fills need the runner to follow an order a fill leaves behind; a two-pool route meets the one-leg rule. Its contracts are private, and no audit is published.
    • VyFinance: its owner is a 56-byte field (payment key hash ‖ stake key hash), the datum travels by hash, and it uses 313 enterprise order scripts.
    • SundaeSwapStable, once a Minswap-built order is seen.
    • CswapV1: closed source, pinned staking part ec39fae0….

Start here

Mainnet runs: the pairs (2026-10-07)

The DEX runs are mainnet’s: preprod’s pools route almost nothing the wallet can buy. Minswap’s mainnet estimate, asked as the wallet asks it (its exclusions, allow_multi_hops: false), routed each of these through one DEX alone, every token on the wallet’s list. A route moves with the pools: the approval names the DEX to check before approving.

DEX Pair Notes
SundaeSwap V3 20 ₳ → SUNDAE, then SUNDAE → ₳ 0.3% impact each way; INDY too
Danogo 20 ₳ → NIGHT, then NIGHT → ₳ 0.3–0.4%; USDM both ways, and USDM ↔ USDA, too
Minswap V2 20 ₳ → NTX, then NTX → ₳ 0.3%; HOSKY too
Minswap (V1) 20 ₳ → MIN Plutus V1: the order’s script and datum go in its cancel
SundaeSwap (V1) MIN → ₳ (3,294 MIN) Plutus V1; 3% impact
WingRiders V2 50 ₳ → USDA, IAG or COPI at 20 ₳, IAG goes through SundaeSwap V3
WingRiders (V1) 50 ₳ → LQ Plutus V1; at 20 ₳ it goes through SundaeSwap V3
MinswapStable USDM → DJED, DJED → iUSD, iUSD → USDM (12 each)  
WingRiders StableV2 iUSD → DJED (12) 0.06%
Spectrum IAG → ₳ (5.9%), ₳ → iBTC (33%) only at a bad price: skip
Splash none found its cancel is tested in Rust only

Minswap charges its aggregator fee (0.85 ₳; 1 ₳ for a stablecoin pair) on every route but its own pools.

Run (the owner, 2026-10-07): “everything works.” Every pair above but Spectrum’s and Splash’s, on a mainnet test wallet: each order placed, filled and its money back, Danogo’s filled in the swap itself; and a Stop on an NTX swap (Minswap V2) and a MIN one (Minswap V1), each cancelled before its fill and the money back. The MIN one is the first live Plutus V1 cancel: the order’s script and datum in the transaction, and its script data hash with_integrity’s, which the node took. With the WingRiders runs, that’s the smoke test. Splash and Spectrum stay open (O2).

Step 3 · Stop’s own cancel (2026-10-07)

Why. The owner’s preprod Stop of a SundaeSwap V3 order (70773ee9…#0, 14 USDR) never cancelled it:

The owner’s call (2026-10-07): Stop must bring the money back. “No one is going to take a wallet seriously that gets the funds effectively stuck.” So the wallet builds every cancel itself, from the session’s own keys and collateral, and asks Minswap for nothing to get money back.

What every DEX’s cancel needs (four research passes, 2026-10-07: real owner cancels decoded from chain, checked against each DEX’s source or bytecode; the SundaeSwap V3 cancel of the stuck order dry-run through Ogmios):

Minswap’s name Order script, Plutus Script Cancel redeemer Signer Notes
Minswap (V1) a65ca58a…, V1, both networks in the transaction (335 B) d87a80 the datum’s sender’s payment key datum by hash: the original bytes go in the witness set
MinswapV2 mainnet c3e28c36…, preprod da952546…1b7a; V2 reference d87a80 canceller = OAMSignature(payment key), field 0 the order’s own staking part is the sender’s
MinswapStable one per pool: 13 mainnet, 3 preprod; V2 reference, per pool d87a80 the sender’s payment key, field 0 Minswap’s SDK lists the wrong reference for 4 mainnet pools; the table has the on-chain ones
SundaeSwap (V1) ba158766…, V1, mainnet in the transaction (2,121 B) d87a80 the destination’s payment key (alternate unset) datum by hash; closed source, the rule found by Ogmios dry runs
SundaeSwapV3 mainnet fa6a58bb…, preprod a989aa2f…; V2 reference d87a80 owner = Signature(stake key): 2/i mainnet’s reference sits at Sundae’s own key
SundaeSwapStable mainnet 6ab62945…, preprod eff5be0d…; V3 reference d87a80 as V3 not routed on mainnet; preprod has no scooper
WingRiders (V1) 86ae9eeb…, V1, mainnet in the transaction (883 B) d87a80 the owner’s payment key datum by hash; Minswap’s orders expire in about 8 h, then only the owner can reclaim
WingRidersV2, WingRidersStableV2 mainnet c134d839…, 23680ea6…; preprod c25f7962…, acefcfe8…; V2 reference d87a80 the owner’s payment key, field 2 references held by a script that can never spend them
Splash, Spectrum both 464eeee8… (Splash’s limit order), V2, mainnet reference d87980 cancellation_pkh (field 10), the payment key output 0 must be the exact refund to the order’s redeemer address: one order a transaction. Partial fills recreate the order at a new outpoint.

The design.

  1. The cost models. ProtocolParameters carries Plutus V1 and V2’s too, and the local evaluator (eval.rs) takes all three.
  2. The table and the readers (seedelf-core orders.rs): for an order output, which DEX’s it is, who must sign its cancel, and where it pays, read exactly from each DEX’s datum.
  3. The builder (cancel_orders): one group of orders (one Plutus version; a Splash order alone), the session’s own UTxOs for the fee, the session’s collateral with its return, every signer a required signer, the scripts by reference (V1’s in the transaction), budgets measured in the wallet, the fee settled. Everything goes back to the session, a Splash order’s exact refund first.
  4. WebAssembly: read_dex_order and build_order_cancel.
  5. The order check (checkOrder): every order sits at a script the table knows, owned by the session’s own key, paying the session’s address. Anything else is refused before it’s signed. So every order the wallet places is one it can cancel itself.
  6. Stop: the orders to cancel are the swap’s recorded ones that are still unspent, and any order under the session’s stake key (a partial fill’s), from Koios, never Minswap’s list. One group a transaction, then the return. A swap waiting on an order it can’t cancel says so.
  7. Tests: for each DEX, a real order cancelled through its real script in the local evaluator, and refused with the wrong key.
  8. Live: the stuck preprod V3 order first; then a preprod Minswap V1 order (tADA→MIN, the only preprod pair the wallet can buy that routes to a batcher that fills: tADA→tUSDM has no route, 2026-10-07), stopped before its fill; then the owner’s mainnet runs, Minswap V2’s cancel among them.

Built (2026-10-07).

Built (2026-10-06)

Committed and pushed: the foundation (7886971), SundaeSwap V3’s swap part (29777c2), Danogo’s (04d0022), and Direct routes and Danogo’s costs (below, 00fde82).

Sundae.

Danogo.

SundaeSwap V3’s swap part (2026-10-06).

Danogo’s swap part (2026-10-06).

Wording outside the swap page: checked. Two lines on the approval were wrong for a pool swap, and are fixed:

Direct routes and Danogo’s costs (2026-10-06).