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: 142/183
Findings: 2
Award: $3.84
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
An NFT owner's withdrawal can be persistently DoS'd by depositing 0 tokens.
The withdraw
functions only lets the NFT owner to withdraw assets do the operation, and immediately checks if there are deposits at the same block, and reverts if so.
function withdraw( uint id, address vault, uint amount, address to ) public isDNftOwner(id) { if (idToBlockOfLastDeposit[id] == block.number) revert DepositedInSameBlock(); // snip...
At the same time, we see in deposit
function:
function deposit( uint id, address vault, uint amount ) external isValidDNft(id) { idToBlockOfLastDeposit[id] = block.number; Vault _vault = Vault(vault); _vault.asset().safeTransferFrom(msg.sender, address(vault), amount); _vault.deposit(id, amount); }
idToBlockOfLastDeposit
is updated each time there is a deposit, the only requirement to call this function is by providing a valid NFT id. Since there is no minimum amount of deposited, which makes the cost of depositing extremely low.
When a malicious actor observes the withdraw action, they can immediately front the transaction by depositing 0 tokens to the correspond id, and make the transaction revert. To some extreme extend, this DoS can even make the entire vault dysfunctional as the only way to withdraw from the vaults is through the vault managers.
Manual review
Add a minimum deposit amount, or allow a minimum amount withdrawable for each id.
DoS
#0 - c4-pre-sort
2024-04-27T11:55:30Z
JustDravee marked the issue as duplicate of #489
#1 - c4-pre-sort
2024-04-29T09:31:30Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-05T20:41:18Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-05T20:42:04Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#4 - c4-judge
2024-05-05T20:45:37Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#5 - c4-judge
2024-05-05T21:55:18Z
koolexcrypto marked the issue as nullified
#6 - c4-judge
2024-05-05T21:55:22Z
koolexcrypto marked the issue as not nullified
#7 - c4-judge
2024-05-08T15:26:33Z
koolexcrypto marked the issue as duplicate of #1001
#8 - c4-judge
2024-05-11T19:48:44Z
koolexcrypto marked the issue as satisfactory
#9 - 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/4a987e536576139793a1c04690336d06c93fca90/src/core/Vault.kerosine.unbounded.sol#L50 https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/Vault.kerosine.sol#L60
The getKeroseneValue
or getUsdValue
function will potentially fail and revert if any of the Kerosine vaults are in the vaults list.
VaultManagerV2.getTotalUsdValue
computes the USD value in both Kerosine and non-Kerosine vaults altogether. In both functions, vault.getUsdValue(id);
is called to get single vault's price, in Kerosine vault, we can see the function is defined in Vault.kerosine.sol
:
function getUsdValue( uint id ) public view returns (uint) { return id2asset[id] * assetPrice() / 1e8; }
which calls assetPrice
, which is implemented in the child contracts. For example, in unbounded Kerosine vault:
function assetPrice() public view override returns (uint) { uint tvl; address[] memory vaults = kerosineManager.getVaults(); uint numberOfVaults = vaults.length; for (uint i = 0; i < numberOfVaults; i++) { Vault vault = Vault(vaults[i]); tvl += vault.asset().balanceOf(address(vault)) * vault.assetPrice() * 1e18 / (10**vault.asset().decimals()) / (10**vault.oracle().decimals()); } uint numerator = tvl - dyad.totalSupply(); uint denominator = kerosineDenominator.denominator(); return numerator * 1e8 / denominator; }
And we see, from all vaults in the KerosineManager
, assetPrice
of each vault is called, and combined with vault.asset
and vault.oracle
.
The issue is, in both bounded and unbounded Kerosine contracts, oracle
is not defined, and when other functions reference this variable, it will revert as the variable doesn't exsist in those contracts. This causes all functions which may potentially call Kerosine vault's assetPrice
function to revert. One example would be VaultManagerV2.liquidate
:
function liquidate( uint id, uint to ) external isValidDNft(id) isValidDNft(to) { uint cr = collatRatio(id); // ... snip
Where:
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); }
Which eventually calls assetPrice
.
Manual review
Add oracle variable in Kerosine contracts.
Context
#0 - c4-pre-sort
2024-04-27T18:11:51Z
JustDravee marked the issue as duplicate of #1048
#1 - c4-pre-sort
2024-04-28T18:38:31Z
JustDravee marked the issue as duplicate of #830
#2 - c4-pre-sort
2024-04-29T08:43:47Z
JustDravee marked the issue as sufficient quality report
#3 - c4-judge
2024-05-11T20:04:14Z
koolexcrypto marked the issue as satisfactory