When the amount of locked tokens is fully removed from SDLPoolPrimary
, the associated lockId
is immediately erased. However, even if all tokens have been withdrawn from SDLPoolSecondary
, the lockId
will persist and will be destroyed only when the owner of that lockId
calls the executeQueuedOperations()
function. Users can still lock additional tokens into the lockId
as long as it exists. Users will lose all locked tokens if the order to withdraw all tokens within the lockId
comes before any further lock orders for the same lockId
.
Vulnerability Steps:
The user initially locks a quantity of tokens in SDLPoolSecondary
, and the lockId
exists.
The user performs an init and withdraws all tokens within the aforementioned lockId
. The lockId
is not destroyed at this point, and the withdraw order is added to queuedLockUpdates
with lock.amount
set to 0.
The user notices that the lockId
still exists and locks additional tokens into it. The additional lock order is added to queuedLockUpdates
.
Now, queuedLockUpdates
contains numerous orders, with the withdraw order at the front of the queue.
Finally, the _executeQueuedLockUpdates()
function is called. The lockId
falls into the withdrawal case and gets deleted (L471-L473).
lockOwners[lockId]
is deleted, additional locks can still be added to that lockId
after that, but they will not be owned by anyone and will be permanently stuck within.
This confusion could lead to the permanent loss of tokens that users lock additionally.
Do not add any orders with an existing lockId
that has lock.amount
= 0 until it is deleted, or
After completing the iteration through the queuedLockUpdates
loops, then perform the check and deletion.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.