Pre-auditThree days of senior audit time for $1,500, credited in full toward your Zealynx audit.3 audit days, credited toward your auditSee how →
When Transferable Claims Become Unredeemable

When Transferable Claims Become Unredeemable

16 min
On this page▾
A token can transfer normally while its underlying claim is already dead.
That failure is easy to miss because transferability and redeemability are usually tested as separate features. The token contract says the holder owns a balance. A market or integration sees an asset it can receive. The issuer's redemption path, however, may consult different state. If that state records history instead of current economic reality, a legitimate claim can become impossible to exercise.
The Mira LP-token case study provides the anchor. This article removes the protocol name from the mechanism and compares it with public tokenized-vault specifications, Fuel storage behavior, and an OpenZeppelin finding where an unsafe default could make withdrawals fail.

TL;DR

  • Transferability proves that a token can move. It does not prove that its issuer will accept the token for redemption.
  • A storage key can remain present after its economic balance reaches zero. Guards that treat presence as ownership can preserve a restriction after its reason has disappeared.
  • An unset configuration value can create the same liveness failure when a strict guard interprets the default as an intentional policy.
  • Claim-token systems need a round-trip invariant: a valid claim that survives a supported lifecycle must retain a reachable exit unless an explicit current-state restriction applies.
  • Tests should move claims through nesting, complete withdrawal, transfer, configuration defaults, and final redemption. Happy-path mint and burn tests are not enough.

Methodology and evidence boundaries

This is a mechanism-led, purposive comparison. A source enters the core set if it describes one of these relationships:
  1. a transferable claim whose exit depends on separate issuer state;
  2. a historical or default state value that can block an otherwise valid exit; or
  3. a public interface contract that defines how claim availability should be exposed to integrators.
The core evidence consists of:
  • Mira finding F-2025-0001 and its public case study;[1][2]
  • Fuel's documentation for persistent storage and StorageMap reads;[3]
  • ERC-4626, which defines vault shares as claims and separates conversion, preview, maximum, and execution methods;[4]
  • OpenZeppelin's Origin Dollar assessment, which records an uninitialized proxy setting that defaulted to an excessively strict redemption threshold;[5]
  • OpenZeppelin's ERC-4626 implementation guidance for shares and redemption.[6]
Four statement types remain separate:
  • Source fact reports behavior, status, or requirements stated by a cited source.
  • Zealynx classification groups mechanisms for review. It is not a new severity rating.
  • Inference is a design conclusion drawn across sources.
  • Limitation identifies what the public evidence does not establish.
This corpus is not a prevalence sample. It does not establish how often claim-liveness failures occur. It also does not imply that the compared systems share code, impact, deployment status, or remediation history.

The invariant: a live claim needs a live exit

A claim token is useful because it connects two state machines:
1token state
2 holder owns a transferable balance
3
4issuer state
5 issuer recognizes that balance as a claim on assets or liquidity
The token state can remain valid while the issuer state rejects redemption. The important property is therefore not simply:
1balanceOf(holder) > 0
It is:
1if a claim is authentic
2and its underlying entitlement has not been consumed
3and no current protocol rule legitimately blocks exit,
4then at least one supported redemption path remains reachable
Zealynx classifies this as a claim-liveness invariant. It is related to protocol solvency, but it asks a different question. Solvency asks whether assets cover obligations. Claim liveness asks whether a holder can exercise an obligation the protocol still recognizes.
A solvent pool can fail claim liveness if its burn path rejects a valid token. A callable burn function can also fail solvency if the assets are not there. Both properties matter, and neither proves the other.

Anchor: storage presence outlived reserve ownership

Mira finding F-2025-0001 describes an LP-token burn guard that queried contract_reserves and required the result to be absent. The guard had a real purpose: under the reviewed Fuel design, the contract needed to distinguish an LP token supplied for burning from one held as a pool reserve.[1]
The failure appeared after a complete lifecycle:
1legitimate LP token exists
2 -> token is used as an asset in another pool
3 -> reserve storage entry is created
4 -> token is fully withdrawn from that pool
5 -> reserve value becomes zero
6 -> storage entry remains present
7 -> burn guard rejects the LP token
The guard answered a storage question:
1Has this key ever acquired a stored value?
The economic rule needed a current-state question:
1Does the contract currently hold a non-zero reserve that must not be burned?
The report states that the token could remain transferable while becoming unredeemable. It recommends allowing the burn when the reserve entry is absent or its value is zero, and records the finding as fixed in commit 65509ec685e322498357504cf75967b06f69314d.[1]
That is a source-reported fix in the reviewed scope. It is not independent proof of deployment, exploitation, later-version security, or monetary impact.

Why zero and missing are different technical states

Fuel's current Sway documentation describes contract storage as persistent. It also explains that StorageMap values are accessed through a key and that try_read() can distinguish a readable stored value from an uninitialized key.[3]
This gives developers at least three conceptual states to model:
1Missing: no value has been stored for the key
2Zero: a value exists and the current amount is zero
3Positive: a value exists and the current amount is greater than zero
Those states may be operationally equivalent for one decision and materially different for another.
For example:
  • A migration may need to know whether a key was ever initialized.
  • An accounting path may need the current numeric balance.
  • A burn guard may care only whether a live reserve is positive.
  • An index may keep zero entries deliberately to preserve enumeration or history.
The mistake is not retaining a zero entry. The mistake is using storage shape as a substitute for economic state.
A safer predicate makes the intended domain explicit:
1burn_allowed(asset) =
2 reserve_entry_is_missing(asset)
3 OR current_reserve_value(asset) == 0
Even that predicate is only locally sufficient. The system must still verify that the token is authentic, that the holder controls it, and that burning it cannot consume reserves assigned to another claim.

Comparison: an unsafe default can also freeze an exit

The OpenZeppelin Origin Dollar assessment records a different route to the same broad outcome. A maximum-slippage variable was initialized in the implementation contract but not in the proxy storage where it was needed. The proxy therefore saw the default value of zero.[5]
OpenZeppelin reports that zero was excessively strict when redeeming metapool tokens and could cause withdrawal to fail until the value was updated. The assessment records a fix in commit 1c524c97ac4e70dbf09447313643a2a53e2da35d.[5]
This is not a stale-key case and should not be described as one. Zealynx classifies it as an unsafe-default exit guard:
1unset configuration
2 -> language or proxy default is zero
3 -> zero is interpreted as an intentional strict threshold
4 -> ordinary redemption can fail
The Mira and Origin records differ in chain, architecture, token model, and reported severity context. Their common lesson is narrower:
A redemption guard must derive its decision from initialized, current, semantically relevant state.
In Mira, history survived as a present key. In Origin, missing initialization appeared as a present numeric zero. In both cases, a technically valid value was given the wrong policy meaning.

ERC-4626 makes exit availability observable

ERC-4626 defines vault shares as tokens representing claims on a fraction of a vault's underlying holdings.[4] It then separates several questions that custom claim systems often collapse:
  • convertToAssets estimates the ideal asset value of shares.
  • previewRedeem estimates the result under current on-chain conditions.
  • maxRedeem reports how many shares the owner can redeem without causing a revert.
  • redeem performs the state change.
The standard requires maxRedeem to account for global and user-specific limits, return zero when redemption is disabled, and not revert.[4] OpenZeppelin's guidance similarly describes shares as claims that can later be burned to redeem underlying assets.[6]
Mira's LP token was not an ERC-4626 vault share. ERC-4626 does not diagnose or repair the Sway finding. It provides a useful interface comparison: exit availability is important enough to expose separately from token balance and ideal conversion.
For custom LP tokens, receipts, staking derivatives, and bridge representations, an equivalent observable model can help integrators distinguish:
1claim exists
2claim has an estimated value
3claim is currently redeemable
4claim is redeemable only up to a bounded amount
Without that distinction, downstream systems may treat transfer success as evidence of exit availability.

A taxonomy of claim-liveness failures

The evidence supports four practical review categories. Only the first two are directly represented by the anchor and comparison records. The final two are derived testing classes, not claims about additional incidents.

1. Historical-state guard

A prior state transition leaves metadata that continues to trigger a restriction after the underlying condition ends.
Mira is the anchor. The reserve key remained readable after the reserve amount reached zero.[1]
Review question:
1Can a supported round trip leave a key, flag, index, or checkpoint
2that changes the rights of the returned claim?

2. Unsafe-default guard

An unset value takes a language, storage, or proxy default that is valid at the type level but invalid as a policy.
The Origin slippage setting is the comparison record.[5]
Review question:
1If initialization is skipped, delayed, or performed on the wrong storage,
2does the default fail closed safely, or does it lock user exits?
Failing closed is not automatically safe when users already hold claims. A pause may be intentional and recoverable. An accidental permanent freeze is not the same control.

3. Hidden dependency guard

A claim's exit depends on another protocol, oracle, strategy, queue, or callback whose availability is not represented in the claim interface.
This category is an inference from the interface comparison. It should be tested, but this article does not attach an incident count or severity claim to it.
Review question:
1Which external states can make redemption revert,
2and can holders or integrators observe those limits before execution?

4. Partial-lifecycle cleanup

The primary balance is cleared, but secondary state survives. Examples can include membership sets, reserve indexes, approvals, cooldowns, withdrawal requests, or per-asset flags.
This is also a derived test class. The risk depends on how surviving state is consumed.
Review question:
1After a complete exit, which storage values remain,
2and what decisions can still read them?

Transferability is a weak integration signal

A token transfer usually proves only that the token contract accepted a balance update. It may not consult the issuer's redemption state at all.
For an integrator, these propositions are distinct:
1A. the token address is authentic
2B. the holder owns the token
3C. the token can transfer
4D. the issuer currently accepts it for redemption
5E. sufficient assets are available for redemption
6F. the expected amount can be redeemed under current limits
A marketplace may check A through C. A lending protocol may also estimate price. A robust collateral decision must consider D through F or explicitly accept the risk that it cannot.
This is why transferable claims deserve complete lifecycle review. The transaction-level backing study examines whether claims are economically covered. The state-dependent settlement study examines whether the correct semantic view feeds an economic action. The staking solvency study separates principal claims from the reserves available to pay rewards. Claim liveness sits beside all three: even an authentic, covered claim fails its holder if protocol history makes its exit unreachable.

Design rules for claim-token systems

Name predicates by economic meaning

Avoid helpers whose names expose only storage mechanics:
1hasReserveEntry(asset)
Prefer predicates that state the policy being enforced:
1isLiveReserveAsset(asset)
2canBurnClaim(asset, holder)
3maxRedeemableClaim(asset, holder)
The implementation can still inspect storage presence. The function boundary should force reviewers to ask whether presence is actually the right evidence.

Define the zero-state policy

For every mapping or configuration used by an exit path, document the meaning of:
  • absent;
  • zero;
  • non-zero;
  • expired;
  • paused;
  • uninitialized.
Do not assume those states are interchangeable because the language can coerce or default them.

Make restrictions current and observable

If a claim cannot be redeemed because reserves are live, liquidity is unavailable, a queue is active, or the protocol is paused, expose that condition through a bounded view where practical.
ERC-4626's maxRedeem model is useful here even outside ERC-4626. It does not promise that every execution succeeds under every concurrent state change. It gives integrators a standard place to ask the current limit.[4]

Keep emergency controls recoverable

A fail-closed exit can protect reserves during an incident, but it can also strand holders. Define who can restore the path, what state proves recovery, and whether users have an alternate exit.
An accidental zero default should not silently impersonate a deliberate pause.

Treat nesting as a first-class lifecycle

When one claim token can become another pool's reserve, collateral, staking input, or bridge asset, its issuer state can be influenced by systems beyond the original holder's direct actions.
The design must answer:
1Can third-party use change the claim's later redeemability?
2Can the issuer distinguish current custody from historical custody?
3Can an integrator detect the difference before accepting the token?

Tests that expose the failure

A useful suite starts with a round-trip property:
1given an authentic claim with an unconsumed entitlement
2when it passes through any supported lifecycle
3and all temporary restrictions are removed
4then the holder can redeem the claim
Concrete tests should include:
  1. Mint, transfer, and redeem the ordinary path.
  2. Deposit the claim as another pool's asset, withdraw it completely, then redeem it.
  3. Repeat the nested lifecycle more than once.
  4. Leave a zero-valued mapping entry and verify the exit predicate reads value, not historical presence.
  5. Delete or clear the entry where supported and compare behavior with the zero-valued state.
  6. Initialize through the real proxy or deployment path, not only the implementation constructor.
  7. Exercise every exit with configuration left at its language default.
  8. Pause and unpause the system, then verify old claims recover their exit.
  9. Partially withdraw, fully withdraw, and withdraw dust amounts.
  10. Transfer the claim after each state transition and test redemption by the new holder.
  11. Query any max, preview, or status view and compare it with the next execution in the same state.
  12. Fuzz operation order across mint, nest, withdraw, transfer, pause, unpause, and redeem.
  13. Assert that a failed redemption does not consume or corrupt the claim.
  14. Assert that relaxing stale-state checks does not permit burning assets that are genuinely still held as live reserves.
The final test matters. Removing a guard is not a structural fix if the guard was protecting another holder's active reserves.

What the evidence does not establish

The Mira report and case study support a specific stale-state mechanism, a High source rating, a recommendation, and a recorded fix.[1][2] They do not establish exploitation, deployment, monetary exposure, or the security of later versions.
The Origin assessment supports a proxy-initialization error, a zero default, a possible withdrawal failure, and a recorded fix.[5] It does not establish that the issue shares Mira's storage-key mechanism or impact.
ERC-4626 is a specification and interface model, not evidence that every implementation preserves redemption liveness.[4] Its own security considerations tell integrators to review implementations for ways user deposits could be lost.
Fuel and OpenZeppelin documentation explain platform behavior and implementation patterns.[3][6] They do not provide prevalence data.
No frequency, loss, funds-protected, or incident-count claim follows from this comparison.

The durable rule: test rights after history

The dangerous state is often not the one created at mint. It is the state left after the claim has been used.
A token may have been nested, withdrawn, transferred, paused, migrated, or processed through a proxy whose configuration was never initialized where execution occurs. Each action can leave technically valid state behind. The redemption path must ask whether that state describes the claim now.
The durable rule is:
A claim's current rights must follow current economic state, not the mere presence of historical storage or an accidental default.
That rule is useful beyond LP tokens. It applies to vault shares, staking receipts, bridge representations, withdrawal claims, and any transferable object whose value depends on a later issuer action.
The test is simple to state and annoying to fake: after every supported round trip, give the claim to a fresh holder and try to exit.

Frequently asked questions

Can a token be transferable but impossible to redeem?
Yes. Transfer logic and redemption logic can consult different contracts and different state. A successful transfer proves neither current issuer acceptance nor available backing.
Should protocols always delete zero-valued storage entries?
No. Keeping zero entries can be valid. The requirement is semantic: a decision about current reserves should inspect current reserve value rather than assume that key presence proves a live balance.
Is failing closed always safer for redemption?
No. A deliberate, recoverable pause may be appropriate. An uninitialized value that silently locks existing claims is a different state. Safety analysis must include holder liveness and the recovery path.
Does ERC-4626 prevent stale-state redemption bugs?
No. It standardizes interfaces and defines relationships among shares, previews, limits, and execution. Implementations can still be incorrect. Its maxRedeem separation is useful because it makes current exit capacity observable.
What is the smallest useful regression test?
Create a valid claim, place it into a supported nested state, remove it completely, transfer it to another account, and redeem it. Then repeat with zero-valued residual storage and default configuration.

Glossary

TermMeaning in this study
LP tokenA transferable claim representing a liquidity position or share of pool reserves.
Pool exitThe lifecycle step that removes liquidity and returns underlying assets.
Round-trip invariantA property that should still hold after entering and then completely leaving a supported state.
ERC-4626The tokenized-vault standard used here as an interface comparison for claim and exit observability.
Protocol solvencyThe relationship between protocol assets and obligations, distinct from whether a particular exit is reachable.

Sources

[2] https://zealynx.io/case-studies/mira-lp-token-redeemability - Zealynx, Mira LP-token redeemability case study
[4] https://eips.ethereum.org/EIPS/eip-4626 - ERC-4626: Tokenized Vaults
[5] https://www.openzeppelin.com/news/origin-dollar-audit-2 - OpenZeppelin, Origin Dollar Audit
[6] https://docs.openzeppelin.com/contracts/5.x/erc4626 - OpenZeppelin Contracts documentation, ERC-4626

Working auditors in your corner, all year

Zealynx Insiders: weekly live sessions, 1:1 advisory, pair-auditing, and Krait runs on your code, from an audit firm that publishes its reports.

Carlos (Bloqarl)
Written by

Founder at Zealynx

Keep reading
When Staking Rewards Spend User Principal
ResearchOct 29

When Staking Rewards Spend User Principal

15 min read
When a Safe View Becomes an Unsafe Settlement Input
ResearchOct 8

When a Safe View Becomes an Unsafe Settlement Input

14 min read
When Caught Failures Commit Broken State
ResearchNov 5

When Caught Failures Commit Broken State

16 min read