| name | token-pr-security-check |
| description | Security review of open token-list PRs. Verifies SAC derivation, issuer home_domain, Horizon records, icon, and file placement; flags non-SAC (WASM) tokens and unlocked issuer accounts as red flags; posts a "Claude Opinion" comment on each PR. Use when asked to review, audit, or give an opinion on token-list pull requests. |
Token PR Security Check
Review open PRs on soroswap/token-list and post an opinion comment on each.
Never merge anything. Opinions are advisory only.
Per-PR checklist
For each open PR, fetch the added/changed JSON (via gh api repos/soroswap/token-list/pulls/<N>/files) and check:
1. Is it a SAC (Stellar Asset Contract)?
- If the JSON has no
issuer (G address), or the contract resolves on-chain to
contractExecutableWasm instead of a SAC, it is a custom Soroban token.
Also cross-check: enumerate classic assets with the same code on Horizon
(/assets?asset_code=X) and derive each one's SAC with
new StellarSdk.Asset(code, issuer).contractId(Networks.PUBLIC) — if none match
the PR's contract, it is not the SAC of any classic asset.
- Opinion in that case: "Not SAC token. It requires a security audit on the
Soroban token code."
- If it claims a SAC, verify
Asset(code, issuer).contractId(PUBLIC) equals both
the contract field and the filename.
2. SAC correctness checks
- Domain: issuer's on-chain
home_domain (Horizon /accounts/<issuer>) must
equal the domain field exactly (bare domain, no https://).
- Existence: Horizon
/assets?asset_code=&asset_issuer= must return a record;
report holders / liquidity-pool amounts as adoption signals.
- Icon: URL must return HTTP 200 with an
image/* content type.
- Auth flags: report
auth_required, auth_revocable, auth_clawback_enabled
(revocable/clawback = issuer can freeze or seize user balances — always mention).
3. Issuer lock status — RED FLAG if unlocked
From Horizon /accounts/<issuer> check signers and thresholds:
- Locked = master key weight 0 and no other signers with weight > 0
(issuer can never mint more or change flags).
- Unlocked = master weight > 0 or active extra signers.
If the issuer is unlocked, post a red-flag comment on the PR tagging the PR
author (@<author>), explaining that the issuer can still mint unlimited supply
and change flags, and asking: "Are you planning to lock the issuer account (set
master key weight to 0, ideally after setting auth_immutable)?"
Note auth_immutable: true as a plus when present.
4. PR hygiene
- The JSON must live at
assets/<CONTRACT>.json. If it was placed at the repo
root (or elsewhere) and the token itself passes the checks, push a commit to the
PR branch moving it into assets/ so the CI verifier picks it up
(gh pr checkout <N>, git mv, run yarn verify, push to the fork).
- PRs must not modify
tokenList.json — the list is regenerated after merge
with yarn merge. If a PR edits it, ask for the change as an assets/ file.
- Flag duplicate PRs (same contract) and third-party submissions (author is not
the asset's organization).
Comment format
Every comment must start with:
## Claude Opinion
*Opinion generated by Claude Code. Not a decision.*
Then a bold one-line verdict, a ✅/❌/⚠️ check list with the on-chain evidence, and
what (if anything) the contributor must fix. Red-flag comments use the header
## 🚩 Claude Opinion — Red Flag: <reason> and tag the author.