Bright Spruce Otter
Medium
When an auction is settled, the AuctionHouse contract calls the StreamEscrow contract to create a new vesting stream.
The settlement logic subtracts 20 % of the actual bid amount (sends it directly to the DAO treasury) and forwards the remaining 80% to the forwardAllAndCreateStream()
call. However, the createStream()
can also permanently take up a part of the other 80 %, breaking the invariant that the whole 80 % should be vested and be recoverable if stream is cancelled.
Here is the createStream()
logic :
uint128 ethPerTick = toUint128(msg.value / streamLengthInTicks);
uint32 streamLastTick = currentTick + streamLengthInTicks;
ethStreamEndingAtTick[streamLastTick] += ethPerTick;
// the remainder is immediately streamed to the DAO
uint256 remainder = msg.value % streamLengthInTicks;
sendETHToTreasury(remainder);
Note that the remainder
is directly sent to the treasury and is out of the stream calculations, which means it will be unrecoverable even if the stream is cancelled immediately or any time in between the streaming window.
Though the bidder is promised that exactly 80 % of their bids will be escrowed, some part of it will be permanently unrecoverable as its not considered in the refund calculation in cancelStream()
.
The remainder
amount is directly sent to the treasury in createStream()
making it permanently unrecoverable even though it is a part of the escrowed 80 % bid amount.
No response
No response
No response
A portion of the bidder's bid amount will be permanently lost while the protocol promises the bidder that 80 % of the bid will be escrowed and can be refunded if they cancel the stream.
No response
The fix is non-trivial. The remainder could be sent back to the bidder while settling the auction in AuctionHouse contract, so that it does not even reach the StreamEscrow contract. Then 20 and 80 % will both be handled smoothly.