You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A private-send recipient can call UndelegateEphemeralAta on the ER before the deferred base materialization of the eATA delegation has landed. Nothing in the API/SDK/program flow prevents this ordering, and it permanently locks the recipient's ATA on the ER:
A private send delivers ER-side first (MergeShuttleIntoEphemeralAta); the base materialization (init + delegate eATA) is deferred.
The recipient sends UndelegateEphemeralAta → the ER schedules a commit-and-undelegate intent and runs mark_account_as_undelegated on the ATA (owner→delegation program, undelegating=true, delegated=false).
The base settlement of that intent can never succeed: the eATA has no delegation record on base yet. The intent dies; the ER-side lock is never rolled back.
The deferred materialization then lands on base. The ER's post-delegation actions fail with PostAct IllegalOwner against the locked ATA.
Every subsequent undelegate fails with ReadonlyDataModified ("account … is required to be writable and delegated") until an operator intervenes with ModifyAccounts. Funds are not at risk (the base eATA state holds the amount, backed by the vault), but the user's exit path is dead.
Observed on mainnet with a real payment; recovery required manual ops intervention.
Validator-side hardening is addressed separately (startup recovery sweep + slot-aware refresh guard for stale undelegating marks). This issue tracks preventing the flow from e-token's side.
Suggested prevention
API/SDK: refuse (or defer) undelegate while the eATA's base delegation record does not exist yet — delegation status is already available via the router (getDelegationStatus), and the balance endpoints return eATA delegation state since feat: return eATA delegation state from balance endpoints #135.
Optionally program/flow-side: don't expose a spendable ER balance until the base delegation record is confirmed, or gate ix 5 on a materialization marker.
Problem
A private-send recipient can call
UndelegateEphemeralAtaon the ER before the deferred base materialization of the eATA delegation has landed. Nothing in the API/SDK/program flow prevents this ordering, and it permanently locks the recipient's ATA on the ER:MergeShuttleIntoEphemeralAta); the base materialization (init + delegate eATA) is deferred.UndelegateEphemeralAta→ the ER schedules a commit-and-undelegate intent and runsmark_account_as_undelegatedon the ATA (owner→delegation program,undelegating=true,delegated=false).PostAct IllegalOwneragainst the locked ATA.ReadonlyDataModified("account … is required to be writable and delegated") until an operator intervenes withModifyAccounts. Funds are not at risk (the base eATA state holds the amount, backed by the vault), but the user's exit path is dead.Observed on mainnet with a real payment; recovery required manual ops intervention.
Validator-side hardening is addressed separately (startup recovery sweep + slot-aware refresh guard for stale undelegating marks). This issue tracks preventing the flow from e-token's side.
Suggested prevention
undelegatewhile the eATA's base delegation record does not exist yet — delegation status is already available via the router (getDelegationStatus), and the balance endpoints return eATA delegation state since feat: return eATA delegation state from balance endpoints #135.