Ethena Labs - 0x_Scar'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: 140/147

Findings: 1

Award: $4.52

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-10-ethena/blob/ee67d9b542642c9757a6b826c82d0cae60256509/contracts/StakedUSDeV2.sol#L78-L121

Vulnerability details

Impact

For users to be able withdraw their staked tokens, they will have to wait for the cooldown period to end then be able to get their funds. Now, the cooldownAssets () and the cooldownShares () functions are used to start the cooldown period https://github.com/code-423n4/2023-10-ethena/blob/ee67d9b542642c9757a6b826c82d0cae60256509/contracts/StakedUSDeV2.sol#L95-L124.

Therefore, when a user calls the cooldownShares () or/and cooldownAssets (), their respective shares or assets is converted then the cooldownEnd for the user is set as cooldowns[owner].cooldownEnd = uint104(block.timestamp) + cooldownDuration; After this period has expired, the user can now call unstake () function which would effectively call the silo withdraw function and tokens would be sent to the user.

Now cooldownEnd is updated when every time the two functions cooldownShares and coolDownAssets is called meaning if these functions are called more than once the cooldownEnd period would be updated more than once. Consider the following scenario:

  1. Alice has staked 1000 Tokens and the cooldownDuration is set to 20 days and the cooldown period is on.
  2. On day 3, Alice calls coolDownAssets wanting to withdraw 400 Tokens.
  3. The coolDownAssets updates here cooldownEnd as follows cooldowns[owner].cooldownEnd = uint104(block.timestamp) + cooldownDuration; meaning she can now unstake her tokens on day 23.
  4. On day 10 she decides to withdraw all her remaining 600 Tokens
  5. She calls coolDownAssets function again which effectively updates her cooldownEnd as follows cooldowns[owner].cooldownEnd = uint104(block.timestamp) + cooldownDuration; subsequently setting here cooldownEnd period to day 30.
  6. After 23 days has elapsed, Alice thinks that here first 400 Token withdrawal has successfully completed the cooldown period and calls unstake () function. This call would fail as the coolDownEnd period was last updated on her last call to coolDownAssets pushing forward her coolDownEnd.
  7. In this case, Alice initial 400 Tokens, would be temporarily frozen in the contract until the period elapses.

With this it is clear that earlier user's cooldowns is overwritten by subsequent calls to coolDownAssets or/and coolDownShares leading to temporary freezing of earlier withdrawn amounts as the contract only uses the last updated cooldown period.

Proof of Concept

The following PoC, was created and added in the StakedUSDeV2.cooldownEnabled.t.sol file. The forge command run as forge test --match-test testTemporaryFreezeonRedeem -vvv to print to console and specifically that test.

function testTemporaryFreezeonRedeem() public { uint256 balBefore = usdeToken.balanceOf(alice); uint256 amount = 100 ether; _mintApproveDeposit(alice, amount); vm.startPrank(alice); uint256 halfShare = amount /2 ; stakedUSDe.cooldownShares(halfShare, alice); (uint104 cooldownEnd, uint256 usdeAmount) = stakedUSDe.cooldowns(alice); console.log("The cooldownEnd Period is [+]", cooldownEnd); vm.warp(50); // Another cooldownShares call to push the cooldownEnd further stakedUSDe.cooldownShares(halfShare, alice); (uint104 newcooldownEnd, uint256 newusdeAmount) = stakedUSDe.cooldowns(alice); // console to see the updated cooldown End period console.log("The cooldownEnd Period is [+]", newcooldownEnd); console.log("The old cooldownEnd is [--] %s and The new cooldownEnd is [++] %s", cooldownEnd, newcooldownEnd); vm.warp(cooldownEnd + 1); vm.expectRevert(); stakedUSDe.unstake(alice); }

Tools Used

Assessed type

Other

#0 - c4-pre-sort

2023-10-30T23:25:58Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-10-30T23:26:11Z

raymondfam marked the issue as duplicate of #4

#2 - c4-pre-sort

2023-11-01T19:36:17Z

raymondfam marked the issue as duplicate of #514

#3 - c4-judge

2023-11-10T21:27:01Z

fatherGoose1 marked the issue as unsatisfactory: Invalid

#4 - c4-judge

2023-11-17T17:04:09Z

fatherGoose1 changed the severity to QA (Quality Assurance)

#5 - c4-judge

2023-11-20T20:18:36Z

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