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: 154/183
Findings: 1
Award: $0.28
🌟 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/main/src/core/VaultManagerV2.sol#L247 https://github.com/code-423n4/2024-04-dyad/blob/main/src/core/VaultManagerV2.sol#L213-L214
function collatRatio( uint id ) public view returns (uint) { uint _dyad = dyad.mintedDyad(address(this), id); if (_dyad == 0) return type(uint).max; >>> return getTotalUsdValue(id).divWadDown(_dyad); } function getTotalUsdValue( uint id ) public view returns (uint) { >>> return getNonKeroseneValue(id) + getKeroseneValue(id); ❌ }
The two functions above from the VaultManagerV2 contract shows how callateral ratio is calculated, it calls getTotalUsdValue(...) which returns the sum of NonKerosene USD Value and Kerosene USD Value.
function getNonKeroseneValue( uint id ) public view returns (uint) { uint totalUsdValue; uint numberOfVaults = vaults[id].length(); for (uint i = 0; i < numberOfVaults; i++) { Vault vault = Vault(vaults[id].at(i)); uint usdValue; >>> if (vaultLicenser.isLicensed(address(vault))) { ❌ >>> usdValue = vault.getUsdValue(id); ❌ } totalUsdValue += usdValue; } return totalUsdValue; } function getKeroseneValue( uint id ) public view returns (uint) { uint totalUsdValue; uint numberOfVaults = vaultsKerosene[id].length(); for (uint i = 0; i < numberOfVaults; i++) { Vault vault = Vault(vaultsKerosene[id].at(i)); uint usdValue; >>> if (keroseneManager.isLicensed(address(vault))) { ❌ >>> usdValue = vault.getUsdValue(id); ❌ } totalUsdValue += usdValue; } return totalUsdValue; }
The two functions above shows the implementation to calculate the non kerosene and Kerosene value, as noted from the pointers the problem is that the usdValue is derived exactly the same way for both functions by calling vault.getUsdValue(id)
. The implication of this is that when the id
has both the license of the keroseneManager and license from the vaultLicenser, the same USD value of the ID would be calculated twice and doubled in the getTotalUsdValue(...) function thereby inflating collateral value and ratio
Manual Review
Protocol should put necessary implementation to ensure a vault cannot have both Vault License and Kerosene License, another way is to add different implementations to calculate these different USD values
Access Control
#0 - c4-pre-sort
2024-04-28T07:03:41Z
JustDravee marked the issue as duplicate of #966
#1 - c4-pre-sort
2024-04-29T08:38:04Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-04T09:46:30Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-28T15:28:24Z
koolexcrypto marked the issue as duplicate of #1133
#4 - c4-judge
2024-05-29T14:03:17Z
koolexcrypto marked the issue as satisfactory