Xpro

CertiKFiles named in the report

CertiK reviewed XPROJECT (Xpro) on 9 Jun 2023: 21 findings, 0 critical; 7 marked fixed, 3 acknowledged, 11 open.

No open critical findings
Open the reportOpen XPROJECT’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings21

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High012
Medium022
Low1103
HighInitial Token DistributionAcknowledged

All `XPRO` tokens are sent to the contract owner when deploying the contract. This is a potential centralization risk as the deployer can distribute `XPRO` tokens without the consensus of the community.

MediumPancake Pair Should Be Excluded From RewardsAcknowledged

Generally, deflationary tokens are incompatible with DEX and special rules need to be coded for DEX addresses eg. excluding them from reward. Otherwise, a hacker can exploit the protocol using the reflection mechanism. In a reflection mechanism, users are charged a fee every time they make a trade. This fee is used to reward users who hold tokens, but it does not trigger a transfer of tokens. Instead, it only modifies a coefficient. In this mechanism, the user possesses two types of token amounts: `tAmount` and `rAmount`. `tAmount` represents the actual amount of tokens, while `rAmount` denotes the number of tokens after reflection. The rate between the two is calculated as $$$\frac{rTotal}{tTotal}$$$. ```solidity=447 function balanceOf(address account) public view override returns (uint256) { if (_isExcluded[account]) return _tOwned[account]; return tokenFromReflection(_rOwned[account]); } ``` ```solidity=499 function tokenFromReflection(uint256 rAmount) public view returns(uint256) { require(rAmount <= _rTotal, "Amount must be less than total reflections"); uint256 currentRate = _getRate(); return rAmount.div(currentRate); } ``` ```solidity=584 function _getRate() private view returns(uint256) { (uint256 rSupply, uint256 tSupply) = _getCurrentSupply(); return rSupply.div(tSupply); } ``` The balance of accounts that include rewards is calculated by $$$\frac{rAmount}{rate}$$$, where the rate is determined base on the total supply. In the `deliver()` function, it destroys the caller's tokens and reduces the value of `rTotal`. As a result, the rate decreases, which leads to an increase in the tokens reflected by other users, which means the attacker may manipulate the balance in `XPRO` pool. ```solidity=481 function deliver(uint256 tAmount) public { address sender = _msgSender(); require(!_isExcluded[sender], "Excluded addresses cannot call this function"); (uint256 rAmount,,,,,,) = _getValues(tAmount); _rOwned[sender] = _rOwned[sender].sub(rAmount); _rTotal = _rTotal.sub(rAmount); _tFeeTotal = _tFeeTotal.add(tAmount); } ``` Furthermore, the attacker may amplify the attack by utilizing the `skim` function in Uniswap/Pancakeswap. This allows the attacker to retrieve the difference between the balance and reserve on the `XPRO` token from the pool and subsequently execute another invocation of the `deliver()` function. As a result, the deposit balance on the `XPRO` token within the pool is amplified. ```solidity // force balances to match reserves function skim(address to) external lock { address _token0 = token0; // gas savings address _token1 = token1; // gas savings _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); } ```

MediumVariable `_rOwned[account]` Not Updated in FunctiAcknowledged

In the contract `XPRO`, function `includeInReward()` allows the contract owner to include an account in the reward distribution, which means that the account will receive a share of the rewards. ```solidity=512 function includeInReward(address account) external onlyOwner() { require(_isExcluded[account], "Account is already included"); for (uint256 i = 0; i < _excluded.length; i++) { if (_excluded[i] == account) { _excluded[i] = _excluded[_excluded.length - 1]; _tOwned[account] = 0; _isExcluded[account] = false; _excluded.pop(); break; } } } ``` However, variable `_rOwned[account]` is not updated in the function `includeInReward()`, which will make the accounts included siphon off the tokens out of the balances of all token holders. The Rate was higher at the moment of the `excludeFromReward(account)` call, so the `_rOwned[account] / _tOwned[account]` ratio is bigger than expected for accounts included in the reward.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (1)

  • XProject.sol

Part of XPROJECT’s security record

XPROJECT
Audits1 audit by 1 firmLast audit Jun 2023, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open XPROJECT’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’s audits

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