As of 3 Nov 2026, Fists has 1 audit report on Trustblock, by CertiK, dated 28 May 2024. That report lists no open critical findings. It also holds 1 deployed contract on 1 chain.
Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.
Newest first
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 6 | 0 | 4 |
| Medium | 6 | 0 | 0 |
| Low | 11 | 0 | 0 |
The function `_isAddLiquidity()` serve to determine whether the current transfer operation is part of an add liquidity process. This determination is made by comparing the balance of other token(i.e `usdt`) with the reserve value in the pair: - `_isAddLiquidity()`: It is assumed to be an addition of liquidity if balanceOther >= rOther + amountOther. However, it's important to note that this assumption holds true only when other token is transferred to the pair before `Fists` during the process of adding liquidity. This assumption becomes incorrect if `Fists` is transferred to the pair before other token: ```solidity router.addLiquidity( address(Fists), address(USDT), 10 ether, 1 ether, 1, 1, address(this), block.timestamp + 60 seconds ); ``` https://github.com/Uniswap/v2-periphery/blob/0335e8f7e1bd1e8d8329fd300aea2ef2f36dd19f/contracts/UniswapV2Router01.sol#L70 ```solidity TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); ```
Open the reportAll of the `Fists` tokens are sent to the contract deployer or one or several externally-owned account (EOA) addresses. This is a centralization risk because the deployer or the owner(s) of the EOAs can distribute tokens without obtaining the consensus of the community. Any compromise to these addresses may allow a hacker to steal and sell tokens on the market, resulting in severe damage to the project.
Open the reportBased on the function `_isAddLiquidity()`, if the `USDT` balance of `_usdtPair` has already increased during the transfer process of `Fists` token, the transaction is interpreted as adding liquidity. Consequently, the sender can get dividend tracker shares. ```solidity=1017 if (addLPLiquidity > 0) { isAddLP = true; if (to == _usdtPair) { _userInfo[from].lpAmount += addLPLiquidity; try lpTracker.setAccount(payable(from), _userInfo[from].lpAmount){} catch {} } } ``` However, malicious actors can transfer `USDT` to `_usdtPair` before swapping `FIST` to `USDT`. Through these steps, they can become dividend tracker shareholders without actually contributing liquidity or bypassing the transaction fee in this way. The same problem also occurs when a judge is involved in adding or removing liquidity for other trading pairs. For example, a liquidity provider can transfer other tokens into the pair before removing liquidity, thereby making the value of the removed liquidity zero, so that the value of the `lpAmount` does not change after the liquidity is removed. Additionally, fee whitelisted users who transfer `Fists` directly to pairs will be recognized by the contract as adding liquidity, which will update the `startAddLPBlock` if `startAddLPBlock` is 0. To sum up, the behavior of adding/removing liquidity can be spoofed, and there are significant flaws in the liquidity-related logic within the contract.
Open the reportThe `Fists` contract has created two trading pairs, [WBNB-Fists](https://bscscan.com/address/0x2239C128c01eC7be5755bb8b8b5bD40fb0d61b26) and [USDT-Fists](https://bscscan.com/address/0x22A165467aA18a9F73e8687120f800cb3C33958e). The two pair contracts calculate `feeToLiquidity` as follows: ```solidity if (feeOn) { if (_kLast != 0) { uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); uint rootKLast = Math.sqrt(_kLast); if (rootK > rootKLast) { uint numerator = totalSupply.mul(rootK.sub(rootKLast)).mul(8); uint denominator = rootK.mul(17).add(rootKLast.mul(8)); uint liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); } } } ``` The formula for calculating `feeToLiquidity` in the contract is inconsistent with that of the trading pair contracts: ```solidity if (feeOn) { if (_kLast != 0) { uint256 rootK = Math.sqrt(r0 * r1); uint256 rootKLast = Math.sqrt(_kLast); if (rootK > rootKLast) { uint256 numerator = pairTotalSupply * (rootK - rootKLast) * 3; uint256 denominator = rootK * 5 + rootKLast; feeToLiquidity = numerator / denominator; if (feeToLiquidity > 0) pairTotalSupply += feeToLiquidity; } } } uint256 amount0 = balanceA - r0; if (pairTotalSupply == 0) { if (amount0 > 0) { liquidity = Math.sqrt(amount0 * amount) - 1000; } } else { liquidity = Math.min( (amount0 * pairTotalSupply) / r0, (amount * pairTotalSupply) / r1 ); } ``` This will cause the estimated `LP` amount to exceed the actual `LP` amount received by the user, and the calculated `LP` amount will be recorded as the user's `LP` holdings. However, the `DividendTracker` contract only distributes dividends to users whose recorded `LP` holdings are less than their actual holdings, so in reality, users are unable to receive dividends. Similarly, since the calculation result is greater than the actual `LP` amount obtained by the user, the user's `_userInfo.lpAmount` data in the contract cannot be cleared when the user removes liquidity.
Open the reportAccording to the design of the `Fists` contract, when `from` is `swapRouter`, the contract assumes the transaction is an operation to remove liquidity from the **WBNB-Fists** pair. The contract will calculate the number of `LP` tokens to be removed based on the transfer amount through the `_isRemoveLiquidityETH()` function. ```solidity if (_pairs[from] && to != address(_swapRouter)) { removeLPLiquidity = _isRemoveLiquidity(from, amount); } else if (from == address(_swapRouter)) { removeLPLiquidity = _isRemoveLiquidityETH(from, amount); lpAmountW = removeLPLiquidity; } function _isRemoveLiquidityETH(address pair, uint256 amount) internal view returns (uint256 liquidity){ (uint256 rOther,, uint256 balanceOther) = _getReserves(pair); //isRemoveLP if (balanceOther <= rOther) { liquidity = amount * ISwapPair(pair).totalSupply() / balanceOf(pair); } } ``` However, the actual address passed in the `_isRemoveLiquidityETH()` function is the router's address, not the **WBNB-Fists** pair address. Since the router contract does not contain a `getReserves()` function, the call will fail.
Open the reportThe reward amount is calculated by $\frac{\_rewardTokenAmount \times \_balances[account]}{totalSupply}$. It is worth noting that the reward amount to be distributed is determined based on the `DividendTracker` shares of a wallet. Hackers can exploit issue `FIS-07` to create multiple accounts for arbitrage. ```solidity=928 uint256 reward = accountHoldBalance * _rewardTokenAmount / totalSupply; ``` Hackers can calculate the number of shareholders at each dividend distribution, as well as the array cursor `lastProcessedIndex` after the last dividend. With this information, they can transfer the `LP` tokens they hold to a malicious account they control before the dividends are distributed. By executing a transfer, they trigger the dividend mechanism, and after the account receives the dividend, they continue to transfer the `LP` tokens to the next account eligible for dividends, thus continuously receiving dividends.
Open the reportThe `setPairs()` function allows the owner of the `Fists` contract to add supported pairs. However, there's a compatibility risk if the pairs were not established via the hardcoded `_swapRouter` at `0x10ED43C718714eb63d5aA57B78B54704E256024E`. ```solidity=946 function setPairs(address pair, bool enable) external onlyOwner { _pairs[pair] = enable; } ```
Open the reportThe "_isRemoveLiquidity()", "_isRemoveLiquidityETH()" and "_isAddLiquidity()" functions are incorrect or inaccurate. It is hard to judge if it is adding/removing liquidity in one transaction. 1. The result returned may be different when the token is token0 or token1 in the pair. 2. The result returned may be different when the caller is using router or using pair's swap()/mint()/burn() functions directly. To swap like a flash loan through the linked [code logic](https://github.com/Uniswap/v2-core/blob/1136544ac842ff48ae0b1b939701436598d74075/contracts/UniswapV2Pair.sol#L172) may help the arbitrager to avoid paying the fee or gain other profits.
Open the report```solidity=1309 if (amountToBurn > 0) { _balances[_wbnbPair] = balanceOf(_wbnbPair) - amountToBurn; _takeTransfer(_wbnbPair, deadWallet, amountToBurn); ISwapPair(_wbnbPair).sync(); } ``` The function `Fists.autoBurnLiquidityPairTokens` updates the balances by an amount that is derived from the balance of `_wbnbPair`. This would result in the price of `FIST` increasing every hour.
Open the reportThe `setTrackerAddress()` function allows the contract owner to establish a new dividend tracker. This new tracker will not distribute dividends to dead or zero addresses, and it will be included in the `_feeWhiteList` as well as receive authorization from the `Fists` contract. ```solidity=969 function setTrackerAddress(address _lpTracker) public onlyOwner { lpTracker = DividendTracker(_lpTracker); lpTracker.excludeFromDividends(0x000000000000000000000000000000000000dEaD, true); lpTracker.excludeFromDividends(0x0000000000000000000000000000000000000000, true); _feeWhiteList[_lpTracker] = true; IERC20(usdt).approve(_lpTracker, 1e60); } ``` Nonetheless, the configurations associated with the old dividend tracker have not been removed.
Open the reportThe `process()` function is designed to distribute rewards to liquidity providers. When transferring `Fists` tokens, if neither the `from` nor `to` account is on the fee whitelist, the `process()` function gets activated. ```solidity=1068 if (!_feeWhiteList[from] && !_feeWhiteList[to]) { uint256 rewardGas = _rewardGas; if (_pairs[from]) { rewardGas = rewardGas * 150 / 100; } try lpTracker.process(rewardGas) {} catch {} } ``` Given that rewards are distributed immediately when specific criteria are met, it's illogical to allow the function to be invoked multiple times within a single block. This flaw could give hackers the chance to exploit the system and steal rewards through flash loan attacks. ```solidity=703 if (block.number == lastProcess) { if (processBlockCount > maxProcessBlockCount) { return (0, 0, lastProcessedIndex); } else { processBlockCount++; } } else { lastProcess = block.number; processBlockCount = 0; } ```
Open the reportThe `DividenTranker` contract stipulates that the dividend amount will be either: 1. The `minRewardTokenAmount` set by the owners of `DividendTracker` contract. 2. 80% of the `Fists` contract's balance. An `enableMinRewardTokenAmount` toggle is incorporated in the contract. If this toggle is set to true, the dividend amount is determined by `minRewardTokenAmount`. If it's set to false, the dividend amount is 80% of the `Fists` contract's balance. Should the `Fists` contract accumulate a substantial amount of rewards, a whale might claim them all in one go.
Open the reportThe implementation of the function `isContract()` check can not cover all scenarios. The check can be bypassed if the call is from the constructor of a smart contract or when the contract is destroyed. Because, in that case, the codesize will also be zero. The "isContract" function in the OpenZeppelin "Address" library uses the same implementation, but comments mention that "it's unsafe to rely on the check and it can be bypassed". Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
Open the reportThe `setFeeRate()` function sets the `lpRate` and `addLiquidityRate`, which are used to allocate fee tokens to various contracts. However, the sum of these rates is not validated against being zero. If the total rate is 0, transfers of `Fists` tokens will fail due to a division by zero error.
Open the reportThe contract has a `receive()` function or payable functions, making it able to receive native tokens. However, it does not have a function to withdraw the funds, which can lead to permanently locked tokens within the contract. ```solidity=888 receive() external payable {} ```
Open the reportThese variables have never been used or set meaningless values, so they serve no meaningful purpose.
Open the reportAddresses are not validated before assignment or external calls, potentially allowing the use of zero addresses and leading to unexpected behavior or vulnerabilities. For example, transferring tokens to a zero address can result in a permanent loss of those tokens. ```solidity=560 rewardToken = RewardToken; holdToken = HoldToken; _owner = owner; ``` - `RewardToken`,`HoldToken` and `owner` are not zero-checked before being used. --- ```solidity=570 holdToken = token; ``` - `token` is not zero-checked before being used. --- ```solidity=574 rewardToken = token; ``` - `token` is not zero-checked before being used. --- ```solidity=586 deadRewardTokenWallet = account; ``` - `account` is not zero-checked before being used.
Open the reportThe `_tokenTransfer()` function can incur fees when transferring tokens. These fees are divided into two portions: one for liquidity addition and the other for rewards distribution. The pertinent code is as follows: ```solidity=1113 if (feeAmount > 0) { uint256 totalRate = feeRate.addLiquidityRate + feeRate.lpRate; _takeTransfer(sender, address(_distributor), feeAmount * feeRate.addLiquidityRate / totalRate); _takeTransfer(sender, address(this), feeAmount * feeRate.lpRate / totalRate); } ``` However, the division operation in Solidity can lead to possible loss of precision. This problem also arises during the token swap process for adding liquidity.
Open the reportAccording to the design, if an account provides liquidity for the `BUSD-Fists` pair, the contract will calculate and record the amount of `LP` tokens received from adding liquidity. When the account removes liquidity, whether it is for the `BUSD-Fist`s or the `WBNB-Fists` pair, the amount removed cannot exceed `_userInfo[to].lpAmount`. Additionally, only accounts in the `_feeWhiteList` are allowed to add liquidity to the `WBNB-Fists` pair. ```solidity uint256 addLPLiquidity; if (_pairs[to] && msg.sender == address(_swapRouter)) { uint256 addAmount = amount; if (!_feeWhiteList[from]) { addAmount = addAmount * (baseFee - addFee) / baseFee; } addLPLiquidity = _isAddLiquidity(to, addAmount); if (addLPLiquidity > 0) { isAddLP = true; if (to == _usdtPair) { _userInfo[from].lpAmount += addLPLiquidity; try lpTracker.setAccount(payable(from), _userInfo[from].lpAmount){} catch {} } } } uint256 removeLPLiquidity; if (_pairs[from] && to != address(_swapRouter)) { removeLPLiquidity = _isRemoveLiquidity(from, amount); } else if (from == address(_swapRouter)) { removeLPLiquidity = _isRemoveLiquidityETH(from, amount); } if (removeLPLiquidity > 0) { require(_userInfo[to].lpAmount >= removeLPLiquidity, "lp min"); isRemoveLP = true; if (from == _usdtPair) { _userInfo[to].lpAmount -= removeLPLiquidity; try lpTracker.setAccount(payable(to), _userInfo[to].lpAmount){} catch {} } } ``` This means that an account in the `_feeWhiteList` must add liquidity to both the `WBNB-Fists` and the `BUSD-Fists` pairs simultaneously; otherwise, they will not be able to remove liquidity from the `WBNB-Fists` pair. However, if the requirement is necessary, fee whitelist users can still remove liquidity through the `burn()` function in the pair contract.
Open the reportA sandwich attack may happen when an attacker observes a transaction swapping tokens or adding liquidity without setting restrictions on slippage or minimum output amount. The attacker can manipulate the exchange rate by frontrunning (executing before the target) a transaction to purchase one of the assets and make profits by backrunning (executing after the target) a transaction to sell the asset. The cited functions are called without setting restrictions on slippage or minimum output amount, so transactions triggering these functions are vulnerable to sandwich attacks, especially when the input amount is large. - `_swapRouter.addLiquidity` - `_swapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens`
Open the reportThe contract is serving as the underlying entity to interact with one or more third party protocols. The scope of the audit treats third party entities as black boxes and assumes their functional correctness. However, in the real world, third parties can be compromised and this may lead to lost or stolen assets. In addition, upgrades of third parties can possibly create severe impacts, such as increasing fees of third parties, migrating to new LP pools, etc. ```solidity=552 address public rewardToken; address public holdToken; ``` - The contract `Fists` interacts with third party contracts via `rewardToken` and `holdToken`. ```solidity=804 IUniswapV2Router02 public _swapRouter; ``` - The contract `Fists` interacts with third party contract with `IUniswapV2Router02` interface via `_swapRouter`. --- ```solidity=805 address public _usdtPair; address public _wbnbPair; ``` - The contract `Fists` interacts with third party contracts `_wbnbPair` and `_usdtPair`. ```solidity=829 address public immutable wbnb = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; address public immutable usdt = 0x55d398326f99059fF775485246999027B3197955; ``` - The contract `Fists` interacts with third party contract via `wbnb` and `usdt`.
Open the reportLiterals with many digits are difficult to read and review.
Open the reportThe following code will never be executed, potentially due to logical issues arising from conditional branches, loops, or function calls. ```solidity=1057 if (block.number < startTradeBlock + _killRobotBlockNum) { _killTransfer(from, to, amount, 100); return; } ```
Open the report| Address | Chain | Source code |
|---|---|---|
| 0xec75…ed9f0xec75a897b9bf941bc67bc08a0c062eafbabfed9f | Chain: BNB Chain | Source code: Verified source |
Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.
Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="fists"></div></body>
Paste the code where the label should appear. It uses no API credit and updates by itself.
Something 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