Skip to content

feat(dapp): let agents read and question each other's strategies, live in the chat - #155

Merged
0xDeon merged 13 commits into
feat/chain-sequencesfrom
feat/agents-talk
Nov 6, 2026
Merged

0xDeon merged 13 commits into
feat/chain-sequencesfrom
feat/agents-talk

Conversation

@0xDeon

@0xDeon 0xDeon commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Stacked on #152. Merge #150, #151 and #152 first. No wallet has signed anything here, and this has not run on a preview.

Agents in a race now read each other's strategies, question each other, and each decide their own final plan, live in the chat, on all six chains.

How a race runs

  1. Each agent thinks through the intent on its own, with the existing prompt and tool, and forms a strategy. It sees no other agent yet.
  2. Each reads the others' strategies and may ask one agent one question.
  3. Agents that were asked answer.
  4. Each decides alone: keep its plan, change it, or hold off.
  5. Scoring runs on final plans only.

Everything closes at 20 seconds. Talk opens once every first take is in, or at 8 seconds with at least two, and never after 14. A late or failed call leaves that agent's last real plan standing, and no words are invented.

Nothing asks agents to agree or to differ. A final plan comes only from that agent's own model call. "All agents agree" is computed from the final plans afterward, and is false if anyone held off.

Safety

  • A changed plan passes the same checks as a first take: validateProposal, settlePlan or settleChainPlan, then measured. The route must have been offered, figures come from the quote, and the amount and tokens stay the person's.
  • Other agents' words reach a prompt through promptSafe, labelled as not instructions.
  • A held plan has no route, no Review button and no score, and can't win. canReview also guards the winner's-route fallback in intent-chat.tsx.
  • If every agent holds off, a pill says so and nothing can be signed, on any chain. This is the one exception to feat(dapp): limit orders off stellar, and agents that recommend resting one #153's rule that every decided race states a recommendation.
  • The server only talks to clients that send talk: true, so a tab open from before this ships gets the race it was built for and never sees a held plan.
  • When someone leaves mid-talk, such as sending a note that restarts the race, the stream's cancel() aborts the model calls still running.

UI

The thread uses agentBubble, systemPill, AgentAvatar and ThinkingDots as they are, with no new styles. Final cards, Review and penalties don't change. The chat scrolls to follow a live race. Talk is saved on the same browser only, because the backend that stores turns isn't in this repo.

What ran

Check Result
Format, lint, typecheck Clean
Unit tests, excluding live 5,095 pass
e2e/agent-talk.spec.ts, real UI with stubbed races 3 of 3 pass

Real models through a local server, quotes only:

Chain Result
Stellar Agents talked, 8.7s
Solana Agents talked, 9.4s
Sui, Avalanche No talk: Qwen's first take was rejected or Groq hit its limit, leaving one agent
NEAR, Monad No race: 1Click refused the test quotes before any agent ran

So talk on NEAR and Monad has only run with faked routes. Speed and eval figures are in lib/agents/evals/RESULTS.md.

Known risks

  • Talk needs two first takes, and those often fail. Qwen gets rejected on some races, and Groq's 8,000 tokens a minute runs out when races are close together. This predates the branch, but it now decides whether talk happens at all.
  • Provider limits. Talk uses up to 8 OpenRouter requests a race against 2 today, so an untopped key runs about 6 races a day instead of 25. Credits should be bought before launch. The default roster also lists poolside/laguna-xs-2.1:free, which OpenRouter no longer serves.
  • Agents may converge. In three eval races with made-up routes, every agent ended on one plan. That sample can't tell sharpening from flattening.
  • Talk turns are shallow by design. Reasoning is off on DeepSeek and OpenRouter so a turn fits the cap. Claude's turn runs at low effort, and is unmeasured because no key was available.
  • Conflicts with feat(dapp): limit orders off stellar, and agents that recommend resting one #153. Task 9 changes brief.ts, settle-chain-plan.ts, chain-race.ts, the race route and the panel. Agents can't choose resting during talk until it lands, at which point the final turn's tool should offer rest wherever a RestOption exists.

Left as is

  • Analytics has no talk counts, to avoid a schema change. A race record stores the final plan.
  • Five minor review findings are open. The one that matters most: a first take that throws, rather than returning a failure, could reject the whole race. Brains don't throw today.

The design is in docs/superpowers/specs/2026-11-05-agents-talking-design.md and the plan in docs/superpowers/plans/2026-11-05-agents-talking.md.

@0xDeon
0xDeon merged commit ad9142e 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