Skip to content

feat(dapp): run onchain venues on every chain, with a way back out of each - #154

Merged
0xDeon merged 4 commits into
feat/chain-sequencesfrom
feat/onchain-venues
Nov 6, 2026
Merged

0xDeon merged 4 commits into
feat/chain-sequencesfrom
feat/onchain-venues

Conversation

@0xDeon

@0xDeon 0xDeon commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #152. Merge #150, #151 and #152 first. #153 also sits on #152, so whichever of this and #153 lands second needs a rebase.

No real wallet has signed anything here. Checks only read chain data, build transactions or simulate them. Preview: https://runintent-dapp-54vsypcym-cookit-labs.vercel.app (behind Vercel login, mainnet, its own Postgres).

What this does

  • New venues on Avalanche, Monad, Sui, Solana and NEAR, each allowlisted and failing closed, with a real logo.
  • A way out of every venue a person can deposit into. Withdraw, unstake and repay where they were missing, claim for exits that take time, and cancel for streams.
  • Exits go to the money. With no venue named, pickExitVenue reads each venue's new positions and goes to whichever holds the token, and asks if two do. "all" reads the live figure, and empties the position exactly where the contract allows.
  • "where is my money" answers in the chat, through /api/chain/[chain]/positions. A venue that couldn't be read is named, never shown as empty.
  • Borrowing on Solana (Kamino Lend), Sui (NAVI, Suilend, Scallop) and NEAR (Rhea Lend).
  • Every chain but Stellar is marked beta. A tag in the chain switcher and connect picker, and a notice on entering a chain, saying a transaction can fail and may still cost the fee. It shows once per chain in a browser, kept in localStorage, so toggling between chains doesn't bring it back. Raising BETA_RELEASE in lib/chain-beta.ts shows it once more.
  • The dollar cap is gone from every route, Stellar and cash-out included, at the owner's request. Tokens with no live price are no longer refused either, and MAINNET_MAX_TRADE_USD is no longer read. NEAR's 1,000 NEAR and 10,000 token ceilings are gone too. The $500 confirm pause stays.
Chain Withdraw Unstake Claim Borrow, repay Cancel stream
Solana Jupiter Lend, Kamino Earn, Kamino Lend, Lulo Jito, Marinade, Solayer Solayer Kamino Lend Streamflow
Sui NAVI, Suilend, Scallop SpringSui, Aftermath, Walrus Walrus NAVI, Suilend, Scallop
NEAR Rhea Lend, 1Click Earn Meta Pool, rNEAR Meta Pool, rNEAR, 1Click Earn Rhea Lend
Avalanche Aave Aave Sablier
Monad Aave, Neverland, Morpho, Euler, Curvance, Beefy FastLane Aave, Neverland Sablier
Stellar Blend, liquidity pools, cancelling orders Blend repay

Bugs fixed on Stellar

  • "supply 5 USDC" signed 5 XLM, and a swap to USDC then lend supplied XLM.
  • "repay all" failed on mainnet for everyone: its i128::MAX is too large for the host's i64.
  • Collateral had no withdraw button, and non-XLM supplies were invisible.
  • "withdraw 25 XLM" typed in chat reached a model whose sheet listed no withdrawal. It now opens a card without the model.

Where to look hardest

  • lib/chains/prepare.ts: exit routing and "all".
  • lib/chains/near/rhea-safety.ts: a separate policy that allows ft_transfer_call only to pinned Rhea contracts, while near/safety.ts keeps refusing it everywhere else.
  • lib/chains/solana/stake-claim.ts: stake accounts now use seeds intent-stake-0..19, because public RPCs refuse getProgramAccounts. An account from the earlier timestamp seed wouldn't be found, which only matters if someone signed a Solayer unstake on the first preview.
  • lib/chains/evm/aave.ts: a whole repay names debt plus 0.01% plus 1 unit with an equal approval, rather than max-uint.

Known limits

  • Rhea lost about $18.4M in April 2026, and recovery is unconfirmed. The owner chose to keep it, and the card says so. Rhea DEX is NEAR's default swap, because 1Click refuses every route with an on-chain NEAR leg. That is on 1Click's side, tested without an API key, and no key exists on Vercel to try.
  • 1Click Earn: its exit sells through 1Click, so with those routes refused nobody can enter it, and the sale has only run on a stubbed balance.
  • NEAR can't simulate writes, so NEAR payloads are checked against contract code and views only. They are the least proven here. Prod also needs NEAR_RPC_URL.
  • Jito's ready reserve held about 0.12 SOL, so larger unstakes refuse and point to a swap on Jupiter.
  • Kamino Earn and Lulo exits need the company's API, so they fail the strict onchain test on exit. One Kamino vault kept refusing during testing while another worked.
  • Scallop can't open a position in the app, and staked Scallop loans refuse and send people to its site. Scallop borrow through prepare never ran to success, because the one usable position sat at its limit.
  • Cash-out: NEAR stays closed and Monad isn't built, since a late or rejected delivery could lose funds. Weave has not paid out a real order in this app.
  • Noether stays off: its mainnet contracts are paused until an audit clears. Blend's mainnet pool is on ice, so new Blend borrows refuse.
  • Haedal is built but on hold, and Euler on Avalanche is built but off. Neither is registered.

Before prod

Set AVALANCHE_RPC_URL, MONAD_RPC_URL and NEAR_RPC_URL. The preview got the first two per deployment, not as project env. Naira through Linq can't be tried on the preview until LINQ_* is added there, because Vercel won't reveal sensitive values to copy.

Checks

  • tsc and eslint: clean, apart from one existing warning in hooks/use-sequence.ts.
  • Non-live vitest: 7,511 of 7,512. route-rate-limit on the compete route times out under full load and passes alone.
  • Live on-chain, on the tree before the final rebase and the NEAR ceiling removal: 445 passed, 18 failed, 66 skipped. Five pass rerun alone. Of the 13 left, 8 are the 1Click refusal, 2 the Kamino vault, 1 the Jito reserve, 1 a Stellar price feed timeout, and 1 a Solayer unstake test with no large enough holder.
  • Browser specs on a local dev server: all pass, including the beta and toggle specs. "a typed swap" in chain-action fails on a cold server, sitting on "Broadcasting to the agent network…", and passes once it has warmed up, so it may need a look if it flakes in CI. network-switch skipped, as it needs a server serving both Stellar networks. CI runs only on PRs into main or develop, so this stacked PR has no checks until it is retargeted.
  • Windows next build fails at /icon, as before. The Vercel build passes.

Adds venues that the person's own wallet signs, on Avalanche, Monad, Sui and
Solana, for swaps, lending, staking and payments, plus paying a name. Every
venue is allowlisted and fails closed. No real wallet has signed any of them.

Removes the mainnet dollar cap from every route, Stellar and cash-out included,
which also ends the refusal of a token with no live price. MAINNET_MAX_TRADE_USD
is no longer read. NEAR's 1,000 NEAR and 10,000 token ceilings stay.

Haedal is built but on hold: not registered or listed, and haSUI is off the Sui
token list. Euler on Avalanche is built but not registered.
Every venue a person can deposit into now has a way out in the app. No real
wallet has signed any of this.

Adds withdraw, unstake and repay where they were missing, a claim step for exits
that take time, and cancelling a stream. An exit with no venue named goes to
wherever the money is, read from the chain, and "all" empties a position exactly
where the contract allows. "where is my money" answers in the chat.

Adds borrowing on Solana through Kamino Lend, on Sui through NAVI, Suilend and
Scallop, and on NEAR through Rhea Lend. Rhea DEX becomes NEAR's default swap while
1Click refuses every route with an on-chain NEAR leg.

Fixes on Stellar: "supply 5 USDC" signed 5 XLM, a swap then lend supplied XLM, and
"repay all" failed on mainnet. Adds the missing collateral, non-XLM, liquidity pool
and order exits.

Removes NEAR's 1,000 NEAR and 10,000 token ceilings, and stops reading a leading
"tell" as a typo of "sell".
@0xDeon
0xDeon merged commit 174752a into feat/chain-sequences Nov 6, 2026
0xDeon added a commit that referenced this pull request Nov 6, 2026
…ng conflicts

Brings #153 onto land/chain-stack, whose tree is feat/chain-sequences with #154 and #155 in.
Merged against chain-sequences, where #153 forked, so only real overlaps conflicted (29 files).

Where the two PRs met:
- sui/deepbook.ts: both added it. #154's swap venue keeps the name; #153's limit venue moves
  to deepbook-limit.ts as deepbookLimitVenue. The limit row is now "DeepBook Limit Orders",
  beside DeepBook's swap row, and deepbook.webp is back for that row.
- The agent race: #155 moved settling and sending into settleAndMeasure and sendProposal, so
  the resting-order route and settleChainPlan's rest option live there now.
- prepareChainAction: the limit check runs on the settled request, inside #154's flow.
- #154 removed the trade caps, so the cap test for limit orders and the size ceiling on a
  Rhea order go with them.
- The native reserve: limit joins SPENDS_FROM_WALLET, or #154's early return skipped the
  setup-cost check for every limit order.
- confirmEvmCall refuses a signed CoW message outright, as 1Click and send already did,
  instead of leaving it pending on #154's new EVM venues.
- Test fakes of EvmClient gain the allowance and code that #153 added.
0xDeon added a commit that referenced this pull request Nov 6, 2026
#154 added a beta notice on entering each chain but Stellar, and gave every spec that clears
storage BETA_NOTICE_SEEN. #155's agent-talk spec was written beside it and cleared everything,
so Solana's notice covered the chat and every click timed out once the two met in #156.
0xDeon added a commit that referenced this pull request Nov 6, 2026
…agents talk on main (#156)

* feat(dapp): land the agent race, chain sequences, onchain venues and agents talk on main

#151, #152, #154 and #155 were squash-merged into their stack branches, not
main, so main held only #150. This commit's tree is feat/chain-sequences as
merged (ad9142e): #150 through #155 except #153, with nothing else added.

* feat(dapp): limit orders off stellar, and agents that recommend resting one (#153)

* feat(dapp): connect a wallet on every chain, behind a wallet gate

Adds wallet connection on Stellar, Solana, Avalanche, Sui, Monad and NEAR,
a connect page in front of the app, the shared prepare, sign and submit
layer for chain actions, venue logos, native coin prices, and mainnet-only
production routing.

* feat(dapp): swap, lend and earn on solana

Jupiter swaps, Jupiter Lend, Kamino and Lulo, each checked against an
allowlist of programs before signing and again on the signed bytes.

* feat(dapp): swap, supply and stake on sui

Cetus swaps, NAVI supply and SpringSui staking, with allowlisted Move calls
checked before signing and again on the signed bytes.

* feat(dapp): swap, earn and stake on near

NEAR Intents 1Click swaps and earn, and Meta Pool and rNEAR staking, with
each wallet payload checked before signing.

* feat(dapp): cash out usdc through weave on five chains

Stellar, Solana, Avalanche, Sui and NEAR pay out to NGN, KES, UGX and TZS.
The chat asks which currency when none is named, and the bank picker is per
country. Stellar naira stays on Linq. Off until WEAVE_SECRET_KEY is set, and
no real payout has been completed yet.

* fix(dapp): accept weave's real order amounts on a live test

Live unfunded orders showed Weave asks for about 1% over the amount named,
so the exact-match check refused every order. A deposit may now run up to 2%
over and the review shows what will really be paid. Also reads Solana
balances without an indexed RPC call, and stops presenting a bare OK from the
account check as a verified holder's name.

* docs: plan the agent race on every chain

* feat(dapp): let the agent race take a chain action

* fix(dapp): refuse a bad race amount before quoting

* feat(dapp): give agents each chain's own facts

Off Stellar the agents get a mainnet prompt with one fill, the chain's own venues and no
Stellar tokens, and routes scored in dollars from display amounts. Supply and stake routes
rank on APY and carry no slippage.

* fix(dapp): keep an unpriced swap from winning and show dollars on chain routes

* feat(dapp): quote near venues for the agent race

* feat(dapp): run the agent race on near from chat

Typing a swap, supply or stake on Solana, Sui or NEAR starts the race, and Review on a route
builds it through the chain's own card with only the venue taken from the route. When the race
ends with nothing to review, the direct route is built and the card says so. A refused action
gets its own error code so it is shown as written and not retried.

* fix(dapp): keep chain routes off the swap hook and close the race's stale paths

A chain route is never given to the Stellar swap hook, which threw on it and would have built
a second signable card. A superseded build is ignored, a race ends on cash-out, history and reset,
and Review stays closed once a signature was given. Copy and figures now say only what is true.

* fix(dapp): hold the signed latch for the whole race and check the wallet before signing

The latch now outlives the card, so Dismiss and Done no longer reopen Review. It is set before a
self-sending wallet is called, and a decline or error there asks the user to check the wallet. The
connected account is compared with the one the card was built for, and the panel stops saying
nothing was signed once something may have been.

* fix(dapp): report an unknown submit outcome as pending so the latch holds

The chain submit route, the Solana confirm timeout, Jupiter's unreadable or unknown reply and
the NEAR confirm paths now say pending whenever the money may have moved. Only an answer that
proves nothing moved stays a clean failure. The panel keeps a separate flag so it never says
nothing was signed after a signature was asked for.

* fix(dapp): only call a solana submit clean when the answer proves nothing moved

A clean answer re-opens signing, so a false one can spend a user's money twice.

- Expired blockhash takes a final status read after the validity answer, and any
  unanswered poll or earlier sighting now means pending.
- A failure in a block only counts at confirmed or finalized.
- Send errors are clean only for -32002 and the preflight error names, and a
  non-2xx RPC answer or AlreadyProcessed is unknown.
- Jupiter -1000, -2000 and non-2xx without a known clean code are pending, and
  pending wording says not to send again and names Jupiter's signature.
- The route separates assertSafe failures, which sent nothing, from later throws.

* feat(dapp): race jupiter and cetus against 1click

Solana and Sui join the agent race. 1Click is a real second swap route
there: a dry quote in the race, a real one only at Review, and one
transfer to its deposit address for USDC or USDT.

The browser carries context back at submit, so the deposit it names is
signed by this server and checked in assertSafe, which now receives it.
A swap that fails at 1Click after the transfer is pending, never clean.

* fix(dapp): value 1click like every other route and answer inside the submit limit

The race now prices every Solana and Sui route from the chain's source, and
takes the Solana deposit's rent off 1Click's value. A native output never
matches a wrapped mint. Jupiter and the chain route's Solana submit answer
pending inside 60 seconds, and the hook reads an unreadable answer as pending.
The Apps rows list 1Click without claiming it runs, as the rows can't read
the secret, and the module wires it only with that secret.

* feat(dapp): swap and race on avalanche and monad through 1click

Avalanche and Monad get their first swaps, and join the agent race, with 1Click
as the one route. AVAX and MON can be spent here, so an EVM payload's value is
now decimal base units. Weave's Avalanche deposit still asserts zero and now
refuses any token but USDC.

The wallet sends for itself, so the proof is checked at prepare and submit asks
the chain: the receipt, the value for a native transfer, and the Transfer log
for a token. Only this account's revert, to the expected address, is clean.
Anything else after a signature is pending, including an expired quote or a
proof that doesn't hold, since neither can show nothing was sent.

Balances are read before the real quote, so someone who can't pay never gets a
deposit address, and native input keeps gas back. Monad says USDT0 by name, and
someone typing USDT is told so.

* fix(dapp): bind an evm revert to this transfer and read the chain's name as no venue

A revert on a token had only from and to behind it, and to is the contract, so
the account's earlier failed call read as nothing moved. The transaction is now
read, and only this transfer's exact calldata and value answers clean.

Naming the chain you are on counts as no venue named, in the race and at
Review, and another chain's name is refused rather than run here.

A native MON spend leaving under 10 MON carries a note on the card, and its
revert names the reserve as the likely cause. It warns and doesn't refuse, since
an undelegated account can succeed.

* fix(dapp): answer pending when an evm revert or amount can't be read

A read that resolved to a transaction with no input, or to null, threw past the
pending answer, because only the read was inside the try. A malformed amount
threw before any answer too. Both are pending now, and never the clean sentence.

* feat(dapp): record the chain of every agent race

Races carry the chain they ran on, other chains' races and submits are logged as mainnet,
a submit only links a race of its own chain, and the history route reads every chain's account.

* fix(dapp): read no stellar network when loading the chain name list

Walking every chain descriptor at import read Stellar's live descriptor, so the compete and
prepare routes threw on load on a deployment serving both networks.

* fix(dapp): send a chain submit's own race id and match evm accounts by any casing

A chain submit now carries the race it was chosen from, on a single-network deployment too, and
none after the direct fallback. History finds an evm account whatever its casing.

* fix(dapp): hold the card's venue on a second press and name the venue and rate in the race panel

Pressing Review or Selected for the venue already on the card built a second deposit
address. It is now ignored, and another venue can still replace the card.

The plan tag read a source chain routes don't have, so "via Jupiter" never showed. It
falls back to the route's venue name.

A route with no rate tied the best rate and could be recommended for a measured fill it
didn't have. It now scores below every route with a rate, and the recommendation names
the rate or says it is unknown. Stellar passes no rates and has no figures, so its scores
and its sentence are as they were.

* fix(dapp): say which chain each race in an account's history ran on

One EVM address can race on Avalanche and Monad, and its history rows couldn't tell the
two apart. The read now returns the race's chain. No screen shows it yet.

* fix(dapp): read an amount like .5 as 0.5 so its build isn't refused

The chat read ".5" but the build route refuses that shape, so "swap .5 USDC to SOL" ended
on the raw code invalid_body. Every other amount reads as before, and Stellar's chat
doesn't use this parser.

* fix(dapp): refuse a race with no venue and stop promising what a chain can't run

Asking for something no venue offers ran through "the agents did not race", then the
direct route, then a refusal. The race now refuses once, with no fallback. Venues that
exist but can't price right now keep today's wording.

The capability sheet reads the chain's venues, so with AUTH_SECRET unset Avalanche and
Monad no longer claim a race. Solana and Sui still race on their own venues. The sheet's
only importer is the orchestrator, which only an API route runs, so nothing server-only
reaches a client bundle.

With the agents offline off Stellar the message no longer says nothing can be executed,
since the direct route is built right after it.

* fix(dapp): warn about a chain transfer already started, even after a reload

The latch that stops a second signature lives in memory, so a reload during a long status
wait lost it, and retyping could spend the amount twice. Each signature now leaves a note
in localStorage for 15 minutes, and a new card for the same chain, account, token and amount
says it was started and links the hash when there is one.

It warns and never blocks, and failed storage changes nothing. An answer that proves nothing
moved removes the note. Pending and success leave it. The latch rules are as they were.

* docs: plan multi-step transactions on every chain

* feat(dapp): show each payout currency's country flag

* feat(dapp): read every token a wallet holds on each chain

* fix(dapp): read held tokens from the chain, bound the read and drop stale balance replies

* fix(dapp): never leave the chat busy after a dropped balance reply, and clear it on new chat

* fix(dapp): show a disconnected person's balance reply instead of a wallet-changed notice

* feat(dapp): keep the chat until a new chat starts

Leaving the intents page unmounted the chat and lost it. ChatHost now holds it
in the chain layout from the first visit, hidden on other pages, so a race, a
card or a payment being followed carries on. A per-wallet, per-chain transcript
of words and explorer links brings the conversation back after a reload, read
only. New chat clears both. Stellar's saved turns are untouched.

* fix(dapp): start a switched wallet fresh and keep private figures out of the transcript

Another wallet connecting now resets the open chat, or waits with a notice while a
signature is open, recording to the signer until it ends. A chain card or position left
open is refused on return once stale. Stored text is masked and capped, signature
notices are not stored, and a reset shows the saved turns as a reload would.

* fix(dapp): make the wallet switch notice true after a cash-out is paid

* feat(dapp): read a swap and what comes after it

* fix(dapp): keep a refused currency, say what reached the wallet, and read only real addresses

* feat(dapp): swap then cash out on solana, sui and avalanche

"cash out 5 SOL" and "swap 5 SOL to USDC then cash out" now run the ordinary race for a
swap to USDC, then measure from the chain what arrived and offer the cash-out on a press.

A pending step 1, or a wallet error after sending, never reaches step 2 and tells the
person to check their wallet. A clean failure ends plainly and can be retried from the
same race. A failed balance read is never guessed at. Supply, stake and send after a swap
are refused as not yet available before anything is signed.

* fix(dapp): check a chain sequence's words, balance and size before the swap is signed

A cash-out the model wrote out runs only if the person's own words carry its amount and
token. The balance before the swap is read from when the card starts building, once more
on failure, and the card says plainly when the cash-out would not follow. A size Weave
would refuse is said before signing, from a quote that makes no order. A currency question
ends on a chain switch and "cash out to KES" answers it. Balance reads get their own limit.

* fix(dapp): read a chain's name as its token in what a person types

"Offramp 0.01477 solana" asked for a token the chain's table does not list, so it was
refused. Off Stellar, solana, avalanche and monad now read as SOL, AVAX and MON, and a
model's written-out cash-out compares through the same words, except where the person
named the chain as a place, such as "5 USDT on solana". Stellar's answers do not change.

* feat(dapp): swap then deposit, stake or send on every chain

A send reuses each chain's deposit builder and signs its recipient, token and amount with an
HMAC proof, so a browser can't swap them. Without AUTH_SECRET no send venue is offered.

Step 2 of a deposit, stake or send runs on the chainAction card from a press at ready, and a
signed step 2 can't return to ready. A new follow-on route refuses what can't run before step 1.

* fix(dapp): close the race once a sequence's swap settles, and check what a send holds

Review on a settled swap's race could build that swap again over step 2's card, and its settling
would tick step 2. A settled sequence now closes the race, and only a card of the follow-on's kind
can finish step 2.

Also: no claim that nothing was signed after a swap or wallet signature, a known shortfall refused
before a send, decimal commas no longer read as ten times the amount, Solana programs refused as
recipients, and the network's fee and balance sentences kept.

* fix(dapp): read no thousands from a leading zero, and no swap from a zero-led cash-out

"send 0,500 USDC" meant 0.5 and built a card for 500. Thousands can no longer start with a zero,
and a cash-out amount with a leading zero starts no swap off Stellar. A step 2 refusal also reads
correctly whatever "so try again" followed its claim.

* feat(dapp): read multi-step requests in ordinary words on every chain

The orchestrator's reading now reaches the same path as a typed sentence off Stellar. Its amount,
token and any recipient must be in the person's own turns, character for character, or it is
refused in words. The fact sheet, help text and prompt say what each chain can run, and a
leading-zero amount in the plain cash-out form is dropped off Stellar so the person types it.

* feat(dapp): hold a chain's readings to its own tokens, and gate the token out on the person's words

Off Stellar the orchestrator route allows the chain module's tokens, coin and name words, and its
deposit venues, instead of Stellar's registry, and Weave as the one payout where a swap can end in
a cash-out. A model's output token must be one the person named, except USDC before a cash-out.

* fix(dapp): keep a swap's order in the person's words, and stop telling other chains about stellar

The amount must sit by the token given up and the token received must come after it, read across
the person's turns in order. The prompt is built per chain, the balance line says what each chain
reads, a venue the model adds to a plain action is dropped unless typed, and a spelling a chain
has a hint for is answered with the hint.

* fix(dapp): keep step 2 from offering the swap again, and stop near cards past their deadline

An expired step 2 card told the person to send their request again, which offers a second swap.
It now points at the button, which is there because an expired card proved nothing moved. A wallet
that gave no answer has no button, so that sentence says to check and not to send the request again.
NEAR's wallet sends for itself, so its deadline is checked before the wallet opens, as EVM's is.

* fix(dapp): report a follow-on the server can't honour, off stellar only

No anchors, no venues or an unknown venue dropped the follow-on and left a plain swap to sign.
Off Stellar the reading now says what was refused, and a venue's name matches whatever its spaces
and hyphens. Stellar's options, reading and prompt are unchanged.

* fix(dapp): send ordinary words to the model, and hold step 2 to what the person said

readChainMessage now decides: only what the strict parsers read in full stays out of the model, and
a verb no longer gets a canned answer. A currency as the token out is a cash-out or its refusal. A
follow-on that can't run is refused before step 1, and a model can't choose step 2's venue.
The gate takes the last figure stated. A question keeps the run and its button, and an action ends
it. Unrelated money arriving no longer inflates a send, deposit or stake.

* fix(dapp): pass no figure with a decimal comma, and say why a message went unread

"1,5" read as 15 at the gate. A comma now counts only as a thousands comma, so "1,5" and "0,500"
pass nothing and are refused in words, and a correction typed that way doesn't fall back to the
figure before it. Off Stellar a 429 says so and doesn't blame the words. A step 2 wallet that gave
no answer now offers the step on its own, and a refusal's example keeps to the follow-on said.

* fix(dapp): size dollar amounts at a live price, and stop reading $5 of sol as 5 sol

"swap $5 SOL to USDC" read as 5 SOL, and "offramp $1 worth of solana" was
refused. A figure in dollars now carries amountIsUsd, must be in the person's
own words, and becomes a count of tokens at the chain's price before any race,
card or signature. With no price it is refused. USDC stays at face value.

* fix(dapp): let no model choose between dollars and a count, and price at answer

"swap $1 of sol, no make it 2" ran as 2 SOL, and "5 sol if above $100" let the
model pick either figure. A bare figure now only corrects dollars already said,
and R$ or CA$ are not dollars. A currency question left open is priced when
answered, and a retyped dollar amount still gets the duplicate warning.

* fix(dapp): say which agents didn't answer, and tell them a later step runs itself

A race that lost agents read as if they never existed, and agents off Stellar
told people a cash-out was a separate job, when step 2 follows the swap.

* docs(dapp): plan limit orders off stellar, with the venue research

* docs(dapp): always state a recommended strategy off stellar

* feat(dapp): read a limit order and do its price sums

* fix(dapp): make a limit order's side and token received the person's own words

* feat(dapp): route limit orders and refuse them where no venue is safe

* fix(dapp): check an exit's signing and count a limit's setup cost whatever is sold

* feat(dapp): place, read and close kamino limit orders on solana

Built by hand with kit, since the SDK pins another kit and pulls in web3.js v1. The order key is
made on the server, signs once and is dropped, so solanaAssertSafe now takes one extra signer: the
account the same transaction creates, at 424 bytes, its exact rent, owned by the program.

limoAssertSafe holds a create or a close to exactly what would be built. The output token account
is added because the SDK leaves it out and a fill can fail without it. The live config is read
because its cost sits inside the program's call, where signed bytes can't show it.

* fix(dapp): verify a limit order's own signature and say its fee comes back

A wallet that changed the message under the order key's old signature passed a null check, and the
network's rejection then read as maybe sent. It is now verified, and refused in words.

Simulation shows the 0.003 SOL returns at close, so the note, the app listing and the close wording
say so, and the research records it. The context exception is written into the assertSafe contract.

* feat(dapp): place, read and collect deepbook limit orders on sui

Selling SUI against USDC or buying it, POST_ONLY for 7 days, in one signature on first use.
Sizes come from the chain, and a new manager is registered so a new device finds it.
Collect settles first, because a maker's fill never reaches the manager on its own.
The DeepBook row becomes this venue, with the logo from deepbook.xyz.

* fix(dapp): refuse a merge into a deepbook deposit and correct its notes

A merge into the split coin put more into the manager than the card said, and passed.
Cancelling brings money back in one signature, so the notes no longer say to collect it.
The new risk note names a multisig: the chain shows one holds the key, and not whose it is.

* feat(dapp): place, read and collect rhea limit orders on near

Adds one fenced exception to the ban on ft_transfer_call: an order on the
USDC/wNEAR pool of dclv2.ref-labs.near, its message compared whole.

Storage is its own signature, with thenPrepareAgain, because a wallet given
several transactions promises neither their order nor to stop on a failure.
What a first order still owes is read per account for the reserve.

Mainnet shows cancel_order pays wNEAR out as native NEAR, so the card says a
purchase pays out in NEAR, against the brief's wording. See near.md.

* fix(dapp): refuse a limit order the wallet can't fund, and note rhea's plain order

A wallet with no USDC could pay Rhea's storage for an order that then fails, so
assertLimitCanRun now reads the wallet for every venue, matched on token id.

Keeps LimitOrderWithSwap: no real mainnet use of plain LimitOrder was found, so
what it does on a crossed point stays unread. near.md records the search, and
what the contract's own errors answer.

* feat(dapp): sign and place cow limit orders on avalanche

The first typed message this app asks a wallet to sign. A new evm-typed family carries only
a CoW order: the server checks it against what was asked, the wallet adapter checks its shape
again before signing, and submit rebuilds it, recovers the signer and compares the order id.

Setup is its own signature with thenPrepareAgain: a WAVAX deposit for what a sale of AVAX
falls short by, then an exact approval to the vault relayer. Cancel is invalidateOrder on
settlement. Other EVM venues refuse a typed payload. The logo is cow.fi's own favicon.

* test(dapp): read and quote cow on avalanche mainnet

Quotes and reads only, creating no order. Settles the brief's two unknowns: an owner's orders
are at /account/{owner}/orders (/orders?owner= answers 405), and buying native AVAX through
0xEeee quotes and has filled, so a purchase pays out in AVAX. Also checks the on-chain domain
separator and vault relayer, and reproduces a real order's uid.

* test(dapp): let an avalanche or monad venue claim execution

The rule that no EVM row executes predates signing on Avalanche and Monad. CoW's row now
executes on Avalanche, so the rule allows those two chains and still refuses Arc and the rest.

* fix(dapp): refuse a second open cow sale of a token, and read a duplicate as placed

Every order selling a token draws on one allowance and one balance, so a second open order
would rest on an allowance that can't cover both, or replace the one the first relies on.
prepare refuses it, and refuses when the book can't be read. A DuplicatedOrder answer after a
lost reply means the same signed order is resting, so submit returns its id.

* feat(dapp): let agents recommend resting an order where a venue can hold it

A race off stellar may now propose resting inside a 0.1% to 5% band, and always states one recommended strategy.

* feat(dapp): place limit orders from the chat, and list, cancel and collect them

* feat(dapp): let the model read a limit order, held to the persons own words

* docs(dapp): format the limit order research

* fix(dapp): hold an implied sale to selling words, refuse contract wallets on cow, and say nothing was sent after a signature

* fix(dapp): refuse an implied sale when the person used a buying word

* docs(dapp): format the sui limit order research

* test(dapp): keep the beta notice seen in the agent talk spec

#154 added a beta notice on entering each chain but Stellar, and gave every spec that clears
storage BETA_NOTICE_SEEN. #155's agent-talk spec was written beside it and cleared everything,
so Solana's notice covered the chat and every click timed out once the two met in #156.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant