Skip to content

feat(token): add refresh_metadata for state-free ERC-4906 refreshes - #121

Merged
starknetdev merged 3 commits into
mainfrom
feat/refresh-metadata
Jul 29, 2026
Merged

feat(token): add refresh_metadata for state-free ERC-4906 refreshes#121
starknetdev merged 3 commits into
mainfrom
feat/refresh-metadata

Conversation

@starknetdev

@starknetdev starknetdev commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary

Adds refresh_metadata(token_id) and refresh_metadata_batch(token_ids) to CoreTokenComponent — an entrypoint that emits the ERC-4906 MetadataUpdate event and does nothing else.

update_game couples two separable concerns: syncing game_over/completed_objective into token_mutable_state, and telling indexers that a token's rendered metadata is stale. Only the first needs the cross-contract reads back into the game and the metagame callbacks. Since token_uri reads score live from the game contract, a bare MetadataUpdate is enough to keep an indexer's view fresh.

That lets a game call refresh_metadata after ordinary mid-game actions and reserve update_game for transitions that must be persisted (game over, objective completion), instead of choosing between paying for the full callback on every action or dropping the event entirely and letting indexed state go stale.

fn refresh_metadata(ref self: ComponentState<TContractState>, token_id: felt252) {
    self.emit_metadata_update(token_id.into());
}

Changes

  • CoreTokenComponent: refresh_metadata and refresh_metadata_batch. The batch form mirrors update_game_batch — same empty-array assert, same loop.
  • IMinigameToken (packages/interfaces/src/token/core.cairo) and the IMinigameTokenMixin dispatcher interface gain both methods.
  • Six mock IMinigameToken implementations across the metagame and ticket-booth tests get no-op stubs, since adding trait methods breaks implementors.

No storage layout, event, or existing-entrypoint changes. Downstream token contracts that embed CoreTokenImpl pick the entrypoints up with no code change.

Permissionless, and no existence check

refresh_metadata is callable by anyone and deliberately does not verify that token_id exists.

An existence check measured ~52k l2 gas on what is meant to be the cheap path, and it bought nothing defensively: a caller who wants to spam MetadataUpdate can do it with any real token id, so the check only blocked the harmless variant. The event is advisory.

The contract for consumers: resolve token_id against your own record of minted tokens before acting on it. token_uri reverts for a token that does not exist, so an indexer that blindly fetches on every event will burn RPC calls on ids that were never minted (or have since been burned). test_refresh_metadata_unminted_token_emits_without_reverting pins this so a future "hardening" change has to be deliberate.

What it deliberately does not do

refresh_metadata never writes token_mutable_state. A game that is over on the game contract stays "not over" on the token until update_game runs, so this cannot be substituted for the game-over sync — is_playable, assert_playable, and the on_game_over callback keep working exactly as before. test_refresh_metadata_does_not_persist_game_state pins that: it sets the mock game to game_over = true, calls refresh_metadata, asserts the token is still playable, then calls update_game and asserts it syncs.

Gas

Like-for-like against update_game — identical deploys, mint, and set_score, differing only in the final call:

call l2 gas
update_game 8,278,460
refresh_metadata 7,567,904
saved 710,556

Dropping the existence check saves a further ~52,530. Treat the total as a floor rather than the expected saving: the mock game's game_over() and score() are trivial storage reads, whereas in a real game they re-run the game's own state loading, which is where the cost actually lives.

Test plan

  • scarb build clean
  • snforge test -p game_components_embeddable_game_standard — 1133/1133 pass
  • snforge test -p game_components_metagame — 437/437 pass
  • scarb fmt --check --workspace clean
  • git diff --check clean

Six new tests in token/tests/test_events.cairo: exact-event assertion, no-state-persistence, single-event emission, unminted-token emits without reverting, per-token batch emission, empty-batch panic.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added token metadata refresh entrypoints for a single token and for a batch.
    • Refresh operations emit ERC-4906 MetadataUpdate events and do not modify gameplay-related token state.
    • Refreshing an unrecognized token ID still emits the expected event; empty batch inputs are rejected.
  • Tests
    • Added event-focused test coverage for both refresh modes, including batch length edge cases and checks that token mutable state is not persisted.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds single-token and batch metadata refresh interfaces and implementations. Refresh calls emit MetadataUpdate events without changing token state, accept unminted IDs, reject empty batches, document interface-ID exclusions, and update test mocks.

Changes

Metadata refresh

Layer / File(s) Summary
Refresh interfaces and implementation
packages/interfaces/src/token/core.cairo, packages/embeddable_game_standard/src/token/interface.cairo, packages/embeddable_game_standard/src/token/token_component.cairo, packages/interfaces/src/AGENTS.md
Adds single-token and batch refresh methods, per-token MetadataUpdate emission, empty-batch rejection, and interface-ID derivation guidance.
Refresh event and state validation
packages/embeddable_game_standard/src/token/tests/test_events.cairo
Tests event contents and counts, state non-persistence, unminted IDs, batch behavior, and empty-batch rejection.
Mock contract compatibility
packages/embeddable_game_standard/src/metagame/tests/*, packages/metagame/src/ticket_booth/tests/test_ticket_booth.cairo
Adds no-op refresh implementations to mock token contracts.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant CoreTokenComponent
  participant EventLog
  Caller->>CoreTokenComponent: refresh_metadata(token_id)
  CoreTokenComponent->>EventLog: emit MetadataUpdate(token_id)
  Caller->>CoreTokenComponent: refresh_metadata_batch(token_ids)
  CoreTokenComponent->>CoreTokenComponent: refresh each token_id
  CoreTokenComponent->>EventLog: emit one MetadataUpdate per token_id
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Clearly summarizes the new state-free metadata refresh entrypoints and matches the diff.
Description check ✅ Passed Detailed and on-topic, covering what changed, why, tests, and behavior; only some template sections are omitted.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/refresh-metadata

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

Copy link
Copy Markdown

Codex Review - General Engineering Review

Review process failed to complete.

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

Copy link
Copy Markdown

Codex Review - Cairo/Starknet Contract Review

Review process failed to complete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/embeddable_game_standard/src/token/token_component.cairo (1)

810-875: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Complete the public entrypoint documentation.

Document token_id existence constraints, batch empty-input behavior, emitted events, and an invocation example; refresh_metadata_batch currently has no doc block.

As per coding guidelines, “Every function must include clear explanation of what it does and why, parameter descriptions with types and constraints, return value documentation, and example usage when appropriate.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/embeddable_game_standard/src/token/token_component.cairo` around
lines 810 - 875, Complete the documentation for the public entrypoints
refresh_metadata, update_player_name, update_game_batch, and
refresh_metadata_batch, including each parameter’s type and constraints, token
existence and ownership requirements where applicable, emitted events, and that
these functions return no value. Add an invocation example where appropriate,
and document refresh_metadata_batch’s non-empty input requirement and per-token
metadata refresh behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/embeddable_game_standard/src/token/tests/test_events.cairo`:
- Around line 452-462: Update the assert_emitted call in the metadata refresh
test to assert three MetadataUpdate events, one for each requested token ID at
token_ids.at(0), token_ids.at(1), and token_ids.at(2), while preserving the
existing event structure and ordering.

In `@packages/interfaces/src/token/core.cairo`:
- Around line 99-104: Regenerate IMINIGAME_TOKEN_ID for the expanded
IMinigameToken trait using the documented src5_rs parse procedure, then update
the exported constant and its matching documentation. Keep CoreTokenComponent
registration aligned with the regenerated selector value so SRC5 advertises the
current trait ABI.

---

Nitpick comments:
In `@packages/embeddable_game_standard/src/token/token_component.cairo`:
- Around line 810-875: Complete the documentation for the public entrypoints
refresh_metadata, update_player_name, update_game_batch, and
refresh_metadata_batch, including each parameter’s type and constraints, token
existence and ownership requirements where applicable, emitted events, and that
these functions return no value. Add an invocation example where appropriate,
and document refresh_metadata_batch’s non-empty input requirement and per-token
metadata refresh behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f72f7f9c-02be-4750-b4a4-33b27b4191d9

📥 Commits

Reviewing files that changed from the base of the PR and between e24bf41 and bb9f2ab.

📒 Files selected for processing (9)
  • packages/embeddable_game_standard/src/metagame/tests/test_fuzz_mint_parameters.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_libs.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_metagame_component.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_tournament_flow.cairo
  • packages/embeddable_game_standard/src/token/interface.cairo
  • packages/embeddable_game_standard/src/token/tests/test_events.cairo
  • packages/embeddable_game_standard/src/token/token_component.cairo
  • packages/interfaces/src/token/core.cairo
  • packages/metagame/src/ticket_booth/tests/test_ticket_booth.cairo

Comment on lines +452 to +462
spy
.assert_emitted(
@array![
(
token_address,
CoreTokenComponent::Event::MetadataUpdate(
CoreTokenComponent::MetadataUpdate { token_id: (*token_ids.at(2)).into() },
),
),
],
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert every refreshed token ID.

The count check plus the single assertion for token_ids.at(2) does not prove the first two metadata events belong to their requested tokens. Assert all three expected events.

Proposed test strengthening
     spy
         .assert_emitted(
             `@array`![
+                (
+                    token_address,
+                    CoreTokenComponent::Event::MetadataUpdate(
+                        CoreTokenComponent::MetadataUpdate {
+                            token_id: (*token_ids.at(0)).into(),
+                        },
+                    ),
+                ),
+                (
+                    token_address,
+                    CoreTokenComponent::Event::MetadataUpdate(
+                        CoreTokenComponent::MetadataUpdate {
+                            token_id: (*token_ids.at(1)).into(),
+                        },
+                    ),
+                ),
                 (
                     token_address,
                     CoreTokenComponent::Event::MetadataUpdate(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
spy
.assert_emitted(
@array![
(
token_address,
CoreTokenComponent::Event::MetadataUpdate(
CoreTokenComponent::MetadataUpdate { token_id: (*token_ids.at(2)).into() },
),
),
],
);
spy
.assert_emitted(
`@array`![
(
token_address,
CoreTokenComponent::Event::MetadataUpdate(
CoreTokenComponent::MetadataUpdate {
token_id: (*token_ids.at(0)).into(),
},
),
),
(
token_address,
CoreTokenComponent::Event::MetadataUpdate(
CoreTokenComponent::MetadataUpdate {
token_id: (*token_ids.at(1)).into(),
},
),
),
(
token_address,
CoreTokenComponent::Event::MetadataUpdate(
CoreTokenComponent::MetadataUpdate { token_id: (*token_ids.at(2)).into() },
),
),
],
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/embeddable_game_standard/src/token/tests/test_events.cairo` around
lines 452 - 462, Update the assert_emitted call in the metadata refresh test to
assert three MetadataUpdate events, one for each requested token ID at
token_ids.at(0), token_ids.at(1), and token_ids.at(2), while preserving the
existing event structure and ordering.

Comment on lines +99 to +104
fn refresh_metadata(ref self: TState, token_id: felt252);
fn update_player_name(ref self: TState, token_id: felt252, name: felt252);

// Batch write functions
fn update_game_batch(ref self: TState, token_ids: Span<felt252>);
fn refresh_metadata_batch(ref self: TState, token_ids: Span<felt252>);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '1,130p' packages/interfaces/src/token/core.cairo

echo
echo "== src5_rs references =="
rg -n "src5_rs parse|IMINIGAME_TOKEN_ID|supports_interface|register_interface|core::src5" packages/interfaces packages -g '*.cairo' -g '*.toml' || true

echo
echo "== locate src5 parse tool/config =="
fd -a 'src5|SRC5|src5' . | head -100

Repository: Provable-Games/game-components

Length of output: 44338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== diff for files tracked (short) =="
git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --stat 2>/dev/null || true

echo
echo "== changed token interfaces context =="
git diff --name-only HEAD~1..HEAD 2>/dev/null | rg 'packages/interfaces/src/.*\.cairo$' || true

echo
echo "== selectors in target trait by external mut/immutable refs =="
python3 - <<'PY'
from pathlib import Path
p = Path('packages/interfaces/src/token/core.cairo')
text = p.read_text()
for i,line in enumerate(text.splitlines(), 1):
    s=line.strip()
    if s.startswith('fn '):
        print(f"{i}: {s}")
PY

Repository: Provable-Games/game-components

Length of output: 3550


🏁 Script executed:

#!/bin/bash
set -euo eou pipefail

echo "== generator/check files mentioning src5/id generation =="
rg -n "src5_rs|interface.*id|IMINIGAME_TOKEN_ID|IMINIGAME_REGISTRY_ID|src5::|supports_interface" packages/interfaces/src -g '*.cairo' -g '*.md' -g '*.toml' || true

echo
echo "== AGENTS interface-id procedure =="
sed -n '1,220p' packages/interfaces/src/AGENTS.md 2>/dev/null || true

echo
echo "== token component support registration excerpt =="
sed -n '900,930p' packages/embeddable_game_standard/src/token/token_component.cairo 2>/dev/null || true

Repository: Provable-Games/game-components

Length of output: 212


🌐 Web query:

src5_rs parse Starknet SRC5 interface ID generator documentation

💡 Result:

src5-rs is a utility tool designed to automatically compute Starknet SRC-5 interface IDs directly from Cairo source code, helping developers avoid the manual effort and potential errors associated with calculating interface selectors [1][2][3]. The SRC-5 standard defines a mechanism for Starknet contracts to introspect and query whether a contract supports specific interfaces [1][4]. The interface ID is defined as the XOR of all the extended function selectors of that interface [4][5]. Key points regarding SRC-5 and interface ID generation: - Standard Definition: Interface ID computation is specified in the SNIP-5 (Starknet Improvement Proposal 5) documentation [1][4]. - Utility: Developers are strongly advised to use automated tools like src5-rs rather than manual computation [4][3]. - Integration: OpenZeppelin's Cairo contracts library provides a standard SRC5Component that can be used to implement interface support and register these IDs in a contract [4][5][6]. - Finding the Tool: You can find the src5-rs project on GitHub (typically at github.com/ericnordelo/src5-rs), which is referenced by the official Starknet community and OpenZeppelin documentation as a primary tool for this purpose [1][2][5]. To compute an ID, the tool processes Cairo traits and translates them into the required selectors compliant with the SNIP-5 specification [1][2]. For those manually verifying, the SNIP-5 document provides specific examples, such as calculating the ISRC5 interface ID (0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055) by running a starknet_keccak hash on its function signature [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== generator/check files mentioning src5/id generation =="
rg -n "src5_rs|interface.*id|IMINIGAME_TOKEN_ID|IMINIGAME_REGISTRY_ID|src5::|supports_interface" packages/interfaces/src -g '*.cairo' -g '*.md' -g '*.toml' || true

echo
echo "== AGENTS interface-id procedure =="
if [ -f packages/interfaces/src/AGENTS.md ]; then
  sed -n '1,220p' packages/interfaces/src/AGENTS.md
else
  echo "missing packages/interfaces/src/AGENTS.md"
fi

echo
echo "== token component support registration excerpt =="
sed -n '900,930p' packages/embeddable_game_standard/src/token/token_component.cairo 2>/dev/null || true

echo
echo "== all IMINIGAME_TOKEN_ID declaration usages =="
rg -n "const IMINIGAME_TOKEN_ID|pub const IMINIGAME_TOKEN_ID|IMINIGAME_TOKEN_ID" packages/interfaces packages/embeddable_game_standard packages -g '*.cairo' | sed -n '1,40p'

Repository: Provable-Games/game-components

Length of output: 17666


Regenerate IMINIGAME_TOKEN_ID for the expanded IMinigameToken trait.

IMinigameToken now exposes additional selectors, but the constant at packages/interfaces/src/token/core.cairo:13 was not updated. That value is exported as IMINIGAME_TOKEN_ID and registered in CoreTokenComponent, so SRC5 support will advertise an ABI surface that no longer matches the trait. Generate it with src5_rs parse per the interfaces README/AGENTS procedure and update the constant and matching docs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interfaces/src/token/core.cairo` around lines 99 - 104, Regenerate
IMINIGAME_TOKEN_ID for the expanded IMinigameToken trait using the documented
src5_rs parse procedure, then update the exported constant and its matching
documentation. Keep CoreTokenComponent registration aligned with the regenerated
selector value so SRC5 advertises the current trait ABI.

Source: Coding guidelines

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 28.57143% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...able_game_standard/src/token/token_component.cairo 28.57% 5 Missing ⚠️

📢 Thoughts on this report? Let us know!

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

Copy link
Copy Markdown

Codex Review - General Engineering Review

Review process failed to complete.

@github-actions

Copy link
Copy Markdown

Codex Review - Cairo/Starknet Contract Review

Review process failed to complete.

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/embeddable_game_standard/src/token/token_component.cairo (2)

860-863: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Move the batch panic message into a descriptive constant.

refresh_metadata_batch adds another inline copy of the empty-token-IDs error. Define a module-level error constant and reuse it here and in the adjacent batch entrypoints.

As per coding guidelines, all error messages must be implemented as descriptive constants.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/embeddable_game_standard/src/token/token_component.cairo` around
lines 860 - 863, Define a descriptive module-level constant for the empty token
IDs error, then update refresh_metadata_batch and the adjacent batch entrypoints
to reuse it in their assertions instead of inline message strings. Preserve the
existing validation behavior and message content.

Source: Coding guidelines


810-826: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Complete the API documentation for both refresh entrypoints.

refresh_metadata lacks explicit parameter/return documentation, and refresh_metadata_batch has no doc comment. Document the felt252 inputs, empty-span constraint, emitted-event behavior, and () return contract.

As per coding guidelines, every function must include a clear explanation, parameter descriptions with types and constraints, return-value documentation, and examples when appropriate.

Also applies to: 860-873

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/embeddable_game_standard/src/token/token_component.cairo` around
lines 810 - 826, Complete the API documentation for refresh_metadata and
refresh_metadata_batch. Add clear descriptions of each felt252 token_id input,
including the batch function’s requirement that the span is non-empty, document
that each call emits MetadataUpdate without changing state, and specify the ()
return value; include usage examples where appropriate while preserving the
existing permissionless and advisory behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/embeddable_game_standard/src/token/token_component.cairo`:
- Around line 860-863: Define a descriptive module-level constant for the empty
token IDs error, then update refresh_metadata_batch and the adjacent batch
entrypoints to reuse it in their assertions instead of inline message strings.
Preserve the existing validation behavior and message content.
- Around line 810-826: Complete the API documentation for refresh_metadata and
refresh_metadata_batch. Add clear descriptions of each felt252 token_id input,
including the batch function’s requirement that the span is non-empty, document
that each call emits MetadataUpdate without changing state, and specify the ()
return value; include usage examples where appropriate while preserving the
existing permissionless and advisory behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ba6a1dc9-94b1-46f7-9275-33355e8e82c8

📥 Commits

Reviewing files that changed from the base of the PR and between bb9f2ab and b09637e.

📒 Files selected for processing (2)
  • packages/embeddable_game_standard/src/token/tests/test_events.cairo
  • packages/embeddable_game_standard/src/token/token_component.cairo

starknetdev and others added 2 commits July 29, 2026 10:08
update_game re-reads game_over and score from the game contract and
notifies the minter, which costs several cross-contract calls. Indexers
only need the MetadataUpdate event to learn that a token's rendered
metadata is stale — token_uri reads score live from the game — so games
can now call refresh_metadata after ordinary mid-game actions and
reserve update_game for transitions that must be persisted (game over,
objective completion).

refresh_metadata asserts the token exists and emits MetadataUpdate. It
writes no state, so it can never substitute for the game-over sync; a
test pins that invariant.

Permissionless, matching update_game. The worst case is a caller paying
to trigger a re-render.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The check cost ~52k l2 gas on what is meant to be the cheap path and
bought nothing defensively: a caller who wants to spam MetadataUpdate
can do it with any real token id, so the check only blocked the
harmless variant. The event is advisory — consumers must resolve the
token id against their own record of minted tokens before acting on
it, and token_uri already reverts for a token that does not exist.

Replaces the should_panic test with one asserting the event is emitted
for an unminted id, so the contract is pinned rather than incidental.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@starknetdev
starknetdev force-pushed the feat/refresh-metadata branch from b09637e to 6e7833a Compare July 29, 2026 17:12
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown

Claude Code Review

The interface ID is a hardcoded constant, not auto-derived, so adding trait methods won't change it at compile time. The AGENTS.md guidance to leave it untouched is intentional and documented. Whether CI's supports_interface tests still pass is confirmed by the PR's green test runs.

The diff is internally consistent. All findings I could raise are already deliberately addressed and pinned by tests (existence check omission, no-state-persistence, interface ID exclusion). The batch loop uses the same loop/break idiom as the existing update_game_batch, so no new idiom deviation is introduced.

lgtm

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown

GPT Code Review

[MEDIUM] packages/interfaces/src/token/core.cairo:99 - refresh_metadata / refresh_metadata_batch are added to IMinigameToken while IMINIGAME_TOKEN_ID remains the legacy selector set.
Impact: Callers that gate on supports_interface(IMINIGAME_TOKEN_ID) cannot distinguish new tokens from already-deployed tokens that return true for the same ID but do not have these selectors, so refresh calls can revert at runtime.
Fix: Keep the legacy IMinigameToken surface unchanged and add a separate refresh-specific interface plus ID, then register that new ID from CoreTokenComponent for contracts that implement these entrypoints.

…KEN_ID

Review flagged the constant as stale after the trait gained
refresh_metadata / refresh_metadata_batch. Keeping the ID: it is
registered on-chain by every deployed token contract, so rederiving it
for two additive optional methods would make supports_interface return
false on all of them and break interface discovery ecosystem-wide.

Recorded in the AGENTS.md that already owns the derivation procedure —
the constant's doc comment points there — so anyone rebuilding the
stripped input knows to omit both methods, and future additive methods
get the same treatment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/embeddable_game_standard/src/token/tests/test_events.cairo`:
- Around line 369-381: Update the test around token_dispatcher.refresh_metadata
to assert the token-side score remains unchanged after refresh_metadata, in
addition to the existing flag assertions. Then extend the update_game
verification to assert that the token score synchronizes to the mock game’s
score of 100, using the state access pattern already present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 568cea6c-2d76-4ba5-9d87-19dc039306f4

📥 Commits

Reviewing files that changed from the base of the PR and between b09637e and df95fd5.

📒 Files selected for processing (10)
  • packages/embeddable_game_standard/src/metagame/tests/test_fuzz_mint_parameters.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_libs.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_metagame_component.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_tournament_flow.cairo
  • packages/embeddable_game_standard/src/token/interface.cairo
  • packages/embeddable_game_standard/src/token/tests/test_events.cairo
  • packages/embeddable_game_standard/src/token/token_component.cairo
  • packages/interfaces/src/AGENTS.md
  • packages/interfaces/src/token/core.cairo
  • packages/metagame/src/ticket_booth/tests/test_ticket_booth.cairo
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/embeddable_game_standard/src/metagame/tests/test_fuzz_mint_parameters.cairo
  • packages/metagame/src/ticket_booth/tests/test_ticket_booth.cairo
  • packages/embeddable_game_standard/src/token/interface.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_libs.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_metagame_component.cairo
  • packages/embeddable_game_standard/src/metagame/tests/test_tournament_flow.cairo
  • packages/embeddable_game_standard/src/token/token_component.cairo
  • packages/interfaces/src/token/core.cairo

Comment on lines +369 to +381
mock_game.set_score(token_id, 100);
mock_game.set_game_over(token_id, true);

token_dispatcher.refresh_metadata(token_id);

let state = token_dispatcher.token_mutable_state(token_id);
assert!(!state.game_over, "refresh_metadata must not persist game_over");
assert!(!state.completed_objective, "refresh_metadata must not persist completed_objective");
assert!(token_dispatcher.is_playable(token_id), "token should still be playable");

// update_game is still the thing that syncs it.
token_dispatcher.update_game(token_id);
assert!(token_dispatcher.token_mutable_state(token_id).game_over, "update_game should sync");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert that refresh leaves the token-side score unchanged.

The test sets the game score to 100, but only checks flags. A regression that persists score during refresh_metadata would still pass; assert the pre-refresh token score remains intact, then verify update_game synchronizes it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/embeddable_game_standard/src/token/tests/test_events.cairo` around
lines 369 - 381, Update the test around token_dispatcher.refresh_metadata to
assert the token-side score remains unchanged after refresh_metadata, in
addition to the existing flag assertions. Then extend the update_game
verification to assert that the token score synchronizes to the mock game’s
score of 100, using the state access pattern already present.

@starknetdev
starknetdev merged commit 19bbf45 into main Jul 29, 2026
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant