Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
638 commits
Select commit Hold shift + click to select a range
b492339
test(web): on a fork, a 1080 xDAI run whose first batch the wallet ne…
tractorss Oct 19, 2026
5b21d02
docs(web): say an unanswered send's wait can end in a pending error, …
tractorss Oct 19, 2026
ca2b634
refactor(web): name the options a run leaves out leftOut, in its save…
tractorss Oct 19, 2026
9dae9ab
feat(web): take the trade and credits slippage from the run's snapsho…
tractorss Oct 19, 2026
4d0f12f
feat(web): name each previewed leg's pool fee and the option's fees i…
tractorss Oct 19, 2026
91d9813
fix(web): give the dev wallet's send on a local node the app's long t…
tractorss Oct 19, 2026
51ec68e
refactor(web): read the local-node timeout from the env-free chains c…
tractorss Oct 19, 2026
380d718
feat(web): size predict batches from the block gas limit, and keep th…
tractorss Oct 19, 2026
ccc35ef
feat(web): re-read the pools when Predict is pressed, and stop at mov…
tractorss Oct 19, 2026
14e8a48
feat(web): add useCreditsSwapPreview, which reads the credits swap's …
tractorss Oct 19, 2026
f0af71e
docs(web): say a credits failure is a short manager or no route, now …
tractorss Oct 19, 2026
367555b
fix(web): say a recovered run's unconfirmed transfer is a transaction…
tractorss Oct 19, 2026
37e3827
feat(web): keep the visitor's predict slippage per browser, Auto or a…
tractorss Oct 19, 2026
78ab51e
feat(web): name in Details each option's pool fees, an option that st…
tractorss Oct 19, 2026
8ca8e48
feat(web): say on the status line how many estimates' prices moved be…
tractorss Oct 19, 2026
ccf1ad2
feat(web): open max-slippage settings from a gear in the predict popu…
tractorss Oct 19, 2026
44d4fc5
feat(web): hold a run to the plans Details showed, show and confirm t…
tractorss Oct 19, 2026
b11165f
test(web): harness states for settings, moved prices, pool fees, a sh…
tractorss Oct 19, 2026
c8099d8
fix(web): warn on a high credits swap slippage in the swap's words, n…
tractorss Oct 19, 2026
6462219
test(web): the settings open under the header, whole, from a popup a …
tractorss Oct 19, 2026
6691baa
fix(web): hold every predict batch to the plans and credits swap Deta…
tractorss Oct 19, 2026
3bbf0ea
fix(web): save a slippage on blur or Enter, refuse 0, warn on a low o…
tractorss Oct 19, 2026
0236a64
fix(web): open Details on moved figures, name what moved, and offer a…
tractorss Oct 19, 2026
73b0ba6
test(web): harness specs for Done, the keyboard wrap, a kept invalid …
tractorss Oct 19, 2026
3a78976
fix(web): hold the funds step at a run's moved stop, and fail the cre…
tractorss Oct 19, 2026
fe13711
fix(web): hold a credits swap to the floor Details showed only for th…
tractorss Oct 19, 2026
ae7bc15
test(web): the fork Predict test names a dropped wallet or a session …
tractorss Oct 19, 2026
91bba10
test(web): keep a Playwright trace for a local failure, as CI keeps o…
tractorss Oct 19, 2026
f304343
fix(web): a held run's retry takes up the visitor's new slippage, and…
tractorss Oct 19, 2026
2ed965d
feat(contracts): grant Foresight credits to a test account on a local…
tractorss Oct 19, 2026
0a062e2
fix(web): name the slippage in use in Details as a value, never Auto,…
tractorss Oct 19, 2026
2966e41
feat(web): compact the predict settings into a card over the dimmed b…
tractorss Oct 19, 2026
4e07db3
feat(web): offer Try again on the button when prices could not be rea…
tractorss Oct 19, 2026
b9aa078
test(web): harness specs for the compact settings, the gear's mark, T…
tractorss Oct 19, 2026
9dcb25a
fix(web): keep a retry's new slippage out of the stored run until the…
tractorss Oct 19, 2026
771948e
fix(web): Details names the slippage the next press signs with, and t…
tractorss Oct 19, 2026
6cd0c2c
fix(web): settings show each hint and one name, offer Reset on a refu…
tractorss Oct 19, 2026
8c25d4c
fix(web): a click on the settings card's blank space leaves the field…
tractorss Oct 19, 2026
6fd1ed4
test(web): a harness state for plans moved by new slippage, and a ret…
tractorss Oct 19, 2026
740ea2f
feat(web): the more-below cue sits under a padded hairline, and its a…
tractorss Oct 19, 2026
85ef98a
fix(web): the share slider draws a plain track, without the step dots…
tractorss Oct 19, 2026
54ff7e2
test(web): Details baselines with the more-below cue's padded strip
tractorss Oct 19, 2026
9d6eede
test(web): the settings and credits harnesses open without waiting ou…
tractorss Oct 19, 2026
c0ec325
Merge branch 'issue/2026-10-19-foresight-predict-round9' into issue/2…
tractorss Oct 19, 2026
28e6cf3
Merge branch 'issue/2026-10-18-foresight-credits' into issue/2026-10-…
tractorss Oct 19, 2026
c49cba1
fix(web): the more-below nudge stops only at the visitor's own scroll…
tractorss Oct 19, 2026
e9f561c
fix(web): the share slider's rail has an edge the panel can be told from
tractorss Oct 19, 2026
6fff4ae
fix(web): the Add funds step says credits and a large xDAI deposit whole
tractorss Oct 19, 2026
7a4e31c
test(web): popup baselines with the edged share-slider rail and the l…
tractorss Oct 19, 2026
87e98f5
fix(web): arrow keys that scroll the popup body from a button settle …
tractorss Oct 19, 2026
2360ecf
chore(web): drop the unused fs-popup-track colour utility and format …
tractorss Oct 19, 2026
6b5c00a
Merge branch 'issue/2026-10-20-foresight-predict-popup-polish' into i…
tractorss Oct 20, 2026
7477536
test(web): xDAI fork runs claim the sDAI vault's pending interest first
tractorss Oct 20, 2026
975fac7
test(web): the popup harness's Add funds step uses the credits-aware …
tractorss Oct 20, 2026
ff7fe3c
feat(web): named duration tokens for loops and nudges
tractorss Oct 20, 2026
7cb420d
fix(web): the more-below cue nudges its words with its arrow, and dro…
tractorss Oct 20, 2026
0580eb1
fix(web): a recovered xDAI run's note names the sDAI its deposit becomes
tractorss Oct 20, 2026
c55bebc
Merge branch 'issue/2026-10-20-foresight-predict-round10' into issue/…
tractorss Oct 20, 2026
d863e75
fix(web): an empty credits pool asks the visitor to pay from their wa…
tractorss Oct 20, 2026
ed1d47a
fix(web): a recovered xDAI run's note names its figure as the deposit…
tractorss Oct 20, 2026
c0bffef
test(web): the popup harness's stored run fills Add funds from its ow…
tractorss Oct 20, 2026
44fa713
test(web): the credits loss line counts its line boxes instead of com…
tractorss Oct 20, 2026
d18a73e
fix(web): the more-below cue lifts 2px and drops 3px over a two-line …
tractorss Oct 20, 2026
dcf28b2
feat(web): the popup's spinners, sweep delay and reduced-motion fade …
tractorss Oct 20, 2026
8f85b36
test(web): the recovery note's line count reads its line boxes, with …
tractorss Oct 20, 2026
86218f1
fix(web): an empty credits pool says "None usable now. Use your own f…
tractorss Oct 20, 2026
0e746af
fix(web): both recovery notes open "Locked to this prediction's amount"
tractorss Oct 20, 2026
fc88171
refactor(web): the reduced-motion fade's token sits with the other du…
tractorss Oct 20, 2026
e38829b
test(web): a stored run's Add funds step keeps its credits once the p…
tractorss Oct 20, 2026
cd5bd43
style(web): import order and formatting in the credits tests
tractorss Oct 20, 2026
213eff4
docs(web): the harness's deposit rate comment holds for the default only
tractorss Oct 20, 2026
8d2900c
Revert "fix(web): the more-below cue lifts 2px and drops 3px over a t…
tractorss Oct 20, 2026
0f13a43
Merge branch 'issue/2026-10-20-foresight-predict-decisions' into issu…
tractorss Oct 20, 2026
a29017a
fix(web): a run short of its fee says it in the wallet dialogs' words
tractorss Oct 21, 2026
f6b8340
fix(web): the more-below cue lifts 2px and drops 3px over a two-line …
tractorss Oct 21, 2026
e802b89
feat(web): the Predict card shows the picks it will send, with a phon…
tractorss Oct 21, 2026
6f02a7e
feat(web): batches are sized by the higher of the budget and a live g…
tractorss Oct 21, 2026
3b1ba50
fix(web): the share slider shows on every screen, short phones included
tractorss Oct 21, 2026
4f9c2f2
fix(web): the phone Predict bar sits under an open dialog
tractorss Oct 21, 2026
88d0f0d
fix(web): the phone Predict bar holds its place, leaves as it came, a…
tractorss Oct 21, 2026
ef21d92
fix(web): the share slider's hit area gives way to the credits line's…
tractorss Oct 21, 2026
bd707e0
test(web): the scroll a first credits tick press makes is recorded, n…
tractorss Oct 21, 2026
130f218
fix(web): batch sizing keeps only a count a live estimate shows fits
tractorss Oct 21, 2026
732639d
fix(web): confirming moved prices keeps the batches the popup showed
tractorss Oct 21, 2026
91b6112
fix(web): the phone bar waits for the stored run to be read, and skip…
tractorss Oct 21, 2026
44f0438
Merge branch 'issue/2026-10-21-foresight-predict-round11' into issue/…
tractorss Oct 21, 2026
bbaa400
test(web): a stored run holds the card's Predict until it is resumed …
tractorss Oct 21, 2026
16d703b
fix(web): the card holds Predict while an unfinished run is stored, a…
tractorss Oct 21, 2026
f2e681c
test(web): at 320 wide the moved popup stacks Confirm over Go back in…
tractorss Oct 21, 2026
f169849
fix(web): under 375px the moved popup stacks Confirm new prices over …
tractorss Oct 21, 2026
1166433
test(web): the card harness stores its run with a bare owner ctx
tractorss Oct 21, 2026
d04c049
test(web): the card holds Predict until the stored run is read, on mo…
tractorss Oct 21, 2026
04aa59c
fix(web): the card holds Predict until the stored run is read, and re…
tractorss Oct 21, 2026
59cec29
test(web): the card says why Predict is held inside the stored run's …
tractorss Oct 21, 2026
0f62e10
fix(web): the stored run's row says to resume or discard it, instead …
tractorss Oct 21, 2026
e2b162a
test(web): the moved footer's focus runs in drawn order, and Go back …
tractorss Oct 21, 2026
e79583b
fix(web): stacked under 375px, Go back follows Confirm in the DOM and…
tractorss Oct 21, 2026
5a1cd79
test(web): the moved status keeps each figure with its unit
tractorss Oct 21, 2026
153966e
fix(web): the moved status joins each figure to its unit with a no-br…
tractorss Oct 21, 2026
262d0d6
Merge branch 'issue/2026-10-21-foresight-predict-round12' into issue/…
tractorss Oct 21, 2026
0ff60a0
fix(web): the moved-credits and credits-unavailable status lines say …
tractorss Oct 21, 2026
e95d81a
fix(web): the type roles set longhands, so a weight, size or leading …
tractorss Oct 21, 2026
bd1f020
feat(web): a status line says when a run is checking something before…
tractorss Oct 21, 2026
07c0a86
feat(web): the status line is a callout, and the popup's bottom half …
tractorss Oct 21, 2026
faf5bec
test(web): the steps' type and row heights, the callout's gap over th…
tractorss Oct 21, 2026
1b4b091
feat(web): explorerTxUrl links a transaction on the chain's explorer
tractorss Oct 21, 2026
1262640
feat(web): a settled step in the run's progress carries the hash it c…
tractorss Oct 21, 2026
54789ef
feat(web): receiptRows lists a finished run's steps with their figure…
tractorss Oct 21, 2026
12660a1
feat(web): a finished run hands the success dialog its steps, what it…
tractorss Oct 21, 2026
71c90f9
feat(web): the success dialog is the run's timeline, finished
tractorss Oct 21, 2026
569b951
fix(web): a dialog's overlay sits over the sticky header, so a tall o…
tractorss Oct 21, 2026
07f70b4
test(web): the popup snapshots draw the overlay over the header strip
tractorss Oct 21, 2026
bde637c
refactor(web): the overlay layer stays private to Modal, and Dialog d…
tractorss Oct 21, 2026
6304819
test(web): the phone Predict bar rises from the bottom edge and docks…
tractorss Oct 21, 2026
6972e48
feat(web): on phones Predict rides a compact bar at the bottom that d…
tractorss Oct 21, 2026
8a39f57
test(web): a leaving phone bar whose exit is cut short still lets go …
tractorss Oct 21, 2026
749a8eb
fix(web): the phone dock settles on animationcancel, so a window wide…
tractorss Oct 21, 2026
6adf573
test(web): the pinned phone bar keeps one footprint and docks once wh…
tractorss Oct 21, 2026
6480739
fix(web): the phone dock re-measures its docked height off a hidden c…
tractorss Oct 21, 2026
e07e3e6
test(web): the docked card's second chip keeps its entrance from the …
tractorss Oct 21, 2026
76c4e76
test(web): a dock that went live on a wide window drops its entrance,…
tractorss Oct 21, 2026
181adae
fix(web): a dock that does not pin at this width ends its entering phase
tractorss Oct 21, 2026
9deae6f
test(web): the pinned chip keeps at least eight characters of a long …
tractorss Oct 21, 2026
1df7c1d
fix(web): under 360px the pinned chip drops its figure so the name ha…
tractorss Oct 21, 2026
2567271
test(web): a leaving phone bar sinks as it was, at its own height, wi…
tractorss Oct 21, 2026
d47dfc1
fix(web): a leaving phone bar keeps the picks and Predict it had whil…
tractorss Oct 21, 2026
2cb473b
test(web): Resume's popup leaves the card's Predict held and draws no…
tractorss Oct 21, 2026
b3f710f
fix(web): the card keeps the stored run as last read while the popup …
tractorss Oct 21, 2026
0d84202
test(web): the stored run's held Predict wears the card's disabled to…
tractorss Oct 21, 2026
e89165a
fix(web): the stored run's held Predict takes the card's disabled fil…
tractorss Oct 21, 2026
9c627bc
test(web): the moved line names its market only while the sentence ke…
tractorss Oct 21, 2026
9bc25f3
fix(web): the moved line names its market only while the whole senten…
tractorss Oct 21, 2026
31de462
test(web): the success receipt keeps one figure column, one-line titl…
tractorss Oct 21, 2026
52b1dd0
fix(web): the success receipt keeps its figure column and one-line ti…
tractorss Oct 21, 2026
ce8727e
docs(web): two comments say what holds now, not what the change was
tractorss Oct 21, 2026
d774045
Merge branch 'issue/2026-10-21-foresight-predict-round13' into issue/…
tractorss Oct 21, 2026
2e3bcae
test(web): every moved-prices line ends "Confirm to go on.", and lock…
tractorss Oct 22, 2026
7124302
fix(web): the unnamed, credits-only and slippage moved lines end "Con…
tractorss Oct 22, 2026
1bf5d30
test(web): the more-below nudge lifts 2px and drops 3px beside any st…
tractorss Oct 22, 2026
740561d
fix(web): the more-below nudge takes its smaller burst whenever a sta…
tractorss Oct 22, 2026
2efc090
test(web): the success dialog is named and headed "Prediction success…
tractorss Oct 22, 2026
0dd0391
fix(web): the success dialog is headed and named "Prediction successful"
tractorss Oct 22, 2026
d6d0266
test(web): the success receipt draws its last check once by stroke-da…
tractorss Oct 22, 2026
6a8ba91
feat(web): the success receipt's last check draws in once as the dial…
tractorss Oct 22, 2026
c7416e2
test(web): a phone on its side, 568 x 320 or 667 x 375, keeps the Pre…
tractorss Oct 22, 2026
bffe3c6
fix(web): the phone Predict bar pins only upright; a phone on its sid…
tractorss Oct 22, 2026
d4c166b
style(web): prettier on two lines the round's edits shortened
tractorss Oct 22, 2026
0e341ce
Merge branch 'issue/2026-10-22-foresight-predict-round14' into issue/…
tractorss Oct 22, 2026
3398e94
test(web): the credits-and-xDAI e2e reads the funds step by its credi…
tractorss Oct 22, 2026
0c9991e
chore: format turbo.json and the branchColor test, and stop tracking …
tractorss Oct 22, 2026
20ea776
fix(web): refuse a Lens quote for another router, recipient, token or…
tractorss Oct 23, 2026
bde1559
test(web): await the lens-answer build as a promise, as tsc types a s…
tractorss Oct 23, 2026
a773e2a
fix(web): stop at Prices moved when a leg's live quote pays less than…
tractorss Oct 23, 2026
a6047b1
fix(tx-orchestrator): a step with a submitted hash adopts it before c…
tractorss Oct 23, 2026
ca0f51b
fix(web): a send that errors after broadcast is held with the run unt…
tractorss Oct 23, 2026
d4326ac
fix(web): a stored run another tab is driving is shown as running the…
tractorss Oct 23, 2026
55049cc
fix(web): a page or popup left open past the close stops trading at t…
tractorss Oct 23, 2026
77f6520
style: trim the run driver's comments to the facts they state
tractorss Oct 23, 2026
8ce5c62
fix(web): a stored run naming other contracts than the app's halts on…
tractorss Oct 23, 2026
1ea6ffc
fix(web): Withdraw sends nothing when the picked credits or WXDAI re-…
tractorss Oct 23, 2026
969defd
fix(web): a removed estimate leaves the run at once, while its row st…
tractorss Oct 23, 2026
9aa913c
fix(web): resetting a halted run that names other contracts forgets it
tractorss Oct 23, 2026
4d47fc6
fix(web): the estimates CSV writes an option name a spreadsheet would…
tractorss Oct 23, 2026
7644327
fix(web): the estimates CSV starts with a UTF-8 byte-order mark
tractorss Oct 23, 2026
eb5ca4d
fix(web): the CSV template leaves options you have not set empty, and…
tractorss Oct 23, 2026
b5eba30
style(web): state what sameContracts answers
tractorss Oct 23, 2026
5d28381
fix(web): a swap's min-out and deadline are set by the app, never tak…
tractorss Oct 23, 2026
5da0de1
fix(web): a refused Web Locks request leaves the run with this tab in…
tractorss Oct 23, 2026
f919ed2
fix(web): Predict retries a trade wallet setup held after its send er…
tractorss Oct 23, 2026
4f8cbd3
fix(web): a stored run whose options name other tokens than the sessi…
tractorss Oct 23, 2026
de6bcbe
test(web): quotesShort's sell, buy-out and buy-in checks, each at its…
tractorss Oct 23, 2026
b5942c1
fix(web): a pick re-read as zero keeps its token and zero balance in …
tractorss Oct 23, 2026
0a3ef07
style(web): prettier and import order on the round's new code
tractorss Oct 23, 2026
6f90f2f
test(web): the fork's tab close after a send landed never answers, so…
tractorss Oct 23, 2026
7f4865a
fix(web): every send is stored with the run before the wallet opens, …
tractorss Oct 23, 2026
0d73e25
fix(web): a disposed popup keeps the run with its tab until the walle…
tractorss Oct 23, 2026
5ad8829
fix(web): a held send found mined is forgotten only once its step is …
tractorss Oct 23, 2026
6fa9b00
fix(web): a money step reads the mempool before the logs, and an unfu…
tractorss Oct 23, 2026
11ce07d
fix: a send is taken as never broadcast only on a decline's code or n…
tractorss Oct 23, 2026
019d48f
fix(web): a held send whose read nonce another send took is looked fo…
tractorss Oct 23, 2026
ac53220
fix(web): a held send's nonce is found by a binary search of the owne…
tractorss Oct 23, 2026
554c019
fix(web): a run stopped at a pending transaction, or a deposit that m…
tractorss Oct 23, 2026
600c6be
fix(web): reset keeps a stored run while a step holds a hash with no …
tractorss Oct 23, 2026
1395097
fix(web): recovering a held send after the session closed reads how i…
tractorss Oct 23, 2026
f9c75ca
fix(web): no wallet opens once the close passes, and every swap's dea…
tractorss Oct 23, 2026
5aa3f65
style(web): one import group in plan.test.ts
tractorss Oct 23, 2026
3f844e1
fix(web): a Confirm at Prices moved holds the run to the quotes it sh…
tractorss Oct 23, 2026
33992c2
test(web): a held run on a fork whose pools' next-swap fee rose an ho…
tractorss Oct 23, 2026
726d3fb
fix(web): a Confirm at moved before anything was signed signs the fun…
tractorss Oct 23, 2026
d2a6768
fix(web): an xDAI deposit settled with its mint unread owes the mint,…
tractorss Oct 23, 2026
fc334f2
fix(web): the popup can be closed while a transaction stored as sent …
tractorss Oct 23, 2026
276f8d3
fix: the trade wallet is derived with CREATE2 in the app, and a node …
tractorss Oct 23, 2026
a3a4908
fix(web): a held send is shown as one that may still land, with Setti…
tractorss Oct 23, 2026
1453400
fix(web): Discard holds the run's lock while it reads and deletes the…
tractorss Oct 23, 2026
1305240
fix(web): a tab counts a run lock as its own until the lock manager h…
tractorss Oct 23, 2026
bbfe8b5
fix(web): a recover run again before the lock has answered the first …
tractorss Oct 23, 2026
4c4318e
fix(web): the estimates CSV refuses a row cut short, and writes a nam…
tractorss Oct 23, 2026
01a5c6c
fix(web): a tiny estimate opens in its field as a plain decimal, not …
tractorss Oct 23, 2026
96418f6
fix(web): Deposit and Withdraw name their amount field, as the popup'…
tractorss Oct 23, 2026
9293792
fix(web): Details drops the credits swap's slippage once the swap lan…
tractorss Oct 23, 2026
fef17e7
fix(web): a row still fading keeps its place when a row above it, rem…
tractorss Oct 23, 2026
8b5ee43
fix(web): an estimate becomes its target price from its decimal, not …
tractorss Oct 23, 2026
0061889
fix(web): Details' Mint row shows what credits split, the swap floor'…
tractorss Oct 23, 2026
72459a4
style(web): the mint's estimate flag on a line of its own
tractorss Oct 23, 2026
b396b40
fix(web): Withdraw reads each held token as it opens, and says a bala…
tractorss Oct 23, 2026
8c1f24f
style(web): prettier on the executor test's imports
tractorss Oct 23, 2026
9e48747
style(web): state what a held send in progress is now
tractorss Oct 23, 2026
986975b
fix(web): a CSV row with the wrong number of cells says how many it h…
tractorss Oct 25, 2026
499027a
fix(web): a CSV row with an empty estimate leaves that option's estim…
tractorss Oct 25, 2026
5f85640
fix(web): a trade wallet the network names wrongly says to switch RPC…
tractorss Oct 25, 2026
5743de1
docs(web): the Gnosis RPC should be an archive node (R15-G19)
tractorss Oct 25, 2026
4e56218
fix(web): the credits swap's floor never sits under one xDAI a credit…
tractorss Oct 25, 2026
56ae7f1
fix(web): each predict step row says to a screen reader whether it is…
tractorss Oct 25, 2026
d343c37
feat(web): every predict transaction is checked against the chain's a…
tractorss Oct 25, 2026
3a035d8
docs(web): money properties for the Lens boundary, held quotes and se…
tractorss Oct 25, 2026
e982dc5
test(web): Details snapshots show the credits-funded Mint row as appr…
tractorss Oct 25, 2026
a376cc9
style(web): prettier on the trade-wallet panel's mismatch state
tractorss Oct 25, 2026
f430ac6
test(web): the sDAI adapter and Swapr router the app names are the al…
tractorss Oct 25, 2026
f205dbf
feat(tx-orchestrator): a hash no node reports stays in flight until t…
tractorss Oct 25, 2026
96f97d9
fix(tx-orchestrator): a stored run is not pruned by age while a step …
tractorss Oct 25, 2026
8e9b837
fix(tx-orchestrator): no wallet prompt opens when the write before it…
tractorss Oct 25, 2026
d2aa330
feat(web): predict reads the owner's nonce through the wallet's own n…
tractorss Oct 25, 2026
88dc6cf
fix(web): a send that errored stays held until its nonce is used or t…
tractorss Oct 25, 2026
d2a9c60
fix(web): predict keeps a hash no node finds until its nonce says it …
tractorss Oct 25, 2026
08d80a7
fix(web): a stored run naming other contracts forgets a hash once its…
tractorss Oct 25, 2026
9d1c962
fix(web): the owner's nonce counts are the higher of the wallet's nod…
tractorss Oct 25, 2026
47d8162
fix(web): a send the client refuses before the wallet is asked holds …
tractorss Oct 25, 2026
6964af8
fix(web): Sign again reads the held send's nonce once more and signs …
tractorss Oct 25, 2026
3de2183
fix(web): a stored run that can never resume settles its hashes and h…
tractorss Oct 25, 2026
b2981f8
test(web): round-16 tests type-check and lint; the pending-transactio…
tractorss Oct 25, 2026
230f68f
test(web): the fork's A7 reload after a tab closed at the batch promp…
tractorss Oct 25, 2026
b2e099a
fix(web): a wallet's coded disconnect or unauthorized answer keeps th…
tractorss Oct 25, 2026
62e7a05
fix(web): run ownership falls back to a localStorage lease where Web …
tractorss Oct 25, 2026
73127b2
fix(web): a run this tab holds for a still-open wallet prompt says so…
tractorss Oct 25, 2026
c05d09b
fix(web): the card does not flash the open-prompt line as a popup clo…
tractorss Oct 25, 2026
682d780
fix: 14 findings from the Codex review of PR #1, each with a regressi…
tractorss Oct 25, 2026
d1ad6e4
fix: recovery signs at the slippage it shows; Discard finishes before…
tractorss Oct 25, 2026
5a1accf
feat(web): the session chart draws a point at every trade, not only o…
tractorss Oct 25, 2026
986ae3a
merge: 18 fixes from the Codex review of PR #1 into the predict-flow …
tractorss Oct 25, 2026
f6034c3
test(web): port predict execution seam cases from e524acf and 46bd5a6
tractorss Oct 26, 2026
02611e0
test(web): port route-check reporting case from 02efab9
tractorss Oct 26, 2026
17690a4
test(web): port buy-budget edge cases from bdfc58c and 3e3f649
tractorss Oct 26, 2026
5318e5f
test(web): port generated stale-balance cases from 608f49d and 8f128ff
tractorss Oct 26, 2026
735f5cc
test(web): port retry boundary cases from 1240640 and 266c2dc
tractorss Oct 26, 2026
d28a24f
test(web): reject unlisted predict money calls
tractorss Oct 26, 2026
3108442
test(web): bind recovery witnesses and deposit accounting
tractorss Oct 26, 2026
433801c
test(web): pin credit allocation and held trading budgets
tractorss Oct 26, 2026
bcf4625
test(web): validate swap requests and multicall shapes
tractorss Oct 26, 2026
f60b008
test(orchestrator): preserve replacement outcomes on recovery
tractorss Oct 26, 2026
91fca69
test: money-line tests derive expectations from the constants they de…
tractorss Oct 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ coverage/

# agent config: shared rules and skills are committed;
# local settings and personal notes are not
.claude/settings.local.json
.claude/settings.local.json*
packages/mock-atlas/.store/
2 changes: 1 addition & 1 deletion apps/indexer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"codegen:gnosis": "envio codegen --config config.gnosis.yaml",
"dev": "envio dev --config config.localhost.yaml",
"dev:gnosis": "node --env-file=.env.gnosis \"$(yarn bin envio)\" dev --config config.gnosis.yaml",
"dev:gnosis-fork": "node --env-file=.env.gnosis-fork \"$(yarn bin envio)\" dev --config config.gnosis-fork.yaml",
"dev:gnosis-fork": "node --env-file=.env.gnosis-fork.example --env-file-if-exists=.env.gnosis-fork \"$(yarn bin envio)\" dev --config config.gnosis-fork.yaml",
"start": "envio start",
"start:local": "envio start --config config.localhost.yaml",
"stop": "envio stop",
Expand Down
4 changes: 4 additions & 0 deletions apps/indexer/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ type ChildMarket {

downToken: String! @index
upToken: String! @index

"burnt alongside DOWN and UP when a set is merged back; the router takes the whole partition"
invalidToken: String!

underlyingToken: String! @index

keyword: String!
Expand Down
1 change: 1 addition & 0 deletions apps/indexer/src/handlers/SessionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ indexer.onEvent({ contract: "SessionFactory", event: "ChildMarketDeployed" }, as
upperBound: market.upperBound,
downToken: market.down,
upToken: market.up,
invalidToken: market.invalid,
underlyingToken: market.underlying,
displayName: display?.displayName,
color: display?.color,
Expand Down
8 changes: 6 additions & 2 deletions apps/indexer/src/utils/contracts/fetchChildMarket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const fetchChildMarket = createEffect(
upperBound: S.bigint,
down: S.string,
up: S.string,
invalid: S.string,
underlying: S.string,
}),
cache: true,
Expand All @@ -24,13 +25,14 @@ export const fetchChildMarket = createEffect(
const market = getSeerMarketContract(input.address);

try {
// outcome 0 is DOWN and outcome 1 is UP
const [marketName, lowerBound, upperBound, down, up, underlying] = await Promise.all([
// outcome 0 is DOWN and 1 is UP; Seer wraps INVALID one past the named outcomes
const [marketName, lowerBound, upperBound, down, up, invalid, underlying] = await Promise.all([
client.readContract({ ...market, functionName: "marketName" }),
client.readContract({ ...market, functionName: "lowerBound" }),
client.readContract({ ...market, functionName: "upperBound" }),
client.readContract({ ...market, functionName: "wrappedOutcome", args: [0n] }),
client.readContract({ ...market, functionName: "wrappedOutcome", args: [1n] }),
client.readContract({ ...market, functionName: "wrappedOutcome", args: [2n] }),
client.readContract({ ...market, functionName: "parentWrappedOutcome" }),
]);

Expand All @@ -40,6 +42,7 @@ export const fetchChildMarket = createEffect(
upperBound,
down: down[0].toLowerCase(),
up: up[0].toLowerCase(),
invalid: invalid[0].toLowerCase(),
underlying: underlying[0].toLowerCase(),
};
} catch (error) {
Expand All @@ -51,6 +54,7 @@ export const fetchChildMarket = createEffect(
upperBound: 0n,
down: UNAVAILABLE,
up: UNAVAILABLE,
invalid: UNAVAILABLE,
underlying: UNAVAILABLE,
};
}
Expand Down
11 changes: 7 additions & 4 deletions apps/indexer/tests/handlers/SessionFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,20 @@ const PARENT_OUTCOME_0 = "0x00000000000000000000000000000000000000a1" as const;
const PARENT_OUTCOME_1 = "0x00000000000000000000000000000000000000a2" as const;
const CHILD_MARKET_0 = "0x0000000000000000000000000000000000000c00" as const;
const CHILD_MARKET_1 = "0x0000000000000000000000000000000000000c01" as const;
const CHILD_0_INVALID = "0x0000000000000000000000000000000000000d10" as const;
const CHILD_1_INVALID = "0x0000000000000000000000000000000000000d11" as const;
const DEPLOYER = "0x0000000000000000000000000000000000000de9" as const;

const ESCAPING_METADATA_URI = "ipfs://../../admin/purge";

/** `wrappedOutcome` and `parentWrappedOutcome` both answer (token, data). */
const wrapped = (token: string) => [token, "0x"];

const childReads = (down: string, up: string, underlying: string) => ({
const childReads = (down: string, up: string, underlying: string, invalid: string) => ({
marketName: CHILD_MARKET_NAME,
lowerBound: LOWER_BOUND,
upperBound: UPPER_BOUND,
wrappedOutcome: [wrapped(down), wrapped(up)],
wrappedOutcome: [wrapped(down), wrapped(up), wrapped(invalid)],
parentWrappedOutcome: wrapped(underlying),
});

Expand All @@ -63,8 +65,8 @@ const marketReads: Record<string, Record<string, unknown>> = {
wrappedOutcome: [wrapped(PARENT_OUTCOME_0), wrapped(PARENT_OUTCOME_1), wrapped(PARENT_INVALID)],
},
// a child on outcome i prices against the parent's wrapped outcome i
[CHILD_MARKET_0]: childReads(CHILD_0_DOWN, CHILD_0_UP, PARENT_OUTCOME_0),
[CHILD_MARKET_1]: childReads(CHILD_1_DOWN, CHILD_1_UP, PARENT_OUTCOME_1),
[CHILD_MARKET_0]: childReads(CHILD_0_DOWN, CHILD_0_UP, PARENT_OUTCOME_0, CHILD_0_INVALID),
[CHILD_MARKET_1]: childReads(CHILD_1_DOWN, CHILD_1_UP, PARENT_OUTCOME_1, CHILD_1_INVALID),
[CHILD_0_DOWN]: { decimals: 18, symbol: "DUNE0-DOWN" },
[CHILD_0_UP]: { decimals: 18, symbol: "DUNE0-UP" },
[PARENT_OUTCOME_0]: { decimals: 18, symbol: "VILLENEUVE" },
Expand Down Expand Up @@ -224,6 +226,7 @@ describe("SessionFactory indexing", () => {

const child = await indexer.ChildMarket.getOrThrow(CHILD_MARKET_0);
t.expect(child.session_id).toBe("0");
t.expect(child.invalidToken).toBe(CHILD_0_INVALID);
t.expect(child.parentOutcomeIndex).toBe(0n);
t.expect(child.parentOutcome).toBe("Villeneuve");
t.expect(child.marketName).toBe(CHILD_MARKET_NAME);
Expand Down
1 change: 1 addition & 0 deletions apps/indexer/tests/support/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const seedMarket = async (indexer: TestIndexer, market: SeededMarket) =>
upperBound: market.upperBound,
downToken: market.down,
upToken: market.up,
invalidToken: `${market.id}-invalid`,
underlyingToken: market.underlying,
displayName: undefined,
color: undefined,
Expand Down
1 change: 1 addition & 0 deletions apps/web/.env.gnosis-fork.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
NEXT_PUBLIC_REOWN_PROJECT_ID=fork-placeholder
NEXT_PUBLIC_ENABLE_LOCAL_CHAIN=false
NEXT_PUBLIC_GNOSIS_RPC=http://127.0.0.1:8545
NEXT_PUBLIC_SUBGRAPH_URL=http://localhost:8080/v1/graphql
Expand Down
4 changes: 4 additions & 0 deletions apps/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ fails the build with the offending names rather than at runtime.
| `NEXT_PUBLIC_SUBGRAPH_URL` | yes | Indexer GraphQL endpoint. Locally `http://localhost:8080/v1/graphql` |
| `NEXT_PUBLIC_ENABLE_LOCAL_CHAIN` | no | Unset follows `NODE_ENV`; `"false"` offers gnosis only |

In production, point `NEXT_PUBLIC_GNOSIS_RPC` at an archive node. Finding a held send reads the
owner's transaction count at past blocks; a pruned node refuses those reads, and the app falls back
to reading blocks one by one from the send's block to the head, which is slow.

```bash
cp .env.gnosis.example .env.gnosis
yarn dev:gnosis
Expand Down
52 changes: 50 additions & 2 deletions apps/web/e2e/fixtures/hardhat.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { test as base } from "@playwright/test";
import { createTestClient, http, publicActions, walletActions } from "viem";
import { hardhat } from "viem/chains";
import {
createTestClient,
encodeFunctionData,
http,
isAddressEqual,
parseAbi,
parseEther,
publicActions,
walletActions,
type Address,
} from "viem";
import { gnosis, hardhat } from "viem/chains";

import { LOCAL_RPC_URL } from "@/config/chains";

const client = createTestClient({
chain: hardhat,
Expand All @@ -18,3 +30,39 @@ export const test = base.extend<{ hardhat: HardhatClient }>({
await use(client);
},
});

/** Gnosis' Foresight credits governor: an admin of the token and the manager's governor. */
const CREDITS_GOVERNOR: Address = "0x4EDCA105188a0783Ab3A6f09c50567D1E3F8591D";

const CREDITS_ADMIN_ABI = parseAbi([
"function governor() view returns (address)",
"function mint(address to, uint256 amount)",
]);

// signs as chain 100, which the gnosis fork answers to; the `hardhat` client signs as 31337
const fork = createTestClient({ chain: gnosis, mode: "hardhat", transport: http(LOCAL_RPC_URL) })
.extend(publicActions)
.extend(walletActions);

/** Mints `amount` Foresight credits to `to` on the gnosis fork, as the governor impersonated for the one call. */
export async function grantCredits(token: Address, to: Address, amount: bigint) {
const governor = await fork.readContract({ address: token, abi: CREDITS_ADMIN_ABI, functionName: "governor" });
if (!isAddressEqual(governor, CREDITS_GOVERNOR)) {
throw new Error(`The credits governor is ${governor}, not the ${CREDITS_GOVERNOR} the fixture acts as.`);
}
await fork.impersonateAccount({ address: CREDITS_GOVERNOR });
try {
if ((await fork.getBalance({ address: CREDITS_GOVERNOR })) < parseEther("1")) {
await fork.setBalance({ address: CREDITS_GOVERNOR, value: parseEther("1") });
}
const hash = await fork.sendTransaction({
account: CREDITS_GOVERNOR,
to: token,
data: encodeFunctionData({ abi: CREDITS_ADMIN_ABI, functionName: "mint", args: [to, amount] }),
});
const receipt = await fork.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error(`Minting ${amount} credits to ${to} reverted.`);
} finally {
await fork.stopImpersonatingAccount({ address: CREDITS_GOVERNOR });
}
}
12 changes: 12 additions & 0 deletions apps/web/e2e/harness/estimate-slider/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Estimate slider harness</title>
</head>
<body class="bg-fs-surface antialiased">
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
46 changes: 46 additions & 0 deletions apps/web/e2e/harness/estimate-slider/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState } from "react";
import { createRoot } from "react-dom/client";

import { EstimateSlider } from "@/features/predict/components/EstimateSlider";

import "@/styles/global.css";
import "../inter.css";

const params = new URLSearchParams(window.location.search);
const number = (name: string, fallback: number) => Number(params.get(name) ?? fallback);
/** `?track=` the slider's width in px, as an option card gives it at 375 (311) or 1280 (1112). */
const track = number("track", 311);
const lowerBound = number("lower", 0);
const upperBound = number("upper", 100);
const marketEstimate = number("market", 75);
/** `?value=` a saved estimate; without it the slider rests at the market. */
const initial = params.has("value") ? number("value", 0) : undefined;
if (params.get("theme") === "dark") document.documentElement.classList.add("dark");
/** `?locked=1` a session that takes no estimates, as a closed one. */
const lockedReason = params.get("locked") === "1" ? "Trading has closed." : undefined;

function Harness() {
const [value, setValue] = useState(initial);
return (
<div className="bg-fs-surface p-4" style={{ width: track + 32 }}>
<EstimateSlider
scale={{
market: "0x1111111111111111111111111111111111111111",
name: "Movie A",
color: params.get("color") ?? "#7e1bd4",
unit: params.get("unit") ?? "%",
lowerBound,
upperBound,
}}
marketEstimate={marketEstimate}
isMarketPending={false}
value={value}
onCommit={setValue}
onClear={() => setValue(undefined)}
lockedReason={lockedReason}
/>
</div>
);
}

createRoot(document.getElementById("root")!).render(<Harness />);
25 changes: 25 additions & 0 deletions apps/web/e2e/harness/inter.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* The files src/app/layout.tsx loads through next/font, which Vite does not run. */
@font-face {
font-family: "Inter";
font-weight: 400;
font-display: swap;
src: url("../../../../node_modules/@fontsource/inter/files/inter-latin-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-weight: 500;
font-display: swap;
src: url("../../../../node_modules/@fontsource/inter/files/inter-latin-500-normal.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-weight: 600;
font-display: swap;
src: url("../../../../node_modules/@fontsource/inter/files/inter-latin-600-normal.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-weight: 700;
font-display: swap;
src: url("../../../../node_modules/@fontsource/inter/files/inter-latin-700-normal.woff2") format("woff2");
}
12 changes: 12 additions & 0 deletions apps/web/e2e/harness/option-card/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Option card harness</title>
</head>
<body class="bg-fs-surface antialiased">
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
56 changes: 56 additions & 0 deletions apps/web/e2e/harness/option-card/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { createRoot } from "react-dom/client";

import { useEstimateStore } from "@/features/predict/stores/estimateStore";
import type { SessionStatus } from "@/features/sessions/types";

import { OptionCard } from "@/app/market/[parentMarket]/_components/OptionCard";

import "@/styles/global.css";
import "../inter.css";

const params = new URLSearchParams(window.location.search);
const number = (name: string, fallback: number) => Number(params.get(name) ?? fallback);
const PARENT = "0x7777777777777777777777777777777777777777";
const MARKET = "0x1111111111111111111111111111111111111111";
const WAD = 10n ** 18n;
/** `?market=none` for an option with no trading. `?up=` and `?down=` a held position in whole tokens, decimals allowed; with neither there is none. */
const tokens = (name: string) => {
const [whole = "0", fraction = ""] = (params.get(name) ?? "0").split(".");
return BigInt(whole) * WAD + BigInt(fraction.padEnd(18, "0").slice(0, 18) || "0");
};
const position = params.has("up") || params.has("down") ? { up: tokens("up"), down: tokens("down") } : undefined;
if (params.get("theme") === "dark") document.documentElement.classList.add("dark");
useEstimateStore.setState({ estimates: params.has("value") ? { [PARENT]: { [MARKET]: number("value", 0) } } : {} });

function Harness() {
return (
<div className="p-4">
<OptionCard
option={{
market: MARKET,
outcomeIndex: 0,
name: params.get("name") ?? "Movie A",
color: params.get("color") ?? "#7e1bd4",
unit: params.get("unit") ?? "%",
lowerBound: number("lower", 0),
upperBound: number("upper", 100),
question: "What percentile score will Scooby assign to Movie A? (session #2)",
upToken: null,
downToken: null,
invalidToken: null,
underlyingToken: null,
blocks: [
{ type: "markdown", body: "Resolves to the score Scooby gives after watching. 0 if he does not watch it." },
],
}}
parentMarket={PARENT}
status={(params.get("status") as SessionStatus | null) ?? "trading"}
marketEstimate={params.get("market") === "none" ? undefined : number("market", 75)}
isMarketPending={false}
position={position}
/>
</div>
);
}

createRoot(document.getElementById("root")!).render(<Harness />);
12 changes: 12 additions & 0 deletions apps/web/e2e/harness/predict-card/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Predict card harness</title>
</head>
<body class="bg-klerosUIComponentsLightBackground flex min-h-screen flex-col antialiased">
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
Loading
Loading