Platform: Code4rena
Start Date: 18/04/2024
Pot Size: $36,500 USDC
Total HM: 19
Participants: 183
Period: 7 days
Judge: Koolex
Id: 367
League: ETH
Rank: 38/183
Findings: 3
Award: $319.60
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Circolors
Also found by: 0x175, 0x486776, 0xAlix2, 0xSecuri, 0xShitgem, 0xfox, 0xlemon, 0xnilay, 3th, 4rdiii, Aamir, Al-Qa-qa, AlexCzm, Egis_Security, Evo, Honour, Infect3d, Josh4324, Limbooo, Mahmud, SBSecurity, TheSchnilch, ahmedaghadi, alix40, amaron, bbl4de, bhilare_, btk, carrotsmuggler, cinderblock, d3e4, dimulski, dinkras, ducanh2706, iamandreiski, itsabinashb, ke1caM, ljj, sashik_eth, shaflow2, steadyman, web3km, y4y
3.8221 USDC - $3.82
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L146-L149 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L195-L198
The withdraw
and redeemDyad
functions will revert when attempting to withdraw from any kerosene vault address. This issue will lead to a scenario where users are unable to withdraw their collateral from kerosene vaults, effectively locking their tokens within the protocol.
The vulnerable code can be found in the withdraw
and redeemDyad
functions of VaultManagerV2
Specifically, the lines that cause the issue are: https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L195-L198 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L146-L149
uint value = amount * _vault.assetPrice() * 1e18 / 10**_vault.oracle().decimals() / 10**_vault.asset().decimals();
value
is the USD value of the token amount
_vault
is the passed in vault address cast to Vault
oracle
is the automatic getter function created for the oracle
public variable on Vault
The KerosineVault
contract does not have an oracle
public variable defined: https://github.com/code-423n4/2024-04-dyad/blob/main/src/core/Vault.kerosine.sol
As a result, when the withdraw
function is called with a kerosene vault address, the transaction will revert due to the absence of the oracle
function.
Manual review
Modify the withdraw
and redeemDyad
functions to handle kerosene vaults differently. The exogenous collateral check should be skipped if the passed in vault address is of a kerosene vault.
DoS
#0 - c4-pre-sort
2024-04-26T21:32:54Z
JustDravee marked the issue as duplicate of #1048
#1 - c4-pre-sort
2024-04-28T18:39:29Z
JustDravee marked the issue as duplicate of #830
#2 - c4-pre-sort
2024-04-29T08:45:28Z
JustDravee marked the issue as sufficient quality report
#3 - c4-judge
2024-05-11T20:05:36Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: 0xAlix2
Also found by: 0xfox, 0xlemon, 0xnev, 3docSec, Aamir, Abdessamed, Dudex_2004, Egis_Security, Evo, FastChecker, Honour, Jorgect, KupiaSec, Limbooo, MrPotatoMagic, SpicyMeatball, TheSchnilch, alix40, bhilare_, favelanky, forgebyola, ke1caM, kennedy1030, koo, oakcobalt, petro_1912, shikhar229169
32.4128 USDC - $32.41
The withdraw
function in the VaultManagerV2
contract has a bug that could prevent users from withdrawing their kerosene collateral even when they are sufficiently overcollateralized. This issue could impact a large amount of the user base.
This is the context of the withdraw function:
function withdraw(uint256 id, address vault, uint256 amount, address to) public isDNftOwner(id) { if (idToBlockOfLastDeposit[id] == block.number) revert DepositedInSameBlock(); uint256 dyadMinted = dyad.mintedDyad(address(this), id); //e18 Vault _vault = Vault(vault); uint256 value = amount * _vault.assetPrice() * 1e18 / 10 ** _vault.oracle().decimals() / 10 ** _vault.asset().decimals(); if (getNonKeroseneValue(id) - value < dyadMinted) revert NotEnoughExoCollat(); _vault.withdraw(id, to, amount); if (collatRatio(id) < MIN_COLLATERIZATION_RATIO) revert CrTooLow(); }
The specific line causing the issue is: https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L150
if (getNonKeroseneValue(id) - value < dyadMinted) revert NotEnoughExoCollat();
id
is the id of the user's nft
value
is the USD value of the token amount to withdraw
dyadMinted
is the amount of dyad minted by the user
This line checks the non-kerosene collateral value associated with the user's nft minus the withdrawal amount - against the minted dyad of the user, even when the withdrawal is for kerosene collateral. If the non-kerosene collateral value minus the withdrawal amount exceeds the minted dyad - the function will wrongly revert and prevent the user from withdrawing their kerosene.
Manual review
To mitigate this issue, the withdraw function should be modified to handle endogenous (currently kerosene) and exogenous collateral separately. The function should check if the vault being withdrawn from is a kerosene vault or a non-kerosene vault, and apply the appropriate collateralization check accordingly.
DoS
#0 - c4-pre-sort
2024-04-26T21:11:02Z
JustDravee marked the issue as duplicate of #397
#1 - c4-pre-sort
2024-04-29T08:48:28Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T19:23:04Z
koolexcrypto marked the issue as satisfactory
#3 - c4-judge
2024-05-13T18:33:04Z
koolexcrypto changed the severity to 3 (High Risk)
🌟 Selected for report: shikhar229169
Also found by: 0x486776, 0xSecuri, 0xfox, 3th, Circolors, Honour, KupiaSec, Maroutis, Sancybars, Stormreckson, Strausses, ke1caM, kennedy1030
283.3687 USDC - $283.37
The inability to liquidate a user whose exogenous collateral falls below the value of their minted DYAD can lead to a scenario where under-collateralized positions are not liquidated promptly putting the protocol in financial risk.
The liquidate
function will only allow the liquidation to proceed if the user's collateralization ratio as calculated by collatRatio
function is below the minimum (MIN_COLLATERIZATION_RATIO
of 150%). The collatRatio
function takes into account both the endogenous (Kerosine) and exogenous collateral when calculating the CR. This means that by holding a sufficiently large ratio of Kerosine tokens a user could prevent themselves from being liquidated even if the value of their exogenous collateral falls below the value of their minted DYAD.
Here is the relevant part of the liquidate
function:
uint256 cr = collatRatio(id); if (cr >= MIN_COLLATERIZATION_RATIO) revert CrTooHigh();
Modify the liquidate
function to allow liquidation based on the value of the exogenous collateral compared to the minted DYAD as well as the overall collateralization ratio.
Manual code review.
Other
#0 - c4-pre-sort
2024-04-28T19:58:38Z
JustDravee marked the issue as duplicate of #128
#1 - c4-pre-sort
2024-04-29T09:03:44Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-08T09:58:56Z
koolexcrypto marked the issue as not a duplicate
#3 - c4-judge
2024-05-08T09:59:04Z
koolexcrypto marked the issue as duplicate of #338
#4 - c4-judge
2024-05-11T12:20:24Z
koolexcrypto marked the issue as satisfactory