Repository navigation
feat!: audit the token catalog for coverage, provenance and transfer constraints - #40
Merged
Merged
Conversation
…constraints Closes #38. Coverage: the catalog now promises an explicit per-chain target instead of "all common tokens" (scripts/token-catalog/coverage.ts), and a test fails when a target asset is neither listed nor a recorded known gap. Every target asset is listed: BNB Chain goes from 2 rows to 17 (WBNB first), Ethereum gains 25 (RLUSD, USDG, GHO, cbETH, ...) and Base 13 (RLUSD, WBTC, ...), covering every Aave V3 Core reserve on the three mainnets. Fixes found by the audit: - Base Sepolia USDT said 6 decimals; the contract returns 18. - lookupToken(56, WBNB) returned "WETH" through Uniswap's wrapped-native slot; WBNB is now catalogued. - Ethereum SolvBTC.BBN is renamed xSolvBTC to follow Solv's on-chain rebrand. Provenance: canonical sources, issuance (native/bridged/test), bridge and legacy status live in src/tokens/provenance/*.json (not shipped). Tests pin each provenance address to the catalog. 80 pre-audit rows are listed as pending, and that list can only shrink. Transfer constraints: TokenChainEntry.transferConstraints records permissionedRecipient (OUSG, BUIDL, USYC) and rebasing (stETH, eETH), established by read-only eth_call simulation of full-balance transfers. Also: yarn verify:tokens (on-chain code/decimals/symbol check), yarn report:tokens (generates docs/TOKEN_COVERAGE.md), docs/TOKEN_CATALOG.md (policy, consumer guidance, audit record), and an EIP-55 checksum test. BREAKING CHANGE: Tokens["SolvBTC.BBN"] no longer exists; use Tokens.xSolvBTC. The Ethereum sidecar carries xSolvBTC for that address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`--rows` dropped rows whose chainId was missing or had no catalog file, so an invalid candidate printed "0 rows checked, 0 with errors" and exited 0. Candidate rows are now validated before any RPC call: a row off the catalog chains, off `--chain`, or with a malformed symbol, address (including a bad EIP-55 checksum) or decimals fails the run, and every bad row is reported. A run that exits 0 checked every row. The argument parser is strict too: `--rows` without a file, and unknown flags such as `--row`, used to fall back to checking the whole catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Closes #38.
What changes for consumers
Tokensby address.USDTsaid 6 decimals; the contract returns 18.lookupToken(56, WBNB)returned symbol"WETH"through Uniswap's wrapped-native slot.Tokens["SolvBTC.BBN"]is renamedTokens.xSolvBTC, following Solv's rebrand (the contract'sname()andsymbol()both returnxSolvBTC). This is amajorchangeset, so the next release is 2.0.0.TokenChainEntry.transferConstraints(TOKEN_TRANSFER_CONSTRAINT):permissionedRecipienton OUSG, BUIDL and USYC: a transfer to a fresh address reverts.rebasingon stETH and eETH: a full-balance transfer can leave 1–2 wei.Audit deliverables (#38)
docs/TOKEN_COVERAGE.md, generated byyarn report:tokens; a test fails if it is staleKNOWN_GAPSis now emptydocs/TOKEN_CATALOG.md(an explicit per-chain target, not "all common tokens")docs/TOKEN_CATALOG.md, "Guidance for consumers"Provenance. Each audited row records its canonical source, issuance (native, bridged or test), bridge, legacy status and
verifiedAtinsrc/tokens/provenance/*.json. These files are not shipped.Tooling
yarn verify:tokens: an on-chain check of code,decimals()andsymbol(). It needs network access, so it is not part ofyarn test.How it was verified
No transaction was sent and nothing was signed.
yarn verify:tokenschecks all 196 rows with 0 errors and 0 warnings.transfer(eth_callwith a state override), except seven bridged rows that had no simulatable holder. They are named in the audit record.yarn typecheckis clean, 127 tests pass, andyarn buildworks. The sidecar has 196 entries, and the tarball excludes the provenance files and docs.Follow-ups outside this repo
core/taskengine/tokenwhitelist/carries the same wrong Base Sepolia USDT decimals (6) and still names EthereumSolvBTC.BBN. Its drift check against the sidecar should flag both.app/lib/erc20/catalog.ts;transferConstraintson the Sweep selection step;@avaprotocol/protocols@^2.🤖 Generated with Claude Code