DYAD - Sancybars'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: 43/183

Findings: 1

Award: $283.37

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
:robot:_97_group
duplicate-338

Awards

283.3687 USDC - $283.37

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/main/src%2Fcore%2FVaultManagerV2.sol#L230-L248

Vulnerability details

During liquidation the for loop iterated through the normal vault list only and not the keroseneVault list https://github.com/code-423n4/2024-04-dyad/blob/main/src%2Fcore%2FVaultManagerV2.sol#L34-L35

mapping (uint => EnumerableSet.AddressSet) internal vaults; 
  mapping (uint => EnumerableSet.AddressSet) internal vaultsKerosene; 

Because of this user's that hold enough kerosene token won't be liquated even if the users normal vault is undercollatralized.

Impact

Vaults will become undercollatralized.

Proof of Concept

Users become liquidatable when the value of their asset drops below 150% minimum collateral ratio the liquidator specifies the id being liquidated and to the address to recieve the liquidation profits. https://github.com/code-423n4/2024-04-dyad/blob/main/src%2Fcore%2FVaultManagerV2.sol#L205-L229

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;
      uint liquidationEquityShare = (cappedCr - 1e18).mulWadDown(LIQUIDATION_REWARD);
      uint liquidationAssetShare  = (liquidationEquityShare + 1e18).divWadDown(cappedCr);

      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 collateralRatio calls getTotalUsdValue to get the value of the vault being liquidated which is the total of the two distinct vaults vault and keroseneVault. https://github.com/code-423n4/2024-04-dyad/blob/main/src%2Fcore%2FVaultManagerV2.sol#L230-L248

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

Which is returned as the cr to be compared to the minimum collateral ratio.

uint cr = collatRatio(id);
      if (cr >= MIN_COLLATERIZATION_RATIO) revert CrTooHigh();

If the user being liquidated holds enough kerosene token of 150% against the minted dyad liquidation reverts. While the normal vault will remain undercollateralized.

Tools Used

Manual Review

Implement a way to liquidate kerosene tokens if the exo-collateral is not enough.

Assessed type

Context

#0 - c4-pre-sort

2024-04-28T10:21:48Z

JustDravee marked the issue as duplicate of #128

#1 - c4-pre-sort

2024-04-29T09:01:34Z

JustDravee marked the issue as sufficient quality report

#2 - c4-judge

2024-05-08T09:57:43Z

koolexcrypto marked the issue as not a duplicate

#3 - c4-judge

2024-05-08T09:57:49Z

koolexcrypto marked the issue as duplicate of #338

#4 - c4-judge

2024-05-11T12:20:31Z

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