Skip to content

refactor(grc721)!: Token/Ledger split with Teller pattern#5603

Open
notJoon wants to merge 22 commits intognolang:masterfrom
notJoon:refactor/grc721
Open

refactor(grc721)!: Token/Ledger split with Teller pattern#5603
notJoon wants to merge 22 commits intognolang:masterfrom
notJoon:refactor/grc721

Conversation

@notJoon
Copy link
Copy Markdown
Member

@notJoon notJoon commented Apr 27, 2026

Description

Restructures gno.land/p/demo/tokens/grc721 along the same Token/Ledger/Teller axis the GRC20 refactor (#2983) used. Extracts royalty and on-chain metadata into opt-in subpackages. Migrates four downstream realms to the new API.

Closes most items in #5546(GRC20/GRC721 spec alignment meta). Refs #3502 (on-chain Metadata fate) by isolating it into a subpackage so the keep/remove decision can land independently.

Timeline

Changes

Summarized by Opus 4.7 (1M context) agent.

Core — gno.land/p/demo/tokens/grc721

  • *basicNFT*NFT (public read view) + *PrivateLedger (admin operations with explicit from / owner arguments). Admin methods on the ledger never inspect runtime.PreviousRealm or runtime.CurrentRealm.
  • New Teller interface; five factories produce concrete *fnTeller instances:
    • (*NFT).CallerTeller()runtime.PreviousRealm() per call; safe to expose publicly.
    • (*NFT).ReadonlyTeller() — write methods return ErrReadonly.
    • (*NFT).RealmTeller() — captures the calling realm at construction.
    • (*NFT).RealmSubTeller(slug) — derived sub-account.
    • (*PrivateLedger).ImpersonateTeller(addr) — admin-grade impersonation.
  • Interface segregation: IGRC721Core (transfer/approve), IGRC721CollectionMetadata, IGRC721Metadata (read: TokenURI), IGRC721MetadataWriter (SetTokenURI), IGRC721Enumerable (TotalSupply). Compile-time witnesses pin the type/interface relationships.
  • TotalSupply() added as an alias of TokenCount() for grc20 parity.
  • Transfer hooks and post-hook re-validation deleted. Gno does not support virtual method override through embedding, so the OZ hook pattern was structurally inapplicable.
  • SafeTransferFrom aliased to TransferFrom with a Deprecated: comment pointing at [META] GRC20 / GRC721 Spec Alignment & Improvement Tasks #5546. The empty checkOnGRC721Received and ErrTransferToNonGRC721Receiver are removed.
  • avl.Treebptree.BPTree throughout, following the precedent set by chore(boards2): use bptree instead of avl package #5568.
  • NewBasicNFT becomes NewNFT and returns (*NFT, *PrivateLedger).

Extensions — new subpackages

  • gno.land/p/demo/tokens/grc721/royaltyRoyaltyNFT, EIP-2981 royalties expressed in basis points (10 000 = 100 %, lets us represent fractional rates like 2.5 % which the legacy integer-percentage representation could not). Own PrivateLedger and Teller. (depends on fix(grc721): migrate royalty to basis points per EIP-2981 #5504)
  • gno.land/p/demo/tokens/grc721/metadataMetadataNFT, the on-chain Metadata/Trait types preserved verbatim. Own PrivateLedger and Teller.

Downstream realms

Migrated within this PR:

  • r/demo/foo721 — admin paths use ledger.Mint/ledger.Burn; user-facing Approve/SetApprovalForAll/TransferFrom route through UserTeller := Token.CallerTeller().
  • r/demo/btree_dao — constructor + dao.MintdaoLedger.Mint.
  • r/jjoptimist/eventix — same pattern; ticket minting uses ticketsLedger.Mint.
  • r/matijamarjanovic/tokenhub — drops the NFTGetter closure indirection. RegisterNFT now takes *grc721.NFT directly. The IGRC721CollectionMetadata runtime check is no longer needed (the new *NFT always satisfies it).

Migration cheat-sheet

For out-of-repo callers:

Before After
nft := grc721.NewBasicNFT(name, symbol) nft, ledger := grc721.NewNFT(name, symbol)
nft.Mint(to, tid) / nft.Burn(tid) ledger.Mint(to, tid) / ledger.Burn(tid)
nft.Approve(to, tid) (caller-resolved) Token.CallerTeller().Approve(to, tid)
nft.TransferFrom(from, to, tid) Token.CallerTeller().TransferFrom(from, to, tid)
grc721.NewNFTWithRoyalty(...) royalty.NewRoyaltyNFT(...)
grc721.NewNFTWithMetadata(...) metadata.NewMetadataNFT(...)
grc721.NFTGetter, nft.Getter() pass *grc721.NFT directly
grc721.IGRC721 (monolithic) one of IGRC721Core / IGRC721Metadata / etc.

@Gno2D2
Copy link
Copy Markdown
Collaborator

Gno2D2 commented Apr 27, 2026

🛠 PR Checks Summary

🔴 Pending initial approval by a review team member, or review from tech-staff

Manual Checks (for Reviewers):
  • IGNORE the bot requirements for this PR (force green CI check)
Read More

🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.

✅ Automated Checks (for Contributors):

🟢 Maintainers must be able to edit this pull request (more info)
🔴 Pending initial approval by a review team member, or review from tech-staff

☑️ Contributor Actions:
  1. Fix any issues flagged by automated checks.
  2. Follow the Contributor Checklist to ensure your PR is ready for review.
    • Add new tests, or document why they are unnecessary.
    • Provide clear examples/screenshots, if necessary.
    • Update documentation, if required.
    • Ensure no breaking changes, or include BREAKING CHANGE notes.
    • Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
  1. Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 The pull request was created from a fork (head branch repo: notJoon/gno-core)

Then

🟢 Requirement satisfied
└── 🟢 Maintainer can modify this pull request

Pending initial approval by a review team member, or review from tech-staff

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 Not (🔴 Pull request author is a member of the team: tech-staff)

Then

🔴 Requirement not satisfied
└── 🔴 If
    ├── 🔴 Condition
    │   └── 🔴 Or
    │       ├── 🔴 At least one of these user(s) reviewed the pull request: [aronpark1007 davd-gzl jefft0 notJoon omarsy MikaelVallenet] (with state "APPROVED")
    │       ├── 🔴 At least 1 user(s) of the team tech-staff reviewed pull request
    │       └── 🔴 This pull request is a draft
    └── 🔴 Else
        └── 🔴 And
            ├── 🟢 This label is applied to pull request: review/triage-pending
            └── 🔴 On no pull request

Manual Checks
**IGNORE** the bot requirements for this PR (force green CI check)

If

🟢 Condition met
└── 🟢 On every pull request

Can be checked by

  • Any user with comment edit permission

@notJoon notJoon changed the title Refactor/grc721 refactor(grc721)!: Token/Ledger split with Teller pattern Apr 27, 2026
@notJoon notJoon marked this pull request as ready for review April 28, 2026 04:49
@Gno2D2 Gno2D2 added the review/triage-pending PRs opened by external contributors that are waiting for the 1st review label Apr 28, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧾 package/realm Tag used for new Realms or Packages. review/triage-pending PRs opened by external contributors that are waiting for the 1st review

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants