Incorrect assumption that PT rate is 1.0 post-expiry
Summary
PT rate will be hardcoded to 1.0 post-expiry, which is incorrect. The price returned from the Notional's PendlePTOracle contract will be inflated. As a result, the account's collateral will be overinflated, allowing malicious users to borrow significantly more than the actual collateral value, stealing assets from the protocol.
Vulnerability Detail
The following are the configuration files for the PT weETH 27JUN2024 taken from the test files of the audit contest's repository.
For PT weETH 27JUN2024, note that the useSyOracleRate is set to True, as per Line 59 below.
In this case, the useSyOracleRate is set to True in the PendlePTOracle contract.
In Line 115 below, the PT rate will be hardcoded to 1.0 post-expiry. Per the comment at Lines 113-114, it assumes that 1 unit of PT is worth 1 unit of the underlying SY at expiration. However, this assumption is incorrect.
File: PendlePTOracle.sol
092: function _calculateBaseToQuote() internal view returns (
..SNIP..
113: // Past expiration, hardcode the PT oracle price to 1. It is no longer tradable and
114: // is worth 1 unit of the underlying SY at expiration.
115: int256 ptRate = expiry <= block.timestamp ? ptDecimals : _getPTRate();
116:
117: answer = (ptRate * baseToUSD * rateDecimals) /
118: (baseToUSDDecimals * ptDecimals);
119: }
In the case of reward-bearing assets, it’s particularly important to note that PT is redeemable 1:1 for the accounting asset, NOT the **underlying asset.
For example, the value of Renzo ezETH increases overtime relative to ETH as staking and restaking rewards are accrued. For every 1 PT-ezETH you own, you’ll be able to redeem 1 ETH worth of ezETH upon maturity, NOT 1 ezETH which has a higher value.
Using PT weETH 27JUN2024, which is used within the ether.fi vault as an example:
Per the Pendle's eETH market page, it has stated that 1 PT eETH is equal to 1 eETH (also equal to 1 ETH) at maturity.
However, as noted earlier, the code assumes that one unit of PT is worth one unit of weETH instead of one unit of PT being worth one unit of eETH, which is incorrect.
On 1 July, the price of weETH was 3590 USD, while the price of eETH was 3438 USD. This is a difference of 152 USD.
As a result, the price returned from the Notional's PendlePTOracle contract will be inflated.
Additional Information
The PT weETH 27JUN2024 has already expired as of 1 July 2024.
Let's verify if the PT rate is 1.0 after maturity by inspecting the rate returned from Pendle PT Oracle's getPtToSyRate function.
As shown above, the PT rate at maturity is 0.9598002817 instead of 1.0. Thus, it is incorrect to assume that the PT rate is 1.0 post-expiry.
Impact
The price returned from the Notional's PendlePTOracle contract will be inflated. As a result, the account's collateral will be overinflated, allowing malicious users to borrow significantly more than the actual collateral value, stealing assets from the protocol.
xiaoming90
High
Incorrect assumption that PT rate is 1.0 post-expiry
Summary
PT rate will be hardcoded to 1.0 post-expiry, which is incorrect. The price returned from the Notional's
PendlePTOracle
contract will be inflated. As a result, the account's collateral will be overinflated, allowing malicious users to borrow significantly more than the actual collateral value, stealing assets from the protocol.Vulnerability Detail
The following are the configuration files for the PT weETH 27JUN2024 taken from the test files of the audit contest's repository.
For PT weETH 27JUN2024, note that the
useSyOracleRate
is set toTrue
, as per Line 59 below.https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/main/leveraged-vaults-private/tests/Staking/PendlePTTests.yml#L51
For PT weETH 27JUN2024, note that the
useSyOracleRate
is set toTrue
, as per Line 118 below.https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/main/leveraged-vaults-private/tests/generated/arbitrum/PendlePT_weETH_ETH.t.sol#L115
In this case, the
useSyOracleRate
is set toTrue
in thePendlePTOracle
contract.In Line 115 below, the PT rate will be hardcoded to 1.0 post-expiry. Per the comment at Lines 113-114, it assumes that 1 unit of PT is worth 1 unit of the underlying SY at expiration. However, this assumption is incorrect.
https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/main/leveraged-vaults-private/contracts/oracles/PendlePTOracle.sol#L113
Per the Pendle documentation:
Using PT weETH 27JUN2024, which is used within the ether.fi vault as an example:
Per the Pendle's eETH market page, it has stated that 1 PT eETH is equal to 1 eETH (also equal to 1 ETH) at maturity.
However, as noted earlier, the code assumes that one unit of PT is worth one unit of weETH instead of one unit of PT being worth one unit of eETH, which is incorrect.
On 1 July, the price of weETH was 3590 USD, while the price of eETH was 3438 USD. This is a difference of 152 USD.
As a result, the price returned from the Notional's
PendlePTOracle
contract will be inflated.Additional Information
The PT weETH 27JUN2024 has already expired as of 1 July 2024.
Let's verify if the PT rate is 1.0 after maturity by inspecting the rate returned from Pendle PT Oracle's
getPtToSyRate
function.As shown above, the PT rate at maturity is
0.9598002817
instead of1.0
. Thus, it is incorrect to assume that the PT rate is 1.0 post-expiry.Impact
The price returned from the Notional's
PendlePTOracle
contract will be inflated. As a result, the account's collateral will be overinflated, allowing malicious users to borrow significantly more than the actual collateral value, stealing assets from the protocol.Code Snippet
https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/main/leveraged-vaults-private/contracts/oracles/PendlePTOracle.sol#L113
Tool used
Manual Review
Recommendation
Ensure that the correct PT rate is used post-expiry.