DYAD - carlitox477's results

The first capital efficient overcollateralized stablecoin.

General Information

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

DYAD

Findings Distribution

Researcher Performance

Rank: 54/183

Findings: 2

Award: $224.23

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

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/script/deploy/Deploy.V2.s.sol#L93-L94 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L75 https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L88

Vulnerability details

Description

The idea of Kerosine manager is whitelisting/license vaults that are going to be consider to calculate Kerosine intrinsict value, while the idea of Licenser is whitelisting/licensing vaults that will be able to be considered exogenous collateral to mint DYAD.

However, this is not the way that they are used in VaultManagerV2. In this contract, considering that WETH and wstETH vaults are licensed by Licenser contract and Kerosine manager, the same balance associated to an NFT in these vault can be used twice to increase collateral ratio avoiding liquidation of undercollateralized vaults.

Impact

wstETH and WETH vault can be used twice to increase collateral ratio, avoiding liquidation of undercollateralize vaults

POC

  1. Bob has an DNFT, associate this NFT to wstETH vault through VaultManagerV2.add(BOB_NFT_ID,wstETH_VAULT).
  2. Bob now associate same NFT to wstETH vault through VaultManagerV2.addKerosene(BOB_NFT_ID,wstETH_VAULT). Given it is licensed by keroseneManager this function does not revert
  3. Bob deposit 100 USD value in wstETH to wstETH vault by calling VaultManagerV2.deposit(BOB_NFT_ID, wstETH_VAULT,USD_100_VALUE)
  4. Vault mint 99 DYAD by calling VaultManagerV2.mint(BOB_NFT_ID, wstETH_VAULT,99 * 10e18). given that collatRatio account for watETH balance twice the transaction does not revert

In addition Bob position cannot be liquidated until wstETH deposit value is reduced to 75 USD, which would leave the protocol totally undercollateralized. This become extremely dangerous in case of an abrupt crash of ETH or stETH price.

The idea of using kerosine manager to also add vault make no sense at all, it should be removed. To track Kerosine and non-Kerosine USD value simply iterate through vaults and check its assets to defien where to add it or not. Here a quick fix to current design, however consider it might also include other bugs. Use it as inspiration for a new contract

Assessed type

Other

#0 - c4-pre-sort

2024-04-29T05:19:07Z

JustDravee marked the issue as duplicate of #966

#1 - c4-pre-sort

2024-04-29T08:37:59Z

JustDravee marked the issue as sufficient quality report

#2 - c4-judge

2024-05-04T09:46:27Z

koolexcrypto marked the issue as unsatisfactory: Invalid

#3 - c4-judge

2024-05-28T15:28:38Z

koolexcrypto marked the issue as duplicate of #1133

#4 - c4-judge

2024-05-29T07:07:10Z

koolexcrypto marked the issue as satisfactory

Findings Information

🌟 Selected for report: SBSecurity

Also found by: AlexCzm, Emmanuel, Stefanov, carlitox477, carrotsmuggler, d3e4, grearlake, peanuts

Labels

bug
2 (Med Risk)
downgraded by judge
high quality report
satisfactory
:robot:_75_group
duplicate-982

Awards

223.9474 USDC - $223.95

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/cd48c684a58158de444b24854ffd8f07d046c31b/src/core/VaultManagerV2.sol#L217-L219

Vulnerability details

Description

According to docs, code walkthrough and sponsor private messages during contest liquidator should receive rewards for

min(20%,max(0,cr−100%))+100%max(cr,100%)\frac{min(20 \%, max(0, cr - 100\%)) + 100\%}{max(cr,100\%)}

DYAD liquidation specification

However this is not the case:

  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));

      uint cappedCr               = cr < 1e18 ? 1e18 : cr; //@audit max(cr,100%)
      uint liquidationEquityShare = (cappedCr - 1e18).mulWadDown(LIQUIDATION_REWARD); // @audit (max(cr,100%) - 100%) * 20% --> Excedent 20%
      uint liquidationAssetShare  = (liquidationEquityShare + 1e18).divWadDown(cappedCr); // @audit  ((max(cr,100%) - 100%) * 20% + 100%) / max(cr,100%) 

      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);
      }
      emit Liquidate(id, msg.sender, to);
  }

The actual reward for a liquidator is a 20% of the remaining associated to the NFT, not a 20% of the 100% collateral. This means that current rewards correspond to:

((max(cr,100%)−100%)×20%+100%)max(cr,100%)\frac{((max(cr,100\%) - 100\%) \times 20\% + 100\%)}{max(cr,100\%)}

Instead of the desired calculation

Impact

  • Liquidators have less incentive to liquidate undercollateralize NFT
  • Wrong liquidator reward calculation

min(20%,max(0,cr−100%))+100%max(cr,100%)\frac{min(20 \%, max(0, cr - 100\%)) + 100\%}{max(cr,100\%)}

Modify current codebase to match intended behaviour

//  VaultManagerV2.liquidate
    uint cappedCr               = cr < 1e18 ? 1e18 : cr; // max(cr,100%)
-   uint liquidationEquityShare = (cappedCr - 1e18).mulWadDown(LIQUIDATION_REWARD); // (max(cr,100%) - 100%) * 20% --> Excedent 20%
+   uint excedentRatio = cappedCr <= 1e18 ? 0 : cappedCr - 1e18;
+   uint liquidationEquityShare = excedentRatio < LIQUIDATION_REWARD ? excedentRatio : LIQUIDATION_REWARD;
    uint liquidationAssetShare  = (liquidationEquityShare + 1e18).divWadDown(cappedCr); 

Assessed type

Math

#0 - c4-pre-sort

2024-04-29T06:34:36Z

JustDravee marked the issue as duplicate of #906

#1 - c4-pre-sort

2024-04-29T08:46:38Z

JustDravee marked the issue as high quality report

#2 - c4-judge

2024-05-05T10:09:12Z

koolexcrypto marked the issue as not a duplicate

#3 - c4-judge

2024-05-05T10:13:57Z

koolexcrypto marked the issue as unsatisfactory: Invalid

#4 - carlitox477

2024-05-16T13:08:07Z

Dup of https://github.com/code-423n4/2024-04-dyad-findings/issues/75

The comment in the POC express (max(cr,100%) - 100%) * 20% --> Excedent 20% Given that the excedent can be at most 50%, is the same than saying that the rewards are capped to 10% of the total debt.

#5 - carlitox477

2024-05-16T14:54:13Z

On the other hand, I honestly think the impact is not fully considered. Capping rewards to 10% of excess collateral is not a good approach. For instance, if collateral goes down sharply to 120% with current implementation a liquidator is just incentivize with by 2% of rewards, leaving the other 18% to the borrower, if this 2% is not enough to cover gas is nonsense to execute the liquidation. I strongly suggest DYAD team to reconsider their decision of keeping current implementation. The suggested mitigation is easy to implement and cover the protocol of this risk, providing a better experience to liquidator and also provide better protection to lenders funds

#6 - c4-judge

2024-05-24T10:29:50Z

koolexcrypto removed the grade

#7 - c4-judge

2024-05-24T10:30:20Z

koolexcrypto marked the issue as duplicate of #75

#8 - c4-judge

2024-05-24T10:30:43Z

koolexcrypto changed the severity to 2 (Med Risk)

#9 - c4-judge

2024-05-28T19:22:08Z

koolexcrypto marked the issue as duplicate of #982

#10 - c4-judge

2024-05-29T11:23:58Z

koolexcrypto marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter