Skip to content

Fix token claim/cancel fallback property-version collision - #67

Open
sausagee wants to merge 2 commits into
mainfrom
cursor/claim-property-version-collision-5cdf
Open

Fix token claim/cancel fallback property-version collision#67
sausagee wants to merge 2 commits into
mainfrom
cursor/claim-property-version-collision-5cdf

Conversation

@sausagee

@sausagee sausagee commented Sep 6, 2026

Copy link
Copy Markdown

Bug

On the PendingClaims-not-rewritten path, from_delete_table_item recovers from_address from in-transaction claim/cancel events. Those maps were keyed only by token_data_id.

Token V1 treats (token_data_id, property_version, from_address, to_address) as the pending-claim PK. Two offers of the same named token with different property versions (e.g. original vs mutated copy, different offerers, claimed in one txn) therefore collide in the event map. The last event wins, so the other delete writes the wrong offerer into the upsert key: the real row is never zeroed (silent skip) and a different PK is written (wrong-row update). Checkpoints still advance.

Same-offerer two-PV cancel/claim is harmless (same from_address). The failing case is different offerers + different property versions in one user transaction — a realistic Token V1 batch-claim script.

This is the existing delete-path fallback, not #42 (write-path offer fallback) and not #16#66.

Root cause

tokens_claimed.insert(token_data_id_struct.to_id(), helper);
tokens_claimed.get(&token_data_id) // ignores property_version

property_version and to_address already come from the TokenOfferId table key. Only from_address is recovered from the map, so a collision changes the PK.

Fix

Key TokenV1Claimed / TokenV1Canceled by (token_data_id, property_version) and look up with the delete item's property version.

Test plan

  • cargo test -p processor --lib token_claims — 2 passed:
    • claim_fallback_does_not_reuse_offerer_across_property_versions
    • cancel_fallback_does_not_overwrite_other_property_version_claim
  • cargo clippy -p processor --all-targets -- -D warnings (rust-toolchain 1.85)

No workspace-level diesel/postgres or SDK postgres_full / testing_framework features were added.

Out of scope

Open in Web Open in Cursor 

Key TokenV1Claimed/Canceled by (token_data_id, property_version) so two
PendingClaims deletes for the same named token resolve the correct offerer
when the parent resource is not rewritten.

Co-authored-by: Young Yang Liauw <sausagee@users.noreply.github.com>
@sausagee
sausagee marked this pull request as ready for review September 6, 2026 17:43
@sausagee
sausagee changed the base branch from main to fix/lint-stable-xclippy September 7, 2026 22:20
@sausagee
sausagee changed the base branch from fix/lint-stable-xclippy to main September 7, 2026 22:31
Stack the CI unblocker files from PR #70 (stable cargo xclippy, bookworm Dockerfiles with make) onto this bugfix branch so CI can go green while #70 awaits review. Merge target remains main; this does not merge #70.
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