The provide() function does not reset withdrawal requests, allowing an attacker to bypass risk-free yield tactics protection
Lines of code
Vulnerability details
Impact
In the Opus protocol, the absorber is a stability pool that permits yin holders to contribute their yin and participate in liquidations (also known as absorptions) as a consolidated pool. Provided yin from users could be absorbed during an absorption. In return, users receive yang, which usually has a higher value than the absorbed yin. However, in the event of bad debt, it could be less. This situation could lead to risk-free yield frontrunning tactics, where an attacker only provides yin when the absorption brings profit then removing all yin right after that.
The Opus team is aware of this attack vector and has therefore implemented a request-withdraw procedure. Users must first request a withdrawal and wait for a certain period before executing the withdrawal.
However, the provide() method does not reset these request timestamps, which allows an attacker to bypass this safeguard.
Proof of Concept
The attacker's tactics will be:
- Deposit a small amount of yin into 100 of his accounts. Note that the total value of these small amounts is negligible. Also please note that the value
100is just arbitrary value to describe the idea. It could be higher or lower depending on theREQUEST_BASE_TIMELOCKandREQUEST_VALIDITY_PERIOD. - Regularly request withdrawals for these accounts to ensure that at least one account has a valid request at any given time. This can be easily achieved by requesting a withdrawal from the 1st account at timestamp X, the 2nd at
X + REQUEST_VALIDITY_PERIOD, the 3rd atX + 2 * REQUEST_VALIDITY_PERIOD, and so on. The 1st account request will expire atX + REQUEST_BASE_TIMELOCK + REQUEST_VALIDITY_PERIOD, but now 2nd request account become valid because it has requested atX + REQUEST_VALIDITY_PERIOD. - Since the
provide()function does not reset the request, the attacker can simply select one account with a valid removing request and perform the "risk-free yield tactics". He does this by providing a large amount of yin to this account to earn yield and then immediately callingremove().
Tools Used
Manual Review
Recommended Mitigation Steps
Reset the withdrawal request in the provide() function.
Assessed type
MEV
