Both timestamp and epoch logic are utilized within the TapiocaOptionBroker contract to determine if a position is active:
In the exitPosition() function, a position can be exited when block.timestamp exceeds lock.lockTime + lock.lockDuration.
Meanwhile, in the exerciseOption() function, the position is considered active if epoch is less than or equal to _timestampToWeek(lock.lockTime + lock.lockDuration).
Additionally, the epoch storage value can be incremented by 1 when a week has passed by invoking the newEpoch() function. This function is open for anyone to call, enabling an attacker to exploit the system by creating a lock position slightly longer than a week (e.g., lockDuration = WEEK + 100 seconds) and locking it near the end of an epoch to exercise the option for two weeks.
Consider the following scenario for the attacker's strategy:
Assume emissionsStartTime = 0.
At block.timestamp = EPOCH_DURATION - 10, the attacker calls participate() with a position duration of EPOCH_DURATION + 10.
At block.timestamp = EPOCH_DURATION, the newEpoch() function is invoked, incrementing epoch to 1.
At block.timestamp = 2 * EPOCH_DURATION - 10, a week after the attacker's participate() call, they execute exerciseOption() to obtain the first option.
At block.timestamp = 3 * EPOCH_DURATION:
newEpoch() is invoked, advancing epoch to 2.
The attacker calls exerciseOption() to obtain the second option (valid since epoch = 3 = _timestampToWeek(lock.lockTime + lock.lockDuration)).
The attacker calls exitPosition to exit their position.
As demonstrated, by locking their position for slightly more than a week, the attacker can acquire two options instead of one.
Impact
The attacker can claim x+1 options by simply locking their position for slightly more than x weeks.
Additionally, the tap token to be exercised at epoch x+1 will be diluted by the attacker.
Tools Used
Manual review
Recommended Mitigation Steps
Ensure that positions can participate in the option broker, they must be divisible by EPOCH_DURATION.
Lines of code
https://github.com/Tapioca-DAO/tap-token/blob/20a83b1d2d5577653610a6c3879dff9df4968345/contracts/options/TapiocaOptionBroker.sol#L512-L514 https://github.com/Tapioca-DAO/tap-token/blob/20a83b1d2d5577653610a6c3879dff9df4968345/contracts/options/TapiocaOptionBroker.sol#L318-L320 https://github.com/Tapioca-DAO/tap-token/blob/20a83b1d2d5577653610a6c3879dff9df4968345/contracts/options/TapiocaOptionBroker.sol#L369-L370
Vulnerability details
Description
Both timestamp and epoch logic are utilized within the
TapiocaOptionBroker
contract to determine if a position is active:exitPosition()
function, a position can be exited whenblock.timestamp
exceedslock.lockTime + lock.lockDuration
.exerciseOption()
function, the position is considered active ifepoch
is less than or equal to_timestampToWeek(lock.lockTime + lock.lockDuration)
.Additionally, the
epoch
storage value can be incremented by 1 when a week has passed by invoking thenewEpoch()
function. This function is open for anyone to call, enabling an attacker to exploit the system by creating a lock position slightly longer than a week (e.g.,lockDuration = WEEK + 100 seconds
) and locking it near the end of an epoch to exercise the option for two weeks.Consider the following scenario for the attacker's strategy:
emissionsStartTime = 0
.block.timestamp = EPOCH_DURATION - 10
, the attacker callsparticipate()
with a position duration ofEPOCH_DURATION + 10
.block.timestamp = EPOCH_DURATION
, thenewEpoch()
function is invoked, incrementingepoch
to 1.block.timestamp = 2 * EPOCH_DURATION - 10
, a week after the attacker'sparticipate()
call, they executeexerciseOption()
to obtain the first option.block.timestamp = 3 * EPOCH_DURATION
:newEpoch()
is invoked, advancingepoch
to 2.exerciseOption()
to obtain the second option (valid sinceepoch = 3 = _timestampToWeek(lock.lockTime + lock.lockDuration)
).exitPosition
to exit their position.As demonstrated, by locking their position for slightly more than a week, the attacker can acquire two options instead of one.
Impact
Tools Used
Manual review
Recommended Mitigation Steps
Ensure that positions can participate in the option broker, they must be divisible by
EPOCH_DURATION
.Assessed type
Timing