Skip to content

Instantly share code, notes, and snippets.

@SakshamGuruji3
Last active January 25, 2024 22:15
Show Gist options
  • Save SakshamGuruji3/f5418a6340e7ae766e406536ff0a58e4 to your computer and use it in GitHub Desktop.
Save SakshamGuruji3/f5418a6340e7ae766e406536ff0a58e4 to your computer and use it in GitHub Desktop.

PandAIEarn Security Re-Audit Report

1. Summary

PandAI Earn smart contract security re-audit report performed by Saksham.

2. In scope

https://github.com/pandai-corp/pandai-earn-sc/tree/main/contracts

3. Findings

3.1 setLpAddress Should be callable by updater role too

Severity : low

Description:

Since the updater should have the privilege to call state update functions , the function here https://github.com/pandai-corp/pandai-earn-sc/blob/main/contracts/PandAIEarnV1.sol#L170 should be also callable by UPDATER_ROLE instead of just DEFAULT_ADMIN , this hinders centralisation too.

3.2 Function depositWithReferral() does not check if the referralAddress Tier is initiated

Severity: low

Description

Based on the docs, the referral address (referralAddress) should be in Tier 1 or higher. The function depositWithReferral() does not check if the referralAddress has made an existing deposit and if a Tier is being assigned to the address. If the Tier is not yet initiated for the referralAddress is not allowed to collect the referral bonus locking out the bonus in the contract.

Consider adding checks to verify that the referralAddress Tier has already been initialized.

3.3 Claim should be called within depositWithReferral and requestWithdraw

Severity: medium

Description:

Eventhough the comments mentions the risk that rewards may be lost if claim is not called prior to calling depositWithReferral and requestWithdraw. Therefor pnding rewards should be stored (for exapmlple, in userMap[msg.sender].referralPendingReward or create separate variable) within these function at the beginning so that users never experience this loss in rewards. A user might not read carefully/neglect the guidlines/comments and hence lose rewards.

Users will loose interest in the project the moment they realise they have lost their rewards.

3.4 Flash loan Price Manipulation attack can Inflate/deflate the value of PandAI/USDT

Severity: medium

Description:

The function getPandaiWorthOf is used to calculate the Pandai worth per USDT, and is used in functions to calculate fee.

Since this function checks tokens balances of lpAddress it allows attaker to use flash loan price manipulation to pay very small fee.

For example, using intermidiate contract an attaker can:

1.) Use flash loan to drain tokens from one side (i.e. Pandai token) of LP pool 2.) Call PandAiEarn contract to claim or withdraw tokens. Now function getPandaiWorthOf returns very high price of Pandai tokens so attaker pay very small amount of fee. 3.) Returns flash loan.

This issue has medium severity because an attaker should pay fee for flash loan (depends on DEX it's 0.2%-0.3% of loan amount). So if pool has a lot of liquidity manipulation with price may cost more than pay normal Pandai fee.

Instead of relying on one pool for getting the swap price , it is always advisable to rely on multiple or something like chainlink. History have shown how catostrophic these attack can be.

Affected Code:

https://github.com/pandai-corp/pandai-earn-sc/blob/main/contracts/PandAIEarnV1.sol#L379

https://github.com/pandai-corp/pandai-earn-sc/blob/main/contracts/PandAIEarnV1.sol#L264

https://github.com/pandai-corp/pandai-earn-sc/blob/main/contracts/PandAIEarnV1.sol#L429

https://github.com/pandai-corp/pandai-earn-sc/blob/main/contracts/PandAIEarnV1.sol#L444

3.5 Struct packing not only limited to the Tier Struct

Severity: note

Description:

The team saved gas by packing together the variables in the Tier struct , but that was meant to be an example as every struct can have that optimization and can save gas in the multiples of 20,000.

All the pending reward variables can be made into uint128 as uint256 depicts a value that will bepractically not achieved , moreover all the timestamp variables can be packed in uint64 as timesatamps can be depicted in uint64 for many many upcoming years.

3.6 Owner Privileges

Description

1.) Contract PandAIEarn inherits the traits of OpenZeppelin AccessControl contract allowing admin to manage admin's, the role could be renounced leading to locking out of access to critical functions of the contract.

2.) Owner completely responisble to maintain an adequate balance on the contract for users' withdrawals and rewards payouts. Otherwise users' will not be able to withdraw or claim.

3.) Function setLpAddress() allows the admin to change the liquidity pool address to any wallet, the value of PandAi tokens would be affected which is computed using the function getPandaiWorthOf() based on the amount of USDT tokens and PandAi tokens available in newLpAddress wallet.

4.) Function withdrawTreasury() allows the admin to withdraw USDT tokens from the contract to the admin address.

5.) Function setUserApprovalLevel() allows admin to change the claim status of any wallet address to NotApproved, Approved, and Forbidden limiting the user's ability to withdraw or restrict a user from withdrawing USDT tokens deposited in the contract based on the approval status.

Recommendation:

Since the owner has unlimited rights to do everything, the ownership must be transferred to a multi-sig contract.

3.7 Follow good coding practice

1.) Unorganized and non-standardized docstrings The contracts in the code base contain unorganized and non-standardized docstring does not explain the contract's state and functionalities in detail. This hinders reviewers’ understanding of the code’s intention, which is fundamental to correctly assess not only security but also correctness. Additionally, detailed docstrings improve readability and ease maintenance. They should explicitly explain the purpose or intention of the functions, the scenarios under which they can fail, the roles allowed to call them, the values returned, and the events emitted.

Consider thoroughly documenting all functions (and their parameters) that are part of the contracts’ public API. Functions implementing sensitive functionality, even if not public, should be documented as well. When writing docstrings, consider following the Ethereum Natural Specification Format (NatSpec).

@yuriy77k
Copy link

3.2 Function depositWithReferral() does not check if the referralAddress Tier is initiated

It is not an issue. Doc was updated: https://docs.pandai.io/products/pandai-earn#referral-program

@yuriy77k
Copy link

3.3 Claim should be called within depositWithReferral and requestWithdraw

An issue was fixed. Pending rewards stores in userPendingReward variable

@yuriy77k
Copy link

3.4 Flash loan Price Manipulation attack can Inflate/deflate the value of PandAI/USDT

An issue was fixed. Flash loan attack is possible only if using an attacker contract. PandAIEarn disallows to use of contracts for depositing, withdrawing, and claiming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment