Skip to content

fix: correctly identify truly cold mint accounts#2275

Open
sergeytimoshin wants to merge 5 commits intomainfrom
sergey/fix-cold-mint
Open

fix: correctly identify truly cold mint accounts#2275
sergeytimoshin wants to merge 5 commits intomainfrom
sergey/fix-cold-mint

Conversation

@sergeytimoshin
Copy link
Contributor

@sergeytimoshin sergeytimoshin commented Feb 11, 2026

Summary by CodeRabbit

  • Tests

    • Added extensive unit tests for account interface handling, covering hot/cold states and delegation behavior.
  • Documentation

    • Minor documentation formatting updates.
  • Refactor

    • Internal code reorganization for improved maintainability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change reorganizes the hot/cold account conversion logic in the RPC client by deferring hot-path account construction to the None branch, and adds comprehensive unit tests for AccountInterface and TokenAccountInterface covering various state transitions and edge cases.

Changes

Cohort / File(s) Summary
Test Coverage & Documentation
sdk-libs/client/src/indexer/types/interface.rs
Added extensive unit tests for AccountInterface and TokenAccountInterface validating hot/cold state behavior, zero discriminator handling, and token account delegation. Minor documentation punctuation fixes.
Hot/Cold Branching Refactoring
sdk-libs/client/src/rpc/client.rs
Reorganized convert_account_interface and convert_token_account_interface to defer hot-account construction from pre-match setup into the None branch, reducing upfront boilerplate while preserving cold-path compressed account handling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

ai-review

Suggested reviewers

  • ananas-block
  • SwenSchaeferjohann

Poem

🔥❄️ Hot and cold paths now dance with grace,
Deferred construction finds its place,
Tests verify each state with care,
Branching logic, clean and fair! 🧊

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (193 files):

⚔️ Cargo.lock (content)
⚔️ external/photon (content)
⚔️ forester/tests/e2e_test.rs (content)
⚔️ forester/tests/test_compressible_ctoken.rs (content)
⚔️ js/compressed-token/src/v3/actions/index.ts (content)
⚔️ js/compressed-token/src/v3/actions/mint-to-interface.ts (content)
⚔️ js/compressed-token/src/v3/actions/mint-to.ts (content)
⚔️ js/compressed-token/src/v3/actions/update-metadata.ts (content)
⚔️ js/compressed-token/src/v3/actions/update-mint.ts (content)
⚔️ js/compressed-token/src/v3/get-mint-interface.ts (content)
⚔️ js/compressed-token/src/v3/instructions/create-associated-ctoken.ts (content)
⚔️ js/compressed-token/src/v3/instructions/index.ts (content)
⚔️ js/compressed-token/src/v3/instructions/mint-to-interface.ts (content)
⚔️ js/compressed-token/src/v3/instructions/mint-to.ts (content)
⚔️ js/compressed-token/src/v3/instructions/update-metadata.ts (content)
⚔️ js/compressed-token/src/v3/instructions/update-mint.ts (content)
⚔️ js/compressed-token/tests/e2e/create-associated-ctoken.test.ts (content)
⚔️ js/compressed-token/tests/e2e/create-ata-interface.test.ts (content)
⚔️ js/compressed-token/tests/e2e/get-or-create-ata-interface.test.ts (content)
⚔️ js/compressed-token/tests/e2e/mint-to-ctoken.test.ts (content)
⚔️ js/compressed-token/tests/e2e/mint-to-interface.test.ts (content)
⚔️ js/compressed-token/tests/e2e/mint-workflow.test.ts (content)
⚔️ program-libs/batched-merkle-tree/src/rollover_address_tree.rs (content)
⚔️ program-libs/batched-merkle-tree/src/rollover_state_tree.rs (content)
⚔️ program-libs/compressed-account/src/instruction_data/zero_copy.rs (content)
⚔️ program-libs/token-interface/src/instructions/create_associated_token_account.rs (content)
⚔️ program-libs/token-interface/src/instructions/mint_action/builder.rs (content)
⚔️ program-libs/token-interface/src/instructions/mint_action/instruction_data.rs (content)
⚔️ program-libs/token-interface/src/instructions/transfer2/instruction_data.rs (content)
⚔️ program-tests/compressed-token-test/tests/compress_only/ata_decompress.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/approve_revoke.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/burn.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/compress_and_close.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/create_ata.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/create_ata2.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/extensions_failing.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/functional_ata.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/shared.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/transfer.rs (content)
⚔️ program-tests/compressed-token-test/tests/light_token/transfer_checked.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/burn.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/cmint_resize.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/edge_cases.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/failing.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/functional.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/mint_to.rs (content)
⚔️ program-tests/compressed-token-test/tests/mint/random.rs (content)
⚔️ program-tests/compressed-token-test/tests/token_pool.rs (content)
⚔️ program-tests/compressed-token-test/tests/transfer2/compress_failing.rs (content)
⚔️ program-tests/compressed-token-test/tests/transfer2/compress_spl_failing.rs (content)
⚔️ program-tests/compressed-token-test/tests/transfer2/decompress_failing.rs (content)
⚔️ program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs (content)
⚔️ program-tests/compressed-token-test/tests/transfer2/shared.rs (content)
⚔️ program-tests/compressed-token-test/tests/transfer2/spl_ctoken.rs (content)
⚔️ program-tests/justfile (content)
⚔️ program-tests/registry-test/tests/compressible.rs (content)
⚔️ program-tests/system-test/Cargo.toml (content)
⚔️ program-tests/utils/src/actions/legacy/mint_action.rs (content)
⚔️ program-tests/utils/src/assert_create_token_account.rs (content)
⚔️ programs/compressed-token/program/docs/compressed_token/MINT_ACTION.md (content)
⚔️ programs/compressed-token/program/docs/compressed_token/TRANSFER2.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/APPROVE.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/BURN.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/BURN_CHECKED.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/MINT_TO.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/MINT_TO_CHECKED.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/REVOKE.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/TRANSFER.md (content)
⚔️ programs/compressed-token/program/docs/ctoken/TRANSFER_CHECKED.md (content)
⚔️ programs/compressed-token/program/src/compressed_token/mint_action/actions/decompress_mint.rs (content)
⚔️ programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs (content)
⚔️ programs/compressed-token/program/src/compressed_token/transfer2/compression/ctoken/compress_and_close.rs (content)
⚔️ programs/compressed-token/program/src/compressed_token/transfer2/compression/mod.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/approve_revoke.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/burn.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/create_ata.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/mint_to.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/transfer/checked.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/transfer/default.rs (content)
⚔️ programs/compressed-token/program/src/ctoken/transfer/shared.rs (content)
⚔️ programs/compressed-token/program/src/shared/compressible_top_up.rs (content)
⚔️ programs/compressed-token/program/src/shared/create_pda_account.rs (content)
⚔️ programs/compressed-token/program/src/shared/initialize_ctoken_account.rs (content)
⚔️ programs/compressed-token/program/src/shared/validate_ata_derivation.rs (content)
⚔️ programs/compressed-token/program/tests/check_extensions.rs (content)
⚔️ programs/compressed-token/program/tests/extensions_metadata.rs (content)
⚔️ programs/compressed-token/program/tests/mint.rs (content)
⚔️ programs/registry/src/compressible/compressed_token/compress_and_close.rs (content)
⚔️ programs/system/src/cpi_context/process_cpi_context.rs (content)
⚔️ programs/system/src/cpi_context/state.rs (content)
⚔️ programs/system/src/invoke_cpi/processor.rs (content)
⚔️ programs/system/tests/cpi_context.rs (content)
⚔️ sdk-libs/account-pinocchio/src/lib.rs (content)
⚔️ sdk-libs/account/README.md (content)
⚔️ sdk-libs/account/src/lib.rs (content)
⚔️ sdk-libs/client/src/indexer/types/interface.rs (content)
⚔️ sdk-libs/client/src/interface/account_interface.rs (content)
⚔️ sdk-libs/client/src/interface/light_program_interface.rs (content)
⚔️ sdk-libs/client/src/interface/load_accounts.rs (content)
⚔️ sdk-libs/client/src/rpc/client.rs (content)
⚔️ sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs (content)
⚔️ sdk-libs/event/tests/parse_test.rs (content)
⚔️ sdk-libs/instruction-decoder/src/programs/ctoken.rs (content)
⚔️ sdk-libs/macros/docs/accounts/architecture.md (content)
⚔️ sdk-libs/macros/docs/accounts/associated_token.md (content)
⚔️ sdk-libs/macros/src/light_pdas/accounts/light_account.rs (content)
⚔️ sdk-libs/macros/src/light_pdas/accounts/token.rs (content)
⚔️ sdk-libs/macros/src/light_pdas/light_account_keywords.rs (content)
⚔️ sdk-libs/program-test/src/program_test/rpc.rs (content)
⚔️ sdk-libs/sdk-types/src/interface/cpi/create_mints.rs (content)
⚔️ sdk-libs/sdk-types/src/interface/cpi/create_token_accounts.rs (content)
⚔️ sdk-libs/sdk-types/src/interface/program/decompression/create_token_account.rs (content)
⚔️ sdk-libs/sdk-types/src/interface/program/decompression/processor.rs (content)
⚔️ sdk-libs/sdk-types/src/interface/program/decompression/token.rs (content)
⚔️ sdk-libs/token-pinocchio/src/instruction/create_ata.rs (content)
⚔️ sdk-libs/token-pinocchio/src/instruction/transfer_from_spl.rs (content)
⚔️ sdk-libs/token-pinocchio/src/instruction/transfer_to_spl.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/burn.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/burn_checked.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/create_associated_token_account.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/create_ata.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/create_mints.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/decompress.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/mint_to.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/mint_to_checked.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/mod.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/transfer.rs (content)
⚔️ sdk-libs/token-sdk/src/instruction/transfer_checked.rs (content)
⚔️ sdk-libs/token-sdk/tests/address_derivation.rs (content)
⚔️ sdk-libs/token-sdk/tests/create_associated_token_account.rs (content)
⚔️ sdk-tests/anchor-manual-test/src/all/derived.rs (content)
⚔️ sdk-tests/anchor-manual-test/src/ata/derived.rs (content)
⚔️ sdk-tests/anchor-manual-test/tests/all.rs (content)
⚔️ sdk-tests/anchor-manual-test/tests/ata.rs (content)
⚔️ sdk-tests/anchor-semi-manual-test/src/instruction_accounts.rs (content)
⚔️ sdk-tests/anchor-semi-manual-test/tests/stress_test.rs (content)
⚔️ sdk-tests/anchor-semi-manual-test/tests/test_create_all.rs (content)
⚔️ sdk-tests/anchor-semi-manual-test/tests/test_create_ata.rs (content)
⚔️ sdk-tests/anchor-semi-manual-test/tests/test_create_token_vault.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/src/amm_test/initialize.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/src/instruction_accounts.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/src/instructions/d10_token_accounts/single_ata.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/src/instructions/d10_token_accounts/single_ata_markonly.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/src/instructions/d11_zero_copy/with_ata.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/src/lib.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/amm_stress_test.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/amm_test.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/basic_test.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/d10_token_accounts_test.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/d11_zero_copy_test.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs (content)
⚔️ sdk-tests/csdk-anchor-full-derived-test/tests/shared.rs (content)
⚔️ sdk-tests/pinocchio-light-program-test/src/all/processor.rs (content)
⚔️ sdk-tests/pinocchio-light-program-test/src/ata/processor.rs (content)
⚔️ sdk-tests/pinocchio-light-program-test/tests/stress_test.rs (content)
⚔️ sdk-tests/pinocchio-light-program-test/tests/test_create_all.rs (content)
⚔️ sdk-tests/pinocchio-light-program-test/tests/test_create_ata.rs (content)
⚔️ sdk-tests/pinocchio-light-program-test/tests/test_create_token_vault.rs (content)
⚔️ sdk-tests/pinocchio-manual-test/src/all/derived.rs (content)
⚔️ sdk-tests/pinocchio-manual-test/src/ata/derived.rs (content)
⚔️ sdk-tests/pinocchio-manual-test/tests/all.rs (content)
⚔️ sdk-tests/pinocchio-manual-test/tests/ata.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/src/create_ata.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/tests/shared/mod.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/tests/test_create_ata.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/tests/test_ctoken_mint_to.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/tests/test_transfer_checked.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/tests/test_transfer_interface.rs (content)
⚔️ sdk-tests/sdk-light-token-pinocchio/tests/test_transfer_spl_ctoken.rs (content)
⚔️ sdk-tests/sdk-light-token-test/src/create_ata.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/scenario_light_mint.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/scenario_light_mint_compression_only.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/scenario_spl.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/scenario_spl_restricted_ext.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/shared.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/test_create_ata.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/test_ctoken_mint_to.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/test_transfer_checked.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/test_transfer_interface.rs (content)
⚔️ sdk-tests/sdk-light-token-test/tests/test_transfer_spl_ctoken.rs (content)
⚔️ sdk-tests/sdk-token-test/src/pda_ctoken/mint.rs (content)
⚔️ sdk-tests/sdk-token-test/src/pda_ctoken/mod.rs (content)
⚔️ sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs (content)
⚔️ sdk-tests/sdk-token-test/tests/pda_ctoken.rs (content)
⚔️ sdk-tests/sdk-token-test/tests/test_4_transfer2.rs (content)
⚔️ sdk-tests/sdk-token-test/tests/test_compress_full_and_close.rs (content)
⚔️ sdk-tests/single-ata-test/src/lib.rs (content)
⚔️ sdk-tests/single-ata-test/tests/test.rs (content)
⚔️ sdk-tests/token-client-test/tests/test_approve_revoke.rs (content)
⚔️ sdk-tests/token-client-test/tests/test_transfer.rs (content)
⚔️ sdk-tests/token-client-test/tests/test_transfer_checked.rs (content)
⚔️ sdk-tests/token-client-test/tests/test_transfer_interface.rs (content)
⚔️ sdk-tests/token-client-test/tests/test_wrap_unwrap.rs (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the core fix: reorganizing hot/cold account handling logic to correctly identify cold mint accounts by deferring hot-path construction.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 70.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sergey/fix-cold-mint
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch sergey/fix-cold-mint
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉


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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
sdk-libs/client/src/rpc/client.rs (1)

1173-1235: 🧹 Nitpick | 🔵 Trivial

Edge case to consider: is_cold() && lamports > 0 now hits the Hot deserialization path.

When the indexer says cold but lamports are non-zero, we fall into the else branch and attempt Mint::try_from_slice(&ai.account.data). If the on-chain account at that address isn't actually a valid Mint (e.g., someone arbitrarily sent SOL to the address, creating a zero-data system-owned account), this will produce a somewhat opaque deserialization error.

This isn't a blocker — the error will surface — but you might want to tighten the error message for this transitional state so operators can distinguish "stale cold flag with live account" from "genuinely corrupt hot mint data":

                    Mint::try_from_slice(&ai.account.data).map_err(|e| {
                        RpcError::CustomError(format!(
-                            "Failed to deserialize hot mint account: {e}"
+                            "Failed to deserialize mint account as hot (is_cold={}, lamports={}): {e}",
+                            ai.is_cold(), ai.account.lamports
                        ))
                    })?;

This gives much better diagnostics when debugging the cold→hot transition edge cases.

🤖 Fix all issues with AI agents
In `@sdk-libs/client/src/rpc/client.rs`:
- Around line 1175-1176: Add a brief inline comment above the is_truly_cold
assignment explaining why we also check ai.account.lamports == 0 (e.g., the
indexer can report ai.is_cold() after decompression, so lamports == 0 confirms
on-chain compression), and keep the existing logic using ai.is_cold(),
ai.account.lamports, and the is_truly_cold variable intact.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@sdk-libs/client/src/indexer/types/interface.rs`:
- Around line 117-132: Add a doc comment to AccountInterface::is_cold()
explaining that its simpler cold.is_some() check intentionally differs from
IndexerAccountInterface::is_cold() (which inspects
DECOMPRESSED_PDA_DISCRIMINATOR) because AccountInterface is produced from
already-filtered client-side data where decompressed placeholders have been
removed; mention that decompressed accounts will have cold: None in the
AccountInterface representation so the simple presence check is correct and
expected.

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.

2 participants