Platform: Code4rena
Start Date: 29/03/2022
Pot Size: $50,000 USDC
Total HM: 16
Participants: 42
Period: 5 days
Judge: 0xean
Total Solo HM: 9
Id: 105
League: ETH
Rank: 17/42
Findings: 3
Award: $723.29
π Selected for report: 0
π Solo Findings: 0
π Selected for report: IllIllI
Also found by: 0xDjango, csanuragjain
560.4852 USDC - $560.49
By design, a user's cooldown period is extended if they receive a transfer of hPal. The cooldown is extended based on the weight of the receiver's original balance and cooldown period compared to the sent amount and sender's cooldown period. Due to this mechanic, a malicious but generous user can indefinitely freeze the funds of another user by continuously extending the receiver's cooldown period, disabling them from unstaking.
In the most extreme case, it is possible that Pal can have negative price action in the period while the funds are frozen such that the user will be losing value despite accruing more hPal. Disregarding negative price action, having a user's funds frozen based on the authority of others would not be desired.
10 Pal
and receives 10 hPal
cooldown()
and waits 9 days, making his remaining cooldown period equal 1 day
10 Pal
, receives 10 hPal
and starts their cooldown()
10 hPal
to User A.cooldown period = 5.5 days
based on the following formula.((amount * _senderCooldown) + (receiverBalance * receiverCooldown)) / (amount + receiverBalance);
With values:
((10 hPal * 10 days) + (10 hPal * 1 day)) / (10 hPal + 10 hPal) = 5.5 days
Manual review
Understanding that this is a mechanism to combat users transferring funds between their own accounts to work around the cooldown system, I recommend adding an acceptTransfer()
function. This function will allow the receiver to accept the sent funds and resulting new cooldown period.
#0 - Kogaroshi
2022-04-02T15:41:21Z
This behavior is wanted in the token design. Any implementation of a acceptTransfer() or any similar design will remove the ability of the hPAL token to be compatible with the ERC20 design, which is not something desired for that token.
And as shown in the example, to effectively have an impact on the cooldown of another user through a transfer, it would require an important amount of token (100% of the balance to push back to 5 days out of 10 days cooldown if the target cooldown is about to be reached), which is the desired logic to reduce this kind of scenario
(for a live example, this system is taken from the stkAave system, where that type of scenario is rarely seen)
#1 - 0xean
2022-04-08T00:17:18Z
Downgrading to Medium based on the fact that there does an exist an attack vector, albeit an expensive one.
2 β Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements.
I think this falls into the hypothetical attack path with external requirements and therefore is a Med.
#2 - 0xean
2022-04-11T12:36:40Z
duplicate of #69
π Selected for report: IllIllI
Also found by: 0v3rf10w, 0xDjango, 0xkatana, 0xmint, Czar102, Dravee, Funen, Ruhum, TerrierLover, defsec, gzeon, hake, hyh, jah, kenta, minhquanym, okkothejawa, pmerkleplant, rayn, reassor, robee, sorrynotsorry, sseefried, teryanarmen
111.355 USDC - $111.35
In the constructor for HolyPaladinToken.sol
, the rewardsVault
is set without requiring that the address not be 0. All other addresses in the constructor are properly verified. Moreover, rewardsVault
is immutable, so the contract would need to be redeployed.
Both files contain a floating pragma. It is recommended to specify a compiler version to reduce the risk of deploying contracts with different versions, potentially leading to compiler-specific bugs.
OpenZeppelin has marked this function as deprecated and recommends using safeIncreaseAllowance()
. See following comments:
Repeated emergency checks can be made a modifier to reduce code duplication.
#0 - Kogaroshi
2022-04-03T06:54:00Z
QA & gas optimizations changes are done in the PR: https://github.com/PaladinFinance/Paladin-Tokenomics/pull/6 (some changes/tips were implemented, others are noted but won't be applied)
π Selected for report: TerrierLover
Also found by: 0v3rf10w, 0xDjango, 0xNazgul, 0xkatana, 0xmint, Cityscape, Czar102, Dravee, Funen, IllIllI, Tomio, antonttc, defsec, gzeon, hake, kenta, minhquanym, pmerkleplant, rayn, rfa, robee, saian, securerodd, teryanarmen
51.4511 USDC - $51.45
In the following code, the second block.timestamp
require statement is more exclusive than the first, making the first redundant.
#0 - Kogaroshi
2022-04-02T15:42:58Z
This is wanted, to allow the user (or the devs) to know why the Lock could not be kicked, based on the current timestamp.