Platform: Code4rena
Start Date: 29/06/2022
Pot Size: $50,000 USDC
Total HM: 20
Participants: 133
Period: 5 days
Judge: hickuphh3
Total Solo HM: 1
Id: 142
League: ETH
Rank: 45/133
Findings: 1
Award: $110.36
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: codexploder
Also found by: ACai, Critical, cccz, horsefacts, ignacio, shenwilly, unforgiven, xiaoming90
Unlike other American Option systems, which the expiration time is set by the maker, in PuttyV2, the maker will set a duration
and an order expiration time (order.expiration
).
This means that the final expiration time of the option will be decided by the taker.
For a short order, it's preferred for the taker to fulfill the order later than sooner, as later means the option will be valid for a longer time.
Furthermore, the current implementation allows the maker to set the duration to an arbitrary value, which can be very short or even 0
, renders the option useless as it will expired immediately:
// save the long position expiration positionExpirations[order.isLong ? uint256(orderHash) : positionId] = block.timestamp + order.duration;
The option's expiration time (positionExpirations
) is base on block.timestamp
and order.duration
, when order.duration == 0
, the option's expiration time will be block.timestamp
.
Even if exercise()
is called within the same block will revert with "Position has expired"
.
function exercise(Order memory order, uint256[] calldata floorAssetTokenIds) public payable { /* ~~~ CHECKS ~~~ */ bytes32 orderHash = hashOrder(order); // check user owns the position require(ownerOf(uint256(orderHash)) == msg.sender, "Not owner"); // check position is long require(order.isLong, "Can only exercise long positions"); // check position has not expired require(block.timestamp < positionExpirations[uint256(orderHash)], "Position has expired");
Given:
Punk#100
market price = 100 ETHPunk#100
Punk#100
transferred from Alice to contractBob tried to exercise()
immediately, the transaction reverted with error: "Position has expired"
Alice called withdraw()
and retrieved the Punk#100
order.duration
and use order.expiration
for the expiration
time of the option;order.deadline
for the order's expiration time, and the maker order can only be filled before that time;order.deadline < order.expiration
.order.duration > MIN_DURATION
.The MIN_DURATION
should be meaningful for a regular end-user to exercise the option even when the network is congested, eg, 12 hours.
#0 - outdoteth
2022-07-05T14:06:03Z
For a short order, it's preferred for the taker to fulfill the order later than sooner, as later means the option will be valid for a longer time.
This is an incorrect assumption. It is preferred for the taker to fulfil the order whenever they believe the IV is priced correctly. This is because there are other participants who are also watching the same order book and will lift the order as soon as it's priced correctly.
However, the proof of concept and other parts of the reported issue align with "Orders with low durations can be easily DOS’d and prevent possibility of exercise".
#1 - outdoteth
2022-07-06T19:43:43Z
Duplicate: Orders with low durations can be easily DOS’d and prevent possibility of exercise: https://github.com/code-423n4/2022-06-putty-findings/issues/265