Lines of code
<https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L226-L228>
In rUSDY.sol, the functions totalSupply(), balanceOf() are calculated.
totalSupply() (<https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L216-L218>):
function totalSupply() public view returns (uint256) {
return (totalShares * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR);
}
balanceOf() (<https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L226-L228>):
function balanceOf(address _account) public view returns (uint256) {
return (_sharesOf(_account) * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR);
}
The calculated value of these two functions depends on oracle.getPrice(). The oracle.getPrice() function determines the USDY price. However, the documentation for the competition states:
βWhere as the price of a single USDY token varies over time, the price of a single rUSDY token is fixed at a price of 1 Dollar, with yield being accrued in the form of additional rUSDY tokens.β
That is, it is assumed that the price of the USDY token may change. Given the collapse of UST, the price of stablecoins can change both for an increase and for a decrease.
The calculation of the totalSupply() and balanceOf() functions may be incorrect in case of low values or decoupling of the USDY rate from $1 when it goes down.
Suppose:
totalShares = 9000
USDY = 1 * 1e18
_sharesOf(_account) = 9000
Means:
totalSupply = (totalShares * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR) = (9000 * 1e18) / (1e18 * 10000) = 0
balanceOf = (_sharesOf(_account) * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR) = (9000 * 1e18) / (1e18 * 10000) = 0
Suppose:
Option 1:
totalShares = 9 * 1e18
USDY = 1.02 * 1e18
_sharesOf(_account) = 3 * 1e18
Option 2:
totalShares = 9 * 1e18
USDY = 0.99 * 1e18
_sharesOf(_account) = 3 * 1e18
Means:
Option 1:
totalSupply = (totalShares * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR) = (9 * 1e18 * 1.02 * 1e18) / (1e18 * 10000) = 9.18 * 1e14
balanceOf = (_sharesOf(_account) * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR) = (3 * 1e18 * 1.02 * 1e18) / (1e18 * 10000) = 3.06 * 1e14
Option 2:
totalSupply = (totalShares * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR) = (9 * 1e18 * 0.99 * 1e18) / (1e18 * 10000) = 8.91 * 1e14
balanceOf = (_sharesOf(_account) * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR) = (3 * 1e18 * 0.99 * 1e18) / (1e18 * 10000) = 2.97 * 1e14
This shows that the value of totalSupply and balanceOf depends on the USDY price. This contradicts the claim that rUSDY is worth one dollar.
Manual review
Remove BPS_DENOMINATOR coefficient. Make a peg to one dollar.
Math
The text was updated successfully, but these errors were encountered:
All reactions