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: 35/183
Findings: 6
Award: $327.20
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Maroutis
Also found by: 0x486776, 0xShitgem, 0xabhay, 0xleadwizard, 0xlemon, 0xnilay, 0xtankr, 3docSec, AM, Aamir, Abdessamed, Al-Qa-qa, AlexCzm, Circolors, CodeWasp, Daniel526, Egis_Security, Emmanuel, Giorgio, Honour, Hueber, Infect3d, Krace, KupiaSec, LeoGold, Limbooo, PoeAudits, SBSecurity, SpicyMeatball, T1MOH, The-Seraphs, TheSavageTeddy, TheSchnilch, Topmark, VAD37, ZanyBonzy, adam-idarrha, bhilare_, btk, carlitox477, cinderblock, dimulski, falconhoof, grearlake, gumgumzum, iamandreiski, itsabinashb, josephdara, ke1caM, kennedy1030, ljj, n0kto, n4nika, neocrao, oakcobalt, petro_1912, pontifex, poslednaya, shaflow2, shikhar229169, web3km, ych18, zhaojohnson, zigtur
0.2831 USDC - $0.28
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L88 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/script/deploy/Deploy.V2.s.sol#L64-L65 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/KerosineManager.sol#L44
keroseneManager verifies/licenses exogenous/non-kerosene vaults rather than keroseneVaults, as a result
keroseneManager::isLicensed determines if a keroseneVault is licensed or not by checking if it exists in the addressSet vaults
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/KerosineManager.sol#L44
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L88,
However the addressSet vaults
stores only non-kerosene/exogenous vaults that are used calculate the TVL of Dyad and the price of Kerosene
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/script/deploy/Deploy.V2.s.sol#L64-L65.
So when adding vaults with vaultManagerV2::addKerosene users will be unable to add keroseneVaults and would instead be able to add non-kerosene vaults. This means that users will be able to add the same exogenous vault as both kerosene and non-kerosene vault and duplicating their collateral
Manual Review
keroseneMAnager should inherit from the licenser to add licensing functions , the add/remove functions on the keroseneManager should be renamed to distingush them from that of the licenser and the isLicensed function should be removed as it's provided by the licenser
// src/core/KeroseneManager.sol contract KerosineManager is Licenser {//note licenser is owned already error TooManyVaults(); error VaultAlreadyAdded(); error VaultNotFound(); using EnumerableSet for EnumerableSet.AddressSet; uint public constant MAX_VAULTS = 10; EnumerableSet.AddressSet private vaults; function addTVLVault( address vault ) external onlyOwner { if (vaults.length() >= MAX_VAULTS) revert TooManyVaults(); if (!vaults.add(vault)) revert VaultAlreadyAdded(); } function removeTVLVault( address vault ) external onlyOwner { if (!vaults.remove(vault)) revert VaultNotFound(); } function getVaults() external view returns (address[] memory) { return vaults.values(); } }
Deploy script should be updated as well with said functions
Other
#0 - c4-pre-sort
2024-04-29T05:20:44Z
JustDravee marked the issue as duplicate of #966
#1 - c4-pre-sort
2024-04-29T08:37:14Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-04T09:46:21Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-29T11:20:16Z
koolexcrypto marked the issue as duplicate of #1133
#4 - c4-judge
2024-05-29T11:43:02Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: Maroutis
Also found by: 0x486776, 0xShitgem, 0xabhay, 0xleadwizard, 0xlemon, 0xnilay, 0xtankr, 3docSec, AM, Aamir, Abdessamed, Al-Qa-qa, AlexCzm, Circolors, CodeWasp, Daniel526, Egis_Security, Emmanuel, Giorgio, Honour, Hueber, Infect3d, Krace, KupiaSec, LeoGold, Limbooo, PoeAudits, SBSecurity, SpicyMeatball, T1MOH, The-Seraphs, TheSavageTeddy, TheSchnilch, Topmark, VAD37, ZanyBonzy, adam-idarrha, bhilare_, btk, carlitox477, cinderblock, dimulski, falconhoof, grearlake, gumgumzum, iamandreiski, itsabinashb, josephdara, ke1caM, kennedy1030, ljj, n0kto, n4nika, neocrao, oakcobalt, petro_1912, pontifex, poslednaya, shaflow2, shikhar229169, web3km, ych18, zhaojohnson, zigtur
0.2831 USDC - $0.28
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/script/deploy/Deploy.V2.s.sol#L95-L96 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L75
Users will be able to add the same kerosene vault twice(as vault and vaultKerosene) allowing the same collateral to be duplicated and breaking the TVL > DYAD invariant ,because undercollateralized positions will still be considered healthy
Kerosene vaults are added to the vaultLicenser in the deploy script
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/script/deploy/Deploy.V2.s.sol#L95-L96,
the vaultLicenser is used verify licensed non-kerosene vaults in the VaultManagerV2
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L75
this means that users can add the same kerosene vault to VaultManagerV2::vaults
and VaultManagerV2::vaultsKerosene
, effectively allowing Dyad to be backed entirely by kerosene instead of exogenous collateral
Manual Review
Kerosene vaults should not be added to the vaultLicenser
Other
#0 - c4-pre-sort
2024-04-29T05:20:36Z
JustDravee marked the issue as duplicate of #966
#1 - c4-pre-sort
2024-04-29T08:37:14Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-04T09:46:21Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-29T11:20:17Z
koolexcrypto marked the issue as duplicate of #1133
#4 - c4-judge
2024-05-29T11:43:05Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: MrPotatoMagic
Also found by: 0x175, 0x486776, 0x77, 0xAkira, 0xAsen, 0xDemon, 0xabhay, 0xblack_bird, 0xlemon, 0xloscar01, 0xtankr, 3docSec, 4rdiii, Abdessamed, AlexCzm, Angry_Mustache_Man, BiasedMerc, Circolors, Cryptor, DMoore, DPS, DedOhWale, Dinesh11G, Dots, GalloDaSballo, Giorgio, Honour, Imp, Jorgect, Krace, KupiaSec, Mrxstrange, NentoR, Pechenite, PoeAudits, Ryonen, SBSecurity, Sabit, T1MOH, TheFabled, TheSavageTeddy, Tychai0s, VAD37, Vasquez, WildSniper, ZanyBonzy, adam-idarrha, alix40, asui, blutorque, btk, c0pp3rscr3w3r, caglankaan, carrotsmuggler, d_tony7470, dimulski, dinkras, djxploit, falconhoof, forgebyola, grearlake, imare, itsabinashb, josephdara, kartik_giri_47538, ke1caM, kennedy1030, koo, lionking927, ljj, niser93, pep7siup, poslednaya, ptsanev, sashik_eth, shaflow2, steadyman, turvy_fuzz, ubl4nk, valentin_s2304, web3km, xyz, y4y, zhaojohnson, zigtur
0.0234 USDC - $0.02
A malicious actor can prevent/delay a DNFT owner from withdrawing their collateral for a period of time
VaultManagerV2::withdraw reverts if a deposit to the same DNFT has been made in the same block https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L143. Whilst the withdraw function can only be called by the DNFT owner, the deposit function can be called by anyone as long as its to a valid DNFT https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L125. In specific cases , an example is if a sufficiently large amount of collateral is about to be withdrawn that might affect the price of kerosene ,a malicious actor might be incentivized to delay the withdrawal of collateral for period of time to prevent a loss(perhaps selling their kerosene) or to profit from the price change by front-running the withdrawal to deposit a sufficiently small amount of collateral to the DNFT
Manual Review
Since this was supposed to mitigate flashLoan attacks , use of transient storage will be more appropriate
// src/core/VaultManagerV2.sol pragma solidity =0.8.24; contract VaultManagerV2 { error DepositedInSameBlock(); modifier flashlock() { assembly { tstore(0, 1) } _; } modifier whenNotflashLocked() { uint isLocked; assembly { isLocked := tload(0) } if (isLocked == 1) revert DepositedInSameBlock(); _; } //...code... function deposit(uint id, address vault, uint amount) external isValidDNft(id) flashLock { } function withdraw(uint id, address vault, uint amount, address to) public isDNftOwner(id) whenNotflashLocked { } }
Timing
#0 - c4-pre-sort
2024-04-29T07:24:24Z
JustDravee marked the issue as duplicate of #489
#1 - c4-pre-sort
2024-04-29T09:30:17Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-05T20:38:09Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-05T21:12:58Z
koolexcrypto marked the issue as nullified
#4 - c4-judge
2024-05-05T21:13:04Z
koolexcrypto marked the issue as not nullified
#5 - c4-judge
2024-05-08T15:29:24Z
koolexcrypto marked the issue as duplicate of #1001
#6 - c4-judge
2024-05-11T19:44:40Z
koolexcrypto marked the issue as satisfactory
#7 - c4-judge
2024-05-13T18:34:30Z
koolexcrypto changed the severity to 3 (High Risk)
🌟 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 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L195
Users will be unable to withdraw/redeem kerosene deposited into the vault
When withdrawing collateral from the VaultManagerV2 the value(in usd) of the amount of collateral is calculated as 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();
The issue is that kerosene vaults don't use oracles so the transction reverts, preventing kerosene withdrawals. Same calulation happens in the VaultManagerV2::redeemDyad function https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L195-L198
Manual Review
The oracle decimals should be calculated if the vault is not kerosene vault other it's set to 8 which is the decimal precision used by kerosene vaults
// src/core/VaultManagerV2.sol uint oracleDecimal = kereseneManager.isLicensed(vault) ? 8 : _vault.oracle().decimals(); uint value = (amount * _vault.assetPrice() * 1e18) / 10 ** oracleDecimal / 10 ** _vault.asset().decimals();
Oracle
#0 - c4-pre-sort
2024-04-26T21:33:57Z
JustDravee marked the issue as duplicate of #1048
#1 - c4-pre-sort
2024-04-28T18:39:26Z
JustDravee marked the issue as duplicate of #830
#2 - c4-pre-sort
2024-04-29T08:44:48Z
JustDravee marked the issue as sufficient quality report
#3 - c4-judge
2024-05-11T20:05:24Z
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
Users may not be able to withdraw kerosene from their vault even if they have a healthy position
VaultManagerV2::withdraw
reverts if the value the token to be withdrawn causes the value of non-kerosene collateral to fall below the Dyad minted by the DNft position
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L150.
The issue is that the check is also done even when withdrawing kerosene, so if the value of kerosene to be withdrawn minus the value of non-kerosene collateral to fall below the Dyad minted the transaction reverts with NotEoughExoCollat()
,which is not the case.
Manual Review
check should be skipped when withdrawing from a kerosene vault.
DoS
#0 - c4-pre-sort
2024-04-26T21:11:41Z
JustDravee marked the issue as duplicate of #397
#1 - c4-pre-sort
2024-04-29T08:48:18Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T19:22:58Z
koolexcrypto marked the issue as satisfactory
#3 - c4-judge
2024-05-13T18:33:03Z
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
TVL > DYAD invariant can be broken
VaultManagerV2::liquidate
only checks the overall collateral ratio of the DNft to determine if its liquidatable or not
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L214
,however the tvl(total exogenous collateral) of a position might be less than the dyad minted by the DNft(TVL(id) < DYAD(id)) if the price of the exogenous token drops, but if a sufficient amount of kerosene is available the collateral ratio will remain above 1.5, in such a case the position has undercollateralized exogenous collateral but is not liquidatable
Manual Review
A DNft position should be liquidatable if total exogenous collateral is less than the dyad minted regardless of the collateral ratio to avoid violating the TVL > DYAD invariant
// src/core/VaultManagerV2.sol -214 if (cr >= MIN_COLLATERIZATION_RATIO) revert CrTooHigh(); +214 if (cr >= MIN_COLLATERIZATION_RATIO && getNonKeroseneValue(id) >= dyad.mintedDyad(address(this), id)) revert CrTooHigh();
Other
#0 - c4-pre-sort
2024-04-28T17:03:21Z
JustDravee marked the issue as duplicate of #128
#1 - c4-pre-sort
2024-04-29T09:03:36Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-08T09:49:10Z
koolexcrypto marked the issue as not a duplicate
#3 - c4-judge
2024-05-08T09:49:18Z
koolexcrypto marked the issue as duplicate of #338
#4 - c4-judge
2024-05-11T12:20:06Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: 0xAlix2
Also found by: 0x175, 0x486776, 0xnev, 3docSec, 3th, Aamir, Abdessamed, AlexCzm, Angry_Mustache_Man, Circolors, DedOhWale, Emmanuel, Giorgio, Honour, Jorgect, KupiaSec, Maroutis, Myrault, SBSecurity, Stefanov, T1MOH, VAD37, Vasquez, adam-idarrha, alix40, ducanh2706, falconhoof, iamandreiski, ke1caM, kennedy1030, koo, lian886, ljj, miaowu, pontifex, sashik_eth, shikhar229169, vahdrak1
7.3026 USDC - $7.30
liquidator might not receive full compensation for burned Dyad token or liquidation reward
VaultManagerV2::liquidate
only distributes non kerosene collateral to the DNft provided by the liquidator
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L221.
However because the minimum value of exogenous collateral required is equal to Dyad minted by the DNft , the amount of exogenous collateral available during liquidation might be less than the Dyad minted while the liquidator burns an equivalent of the Dyad minted by the DNft.
For example , a healthy DNft position of 100Dyad backed by 0.0285WETH(100usd @3500/ETH) and 50usd worth of kerosene Collateral ratio=1.5, if WETH falls to 3400usd the position becomes liquidatable because 0.0285WETH is now 97usd and CR < 1.5. The liquidator burns 100Dyad but recieves 97usd(for simplicity , in reality the liquidator recieves less due to how the liquidityAssetShare
is calculated) which doesn't even cover the burned Dyad without including the liquidation reward.
Manual Review
Kerosene should be distributed as well on liquidation
// src/core/VaultManagerV2.sol function liquidate( uint id, uint to ) external isValidDNft(id) isValidDNft(to) { //...code... uint numberOfVaults = vaults[id].length(); for (uint i = 0; i < numberOfVaults; i++) { Vault vault = Vault(vaults[id].at(i)); uint collateral = vault.id2asset(id).mulWadUp( liquidationAssetShare ); vault.move(id, to, collateral); } numberOfVaults = vaultsKerosene[id].length(); for (uint i = 0; i < numberOfVaults; i++) { Vault vault = Vault(vaultsKerosene[id].at(i)); uint collateral = vault.id2asset(id).mulWadUp( liquidationAssetShare ); vault.move(id, to, collateral); } }
Other
#0 - c4-pre-sort
2024-04-28T10:22:54Z
JustDravee marked the issue as duplicate of #128
#1 - c4-pre-sort
2024-04-29T09:03:34Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T19:41:20Z
koolexcrypto marked the issue as satisfactory