CertiK reviewed PAAL AI (PAAL AI - Audit) on 4 Apr 2024: 9 findings, 0 critical; 6 marked fixed, 1 acknowledged, 2 open.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 1 | 0 |
| Medium | 0 | 0 | 3 |
| Low | 2 | 0 | 3 |
The "swapExactTokensForETH" function calculates the "actualReceived" amount by comparing the token balance in the contract before and after the swap, which is a correct and recommended way to obtain the "amountIn". However, the "swapExactTokensForTokens" function doesn't follow the same practice, which means the amountIn value could be off if the token is a special ERC20 token, such as a deflationary token.
The code utilizes `address(this)` when calculating the `initialBalance` and `afterBalance`. This logic is incorrect because the tokens are sent to the `sender` address. The current calculation will result in the `amountOut` becoming a zero value. ```sol uint256 initialBalance = tokenOutContract.balanceOf(address(this)); ... // Calculate the amount of tokenOut received uint256 afterBalance = tokenOutContract.balanceOf(address(this)); amountOut = afterBalance - initialBalance; ```
There are no upper boundaries for **swappingFee** which is used to **calculate the swap fee**. It is possible to set the total fee up to any arbitrary amount.
In the smart contract's event emission logic, there's an inconsistency observed in the representation of `amountIn` across different transaction types. Specifically, the `Buy` and `Sell` events emit the `amountIn` value before the deduction of any transaction fees. These events are structured as follows: - `event Buy(address indexed sender, uint256 amountIn, address indexed tokenOut, uint256 amountOut);` - `event Sell(address indexed sender, address indexed tokenIn, uint256 amountIn, uint256 amountOut);` In contrast, the `SellTokensForTokens` event uses `amountInAfterFee` instead of the gross `amountIn`: - `event SellTokensForTokens(address indexed sender, address indexed tokenIn, address indexed tokenOut, uint256 amountInAfterFee, uint256 amountOut);` This discrepancy leads to a lack of uniformity in how the input amounts are reported, potentially causing confusion when interpreting the events, especially for off-chain services and analyses that rely on these events for transaction data.
An inconsistency in the fee calculation methodology was identified. The functions `swapExactTokensForETH` and `swapExactETHForTokens` calculate the transaction fee using the formula `uint256 fee = (msg.value * swappingFee) / swappingFeeDivisior;`, which utilizes a dynamic fee rate determined by the `swappingFee` and `swappingFeeDivisior` variables. Conversely, the `swapExactTokenForToken` function employs a static fee calculation method: `uint256 fee = (amountIn * swappingFee) / 1000000;`, which effectively hardcodes the fee rate to a specific value, assumed to be 1% based on the comment.
In the `swapExactETHForTokens` function, the function "swapExactETHForTokensSupportingFeeOnTransferTokens" accepts the native token, such as ETH, instead of the wrapped version (e.g., WETH). Therefore, performing the approval operations is not necessary. ```sol // Approve the router to spend the tokens for the swap weth.safeApprove(address(router), amountIn); ```
| Address | Chain | Source code |
|---|---|---|
| 0xe737…a1720xe7373fdae34951426a579455ca24d7388a12a172 | Chain: Ethereum | Source code: Verified source |
| 0xd232…a8bc0xd2326e0b4ad26432da0eb94dc7890770ac11a8bc | Chain: Base | Source code: Verified source |
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us