Lucene search

K
code423n4Code4renaCODE423N4:2023-09-ASYMMETRY-FINDINGS-ISSUES-62
HistorySep 27, 2023 - 12:00 a.m.

Intrinsic arbitrage from price discrepancy

2023-09-2700:00:00
Code4rena
github.com
2
chainlink
afeth contract
deposits and withdrawals
price discrepancy
safeth
vafeth
arbitrage opportunities

6.9 Medium

AI Score

Confidence

Low

Lines of code

Vulnerability details

Impact

The up to 2 % price discrepancy from Chainlink creates an intrinsic arbitrage. Especially, it makes withdrawals worth more than deposits in the sense that one can immediately withdraw more than just deposited.

Proof of Concept

When depositing ETH into AfEth, the ETH is split according to ratio and sold for safEth and vAfEth. The received share of afEth is then determined by the value in ETH of the resulting amounts of safEth and vAfEth. Note that there are two prices involved here: the true price at which ETH is traded for safEth and vAfEth (in sellCvx() and buyCvx()), and the estimated value in ETH that safEth and vAfEth is considered to have (ISafEth.approxPrice() and VotiumStrategy.price()). These are not necessarily the same.

If the ratio by which the deposited ETH is split is not the same as the ratio of the true values of the underlying assets, this implies that a deposit implicitly makes a trade between safEth and vAfEth according to the estimated price which may thus differ from the true price obtained when withdrawing. This presents an arbitrage opportunity.
Note that if all prices were the same it would not matter if safEth is β€œtraded” for vAfEth within a deposit as the trade then makes no change in the total value deposited.

The conditions for this issue is thus that VotiumStrategy.price() is different from the price obtained by sellCvx() and buyCvx(), and that the deposit ratio is not the same as the withdrawal ratio.

VotiumStrategy.price() in particular is based on a Chainlink oracle with a 2 % deviation threshold, which means that the true price is allowed to deviate up to 2 %, within 24 hours, from the reported price. ISafEth.approxPrice() may perhaps be similarly inaccurate (I have not looked into this).

The ratio can skew in this way for two reasons. One is when the ratio is different from the ratio of the underlying balances, such as when ratio is changed. Deposits are made according to ratio but withdrawals are made proportionally from the extant balances. In this case the implicit trade between safEth and vAfEth can happen in either direction, either beneficial or detrimental to the depositor (if there is a price discrepancy).
The other is caused by the price discrepancy itself when depositing. In this case it is always beneficial to the depositor (and detrimental to the holders).

Example 1a - reconverging ratio, vAfEth is actually more expensive
Suppose the contract holds 100 safEth and 0 vAfEth, but that the ratio has now been changed to 0. Further suppose that the contract thinks all prices are 1, but that 100 ETH actually trades for 102 vAfEth.
Then depositing 100 ETH will convert it to 102 vAfEth, which will be valued as 102 ETH. This mints 102 afEth.
The balances are now 100 safEth and 102 vAfEth and the total supply is 202 afEth.
Withdrawing 102 afEth converts 102/202 of the underlying, i.e. 50.495 safEth and 51.505 vAfEth, into 50.495 + 51.505/1.02 = 100.99 ETH.

Example 1b - reconverging ratio, vAfEth is actually cheaper
Suppose the contract holds 100 safEth and 0 vAfEth, but that the ratio has now been changed to 0. Further suppose that the contract thinks all prices are 1, but that 100 ETH actually trades for 98 vAfEth.
Then depositing 100 ETH will convert it to 98 vAfEth, which will be valued as 98 ETH. This mints 98 afEth.
The balances are now 100 safEth and 98 vAfEth and the total supply is 198 afEth.
Withdrawing 98 afEth converts 98/198 of the underlying, i.e. 49.495 safEth and 48.505 vAfEth, into 49.495 + 48.505/0.98 = 98.99 ETH.

Example 2a - stable ratio, vAfEth is actually more expensive
Suppose the contract holds 50 safEth and 50 vAfEth and that the ratio is 0.5. Further suppose that the contract thinks all prices are 1 but that 50 ETH actually trades for 51 vAfEth.
Then depositing 100 ETH will convert 50 ETH to 50 safEth and 50 ETH to 51 vAfEth, which will be valued as 101 ETH. This mints 101 afEth.
The balances are now 100 safEth and 101 vAfEth and the total supply is 201 afEth.
Withdrawing 101 afEth converts 101/201 of the underlying, i.e. 50.249 safEth and 50.751 vAfEth, into 50.249 + 50.751/1.02 = 100.005 ETH.

Example 2b - stable ratio, vAfEth is actually cheaper
Suppose the contract holds 50 safEth and 50 vAfEth and that the ratio is 0.5. Further suppose that the contract thinks all prices are 1 but that 50 ETH actually trades for 49 vAfEth.
Then depositing 100 ETH will convert 50 ETH to 50 safEth and 50 ETH to 49 vAfEth, which will be valued as 99 ETH. This mints 99 afEth.
The balances are now 100 safEth and 99 vAfEth and the total supply is 199 afEth.
Withdrawing 99 afEth converts 99/199 of the underlying, i.e. 49.749 safEth and 49.251 vAfEth, into 49.749 + 49.251/0.98 = 100.005 ETH.

Thus one can make a profit by depositing and immediately withdrawing. Immediate withdrawals are possible at the moment locks expire (and before they have been relocked), but it may be enough to just immediately request a withdrawal if the true price is the same (or better) when eventually withdrawn.

The price discrepancy will appear whenever there are price fluctuations of up to 2 % within 24 hours, which seems quite likely.

Regarding the case where the underlying is reconverging after a change of ratio it is worth noting that convergence is quite slow. Several times the entire balances must be traded before the new ratio is approached.

Recommended Mitigation Steps

I would have to think more about this.

Assessed type

Math


The text was updated successfully, but these errors were encountered:

All reactions

6.9 Medium

AI Score

Confidence

Low