Activity Overview

Commits and releases over time

  • Commits
  • Releases
  • Authors

Repository Explorer

128 commits in all time Jun 16, 2026 12:01 – Sep 14, 2026 12:01 UTC
ipaleka widgets
Initial setup for the liverefresh widget
Git Commit 686ae367 Branch main Document 12/367 ++ 1 --
ipaleka widgets
Initial setup for the liverefresh widget
Git Commit 9e2e16d1 Branch main Document 9/363 ++ 0 --
ipaleka widgets
New connectionSource() reads asastatsWallet first, falling back to asastatsSwap
Git Commit 3049b05f Branch main Document 2/78 ++ 10 --
ipaleka widgets
ASA Stats router uses reauthorize endpoint for post-quantum accounts
Git Commit 61694a6d Branch main Document 6/201 ++ 4 --
ipaleka widgets
Bugfix for quote-signed group cannot carry the opt-in
Git Commit b82d6e80 Branch main Document 2/106 ++ 0 --
ipaleka widgets
Bugfix for ASA Stats router discounts are not being triggered
Git Commit 24d7c484 Branch main Document 3/134 ++ 3 --
ipaleka widgets
Updated documentation
Git Commit 1466f999 Branch main Document 11/159 ++ 197 --
ipaleka widgets
Router name in the swap window moved to the last row
Git Commit 062c0916 Branch main Document 1/9 ++ 1 --
ipaleka widgets
Bugfix for not erased USD values upon switching tabs in the swap window
Git Commit 26fcdc18 Branch main Document 1/12 ++ 4 --
ipaleka widgets
Both input and output values in USD are shown in the swap window
Git Commit d20465e8 Branch main Document 3/220 ++ 104 --
ipaleka widgets
Bugfix for swap window from a bundle page uses a wrong address
Git Commit d8174ff3 Branch main Document 2/159 ++ 7 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit 3f83e69a Branch main Document 7/688 ++ 170 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit da9d0dcd Branch main Document 6/603 ++ 144 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit cc778e28 Branch main Document 6/603 ++ 144 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit 382f9732 Branch main Document 5/591 ++ 143 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit 186e555f Branch main Document 5/584 ++ 141 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit ddaf6f17 Branch main Document 4/535 ++ 129 --
ipaleka widgets
Added interface state function to the Dust Sweep, carrying the page context it must not lose
Git Commit 651b8db4 Branch main Document 2/71 ++ 5 --
ipaleka widgets
The forfeit destination in the Dust Sweep comes from the chain
Git Commit 8dd4cae5 Branch main Document 8/1,086 ++ 47 --
ipaleka widgets
Require the router to be in the group, and show where a forfeit goes (S7, S2)
**S7.** The S6 fix mirrored `_assert_group_is_clean` into the browser, and the
mirror was faithful and insufficient. That guard checks hygiene - rekey, close,
group fee - and hygiene is not what a hostile conversion violates. A plain
asset transfer of the whole balance to a stranger carries no close, no rekey
and an ordinary fee, and passed the mirror completely.

The contract does not check `aamt` or `arcv` either, and does not need to: on a
routed group the rest of it checks - the input proven spent, the co-signed
floor, the pinned pools - and none of that runs unless the router is called. So
the mirror had copied the cheap outer shell and left out the part doing the
work. The two exempt entry points say the same thing from the other side:
`pool_budget` and `verify_discount` skip the hygiene guard precisely because
they ride alongside a route, so hygiene alone was never the safety argument.

`routedGroupProblems` now also requires a call to the router whose ARC-4
selector is not one of those two - "calls the router" would have passed
`[pool_budget, transfer-to-attacker]`, which calls the router and is checked by
nothing. The app id comes from `data-router-app`, handed down by the view and
overridable by a setting, with the same number in the widget as a fallback so a
missing attribute cannot switch the rule off. Not from the plan response: an id
the engine supplied would make the check agree with whatever the engine wanted,
which is S2 for the third time. The two excluded selectors are recomputed from
the method signatures by verify-sweep.sh rather than trusted as constants.

All four router groups in the audit's evidence carry non-exempt selectors, so
the rule accepts every conversion that has actually executed.

It also caught a test that had gone quiet. "Accepting implies no transaction
closes or rekeys" became vacuous the moment this landed - no corpus transaction
is an application call, so every generated group was refused for that reason
and the implication was never exercised. It now prefixes a real route call and
asserts that something really was accepted.

**S2 recommendation 2.** The row showed unit, id, badge, value and reason and
never the address the tokens went to, so on the one disposition that gives
something away the destination was the single fact the reader was not shown.
`destinationLabel` is the pure half, tested; `renderLine` only appends it. A
close says plainly that nothing leaves, because a blank cell there reads as a
missing fact rather than as reassurance. The audit is explicit that this
complements the chain lookup rather than replacing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqeQenXa9oWnLCWEvuiy8B
Git Commit 4fe081b9 Branch review/S2-hardening Document 6/331 ++ 5 --
ipaleka widgets
Check the conversion path too, and stop a creator lookup hanging (S6)
`signAction` decided whether to inspect a group by reading `action.kind` out
of the same response that carried the bytes. Every honest conversion carries a
router call the contract checks - but an assertion inside an application only
runs if the application is called, so a group labelled `convert` with no
application call in it was refused by nobody: not by this file, which returned
early, and not by `_assert_group_is_clean`, which was never in the group to
object. S2 was a reference value the engine supplied; this was the switch
deciding whether any checking happened.

`routedGroupProblems` mirrors that guard where it always runs - no rekey, no
close, no aclose, and the group's fee total against the contract's own
MAX_GROUP_FEE rather than a number picked here. Mirroring cannot refuse a group
the contract would accept.

The decoder risk this raised is settled with evidence rather than reasoning.
The seven groups in the audit's evidence/ were re-encoded from what the indexer
returned and run through the shipped decodeMsgpack: 97 of 97 decode,
application calls included, using only tags already supported. They are now a
fixture, so the accepting side of this rule is tested against traffic that
executed on mainnet instead of fixtures written to pass - and the ceiling has
fourteen times the headroom it needs, the dearest real group paying 71,000
against 1,000,000.

Writing it found something. "A conversion goes through the quote-signed path"
passed [CLOSE_TO_SELF] as its group, a stand-in chosen because the path did not
look at it. The new rule looked and refused it, correctly. That test now uses a
real convert group.

CREATOR_LOOKUP_TIMEOUT closes the one failure on the S2 path that neither
refused nor accepted: algosdk v3 sets no timeout, so a node that never answered
left the reader on a spinner with no prompt and no error. Ten seconds, then
null, which is the refusal the unreachable node already produced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqeQenXa9oWnLCWEvuiy8B
Git Commit ffe76831 Branch review/S2-hardening Document 4/495 ++ 12 --
ipaleka widgets
Bind the forfeit predicate to one function, and issue the lookups together
The S2 fix rests on an invariant that spans two functions: a transaction may
close somewhere other than the sweeper's own account only when the plan calls
the holding a forfeit, and that same condition is what sends the destination
to the chain to be confirmed. Both spelled `Number(x.amount) !== 0` out
separately, so nothing failed if one of them changed - `closeOutProblems`
would keep accepting a forfeit that `forfeitTargetProblems` had quietly
stopped looking up. That is S2 reopening with a green suite.

`isForfeit` is now the single predicate, sitting beside `planLines`: that one
decides which lines are readable, this one decides what a readable line means.
A test crosses both halves over the amount shapes an engine can actually send.
Mutating one side to `> 0` fails three of them; before, it failed nothing.

The lookups also move into one `Promise.all` over the distinct asset ids,
decoding once up front. A group of sixteen forfeits waited sixteen times the
node's latency before the wallet prompt opened, because the await sat in the
compare loop. The rejection-to-null fold moved with it, so "could not be
confirmed" is still the single refusal path. The compare loop becoming a `.map`
is why the group side now gets the shape guard the `described` side has had
since `planLines`.

Three docstrings had drifted from the code and are corrected rather than left
to mislead the next reader of a security control: the fee is bounded per
transaction only, and `summaryFigures` reports the planner's figures without
verifying them - a planner reporting zero fees renders "0.00 ALGO"
unchallenged, and what bounds the loss is MAX_CLOSE_OUT_FEE on the bytes being
signed. `recoverable` genuinely is net of fees; the planner subtracts them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqeQenXa9oWnLCWEvuiy8B
Git Commit 2dfc2188 Branch review/S2-hardening Document 2/181 ++ 34 --
ipaleka widgets
Bugfix for tabs activation in historic widget
Git Commit 8952bcf1 Branch main Document 2/98 ++ 9 --
ipaleka widgets
Stop the login dialog's tabs from hiding the historic charts
`mainHistoric` delegated from `[role=tablist]`, and this page has two of
them: base.html's login dialog is built to the same shape. Clicking
Social or Wallet in that dialog ran `tabShow("modal-tab-social")`, which
found the panel, decided none of the four `.historic-tab-panel`s was it,
and hid all of them -- charts gone when the reader closed the dialog.

The `aria-selected` sweep was unscoped for the same reason, and that one
ran unprompted: `showBars()` fires on load and on every unlock, and it
cleared the flag on the dialog's Log in tab each time.

Two locks now. The delegation is scoped to `.historic-tabs`, as the
stylesheet has always been, and `tabShow` requires the id to name a
`.historic-tab-panel` rather than merely to exist.

Found while covering the one uncovered branch in `tabClick`, the `|| ""`
fallback for a tab with no href. A test for it existed and had never
touched the anchor it appended: it clicked `$('[role="tab"]').last()`,
which is the dialog's Wallet tab, not the stray one at the end of the
widget's own tablist. It now clicks by id.

Six tests around the chain, all through the delegated click. The
isolation test also asserts the dialog's click was not default-prevented:
that is the only effect with no second lock behind it, and without it
reverting the delegation scoping still passed -- the panel-class guard
masks it, since neither leaves a trace in the DOM.

historic.js: 100% statements, branches, functions and lines. 105 jest
tests, 107 python tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LdZ42323XxKzzpGVdzj4C
Git Commit 79d2a924 Branch review/S2-hardening Document 2/98 ++ 9 --
ipaleka widgets
Historic widget's Jest fixture is updated
Git Commit 74ab11fa Branch main Document 7/731 ++ 195 --