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: 13/183
Findings: 7
Award: $677.93
🌟 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/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L34 https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/script/deploy/Deploy.V2.s.sol#L95-L96 https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L67-L78 https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L250-L267
In order to determine the current collateral a user has, both values of the vaults and vaultsKerosene are added together. The issue we are facing here is that Kerosene vaults can be added to vault, essentially creating collateral that is 100% Kerosene based and doubled in value.
This will allow for borrowers to take undercollaterized positions.
In the deployment script and the video that the dev posted we can see a clear intent of licensing both kerosene vaults.
vaultLicenser.add(address(unboundedKerosineVault)); // vaultLicenser.add(address(boundedKerosineVault));
Since now both Kerosene vaults are licensed, this will allow anyone to add them in the vaults
mapping.
function add( uint id, address vault ) external isDNftOwner(id) { if (vaults[id].length() >= MAX_VAULTS) revert TooManyVaults(); @> if (!vaultLicenser.isLicensed(vault)) revert VaultNotLicensed(); if (!vaults[id].add(vault)) revert VaultAlreadyAdded(); emit Added(id, vault); }
This is will completely break the logic of the protocol since, getTotalUsdValue() will now calculate the value of kerosene + kerosene, allowing any users to not only get their collateral doubled, but also provide kerosene only(endogenous collateral) which is initially supposed to support 1/3 rd of the position maximum.
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; }
Manual review
The easiest way to mitigate this issue is to not license the kerosene vaults.
Invalid Validation
#0 - c4-pre-sort
2024-04-28T19:24:35Z
JustDravee marked the issue as duplicate of #966
#1 - c4-pre-sort
2024-04-29T08:37:17Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-04T09:46:23Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-29T11:19:59Z
koolexcrypto marked the issue as duplicate of #1133
#4 - c4-judge
2024-05-29T14:03:58Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: MrPotatoMagic
Also found by: 0xtankr, ArmedGoose, Egis_Security, Giorgio, KYP, Maroutis, NentoR, OMEN, Sabit, Shubham, SpicyMeatball, T1MOH, d3e4, dimulski, peanuts
200.8376 USDC - $200.84
In order to liquidate an undercollaterized position the liquidator must pay the borrower's minted DYAD. This means that the liquidator must have at least enough liquidity to cover the borrowed amount. If a whale decides to borrow 50 000 000 DYAD there might not be many people able to cover this much liquidity, hence the position becomes hardly liquidatable.
Huge positions can make the protocol become insolvent.
In the liquidate function we can see that we need to supply the borrowed amount of the liquidatee.
function liquidate( uint id, uint to ) . . . @> dyad.burn(id, msg.sender, dyad.mintedDyad(address(this), id));
But if some actors with immense amount of liquidity decide to deposit and borrow it will become very hard to liquidate them if their position doesn't satisfy the collateral ratio.
Manual review
Consider adding a limit to how much a user can borrow, 400 000 USD per NFT sounds reasonable.
function mintDyad( uint id, uint amount, address to ) external isDNftOwner(id) { uint newDyadMinted = dyad.mintedDyad(address(this), id) + amount; ++ if(newDyadMinted > 400_000 eth ) revert; if (getNonKeroseneValue(id) < newDyadMinted) revert NotEnoughExoCollat(); dyad.mint(id, to, amount); if (collatRatio(id) < MIN_COLLATERIZATION_RATIO) revert CrTooLow(); //@note which means can be 150 emit MintDyad(id, amount, to); }
Other
#0 - c4-pre-sort
2024-04-28T10:04:36Z
JustDravee marked the issue as duplicate of #1097
#1 - c4-pre-sort
2024-04-29T08:34:45Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T12:22:03Z
koolexcrypto marked the issue as satisfactory
#3 - c4-judge
2024-05-13T18:38:06Z
koolexcrypto changed the severity to 3 (High Risk)
🌟 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
https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L142-L143 https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L127
Whenever a deposit is made in the VaultManagerV2
the block.number is registered. Whenever a withdrawal is being processed the block.number is being checked and cannot be the same as the the one registered in the deposit()
, which means that deposit and withdrawal cannot happen in the same block for a user.
The issue at hand is that a user can be denied from withdrawing if a malicious actor frontruns the user's withdrawals and deposits 1 wei of assets in the user's vault.
Users will experience withdraw denial.
The deposit()
function will register when deposits are made into a vault.
function deposit( @> uint id, address vault, uint amount ) external isValidDNft(id) { @> idToBlockOfLastDeposit[id] = block.number;
And withdraw()als
revert when idToBlockOfLastDeposit[id] == block.number
function withdraw( uint id, address vault, uint amount, address to ) public isDNftOwner(id) { @> if (idToBlockOfLastDeposit[id] == block.number) revert DepositedInSameBlock();
This means that anyone can deposit one wei worth of assets in order to constantly front run the withdrawer whenever he fires a withdrawal transaction.
Attack scenario
Bob wants to attack Eve, he sets up a bot that frontruns any of Eve's withdrawal requests.
Eve withdraws. Bob's bot deposits. Eve transaction reverts. Eve is sad
In order to mitigate this issue consider adding a minimum deposit, this will make such attacks very costly, undoable.
function deposit( uint id, address vault, uint amount ) external isValidDNft(id) { + require(amount > minDepositAmount, "deposit too small");
DoS
#0 - c4-pre-sort
2024-04-27T12:01:33Z
JustDravee marked the issue as duplicate of #489
#1 - c4-pre-sort
2024-04-29T09:25:21Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-05T20:39:26Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-05T20:45:35Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#4 - c4-judge
2024-05-05T21:49:03Z
koolexcrypto marked the issue as nullified
#5 - c4-judge
2024-05-05T21:49:08Z
koolexcrypto marked the issue as not nullified
#6 - c4-judge
2024-05-08T15:26:44Z
koolexcrypto marked the issue as duplicate of #1001
#7 - c4-judge
2024-05-11T19:49:18Z
koolexcrypto marked the issue as satisfactory
#8 - c4-judge
2024-05-13T18:34:30Z
koolexcrypto changed the severity to 3 (High Risk)
🌟 Selected for report: 0xAlix2
Also found by: 0x486776, 0xabhay, 0xlucky, 0xtankr, Abdessamed, Circolors, CodeWasp, DarkTower, Egis_Security, Giorgio, Infect3d, Krace, KupiaSec, Limbooo, Maroutis, NentoR, Ryonen, SpicyMeatball, T1MOH, TheFabled, TheSavageTeddy, TheSchnilch, VAD37, XDZIBECX, btk, carrotsmuggler, cu5t0mpeo, dimulski, gumgumzum, iamandreiski, imare, itsabinashb, ke1caM, kennedy1030, lian886, n4nika, oakcobalt, sashik_eth, shaflow2, steadyman, web3km, windhustler, zhaojohnson
3.8221 USDC - $3.82
The price of $kerosene
is determined by the several factors, such as the tvl - borrowed assets and circulating supply of kerosene. The issue here is that if the tvl happens to be lower than the total borrowed amount, minor insolvency, the kerosene price function will revert, locking the whole protocol.
The protocol will suffer DOS for any calls to withdraw()
, mintDyad()
and liquidate()
. Given that positions sinking the boat are not liquidatable the impact will be severe.
The issue at hand stems from the UnboundedKerosineVault::assetPrice.
//UnboundedKerosineVault.sol //assetPrice() @> uint numerator = tvl - dyad.totalSupply(); uint denominator = kerosineDenominator.denominator(); // e18 return numerator * 1e8 / denominator;
Here above we can see that the numerator is calculated by subtracting the total borrowed assets from the tvl.
Since the protocol only allows to borrow assets if the collaterization ratio of the borrower is >= to 150%, tvl - dyad.totalSupply()
might appear as always > 0. However this might not be the case if the value the collateral asset crashes abruptly, in this situation the liquidators might no be able to liquidate the positions in time due to the chain being clogged and hardly usable.
When the protocol becomes insolvent, the assetPrice() function will revert, causing all the related functions that rely on assetPrice() to also revert, leading to dos.
The assetPrice() is called in the
getUsdValue function
function getUsdValue( uint id ) public view returns (uint) { @> return id2asset[id] * assetPrice() / 1e8; }
The get getUsdValue()
is being called in getKeroseneValue, which is being called in getTotalUsdValue and then getTotalUsdValue is being called in collatRatio.
So every function that relies on collatRatio()
will revert if the protocol happens to be insolvent. The concerned functions are withdraw(), mintDyad() and liquidate().
In case the protocol becomes momentarily it is important to keep the assetPrice()
from reverting, this will allow the protocol to be able to liquidate insolvent positions.
This can be done as such :
+ if(dyad.totalSupply() >= tvl) return 0; uint numerator = tvl - dyad.totalSupply(); uint denominator = kerosineDenominator.denominator(); return numerator * 1e8 / denominator;
Invalid Validation
#0 - c4-pre-sort
2024-04-28T17:11:23Z
JustDravee marked the issue as duplicate of #415
#1 - c4-pre-sort
2024-04-29T09:31:20Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-05T11:02:13Z
koolexcrypto marked the issue as duplicate of #308
#3 - c4-judge
2024-05-11T20:08:38Z
koolexcrypto marked the issue as satisfactory
#4 - c4-judge
2024-05-13T18:34:04Z
koolexcrypto changed the severity to 3 (High Risk)
🌟 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
During the liquidation process, assets get transferred to the liquidator. But the kerosene assets are not being transferred.
The liquidator expects to receive kerosene assets, liquidator may not be able to cover the liquidated position. Liquidation incentive decreases. Protocol accumulates bad debt. DYAD peg is lost.
To confirm this vulnerability we just have to look at the liquidate function.
//VaultManagerV2 function liquidate() { . . . 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); }
As we can clearly see, the rewarding process only loops through the vaults
mapping, however vaultsKerosene also holds rewards to be moved.
Manual review
Add a loop to liquidate kerosene vaults as well.
uint 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); }
Invalid Validation
#0 - c4-pre-sort
2024-04-28T10:25:25Z
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-11T19:39:50Z
koolexcrypto marked the issue as satisfactory
460.7972 USDC - $460.80
When borrowers deposit Kerosene tokens into the KeroseneBoundedVault, the deposited tokens become illiquid, rendering them non-withdrawable. Consequently, the restricted Kerosene tokens doubles in value. Allowing for the borrower to borrow more with the same amount of Kerosene. The issue is when this borrow position is at risk of liquidation due to insufficient collateral, the kerosene liquidated will be bought at two fold the normal price.
Liquidators earn less rewards, because in the bounded kerosene is just inflated kerosene. Resulting in a decreased liquidation incentive.
In order to liquidate a borrower position, the liquidator has to buy the borrower's loan.
dyad.burn(id, msg.sender, dyad.mintedDyad(address(this), id));
The liquidattions process will go through every vault, and transfer the amount amount to the liquidator.
//VaultManagerV2.sol 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); }
However since the Kerosene
in the bounded Kerosene vault is inflated,
//BoundedKerosineVault function assetPrice() public view override returns (uint) { return unboundedKerosineVault.assetPrice() * 2; }
Let's have a quick look at the graph below.
https://www.desmos.com/calculator/nklmpzug4g
In the best case scenario, the liquidator is able to earn 10% of liquidated assets as a reward.
Let's consider a postion that has 99 USD
worth of wETH
and 50 USD
worth of bounded Kerosene
.
This position initially borrowed 100 DYAD and is now being liquidated. In a normal setting the liquidator should be able to receive 15 USD worth of assets as a reward.
10 % 149 = 15 (div up).
But since the bounded kerosene value is inflated, the liquidator will earn less rewards, 12 USD
.
10 % 12
This results in 20 % expected reward decrease for the liquidator which is quite considerable, this assumes an example where Kerosene accounts 1/3 rd of the collateral. But when liquidated position could represent higher amounts of bounded kerosene and thus even greater reward decrease.
Manual review
To mitigate this issue consider normalizing the inflated Kerosene before transferring it to the liquidator.
A simple fix would be to simply move all the bounded Kerosene to the liquidator.
for (uint i = 0; i < numberOfVaults; i++) { ++ if(vault == boundedKerosine) { vault.move(id, to, vault.id2asset(id)); continue; } Vault vault = Vault(vaults[id].at(i)); uint collateral = vault.id2asset(id).mulWadUp(liquidationAssetShare); vault.move(id, to, collateral); }
Other more precise solution might require more calculation.
Other
#0 - c4-pre-sort
2024-04-28T10:18:30Z
JustDravee marked the issue as duplicate of #128
#1 - c4-pre-sort
2024-04-29T09:03:35Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T19:39:40Z
koolexcrypto marked the issue as satisfactory
#3 - c4-judge
2024-05-13T18:40:17Z
koolexcrypto changed the severity to 3 (High Risk)
#4 - GiorgioDalla
2024-05-16T15:52:18Z
This issue appears to be wrongly duped, it is similar to #343 which is also wrongly duped for now. Thank you for your consideration
#5 - koolexcrypto
2024-05-23T10:56:59Z
Hi @GiorgioDalla
Thank you for your feedback. yes, wrongly duped.
#6 - c4-judge
2024-05-23T10:57:05Z
koolexcrypto marked the issue as not a duplicate
#7 - c4-judge
2024-05-28T16:59:23Z
koolexcrypto marked the issue as duplicate of #343
#8 - c4-judge
2024-05-28T17:47:09Z
koolexcrypto changed the severity to 2 (Med Risk)
🌟 Selected for report: dimulski
Also found by: 0xleadwizard, 0xlemon, Aamir, Al-Qa-qa, AvantGard, Bauchibred, Cryptor, DarkTower, Egis_Security, Giorgio, Maroutis, MrPotatoMagic, OMEN, Ocean_Sky, Ryonen, SBSecurity, Sabit, SpicyMeatball, Stefanov, T1MOH, Tigerfrake, WildSniper, atoko, bhilare_, darksnow, fandonov, grearlake, iamandreiski, igdbase, pontifex, web3km, xiao
4.8719 USDC - $4.87
To initiate a liquidation, the protocol requires the liquidator to repay the outstanding debt (borrowed amount) of the undercollateralized position(>150%). In return, the liquidator receives a bonus up to <10% of the liquidated position collateral. The current issue that the protocol faces is that there is no incentive to liquidate positions that that are at 100% or below.
Insolvent position don't get liquidated, the protocol accumulates bad debt, the protocol might end up losing its peg.
The graph below describes the relation between the liquidation reward to collateral ratio.
https://www.desmos.com/calculator/fchm6grwwt
We can observe that as the collateralization ratio approaches one, the incentive for liquidators diminishes. Once the collateralization ratio reaches exactly one, liquidators would not earn any rewards, and they may even incur losses due to gas transaction costs. While liquidators can potentially earn up to >10% of the liquidated position as a reward, this incentive becomes less attractive when the collateralization ratio nears one. In such cases, considering the gas costs involved and the possibility of earning only a small amount of bounded and illiquid tokens like Kerosene, liquidating positions with a collateralization ratio close to one becomes unappealing for liquidators.
//VMV2.sol //liquidate() uint cappedCr = cr < 1e18 ? 1e18 : cr; // cappedCr >= 1 uint liquidationEquityShare = (cappedCr - 1e18).mulWadDown(LIQUIDATION_REWARD); // cappedCr - 1 * 0.2 uint liquidationAssetShare = (liquidationEquityShare + 1e18).divWadDown(cappedCr); // ((cappedCr - 1 * 0.2) + 1) / cappedCr . . . uint collateral = vault.id2asset(id).mulWadUp(liquidationAssetShare); // collateral * ((cappedCr - 1 * 0.2) + 1) / cappedCr)
In case an asset value plunges abruptly, which is infrequent but may occur in crypto, and the position becomes undercollateralized before a liquidator has a chance to liquidate it due to chain congestion or other factors, the undercollateralized position may not be liquidated. This will bring bad debt upon the protocol.
desmos
Consider adding a fixed liquidation reward for when the position cr is below 1.01e18. A fixed amount of kerosene could be sent to the liquidator instead of having the liquidator repay for the position, to at least cover gas costs and incentivize the termination of insolvent positions.
Other
#0 - c4-pre-sort
2024-04-27T17:35:12Z
JustDravee marked the issue as duplicate of #1258
#1 - c4-pre-sort
2024-04-29T09:16:46Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-03T14:07:47Z
koolexcrypto changed the severity to QA (Quality Assurance)
#3 - c4-judge
2024-05-12T09:32:16Z
koolexcrypto marked the issue as grade-b
#4 - c4-judge
2024-05-12T09:32:28Z
koolexcrypto marked the issue as grade-c
#5 - c4-judge
2024-05-22T14:26:06Z
This previously downgraded issue has been upgraded by koolexcrypto
#6 - c4-judge
2024-05-28T16:51:33Z
koolexcrypto marked the issue as satisfactory
#7 - c4-judge
2024-05-28T20:06:01Z
koolexcrypto marked the issue as duplicate of #175
🌟 Selected for report: dimulski
Also found by: 0xleadwizard, 0xlemon, Aamir, Al-Qa-qa, AvantGard, Bauchibred, Cryptor, DarkTower, Egis_Security, Giorgio, Maroutis, MrPotatoMagic, OMEN, Ocean_Sky, Ryonen, SBSecurity, Sabit, SpicyMeatball, Stefanov, T1MOH, Tigerfrake, WildSniper, atoko, bhilare_, darksnow, fandonov, grearlake, iamandreiski, igdbase, pontifex, web3km, xiao
4.8719 USDC - $4.87
When a borrow position's collateral ratio falls below 150%, it becomes subject to liquidation. Liquidation of positions with a cr between [100% and 150%[ will at most earn <10% of the collateral, this will not be enough to cover the mainnet gas costs for liquidation of a small borrow postion of 1 USD, hence the protocol will accumulate bad debt.
There is no incentive to liquidate small positions when they become undercollaterized. This means that the protocol will accumulate bad debt, if the protocol accumulate too much bad debt it may become insolvent, and the stable coin will lose its peg.
If we take a look at the mintDyad
function mintDyad( uint id, uint amount, address to ) external isDNftOwner(id) { uint newDyadMinted = dyad.mintedDyad(address(this), id) + amount; if (getNonKeroseneValue(id) < newDyadMinted) revert NotEnoughExoCollat(); dyad.mint(id, to, amount); if (collatRatio(id) < MIN_COLLATERIZATION_RATIO) revert CrTooLow(); emit MintDyad(id, amount, to); }
We can see that there is not min borrow amount, small undercollaterized can thus be accumulated. Since gas cost can be relatively high on mainnet, these positions will remain unliquidated. They are still technically liquidatable but at a loss that no liquidator will take.
Manual review
In order to mitigate this issue, consider adding a minimum borrow position, could be 100 usd for example.
Here's how to implement this fix:
function mintDyad( uint id, uint amount, address to ) external isDNftOwner(id) { uint newDyadMinted = dyad.mintedDyad(address(this), id) + amount; ++ require(newDyadMinted >= 100e18, "Borrow more"); if (getNonKeroseneValue(id) < newDyadMinted) revert NotEnoughExoCollat(); dyad.mint(id, to, amount); if (collatRatio(id) < MIN_COLLATERIZATION_RATIO) revert CrTooLow(); emit MintDyad(id, amount, to); }
Don't forget to modify the redeem function as well.
++ function isAbove100(uint id) returns(bool) { ++ if(dyad.mintedDyad(address(this), id) < 100e18 && dyad.mintedDyad(address(this), id) != 0) return false; ++ return true; } function redeemDyad( uint id, address vault, //@note I can chose the vault .. uint amount, address to ) external isDNftOwner(id) returns (uint) { dyad.burn(id, msg.sender, amount); ++ if(!isAbove100(id)) revert; Vault _vault = Vault(vault); uint asset = amount * (10**(_vault.oracle().decimals() + _vault.asset().decimals())) / _vault.assetPrice() / 1e18; withdraw(id, vault, asset, to); emit RedeemDyad(id, vault, amount, to); return asset; } function liquidate( uint id, uint to ) external isValidDNft(id) isValidDNft(to) { uint cr = collatRatio(id); if (cr >= MIN_COLLATERIZATION_RATIO) revert CrTooHigh(); dyad.burn(id, msg.sender, dyad.mintedDyad(address(this), id)); ++ if(!isAbove100(id)) revert; . . . function burnDyad( uint id, uint amount ) external isValidDNft(id) { dyad.burn(id, msg.sender, amount); ++ if(!isAbove100(id)) revert; emit BurnDyad(id, amount, msg.sender); }
Other
#0 - c4-pre-sort
2024-04-27T13:31:16Z
JustDravee marked the issue as duplicate of #1258
#1 - c4-pre-sort
2024-04-29T09:16:48Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-03T14:07:47Z
koolexcrypto changed the severity to QA (Quality Assurance)
#3 - c4-judge
2024-05-12T09:32:36Z
koolexcrypto marked the issue as grade-c
#4 - c4-judge
2024-05-22T14:26:07Z
This previously downgraded issue has been upgraded by koolexcrypto
#5 - c4-judge
2024-05-28T16:51:36Z
koolexcrypto marked the issue as satisfactory
#6 - c4-judge
2024-05-28T20:06:02Z
koolexcrypto marked the issue as duplicate of #175