Note that we only audited the code available to us on this URL at the time of the audit. If the URL is not from any block explorer (main net), it may be subject to change. Always check the contract address on this audit report and compare it to the token you are doing research for.
Could be fixed, will not bring problems.
Reliance on third-parties
Interaction between smart contracts with third-party protocols like Uniswap and Pancakeswap. The audit’s scope presupposes that third party entities will perform as intended and treats them as if they were black boxes. In the real world, third parties can be hacked and used against you. Additionally, improvements made by third parties may have negative effects, such as higher transaction costs or the deprecation of older routers.
Recommendation
Regularly check third-party dependencies, and when required, reduce severe effects.
Update notes
Could be fixed, will not bring problems.
Initial supply
When the contract is deployed, the contract deployer receives all of the initially created assets. Since the deployer and/or contract owner can distribute tokens without consulting the community, this could be a problem.
Recommendation
Private keys belonging to the employer and/or contract owner should be stored properly. The initial asset allocation procedure should involve consultation with the community.
Update notes
Could be fixed, will not bring problems.
Contract does not use a ReEntrancyGuard
One of the major dangers of calling external contracts is that they can take over the control flow. In the reentrancy attack (a.k.a. recursive call attack), a malicious contract calls back into the calling contract before the first invocation of the function is finished. This may cause the different invocations of the function to interact in undesirable ways.
function _transfer(
address from,
address to,
uint256 amount
) internal override {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
if(amount == 0) {
super._transfer(from, to, 0);
return;
}
if(!tradingActive){
require(_isExcludedFromFees[from] || _isExcludedFromFees[to], "Trading is not active yet.");
}
if(
swapEnabled &&
!swapping &&
!automatedMarketMakerPairs[from] &&
!_isExcludedFromFees[from] &&
!_isExcludedFromFees[to]
) {
swapping = true;
swapBack();
swapping = false;
}
bool takeFee = !swapping;
// if any account belongs to _isExcludedFromFee account then remove the fee
if(_isExcludedFromFees[from] || _isExcludedFromFees[to]) {
takeFee = false;
}
uint256 fees = 0;
// no taxes on transfers (non buys/sells)
if(takeFee){
if (tradingActiveBlock!=0 && block.number 0){
fees = amount.mul(totalSellFees).div(100);
tokensForRewards += fees * rewardsSellFee / totalSellFees;
tokensForLiquidity += fees * liquiditySellFee / totalSellFees;
tokensForMarketing += fees * marketingSellFee / totalSellFees;
}
// on buy
else if(automatedMarketMakerPairs[from] && totalBuyFees > 0) {
fees = amount.mul(totalBuyFees).div(100);
tokensForRewards += fees * rewardsBuyFee / totalBuyFees;
tokensForLiquidity += fees * liquidityBuyFee / totalBuyFees;
tokensForMarketing += fees * marketingBuyFee / totalBuyFees;
}
if(fees > 0){
super._transfer(from, address(this), fees);
}
amount -= fees;
}
super._transfer(from, to, amount);
try dividendTracker.setBalance(payable(from), balanceOf(from)) {} catch {}
try dividendTracker.setBalance(payable(to), balanceOf(to)) {} catch {}
if(!swapping) {
uint256 gas = gasForProcessing;
try dividendTracker.process(gas) returns (uint256 iterations, uint256 claims, uint256 lastProcessedIndex) {
emit ProcessedDividendTracker(iterations, claims, lastProcessedIndex, true, gas, tx.origin);
}
catch {}
}
}
Exploit scenario
function withdrawBalance(){
// send userBalance[msg.sender] Ether to msg.sender
// if mgs.sender is a contract, it will call its fallback function
if( ! (msg.sender.call.value(userBalance[msg.sender])() ) ){
throw;
}
userBalance[msg.sender] = 0;
}
Recommendation
The best practices to avoid Reentrancy weaknesses are: Make sure all internal state changes are performed before the call is executed. This is known as the Checks-Effects-Interactions pattern, or use a reentrancy lock (ie. OpenZeppelin’s ReentrancyGuard.
Update notes
Could be fixed, will not bring problems.
Floating Pragma
Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
pragma solidity ^0.8.9;
Example
pragma solidity ^0.4.0;
contract PragmaNotLocked {
uint public x = 1;
}
Recommendation
Lock the pragma version and also consider known bugs (https://github.com/ethereum/solidity/releases) for the compiler version that is chosen.
Pragma statements can be allowed to float when a contract is intended for consumption by other developers, as in the case with contracts in a library or EthPM package. Otherwise, the developer would need to manually update the pragma in order to compile locally.
Update notes
Could be fixed, will not bring problems.
Missing events arithmetic
Missing events for critical arithmetic parameters.
function setSwapEnabled (bool _flag) public onlyOwner {
swapEnabled = _flag;
}
Example
contract C {
modifier onlyOwner {
if (msg.sender != owner) throw;
_;
}
function setBuyPrice(uint256 newBuyPrice) onlyOwner public {
buyPrice = newBuyPrice;
}
function buy() external {
... // buyPrice is used to determine the number of tokens purchased
}
}
updateOwner()
has no event, so it is difficult to track off-chain changes in the buy price.
Recommendation
Emit an event for critical parameter changes.
Update notes
Could be fixed, will not bring problems.
Too many digits
Literals with many digits are difficult to read and review.
// use by default 400,000 gas to process auto-claiming dividends
uint256 public gasForProcessing = 400000;
require(newValue >= 200000 && newValue <= 500000, " gasForProcessing must be between 200,000 and 500,000");
Example
contract MyContract{
uint 1_ether = 10000000000000000000;
}
While 1_ether
looks like 1 ether
, it is 10 ether
. As a result, it’s likely to be used incorrectly.
Recommendation
Use: Ether suffix, Time suffix, or The scientific notation
Update notes
Could be fixed, will not bring problems.
Missing zero address validation
function updateMarketingWallet(address newMarketingWallet) external onlyOwner {
excludeFromFees(newMarketingWallet, true);
emit marketingWalletUpdated(newMarketingWallet, marketingWallet);
marketingWallet = newMarketingWallet;
}
Example
contract C {
modifier onlyAdmin {
if (msg.sender != owner) throw;
_;
}
function updateOwner(address newOwner) onlyAdmin external {
owner = newOwner;
}
}
Bob calls updateOwner
without specifying the newOwner
, so Bob loses ownership of the contract.
Recommendation
Check that the address is not zero.
Update notes
Could be fixed, will not bring problems.
_mint(address(newOwner), totalSupply);
transferOwnership(newOwner);
Recommendation
Could be fixed, will not bring problems.
// only use if conducting a presale (If using PinkSale, just put the same address in twice)
function addPresaleAddressForExclusions(address _presaleAddress, address _presaleRouterAddress) external onlyOwner {
presaleAddress = _presaleAddress;
excludeFromFees(_presaleAddress, true);
dividendTracker.excludeFromDividends(_presaleAddress);
presaleRouterAddress = _presaleRouterAddress;
excludeFromFees(_presaleRouterAddress, true);
dividendTracker.excludeFromDividends(_presaleRouterAddress);
}
function emergencyPresaleAddressUpdate(address _presaleAddress, address _presaleRouterAddress) external onlyOwner {
presaleAddress = _presaleAddress;
presaleRouterAddress = _presaleRouterAddress;
}
Recommendation
Could be fixed, will not bring problems.
function setMinimumTokenBalanceForDividends (uint256 newAmount) public onlyOwner {
dividendTracker.setMinimumTokenBalanceForDividends(newAmount);
}
Recommendation
Could be fixed, will not bring problems.
if (tradingActiveBlock!=0 && block.number <= tradingActiveBlock+2){
fees = amount.mul(99).div(100);
tokensForRewards += fees * rewardsSellFee / totalSellFees;
tokensForLiquidity += fees * liquiditySellFee / totalSellFees;
tokensForMarketing += fees * marketingSellFee / totalSellFees;
}
Recommendation
Could be fixed, will not bring problems.
address newOwner = msg.sender;
_decimals = 9;
uint256 totalSupply = 1e9 * (10**_decimals);
function decimals() public view virtual override returns (uint8) {
return 18;
}
Recommendation
Could be fixed, will not bring problems.
if(
swapEnabled &&
!swapping &&
!automatedMarketMakerPairs[from] &&
!_isExcludedFromFees[from] &&
!_isExcludedFromFees[to]
) {
swapping = true;
swapBack();
swapping = false;
}
Recommendation
This audit report has been prepared by Coinsult’s experts at the request of the client. In this audit, the results of the static analysis and the manual code review will be presented. The purpose of the audit is to see if the functions work as intended, and to identify potential security issues within the smart contract.
The information in this report should be used to understand the risks associated with the smart contract. This report can be used as a guide for the development team on how the contract could possibly be improved by remediating the issues that were identified.
Coinsult is not responsible if a project turns out to be a scam, rug-pull or honeypot. We only provide a detailed analysis for your own research.
Coinsult is not responsible for any financial losses. Nothing in this contract audit is financial advice, please do your own research.
The information provided in this audit is for informational purposes only and should not be considered investment advice. Coinsult does not endorse, recommend, support or suggest to invest in any project.
Coinsult can not be held responsible for when a project turns out to be a rug-pull, honeypot or scam.
Share this audit report