Ecosystem metrics
- New Repos
- 16
- New
- Commits
- 796
- down 25.1%
- Releases
- 4
- down 50.0%
- Contributors
- 40
- down 24.5%
- Merges
- 37
- down 5.1%
Activity Overview
Commits and releases over time
- Commits
- Releases
- Authors
Repository Explorer
No repositories match that filter.
6819 commits in all time
Jun 03, 2026 12:24 – Sep 01, 2026 12:24 UTC
Merge 87cbfe7268ac9acef6382ae278d5f277631a60b6 into 623f3c058154e12632360cbd84a2d3c0c078314e
b023f175
pull/613/merge
3/4,217 ++ 0 --
docs: add v5 security notes on size-changing updates and post-quantum keys
87cbfe72
security-guide
1/24 ++ 0 --
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
ffe76831
review/S2-hardening
4/495 ++ 12 --
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
2dfc2188
review/S2-hardening
2/181 ++ 34 --
test: fix test script explorer to be network agnostic
30b9c7c8
main
3/37 ++ 1 --
feat: vault plugin for algorand post-quantum accounts
Adds a custom Vault secrets engine that manages Algorand post-quantum
(Falcon-1024) accounts, which the transit engine cannot do natively.
The plugin derives a Falcon-1024 keypair deterministically from 32 bytes of
entropy (the 25-word mnemonic) and stores the entropy, the canonical address
salt and the key material in the mount's barrier-encrypted storage — a PQ
account needs more than the mnemonic, since one public key can derive up to
256 addresses depending on the salt. Derivation follows go-algorand exactly
(SHA512-256 "PQK"/"PQA" domain separation, off-curve salt scan) and is pinned
by the official algokey test vector.
The API mirrors transit so the service can reuse its existing call patterns:
POST keys/{name} creates (idempotent), GET keys/{name} returns scheme, salt,
public key and address, POST sign/{name} signs base64 input, LIST keys
enumerates. Deletion, rotation, versioning and export are deliberately absent.
Wiring: scripts/build_vault_plugin.sh builds a static musl binary into the
plugin directory the vault container now mounts, and development-init
registers it by sha256, mounts it at pawn/pq-users and extends the AppRole
policies (users create, managers create/list/sign). CI builds the plugin
before the stack starts and runs the Go tests under the race detector.
The plugin is pinned to Go 1.23 because Vault 1.15 injects
GODEBUG=x509sha1=1 into the plugin processes it spawns and Go removed that
setting in 1.24; a newer toolchain aborts before the go-plugin handshake.
Go tests cover derivation against the official algokey vector, persistence
across a fresh backend instance and concurrent creates. The e2e suite adds a
block that talks to the mount directly — no service endpoint exposes PQ
accounts yet — re-deriving the returned address independently in TypeScript
and asserting the user AppRole can create but not sign.
f01a5667
feat/pq-accounts
13/1,124 ++ 3 --
Merge 6960bf62973759e65237740867ae52adfb4f908d into dd7be47db270b641b07a8abb0bb3995360a8e34f
3517daec
pull/911/merge
1/1 ++ 1 --
build(deps-dev): bump @typescript-eslint/eslint-plugin
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.69.0 to 8.68.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.68.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.68.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
6960bf62
dependabot/npm_and_yarn/typescript-eslint/eslint-plugin-8.68.0
1/1 ++ 1 --
Merge edd1d2b93928f70946b29992936784b82cab0cb4 into 7861a68efdc034d4a01f5ba68f1acff97e28e8e6
42379a4a
pull/454/merge
15/1,388 ++ 954 --
chore(deps): update non-major dependencies
edd1d2b9
renovate/non-major-dependencies
15/1,388 ++ 954 --
feat: switch lsig to be funded/refunded to payee
cab88a45
main
4/343 ++ 158 --
Merge e19bda6a0673f116aa0b77be938e57848be7a85a into 9bc334a8819e21a61e5717e04c07dec184a7c579
18ba1d5e
pull/99/merge
2/5 ++ 3 --
chore(deps): update dependency conventional-changelog-conventionalcommits to v10
e19bda6a
renovate/conventional-changelog-conventionalcommits-10.x
2/5 ++ 3 --
Merge 8076e736e409d33e49b9f0f8b93330517469b2a9 into 9bc334a8819e21a61e5717e04c07dec184a7c579
0641241a
pull/98/merge
2/4 ++ 4 --
chore(deps): update dependency @types/node to v26
8076e736
renovate/node-26.x
2/4 ++ 4 --
fix: NFD bug in real liquid stream screen (#400)
0f211bf1
main
14/304 ++ 54 --
fix(agent): share works on mobile — clipboard gets the pending link, the sheet opens on touch
iOS Safari revokes the tap's transient activation while /api/share is in flight, so writeText afterwards throws NotAllowedError. Hand clipboard.write the pending URL as a promise-valued ClipboardItem instead, then offer the native share sheet on coarse pointers.
654c02df
main
1/17 ++ 6 --
Merge efec3005657ff5b6f57cdbdbda4d05cd05d5da2e into 12f5a4f9fa02ddd43ff125b8c90f6c8c12a5fd48
f75ab6bc
pull/361/merge
1/1 ++ 1 --
fix(agent): the Nodely credit reads Nodely AI
The host slug is still nodely; the GET label (and both credits) is the brand.
326d6bac
main
2/4 ++ 3 --
feat(agent): the provider credit is a link
The agent GET now carries providerUrl — https:// plus the host's last two labels (router.ai.nodely.io → https://nodely.io) — and both credits wear it: the composer's standing line and the first mention in qt314's hello. Brass like every other link; plain text when the URL can't be derived.
1f268cde
main
8/62 ++ 16 --