A fully on-chain, modular TRC-721 on TRON, engineered to audit-grade practice — and a complete, brutally honest dogfooding case study of TronIDE.
English · 简体中文
Three Kingdoms general cards: four factions (WEI / SHU / WU / QUN), five rarities (N → LEGEND), four 0–100 stats, and a one-shot "Peach Garden" genesis — Liu Bei, Guan Yu, Zhang Fei as LEGEND 1/1s, sealed forever after one mint. Metadata — and, through the sealable SVG renderer, the card art itself — lives entirely on chain as data URIs: no IPFS pin to lapse, no metadata server to die. If the chain is up, the cards are whole.
- A reference TRC-721, zero dependencies. The full core + metadata surface — both
safeTransferFromoverloads with atry/catchreceiver probe, TRC-165 with compiler-computedtype(X).interfaceId(no hand-copied magic constants), spec-grade revert semantics onownerOf/balanceOf/getApproved, two-step ownership handover, custom errors throughout. No OpenZeppelin import: every byte that ends up on chain is in this repo, which makes the whole surface auditable in one sitting. - Fully on-chain metadata and artwork.
Card → JSON → Base64 → data:URI for metadata, plusCardRenderer— the card face drawn as pure SVG in Solidity (faction-themed frame, rarity stars, stat bars) and embedded as a nesteddata:image/svg+xml;base64URI. User strings are JSON-escaped and XML-escaped on chain; a broken or hostile renderer degrades to imageless metadata instead of brickingtokenURI; the suzerain cansealRenderer()forever once the art is final. - Deliberately spiky Solidity. File-level types and free functions, a
globalusing-for, aliased named imports, a same-file-two-paths import trap, a public-state-var overriding an interface function,uncheckedblocks, an assembly guard, revertingreceive/fallback— each one placed on purpose to stress compilers, flatteners, UML generators, linters and analyzers, and annotated with why. See docs/architecture.md. - Signature-driven lazy minting (虎符 TigerTally). A tally contract takes the suzerainty — the two-step handover exists precisely so a contract can hold the throne safely — and redeems EIP-712
MintOrders: nested-struct hashing (the order wraps a fullCard), bearer and bound-with-relayer voucher modes, voidable nonces, malleability-guardedecrecover, and a marshal-gated passthrough for every suzerain power including the escape hatch back. The on-chain digest is differentially anchored to ethers'TypedDataEncoderin tests. - Real value handled the boring way (市集 CardBazaar). A fixed-price, TRX-settled stall market with escrowed listings and pull-payment proceeds — paying sellers inline would let any seller with a reverting
receive()brick their own listing's purchase.withdraw()is checks-effects-interactions, proven by a hostile seller that attempts a reentrant drain mid-payout and finds an already-zeroed ledger. No owner, no fees, no sweep: the bazaar's admin column in the trust model reads nobody. - A dual verification stack, gated in CI. Hardhat: 120 specs at 100% statement/branch/function/line coverage, with differential tests of every on-chain codec (Base64, decimal, JSON/XML escapes, the EIP-712 digest) against reference implementations. Foundry: a stateful invariant campaign — 64 fuzzed sequences × 128 guarded ecosystem ops (mints, trades, gifts, time warps) under
fail_on_revertstrict mode — proving card conservation, bazaar solvency, ledger accounting, and that custody contracts can never strand a card across every reachable sequence. The forge harness shim (ForgeLite) is written in-repo: zero external dependencies extends to the test base itself. - A real dogfooding campaign, honestly kept. The entire project — scaffold, edit, lint, compile, VM deploy, debug, record/replay, TronBox export, git push, TronLink mainnet-style deploys, flatten & verification — was executed inside TronIDE, driving 23 IDE features and filing 13 findings, of which 6 were fixed upstream with regression gates and 3 were retracted after strict re-verification (the ledger counts our own misreads too). See docs/case-study.md.
Audit status: engineered to audit-grade practice, not yet externally audited. Read SECURITY.md before depositing value you care about.
contracts/
├── ThreeRealmsCards.sol the TRC-721 card contract
│ ├── interfaces/
│ │ ├── ITRC165.sol interface detection
│ │ ├── ITRC721.sol core surface (is ITRC165) — 9 fns XOR to 0x80ac58cd
│ │ ├── ITRC721Metadata.sol name / symbol / tokenURI (is ITRC721)
│ │ ├── ITRC721Receiver.sol safe-transfer hook
│ │ └── IRenderer.sol pluggable art hook (Card in, image URI out)
│ ├── access/Suzerain.sol two-step Ownable (主公): designate heir → heir accepts
│ ├── render/CardRenderer.sol 丹青 — the card face as pure on-chain SVG
│ ├── types/CardTypes.sol file-level enums, Card struct, free fns, global using-for
│ ├── libs/CardCodec.sol Card → data:application/json;base64 (JSON-escaped)
│ ├── libs/Base64.sol assembly encoder (public-node CPU caps forced it — see docs)
│ └── utils/StrUtils.sol toString / equal / escapeJson / escapeXml
├── PeachPavilion.sol gift escrow with claim windows: the heir claims until
│ the deadline (boundary inclusive), the giver reclaims after
├── TigerTally.sol 虎符 — EIP-712 signed mint orders (lazy minting);
│ holds the suzerainty while in service
├── CardBazaar.sol 市集 — fixed-price stalls, TRX-settled, escrowed
│ listings, pull-payment proceeds; no owner, no fees
└── mocks/TestMocks.sol test doubles only — never deploy
| Version | Contract | Address | Notes |
|---|---|---|---|
| v5 (current) | ThreeRealmsCards + CardRenderer + TigerTally + CardBazaar + PeachPavilion |
TDQ9k3oqaV1tErua4uft1ZnndV96oFBH4X · TAsJa3bb… · TMUmN6NK… · TKfYhL4A… |
on-chain SVG art live; the tally holds the suzerainty (Zhuge Liang #4 minted via EIP-712 voucher); the bazaar closed a full list → buy → withdraw cycle with real TRX; the pavilion (TTSyQWDj…) proved its claim/regret windows in real chain time |
| v4 (historical) | first renderer deploy | THRSFpEV… |
renderer accidentally sealed by a driver bug; 4.07M-gas tokenURI refused by public nodes (OutOfTimeException) — both documented |
| v3 (historical) | hardened, 11 files | TYK5P6bU… |
supportsInterface + two-step ownership verified on chain |
| v2 (historical) | modular, 9 files | TEzyMokX… |
cardKeyOf (global using-for) verified on chain |
| v1 (historical) | single file | TBig1iST… |
first campaign deploy |
Transactions, deployer, energy numbers, the honest incident notes and verification materials: deployments/nile.md.
npm install
npm test # 120 specs, ~3s, no local TRON node needed
npm run coverage # istanbul report; CI enforces 100%
forge test # invariant campaign: 64×128 guarded ops, 5 invariants
npx hardhat compile # solc 0.8.20, evm target paris (no PUSH0 ahead of the TVM)The Hardhat suite is a logic-regression harness: upstream solc + an EVM is instruction-equivalent to the TVM for everything this codebase uses, so unit tests run anywhere, fast. On-chain integration (energy model, TronLink signing, TronScan verification) is exercised separately through the TronIDE scenario replays (scenarios/) and the TronBox export (exports/tronbox/).
| Path | What it is |
|---|---|
contracts/ |
the production sources (see map above) |
test/ |
Hardhat suite — conformance, receiver matrix, differentials, invariants |
docs/architecture.md |
module walkthrough + the annotated "spiky constructs" inventory |
docs/case-study.md |
the TronIDE dogfooding campaign, in English |
docs/journal.md |
full campaign journal (Chinese, primary source) |
docs/dogfooding-matrix.md |
23-feature coverage matrix |
deployments/nile.md |
live addresses, txids, compiler settings |
scenarios/ |
IDE recorder scenario (deploy → genesis → reads), replayable |
exports/ |
IDE-generated TronBox project + flattened verification sources |
tools/ |
Playwright scripts that drove the IDE for each campaign phase |
23 IDE features exercised end-to-end · 13 findings filed (J-001…J-013) · 6 fixed upstream with regression gates · 3 honestly retracted after re-verification · 2 root-caused to a shared LocalStorage-backend design and scheduled as upstream migration work · 2 live deployments signed through TronLink on Nile.
The campaign's discipline — verify strictly before concluding, retract in public, prefer reading the chain over reading the UI — is documented in docs/case-study.md.