Ecosystem metrics

New Repos
12
New
Commits
990
up 22.4%
Releases
11
up 10.0%
Contributors
51
down 10.5%
Merges
23
up 187.5%

Repository Explorer

10299 commits in all time May 19, 2026 11:34 – Aug 17, 2026 11:34 UTC
ipaleka frontend
Bugfix for charts not being fully responsive in the address page
Git Commit 7c154fca Branch development Document 6/93 ++ 22 --
ipaleka widgets
Bugfix for charts placement in the historic widget page
Git Commit 1cd1bee7 Branch main Document 2/8 ++ 3 --
ipaleka frontend
Added profile appearance page
Git Commit 423d6a0a Branch development Document 19/1,195 ++ 226 --
Reject the zero address as a controlling owner; it permanently bricks a cell
Found by a multi-agent adversarial review of this repo and confirmed by an
independent refuter at bytecode level.

MECHANISM. update_owner validated the CALLER (controlling_owner[cid] ==
Txn.sender.bytes) and the cell STATE (cid not in inscriptions), and performed
zero validation on the DESTINATION -- it wrote any 32 bytes. The committed TEAL
has nothing between the ARC-4 `len == 32` decode assert and
`dup / box_del / pop / swap / box_put`.

WHY THE ZERO ADDRESS IS DIFFERENT. It is an absorbing state. Both remaining
movers -- inscribe (C1) and update_owner itself -- require
controlling_owner[cid] == Txn.sender.bytes, which no key can ever satisfy for
it. Re-registration is blocked by the register-once guards; the box is never
deleted without being rewritten; on_update/on_delete hard-fail (I5,
non-upgradable); there is no admin override. The cell is un-inscribable
forever: one of only 1,024, dead, with no remedy short of minting a replacement.

REACHABLE TWO WAYS. Deliberate griefing -- and update_owner carries no
asset-balance requirement, unlike inscribe, so a seller who transferred the Cell
ASA but remained the recorded controlling owner can brick a cell someone else
now holds (a state this suite's own
test_recorded_owner_who_no_longer_holds_is_rejected documents as expected, not
hypothetical). And by accident: algosdk encodes a default-constructed
arc4.Address as 32 zero bytes, satisfying the only check that existed.

THE INCONSISTENCY THIS CLOSES. THREAT_MODEL_AND_TRACEABILITY.md lists "commit a
malformed key (brick a cell)" as a DEFENDED attack, and register_cell already
applies exactly that reasoning to the other field committed at mint -- "A
malformed key would brick the cell -- reject it at the source." The owner
pointer was simply missed. Both writers are now guarded, so the invariant is
"no cell is ever owned by the zero address", not "one path happens to check".

TESTS. Two added. Each also asserts the REJECTED call did not consume the cell:
a half-registering failure would be a worse bug than the one being fixed.

The zero address in the tests is DERIVED via encode_address(bytes(32)), not
written down. My first draft hard-coded the base32 literal and got it wrong --
73 characters against the real 58 -- which is the precise defect shape this
repository's register exists to catch. Deriving it means it cannot drift from
what the contract compares against.

ARTIFACTS REGENERATED. contracts/out/ rebuilt with the pinned toolchain
(puyapy 5.8.1, AVM 12) from contracts/ with the bare filename, so all five stay
byte-reproducible. Approval program 413 -> 423 ops; both assert strings present
in the emitted TEAL.

NOT RUN HERE, STATED PLAINLY: the localnet suite needs algokit LocalNet, which
is not running on this machine (no algod on :4001, no container). The two new
tests are written against the existing fixtures and style but have NOT been
executed. They must go green on the LocalNet CI job before this merges.

This changes the contract, so it widens the already-recorded gap between the
committed source and the deployed TestNet app. It belongs in the same redeploy.
Git Commit 06dd8823 Branch fix/owner-zero-address Document 5/635 ++ 349 --
Ganainmtech devportal
Merge 7c3ec16cd7f80798554a98e90606463cba694a48 into 9ccf32ecd596eac20065b70904206694aa41247b
Git Commit 68550294 Branch pull/640/merge Document 1/20 ++ 0 --
meetthosar devportal
Merge 553aeaf600ab6b0f4450f27bbf75b638fbb6c82d into 9ccf32ecd596eac20065b70904206694aa41247b
Git Commit be8a52c4 Branch pull/639/merge Document 5/184 ++ 13 --
renovate[bot] use-wallet
Merge 3e5dd3113a2b3752f180894307f38f9f393c74ab into 7861a68efdc034d4a01f5ba68f1acff97e28e8e6
Git Commit ab5ee5cf Branch pull/448/merge Document 3/9 ++ 9 --
renovate[bot] use-wallet
chore(deps): pin dependencies
Git Commit 3e5dd311 Branch renovate/react-monorepo Document 3/9 ++ 9 --
build(deps-dev): update @typescript-eslint/eslint-plugin requirement
Updates the requirements on [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) to permit the latest version.
- [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.67.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.67.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Git Commit 6c25b741 Branch dependabot/npm_and_yarn/typescript-eslint/eslint-plugin-tw-8.67.0 Document 1/1 ++ 1 --
ipaleka frontend
Static files are served under a content-hashed name in production
Git Commit 64deb886 Branch development Document 57/291 ++ 171 --
Also verify the typed client, the artifact the tests actually run against
There are TWO arrows out of the committed artifact, not one, and neither was
checked:

    contracts/out/TrelyanInscription.*
        |  algod compile                |  algokit generate client
        v                               v
    bytecode ==? chain              contracts/trelyan_client.py

The client branch matters more than it looks. contracts/trelyan_client.py is an
89 KB generated file stamped "DO NOT MODIFY IT BY HAND", and the LocalNet suite
deploys the committed TEAL and drives it THROUGH that client. CI only ever
consumes it; nothing regenerated it and compared. A contract whose ABI moved
without the client being regenerated would be exercised by a suite talking to
the old interface -- and the suite would pass.

CHECKED WITHOUT RUNNING THE GENERATOR, DELIBERATELY

`algokit generate client` needs algokitgen-py, which would pin this check to a
generator version whose formatting churn is not a finding. It is also, on the
machine this was written on, blocked outright by a Windows Application Control
policy (os error 4551) -- the same policy that currently blocks cargo-deny.

No generator is needed: the client EMBEDS the full spec it was generated from,
in _APP_SPEC_JSON. Comparing that to the committed arc56.json needs nothing but
the two committed files, runs anywhere, and is stable across generator versions.

The comparison is on PARSED JSON rather than bytes, because the client embeds
the spec minified while arc56.json is pretty-printed -- a byte comparison would
fail always and therefore mean nothing.

Failure reporting distinguishes an ABI-method change (names differ; the suite is
testing a different interface) from a signature/struct/metadata change (names
agree), because those read very differently to a reviewer.

VERIFIED

  - clean tree: all five artifacts plus the client in step, exit 0
  - rename a method inside the client's embedded spec: CLIENT DRIFT, exit 1,
    naming both method lists
  - a missing _APP_SPEC_JSON block is reported as "repair the check", not
    silently passed -- if the generator's output shape changes, this check stops
    reading what it thinks it reads, and that is a finding about the check
Git Commit ee6e17aa Branch ci/verify-teal-matches-source Document 1/87 ++ 4 --
Put inscription.py inside the verified chain; it was never in it
verify_deployment.py documents a derivation chain in which nothing is stored
and everything is recomputed:

    contracts/inscription.py
        |  puya                                  <-- THIS ARROW
        v
    contracts/out/TrelyanInscription.*           [committed artifacts]
        |  algod /v2/teal/compile
        v
    expected bytecode --sha512_256--> fingerprint  ==?  deployed program

CI only ever ran the part BELOW the committed artifact. The --recompile flag
covering the top arrow exists, and no workflow ever passed it: grep across
.github/workflows/ returns zero occurrences of "recompile".

So inscription.py -- the ONLY human-readable artifact in the chain, the file a
reviewer reads and an auditor is handed -- was not verified to correspond to
anything. An edit that changed behaviour, committed without regenerating
contracts/out/, passed every gate green: the committed TEAL still assembles to
the bytecode still on chain, and nothing compared the source to the artifact.
The reviewer reads one program, the network runs another, all checks pass.

That is the exact failure verify_deployment.py warns about in its own output --
"before treating any review of this source as a review of the live
application" -- arriving through the door nobody was watching.

WHAT THIS ADDS

contracts/verify_teal_matches_source.py recompiles from source with the pinned
toolchain and compares ALL FIVE committed artifacts as text, separating two
failure modes that need different responses:

  BEHAVIOURAL  instruction streams differ -- the artifact does not implement the
               source. A correctness finding.
  STALE        instructions identical, only comments and '// inscription.py:NNN'
               references differ. Bytecode unaffected, but an auditor tracing
               TEAL back to source lands on the wrong line.

Running verify_deployment.py --recompile in CI would close most of this, and is
still worth doing. It would not close all of it: after its repair it compares
ASSEMBLED BYTECODE, deliberately, so comment churn cannot raise a false alarm --
which also means stale source references pass, since the assembler discards
comments. It also covers only the two .teal files, not the maps or the ARC-56
client contract.

REPRODUCIBILITY IS INVOCATION-SENSITIVE, AND NO DOCUMENTED COMMAND REPRODUCED

puya records the source path AS TYPED, in two forms in two places:

  - .teal comments carry the path as given. Compiling from the repo root emits
    '// contracts/inscription.py:156' where the committed artifact carries
    '// inscription.py:156' -- 124 differing lines, every one cosmetic.
  - .puya.map 'sources' is the path RELATIVE TO THE OUT-DIR. The committed map
    says '../inscription.py', which only reproduces when the out-dir is a
    SIBLING of inscription.py's parent, as contracts/out/ is.

Three build commands were documented -- README.md, CONTRIBUTING.md and
contracts/requirements.txt -- and NONE reproduced the committed artifacts. Two
ran from the repository root; the third referenced crypto/contracts/, a
directory that does not exist in this repository. THREAT_MODEL_AND_TRACEABILITY
carried the same non-existent path through its entire reproduction recipe --
an audit-facing document whose every step failed on file-not-found. All are
corrected to the invocation that actually reproduces:

    cd contracts && puyapy inscription.py --out-dir out --target-avm-version 12

Verified: all five artifacts then reproduce BYTE-FOR-BYTE.

THE PIN IS NOW INSTALLABLE

puyapy==5.8.1 / algorand-python==3.5.0 existed only as a COMMENT describing a
venv on one developer's machine at %USERPROFILE%\trelyan-build. A commented pin
cannot be installed, so CI could not reproduce the build even in principle and
nothing would detect the toolchain moving. Now contracts/requirements-compile.txt,
with exact == pins: byte-comparison against a committed artifact is only
meaningful against a fixed compiler.

VERIFIED, NOT ASSUMED

  - unmodified tree: all five artifacts identical, exit 0
  - comment-only edit to inscription.py: reported STALE, exit 1
  - behavioural edit (UInt64(0) -> UInt64(1)): reported BEHAVIOURAL DRIFT on
    approval.teal (intcblock 0 1 8 32 -> 1 0 8 32) AND stale on the two
    position-bearing files, in one report, exit 1
  - the newly documented command run verbatim: git diff empty

Line endings are normalised before comparison. The committed blobs contain
CRLF while puya writes LF, so without that the job would fail on every Linux
run -- a verdict that depended on the operating system would not be a check.
Git Commit 58b61ff4 Branch ci/verify-teal-matches-source Document 8/411 ++ 15 --
ipaleka frontend
Added a new set of DaisyUI themes
Git Commit d52db6d5 Branch development Document 26/1,026 ++ 28 --
Stop the version test from aborting the whole 3.10 suite
My own test broke CI, and the way it broke is worth more than the fix.

It imported `tomllib` at module scope. That is stdlib only from 3.11, and this
package supports 3.10 -- requires-python = ">=3.10", and the wire-format matrix
tests it. So on the 3.10 leg the import raised, and pytest reported:

    collecting ... collected 69 items / 1 error
    ERROR tests/test_version_is_single_sourced.py
    E   ModuleNotFoundError: No module named 'tomllib'
    !!!!!!!! Interrupted: 1 error during collection !!!!!!!!

A collection error is not one failing test -- it aborts the ENTIRE session. All
69 wire-format tests stopped running on 3.10, and the job surfaced as a single
red check, indistinguishable from one ordinary failure. A green-looking matrix
with one red leg hid "68 tests never ran".

Fix: import the parser inside the function that uses it, with a 3.10 branch to
the `tomli` backport. Local scope means a parser problem fails THIS test and
leaves the rest of the suite running.

Verified against a real CPython 3.10.20, not assumed:
  - before: Interrupted, 0 tests run
  - after:  53 passed, 19 skipped -- and all three version tests RUN, not skip
  - mutation (break the in-function import deliberately): 2 failed, 51 passed,
    no Interrupt -- which is the property the change is actually for
  - 3.12 unchanged: 53 passed, 19 skipped

Also declares `tomli>=2 ; python_version < "3.11"` in the dev extra. Stated
precisely: this is NOT what fixes the failure. pytest already depends on tomli
on <3.11 (it parses pyproject.toml config with it), so it was installed the
whole time -- removing it stops pytest from starting at all, before collection.
The declaration is so the suite names its own dependency instead of resting on
a transitive dependency of the test runner.
Git Commit 8b3c0bfb Branch fix/version-drift-and-missing-audit-docs Document 2/22 ++ 2 --
ipaleka frontend
Removed MaterializeCSS dependencies from historic widget
Git Commit eec12d15 Branch development Document 5/92 ++ 21 --
ipaleka widgets
Removed MaterializeCSS dependencies from historic widget
Git Commit ab64a736 Branch main Document 9/464 ++ 241 --
Merge 9e2bbebff833474cc4ef2f5ab64d9270955e0c79 into 337211c9b279ae7ee811998064b3de3f0ced7f73
Git Commit 35206bbf Branch pull/389/merge Document 15/250 ++ 224 --