Platform: Code4rena
Start Date: 13/02/2024
Pot Size: $24,500 USDC
Total HM: 5
Participants: 84
Period: 6 days
Judge: 0xA5DF
Id: 331
League: ETH
Rank: 55/84
Findings: 1
Award: $25.73
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: nuthan2x
Also found by: 0x0bserver, AM, CaeraDenoir, DanielArmstrong, JrNet, Kirkeelee, KmanOfficial, Krace, Limbooo, Meera, SovaSlava, SpicyMeatball, TheSavageTeddy, agadzhalov, aslanbek, atoko, csanuragjain, d3e4, imare, jesjupyter, juancito, kartik_giri_47538, kutugu, max10afternoon, offside0011, pkqs90, turvy_fuzz, xchen1130, zhaojohnson, ziyou-
25.7286 USDC - $25.73
https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L441-L445 https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L214-L231
The revenue distribution process can be permanently disrupted.
It is important to note that the distribute(uint256 numDistributions)
function is publicly accessible and can be called by anyone, at any time. This function has the ability to set the LiquidInfrastructureERC20 contract into Distribution Lock Mode by setting the LockedForDistribution
variable to true
. In the Distribution Lock Mode, the majority of the contract's functions are disabled, and users are unable to transfer LiquidInfrastructureERC20 tokens.
Most of the function will check whether the contract is under Distribution Lock Mode at the very begining, but one important function setDistributableERC20s(address[] memory _distributableERC20s)
which is only callable by contract owner does not check that. The setDistributableERC20s()
function set a very important vaiable distributableERC20s
. It is used in the revenue distribution process as well.
File: LiquidInfrastructureERC20.sol 441: function setDistributableERC20s( 442: address[] memory _distributableERC20s 443: ) public onlyOwner { 444: distributableERC20s = _distributableERC20s; 445: }
Suppose there are currently 10 holders. By calling distribute(x)
, (1 <= x <= 9), anyone can set the LiquidInfrastructureERC20 contract in a Distribution Lock Mode. After that, if the unconscious contract owner call the setDistributableERC20s()
function and setting distributableERC20s
to a new array, the whole revenue distribution process is tampered, while the contract is still in a Distribution Lock Mode.
It is crucial to recognize that a malicious and well-prepared hacker can monitor the transaction mempool and front-run the owner's transaction that calls the setDistributableERC20s function. Consequently, if the transaction is front-run, the setDistributableERC20s call becomes highly dangerous.
Audit
Add check for LockedForDistribution before reassigning distributableERC20s
.
function setDistributableERC20s( address[] memory _distributableERC20s ) public onlyOwner { + require(!LockedForDistribution); distributableERC20s = _distributableERC20s; }
Side note: Instead of proactively sending back the revenue to the holders, the LiquidInfrastructureERC20 token developers can consider doing ledger in the LiquidInfrastructureERC20 and wait for holder to withdrawal.
Invalid Validation
#0 - c4-pre-sort
2024-02-20T04:17:13Z
0xRobocop marked the issue as duplicate of #151
#1 - c4-pre-sort
2024-02-20T04:38:34Z
0xRobocop marked the issue as duplicate of #260
#2 - c4-judge
2024-03-04T15:16:53Z
0xA5DF marked the issue as satisfactory
#3 - c4-judge
2024-03-08T15:26:18Z
0xA5DF changed the severity to 2 (Med Risk)