`LiquidInfrastructureERC20::distributeToAllHolders()` - Gas griefing combo DoS attack vector: Due to lack of access control and/or lack of throttling/frequency-limiting mechanisms, an attacker can repeatedly call this function manually or via mempool bots and DoS contract/protocol functionality.
Audit: 2024-02-althea-liquid-infrastructure-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/3adc34600561077ad4834ee9621060afd9026f06/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L161-L169
https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/3adc34600561077ad4834ee9621060afd9026f06/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L178
https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/3adc34600561077ad4834ee9621060afd9026f06/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L289


# Vulnerability details

An attacker can repeatedly call this function manually or via mempool bots (with higher gas prices if necessary) to effectively gobble up block gas limits quickly and thereby make it difficult for any other function calls to be included into current block during the ongoing attack, effectively DoS-ing any other contract/protocol functionalities for as long a the attack continues.

This attack will be more effective when the `holders` array length is large enough. However, due to the existing gas gobbling implementation of the `distribute()` function, `holders.length` doesn't need to be that large at all.

Should either add access control here so only owner can call this function, or implement mechanisms to throttle or limit the frequency at which this function can be called, to help mitigate this attack vector.
This should be the primary mitigation approach. Secondary measures would be to gas optimize the hell out of the `distribute()` function.

IMPACT:
- at best would cause unnecessary gas usage and fees when normal users unsuccessfully call this function when it reverts due to out of gas errors.
- at worst an attacker takes advantage of the gas guzzling nature of the function to reach block gas limit quickly and interfere with successful block inclusion of the `distribute()` function (or other function calls) when owner or normal user calls it directly with less holders to bypass out of gas errors.

Ideal scenario for attacker:
If the attacker repeatedly calls `distributeToAllHolders()` or `burnAndDistribute()` when the `holders.length` is too large for the function call to succeed before running out of gas, then the attacker could exploit this to guzzle up the block gas limit quickly, which would potentially prevent anyone from successfully calling the `distribute()` function directly where the `holders.length` value can be controlled, effectively DoS-ing critical distribution functionality of the contract, including any other function calls.

This DoS attack can keep going for as long as the attacker can maintain it, which could also DoS any attempts to change the `holders.length` value via onlyOwner function call `approveHolder()`.

Since the attacker can increase their gas price to prioritize their transactions over the contract owner's or normal users' function calls, ensuring that attacker's function calls are included first in the block(s), the attacker can a