Make the docs match the programs, and close the gaps nothing was checking - #131
Merged
Conversation
The TypeScript workflow runs `biome check ./`, which formats JSON as well as TypeScript. `basics/cross-program-invocation/anchor/idls/lever.json` was regenerated by `anchor build` with one array element per line, which Biome reformats onto a single line, so the check has failed on every commit since the IDL was last regenerated. Reformatted; the file's contents are unchanged. The ASM workflow installs the sbpf assembler with `cargo install --git`. The upstream repository now ships a second binary crate, `xtask`, and cargo refuses to pick between two binaries, so the install step dies before any project is built. Naming the package fixes it.
Both counter examples exist to show a hook writing to a PDA, and both READMEs say the hook increments a counter on every transfer. The handler added one to the stored count, logged the result, and dropped it: `counter_account` was not `mut`, so nothing was ever written back and the count read one after every transfer no matter how many had happened. The extra account meta already declares the PDA writable, so the fix is the `mut` constraint and the assignment. A new assertion in each test reads the counter back after the hooked transfer. The dead `amount > 50` check kept a commented-out `return err!(...)` beside it. `amount` arrives in minor units, so any transfer of a token with decimals clears 50, and returning the error there would fail the example's own test. Replaced the commented-out line with a comment saying what to change to make the limit binding. `AmountTooBig` was also standing in as the checked-add overflow error, which is a different failure. Added `CounterOverflow` for that.
The v2 port changed code that five READMEs still show in its pre-port form, so the repository documented account types, handler signatures and CPI builders that no longer exist. Each code block now matches the source it is quoting, and each identifier named in prose resolves to a real definition. - `tokens/nft-operations`: the CPIs go through anchor-spl's `create_metadata_accounts_v3` / `create_master_edition_v3` / `verify_sized_collection_item` wrappers and a `CpiContext`, not the `mpl-token-metadata` `*Cpi` builders with `invoke_signed`. Added a note on why, and on how the read-only and mutable `CpiHandle`s differ. - `tokens/token-extensions/transfer-hook/account-data-as-seed`: the extra account metas come from a free function, the constraint structs carry the `AccountConstraints` suffix, and `extra_account_meta_list` is an `UncheckedAccount`. - `finance/order-book`: `initialize_market` takes `base_lot_size` and `quote_lot_size` (with the errors that reject zero), `place_order` takes `&mut Context`, the state accounts store `Address`, and the maker pairs arrive as `AccountView`s from `context.remaining_accounts()`. - `basics/close-account` and `finance/token-fundraiser`: `BorshAccount`, `#[account(borsh)]`, `Address`, and `user.address()` in seeds. - `basics/counter` and `finance/token-fundraiser` named an `initialize` handler; the handlers are `initialize_counter` and `initialize_fundraiser`. `tokens/nft-operations`'s program is not a workspace member, so nothing lints it: its account fields were private (which the README's example could not be), one handler took a `mut` binding on a reference, and one `use` was not rustfmt-clean. Fixed alongside the README that quotes them.
Twenty comments across workflows, manifests and program sources explained a version skew or a workaround in terms of "Anchor 1.0" or "anchor-lang 1.0". The programs are on 2.0.0-rc.1, so a reader checking one of these against the manifest finds a version that is not there and cannot tell whether the workaround still applies. Each now names v2. Two mentions stay: `README.md` on when `anchor init` began scaffolding LiteSVM, and the abl-token manifest on when `interface-instructions` was removed. Both are statements about the past and both are true.
Each proof crate declares its own `[workspace]` (deliberately: the Kani model must not drag in the Solana and SPL dependency tree), so the repository-wide `cargo fmt` and `cargo clippy` jobs in rust.yml never see it. Nothing else did either, and seven of the eight crates had drifted out of rustfmt. `kani.yml` already runs a per-crate matrix for the unit tests, so the fmt and clippy steps go there. Reformatted all eight. `token-swap`'s copy of `integer_sqrt` also needed two fixes to pass clippy. It is documented as a verbatim copy of the program's function, so the `(x + 1) / 2` that clippy wants written as `div_ceil` is changed in the program and in the proof together, keeping the two identical. Only the `#[cfg(kani)]` proof and the unit tests call it, so the plain library build sees no caller; that now says so with an `allow`.
`finance/vault-strategy/anchor/app` is the repository's only TypeScript application: 110 files, an Anchor client, and a committed IDL. The TypeScript workflow ran Biome over it, which formats and lints but never compiles, so a client that had drifted from the program's IDL would have looked fine. The app already ships the two scripts that catch it. `typecheck` compiles it, and `verify` exercises instruction encoding, account decoding and PDA derivation against the committed IDL offline, with no validator. Both pass today; CI now runs them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The follow-up work from the repository audit: documentation that described programs as they used to be, two examples that did not do the thing their README said they did, and three places where CI was not looking.
Six commits, each independent. Merges cleanly onto
mainas ofe0fcaa25.ci: fix the two red workflows on mainThe ASM workflow installs the sbpf assembler with
cargo install --git. Upstream now ships a second binary crate,xtask, and cargo refuses to pick between two binaries, so the install step dies before any project is built. Naming the package fixes it. This is still red onmain.This commit also reformats
basics/cross-program-invocation/anchor/idls/lever.json, which #130 has since landed independently. Same content, so the merge is a no-op for that file.transfer-hook: keep the transfer count the examples say they keepBoth counter examples exist to show a hook writing to a PDA, and both READMEs say the hook increments a counter on every transfer. It did not. The handler added one to the stored count, logged the result and dropped it:
counter_accountwas notmut, so nothing was written back and the count read one after every transfer no matter how many had happened. The extra account meta already declares the PDA writable, so the fix is themutconstraint and the assignment. A new assertion in each test reads the counter back after the hooked transfer.The dead
amount > 50check kept a commented-outreturn err!(...)beside it.amountarrives in minor units, so any transfer of a token with decimals clears 50 and returning there would fail the example's own test. Replaced the commented-out line with a comment saying what to change to make the limit binding.AmountTooBigwas also standing in as the checked-add overflow error, which is a different failure, soCounterOverflownow covers that.docs: describe the programs as they are now implementedFive READMEs still showed pre-port code, so the repository documented account types, handler signatures and CPI builders that no longer exist.
tokens/nft-operationsshowedCreateMetadataAccountV3Cpi::new(...).invoke_signed()where the program uses anchor-spl'screate_metadata_accounts_v3with aCpiContext, andVerifyCollectionV1Cpiwhere the source callsverify_sized_collection_itemtransfer-hook/account-data-as-seed: free function for the extra metas,AccountConstraintssuffixes,UncheckedAccountfor the meta listfinance/order-book:initialize_markettakesbase_lot_sizeandquote_lot_sizewith the errors that reject zero,place_ordertakes&mut Context, state storesAddress, maker pairs arrive asAccountViews fromcontext.remaining_accounts()basics/close-accountandfinance/token-fundraiser:BorshAccount,#[account(borsh)],Address,user.address()in seedsbasics/counterandfinance/token-fundraisernamed aninitializehandler; they areinitialize_counterandinitialize_fundraiserEvery fenced Rust block in every tracked markdown file now matches its source, and every identifier named in prose resolves to a real definition.
comments: stop describing the framework as Anchor 1.0Twenty comments across workflows, manifests and program sources explained a version skew or a workaround in terms of "Anchor 1.0" or "anchor-lang 1.0". A reader checking one against the manifest finds a version that is not there and cannot tell whether the workaround still applies. Two mentions stay, both true statements about the past.
kani: lint the proof crates, which nothing was lintingEach proof crate declares its own
[workspace], deliberately, so the Kani model does not drag in the Solana dependency tree. That also means the repository-widecargo fmtandcargo clippyjobs never see it, and nothing else did either: seven of the eight crates had drifted out of rustfmt.kani.ymlalready runs a per-crate matrix, so the fmt and clippy steps go there.token-swap's copy ofinteger_sqrtneeded two fixes to pass clippy. It is documented as a verbatim copy of the program's function, so the(x + 1) / 2clippy wants asdiv_ceilchanged in the program and the proof together, keeping them identical.ci: typecheck and verify the vault strategy appfinance/vault-strategy/anchor/appis the only TypeScript application here: 110 files, an Anchor client, a committed IDL. Biome formatted and linted it; nothing compiled it, so a client that had drifted from the program's IDL looked fine. The app already ships the two scripts that catch it, and both pass today.Verification
cargo fmt --all --checkandcargo clippy -- -D warnings -A clippy::diverging_sub_expressionclean at the repository root; all eight kani-proof crates clean on fmt, clippy and their unit tests;biome checkover the tracked files CI sees reports zero errors.Not verified: the transfer-hook counter change has never been executed.
anchor testneeds a toolchain this session cannot install, so it is backed bycargo checkand by the extra account meta already declaring the PDA writable. CI on this PR is the first real run.This does not touch the nine projects failing at
anchor idl build; those are tracked in the discussion on #130.Generated by Claude Code