Ethena Labs - ayden's results

Enabling The Internet Bond

General Information

Platform: Code4rena

Start Date: 24/10/2023

Pot Size: $36,500 USDC

Total HM: 4

Participants: 147

Period: 6 days

Judge: 0xDjango

Id: 299

League: ETH

Ethena Labs

Findings Distribution

Researcher Performance

Rank: 10/147

Findings: 2

Award: $681.07

QA:
grade-b

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

Labels

bug
2 (Med Risk)
downgraded by judge
primary issue
satisfactory
selected for report
sufficient quality report
M-04

Awards

676.5498 USDC - $676.55

External Links

Lines of code

https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/StakedUSDe.sol#L191#L194

Vulnerability details

Impact

Malicious users can transfer USDe token to StakedUSDe protocol directly lead to a denial of service (DoS) for StakedUSDe due to the limit shares check .

Proof of Concept

User deposit USDe token to StakedUSDe protocol to get share via invoke external deposit function. Let's see how share is calculate :

    function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) {
        return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);
    }

Since decimalsOffset() == 0 and totalAssets equal the balance of USDe in this protocol

    function totalAssets() public view virtual override returns (uint256) {
        return _asset.balanceOf(address(this));
    }
f(share)=(USDeAmountβˆ—totalSupply)/(totalUSDeAssets()+1) f(share) = (USDeAmount * totalSupply) / (totalUSDeAssets() + 1)

The minimum share is set to 1 ether。

  uint256 private constant MIN_SHARES = 1 ether;

Assuming malicious users transfer 1 ether of USDe into the protocol and receive ZERO shares, how much tokens does the next user need to pay if they want to exceed the minimum share limit of 1 ether? That would be 1 ether times 1 ether, which is a substantial amount.

I add a test case in StakedUSDe.t.sol:

  function testMinSharesViolation() public {
    address malicious = vm.addr(100);

    usdeToken.mint(malicious, 1 ether);
    usdeToken.mint(alice, 1000 ether);

    //assume malicious user deposit 1 ether into protocol.
    vm.startPrank(malicious);
    usdeToken.transfer(address(stakedUSDe), 1 ether);

    
    vm.stopPrank();
    vm.startPrank(alice);
    usdeToken.approve(address(stakedUSDe), type(uint256).max);

    //1000 ether can't exceed the minimum share limit of 1 ether
    vm.expectRevert(IStakedUSDe.MinSharesViolation.selector);
    stakedUSDe.deposit(1000 ether, alice);
  }

We can see even alice deposit a substantial number of tokens but still cannot surpass the 1 ether share limit which will lead to a denial of service (DoS) for StakedUSDe due to MinShares checks

Tools Used

vscode

We can solve this issue by setting a minimum deposit amount

Assessed type

DoS

#0 - c4-pre-sort

2023-10-31T01:48:34Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-10-31T01:48:52Z

raymondfam marked the issue as duplicate of #32

#2 - c4-judge

2023-11-10T20:52:18Z

fatherGoose1 changed the severity to 2 (Med Risk)

#3 - c4-judge

2023-11-10T20:58:07Z

fatherGoose1 marked the issue as satisfactory

#4 - c4-judge

2023-11-14T17:17:07Z

fatherGoose1 marked the issue as selected for report

#5 - fatherGoose1

2023-11-14T17:17:29Z

Solid and succinct report providing an easy-to-understand POC.

#6 - k4zanmalay

2023-11-17T07:12:21Z

Hey @fatherGoose1! In light of this sponsor's comment https://github.com/code-423n4/2023-10-ethena-findings/issues/90#issuecomment-1815520156, will this issue be invalidated too? If there will be prestaked MIN_SHARES amount, _checkMinShares() will never revert, to be honest it can be completely omitted at this point.

#7 - fatherGoose1

2023-11-27T20:36:49Z

Despite the sponsor claiming that they will personally stake MIN_SHARES, that cannot be verified via the code. This will remain a medium.

1.should use EIP-1271 Standard Signature Validation Method for Contracts Standard way to verify a signature when the account is a smart contract https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/EthenaMinting.sol#L342 Recommend to use EIP-1271 Standard to verify a signature when the account is a smart contract

2.unnecessary bitwise or opration https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/EthenaMinting.sol#L394 If invalidator not it zero transaction must be revert in verifyNonce , thus invalidator == 0 , The bitwise OR operation with 0 on any number always results in the same number, so the OR operation is unnecessary

3.unnecessary addition operation If the result of getUnvestedAmount is bigger than zero the transaction must be revert. So blow addition operation is unnecessary result in waste of gas https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/StakedUSDe.sol#L91

4.unstake not checked the unstake amount lead to waste of gas fee. https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/StakedUSDeV2.sol#L78#L90 user can invoke unstake directly without invoking cooldown.Since userCooldown.cooldownEnd ==0 , silo will withdraw zero amount assets which can lead to waste of gas fee.

-   if (block.timestamp >= userCooldown.cooldownEnd) { //@audit should ensure >0.
+   if (block.timestamp >= userCooldown.cooldownEnd && userCooldown.underlyingAmount>0) { 
      userCooldown.cooldownEnd = 0;
      userCooldown.underlyingAmount = 0;

      silo.withdraw(receiver, assets);
    } else {
      revert InvalidCooldown();
    }

#0 - c4-pre-sort

2023-11-02T03:34:46Z

raymondfam marked the issue as sufficient quality report

#1 - c4-judge

2023-11-14T16:45:23Z

fatherGoose1 marked the issue as grade-b

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