Platform: Code4rena
Start Date: 07/08/2023
Pot Size: $36,500 USDC
Total HM: 11
Participants: 125
Period: 3 days
Judge: alcueca
Total Solo HM: 4
Id: 274
League: ETH
Rank: 89/125
Findings: 1
Award: $9.82
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: RED-LOTUS-REACH
Also found by: 0x3b, 0x4non, 0xCiphky, 0xDING99YA, 0xDetermination, 0xE1, 0xG0P1, 0xStalin, 0xWaitress, 0xbrett8571, 0xhacksmithh, 0xkazim, 0xmuxyz, 0xweb3boy, 14si2o_Flint, AlexCzm, Alhakista, Bube, Bughunter101, Deekshith99, Eeyore, Giorgio, HChang26, InAllHonesty, JP_Courses, KmanOfficial, MatricksDeCoder, Mike_Bello90, MrPotatoMagic, Naubit, QiuhaoLi, RHaO-sec, Raihan, Rolezn, SUPERMAN_I4G, Shubham, Silverskrrrt, Strausses, T1MOH, Topmark, Tripathi, Watermelon, _eperezok, aakansha, auditsea, audityourcontracts, ayden, carlos__alegre, castle_chain, cducrest, ch0bu, d23e, deadrxsezzz, deth, devival, erebus, fatherOfBlocks, halden, hassan-truscova, hpsb, hunter_w3b, imkapadia, immeas, jat, kaden, kaveyjoe, klau5, koxuan, kutugu, ladboy233, lanrebayode77, leasowillow, lsaudit, markus_ether, matrix_0wl, merlin, nemveer, ni8mare, nonseodion, oakcobalt, owadez, p_crypt0, pipidu83, piyushshukla, popular00, ppetrov, rjs, sandy, sl1, supervrijdag, tay054, thekmj, wahedtalash77, windhustler, zhaojie
9.8204 USDC - $9.82
There is a lack of a feature in the contract that allows for the pausing or stopping of certain functionalities in case of emergencies, such as the exploitation of a vulnerability by malicious actors, or regulatory requirements. In the case of an emergency or when an unknown vulnerability is discovered, this mechanism provides the ability to stop the contract from further operation thereby limiting potential damage.
claim()
[LendingLedger.sol]The claim()
function fails to handle the case where transferring the CANTO rewards fails (ref. to code). If such failure happens, the whole transaction is reverted. Using a low-level function like address.call()
can lead to problems. If the recipient contract doesnโt have a fallback function defined, consumes more than the 2300 gas (the stipend given to a fallback function when call.value()
is used) or throws an exception, the operation will fail and hence the whole transaction will revert.
To fix this problem, we should add some error handling code, such as : if (cantoToSend > 0) { try { (bool success, ) = msg.sender.call{value: cantoToSend}(""); require(success, "Failed to send CANTO"); } catch { // Handle the failure accordingly } }
Alternatively, a safer method for the value transfer such as the transfer()
function or the send()
function should be used instead of the call()
function.
sync_ledger()
[LendingLedger.sol]The function sync_ledger()
in this smart contract is vulnerable to an underflow attack (ref. 1 and ref. 2) in a very specific situation, for instance when the contract doesn't properly validate its inputs or there is a bug in the state of lendingMarketBalances
. The vulnerability is present when the number used to initialize the balance is larger than what int256 can hold (this would not occur in a standard behaviour of the contract, but it may happen because of a bug or other kind of failure). Let's set lendingMarketBalances[marketAddress][lenderAddress][currentEpoch]
to 1 plus the maximum positive value of an uint256, this would overflow in the casting and become negative. If _delta
is also a large negative number, an underflow occurs, and then updatedLenderBalance
becomes some extremely large positive (and unexpected) value greater than zero due to underflow. This would be also possible for updatedMarketBalance
, where the same require
statement is not sufficient.
withdraw()
[VotingEscrow.sol]The newLocked.delegated
is duplicated. With a correct functioning of the code logic newLocked.delegated
should be equal to 0 in any case.
delegate()
[VotingEscrow.sol]In the delegate(address _addr)
function, there is no sanity check to ensure that the address being delegated to is not the zero address, potentially leading to the loss of a user's voting power.
Transactions that contain some function calls such as withdraw()
, increaseAmount()
, delegate()
are vulnerable to transaction order dependency. If multiple transactions are sent by an user calling some of the different functions stated before, the miner of the block can change their order of execution and that can lead to unexpected results to the user, such as amounts delegation of higher or lower amounts. To fix this, nonces can be added to enforce that the transactions corresponding to a single user are executed in order.
The smart contract uses block.timestamp
to manage the timing of lock and unlock events. This could be manipulated by a miner to result in inaccurate timer setting. The miner has a certain degree of freedom in manipulating the block.timestamp (and effects can be noticeable in the change of a week, for instance, where the miner may choose if the timestamp corresponds to the previous or next week). In any case, this vulnerability may not be critically harmful as the degree of freedom is limited. As recommendation, we should avoid relying solely on block.timestamp for time-keeping, and instead use multiple sources, or rather the block number.
#0 - c4-judge
2023-08-22T13:40:58Z
alcueca marked the issue as grade-a