In the proposeExtraordinary function in the Funding contract. Specifically, in the following line: #L105
if (uint256(totalTokensRequested) > _getSliceOfTreasury(Maths.WAD - _getMinimumThresholdPercentage())) revert InvalidProposal();
If the totalTokensRequested parameter is greater than the available balance in the treasury, the _getSliceOfTreasury function will return a value that is less than totalTokensRequested, and the condition in the if statement will be true. As a result, the InvalidProposal() error will be thrown, which will prevent the proposal from being accepted.
However, this will not prevent a user from attempting to submit a proposal with a totalTokensRequested value greater than the available balance in the treasury, which could result in the loss of tokens and negatively impact the functioning of the contract. Therefore, the _getSliceOfTreasury function.
Proof of Concept
Alice would create a proposal with a totalTokensRequested value that is greater than the available balance in the treasury. She then convinces Bob to vote in favor of the proposal.
Alice would call the proposeExtraordinary function with the totalTokensRequested value that is greater than the available balance in the treasury.
if (uint256(totalTokensRequested) > _getSliceOfTreasury(Maths.WAD - _getMinimumThresholdPercentage())) revert InvalidProposal();
The _getSliceOfTreasury function determines the maximum number of tokens that can be withdrawn by the proposal from the treasury, based on the available balance and the minimum threshold percentage. If the totalTokensRequested value is greater than the maximum amount that can be withdrawn, the proposal will be rejected with the InvalidProposal error.
Once the proposal is approved and the tokens are transferred to the contract, the _getSliceOfTreasury function is called to determine the maximum number of tokens that can be withdrawn by the proposal.
Since the totalTokensRequested value is greater than the available balance in the treasury, the function returns a value that is less than the requested amount. However, the contract does not perform any further validation on the returned value and allows the proposal to withdraw the full requested amount.
Alice and Bob can then split the excess tokens between themselves, effectively stealing from the contract and negatively impacting its functioning.
Tools Used
Manual review, vscode
Recommended Mitigation Steps
The _getSliceOfTreasury function should be updated to handle cases where the totalTokensRequested parameter is greater than the available balance in the treasury by adding an additional check before calculating the slice of the treasury to ensure that the requested tokens are available for claiming from the treasury.
With this fix, the _getSliceOfTreasury function will now throw an error if the totalTokens parameter is greater than the available balance in the treasury, preventing any potential loss of funds and protecting the contract from attackers.
Lines of code
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L85-L124 https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L105
Vulnerability details
Impact
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L85-L124
In the proposeExtraordinary function in the Funding contract. Specifically, in the following line: #L105
If the
totalTokensRequested
parameter is greater than the available balance in the treasury, the_getSliceOfTreasury
function will return a value that is less thantotalTokensRequested
, and the condition in theif
statement will be true. As a result, theInvalidProposal()
error will be thrown, which will prevent the proposal from being accepted.However, this will not prevent a user from attempting to submit a proposal with a
totalTokensRequested
value greater than the available balance in the treasury, which could result in the loss of tokens and negatively impact the functioning of the contract. Therefore, the_getSliceOfTreasury
function.Proof of Concept
totalTokensRequested
value that is greater than the available balance in the treasury. She then convinces Bob to vote in favor of the proposal.Alice would call the
proposeExtraordinary
function with thetotalTokensRequested
value that is greater than the available balance in the treasury.The
_getSliceOfTreasury
function determines the maximum number of tokens that can be withdrawn by the proposal from the treasury, based on the available balance and the minimum threshold percentage. If thetotalTokensRequested
value is greater than the maximum amount that can be withdrawn, the proposal will be rejected with theInvalidProposal
error.Once the proposal is approved and the tokens are transferred to the contract, the _getSliceOfTreasury function is called to determine the maximum number of tokens that can be withdrawn by the proposal.
Since the totalTokensRequested value is greater than the available balance in the treasury, the function returns a value that is less than the requested amount. However, the contract does not perform any further validation on the returned value and allows the proposal to withdraw the full requested amount.
Alice and Bob can then split the excess tokens between themselves, effectively stealing from the contract and negatively impacting its functioning.
Tools Used
Manual review, vscode
Recommended Mitigation Steps
The
_getSliceOfTreasury
function should be updated to handle cases where thetotalTokensRequested
parameter is greater than the available balance in the treasury by adding an additional check before calculating the slice of the treasury to ensure that the requested tokens are available for claiming from the treasury.With this fix, the
_getSliceOfTreasury
function will now throw an error if thetotalTokens
parameter is greater than the available balance in the treasury, preventing any potential loss of funds and protecting the contract from attackers.Assessed type
Error