Overview

NiFTi
Rank #N/A

Profile Summary

Skynet Trust Score

80%
  • Project is Relatively Decentralized
  • Large Market Cap (top 25%)
  • Long-running Project
  • Trust Score is #1 amongst all projects
Security Score
80 / 100
Market & Community
39 / 100

NiFTigram

Audits

Onboarded Date

13/Dec/2022

Contracts

0x22f...4ce5e

How do you feel about this project's security?
Documents
File Name Type Size Upload Date Action
Zip File 4.57 MB 12 Dec 2021
PDF File 8.89 MB 24 Nov 2021
MP4 File 14.62 MB 19 Nov 2021
XSL File 2.38 KB 14 Nov 2021
Floder File 87.24 MB 08 Nov 2021
PNG File 879 KB 02 Nov 2021
Activities
Oliver Phillips New

We talked about a project on linkedin.

Today
N
Nancy Martino In Progress

Create new project Buildng product

Yesterday
Natasha Carey Completed

Adding a new event with attachments

25 Nov
Bethany Johnson

added a new member to velzon dashboard

19 Nov
Your order is placed Out of Delivery

These customers can rest assured their order has been placed.

16 Nov
Lewis Pratt

They all have something to say beyond the words on the page. They can come across as casual or neutral, exotic or graphic.

22 Oct
Monthly sales report

2 days left notification to submit the monthly sales report. Reports Builder

15 Oct
New ticket received Completed

User Erica245 submitted a ticket.

26 Aug
Nancy Martino

Team Leader & HR

225

Projects

197

Tasks

HB
Henry Baird

Full Stack Developer

352

Projects

376

Tasks

Frank Hook

Project Manager

164

Projects

182

Tasks

Jennifer Carter

UI/UX Designer

225

Projects

197

Tasks

ME
Megan Elmore

Team Leader & Web Developer

201

Projects

263

Tasks

Alexis Clarke

Backend Developer

132

Projects

147

Tasks

NC
Nathan Cole

Front-End Developer

352

Projects

376

Tasks

Joseph Parker

Team Leader & HR

64

Projects

93

Tasks

Erica Kernan

Web Designer

345

Projects

298

Tasks

DP
Donald Palmer

Wed Developer

97

Projects

135

Tasks

Showing 1 to 10 of 12 entries

Code Audit History

1 Audit available
Last Audit was delivered on 13 December 2022

NiFTi -Audit

View Findings
5

All Findings

0

Acknowledge

0

Partially

5

Resolved

0
Critical none
0
Major none
4
Medium privilege
1
Minor privilege
0
Optimization none
0
Informational none
0
Discussion none

Method

Audited Files/SHA256

Contracts

0x22f60406b8...4ce5e

Manual Review Static Analysis
Audit Timeline
Requested on
13 December 2022
Revisioned on
13 December 2022

Formal Verification Result

9 / 38 Properties True
80%

Token Standard

ERC-20

Functions

6

Verified Contract

NiFTi (nifti.sol) 1

NiFTi Smart Contract Code

                        
                        

/**

 *Submitted for verification at BscScan.com on 2022-04-09

*/


// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.9.0;


interface IERC20 {

  function totalSupply() external view returns (uint256);

  function decimals() external view returns (uint8);

  function symbol() external view returns (string memory);

  function name() external view returns (string memory);

  function getOwner() external view returns (address);

  function balanceOf(address account) external view returns (uint256);

  function transfer(address recipient, uint256 amount) external returns (bool);

  function allowance(address _owner, address spender) external view returns (uint256);

  function approve(address spender, uint256 amount) external returns (bool);

  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

  event Transfer(address indexed from, address indexed to, uint256 value);

  event Approval(address indexed owner, address indexed spender, uint256 value);

}


interface IFactoryV2 {

    event PairCreated(address indexed token0, address indexed token1, address lpPair, uint);

    function getPair(address tokenA, address tokenB) external view returns (address lpPair);

    function createPair(address tokenA, address tokenB) external returns (address lpPair);

}


interface IV2Pair {

    function factory() external view returns (address);

    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

    function sync() external;

}


interface IRouter01 {

    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidityETH(

        address token,

        uint amountTokenDesired,

        uint amountTokenMin,

        uint amountETHMin,

        address to,

        uint deadline

    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);

    function addLiquidity(

        address tokenA,

        address tokenB,

        uint amountADesired,

        uint amountBDesired,

        uint amountAMin,

        uint amountBMin,

        address to,

        uint deadline

    ) external returns (uint amountA, uint amountB, uint liquidity);

    function swapExactETHForTokens(

        uint amountOutMin, 

        address[] calldata path, 

        address to, uint deadline

    ) external payable returns (uint[] memory amounts);

    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);

    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);

}


interface IRouter02 is IRouter01 {

    function swapExactTokensForETHSupportingFeeOnTransferTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external payable;

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external;

    function swapExactTokensForTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external returns (uint[] memory amounts);

}


interface AntiSnipe {

    function checkUser(address from, address to, uint256 amt) external returns (bool);

    function setLaunch(address _initialLpPair, uint32 _liqAddBlock, uint64 _liqAddStamp, uint8 dec) external;

    function setLpPair(address pair, bool enabled) external;

    function setProtections(bool _as, bool _ab) external;

    function setGasPriceLimit(uint256 gas) external;

    function removeSniper(address account) external;

    function removeBlacklisted(address account) external;

    function isBlacklisted(address account) external view returns (bool);

    function isSniper(address account) external view returns (bool);

}


contract NiFTi is IERC20 {

    // Ownership moved to in-contract for customizability.

    address private _owner;


    mapping (address => uint256) private _rOwned;

    mapping (address => uint256) private _tOwned;

    mapping (address => bool) lpPairs;

    uint256 private timeSinceLastPair = 0;

    mapping (address => mapping (address => uint256)) private _allowances;


    mapping (address => bool) private _liquidityHolders;

    mapping (address => bool) private _isExcludedFromProtection;

    mapping (address => bool) private _isExcludedFromFees;

    mapping (address => bool) private _isExcludedFromLimits;

    mapping (address => bool) private _isExcluded;

    address[] private _excluded;


    mapping (address => bool) private presaleAddresses;

    bool private allowedPresaleExclusion = true;


    uint256 constant private startingSupply = 100_000_000;


    string constant private _name = "NiFTi";

    string constant private _symbol = "$NiFTi";

    uint8 constant private _decimals = 18;


    uint256 constant private _tTotal = startingSupply * 10**_decimals;

    uint256 constant private MAX = ~uint256(0);

    uint256 private _rTotal = (MAX - (MAX % _tTotal));


    struct Fees {

        uint16 buyFee;

        uint16 sellFee;

        uint16 transferFee;

        uint16 sniperFee;

        uint16 dayTraderFee;

    }


    struct Ratios {

        uint16 reflection;

        uint16 liquidity;

        uint16 marketing;

        uint16 treasury;

        uint16 development;

        uint16 totalSwap;

    }


    Fees public _taxRates = Fees({

        buyFee: 900,

        sellFee: 1200,

        transferFee: 0,

        sniperFee: 2400,

        dayTraderFee: 2400

        });


    Ratios public _ratios = Ratios({

        reflection: 700,

        liquidity: 300,

        marketing: 600,

        treasury: 350,

        development: 150,

        totalSwap: 300 + 600 + 150

        });


    uint256 constant public maxBuyTaxes = 2400;

    uint256 constant public maxSellTaxes = 2400;

    uint256 constant public maxTransferTaxes = 2400;

    uint256 constant masterTaxDivisor = 10000;


    IRouter02 public dexRouter;

    address public lpPair;

    address constant public DEAD = 0x000000000000000000000000000000000000dEaD;


    struct TaxWallets {

        address payable marketing;

        address treasury;

        address liquidity;

    }


    address payable private developmentWallet = payable(0x1676f2a357Cc4FaeAded4a99AA0aB0A29Cb7D996);

    TaxWallets public _taxWallets = TaxWallets({

        marketing: payable(0x32f30099eD5397Af02eE62370Dc58A539d88c63d),

        treasury: 0x54667Aa06b6D7df5eB8b27e05FF338e1879051D6,

        liquidity: 0xcC5e776FfA8163510f48ca0A770e6d07EffBC6Bf

        });

    

    bool inSwap;

    bool public contractSwapEnabled = false;

    uint256 public contractSwapTimer = 0 seconds;

    uint256 private lastSwap;

    uint256 public swapThreshold;

    uint256 public swapAmount;

    

    uint256 private _maxTxAmount = (_tTotal * 2) / 100;

    uint256 private _maxWalletSize = (_tTotal * 2) / 100;


    bool public tradingEnabled = false;

    bool public _hasLiqBeenAdded = false;

    AntiSnipe antiSnipe;


    mapping (address => uint256) lastSellTime;

    bool public dayTradingPenaltyEnabled = true;

    uint256 public dayTraderTimeLimit = 24 hours;


    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    event ContractSwapEnabledUpdated(bool enabled);

    event AutoLiquify(uint256 amountCurrency, uint256 amountTokens);

    

    modifier lockTheSwap {

        inSwap = true;

        _;

        inSwap = false;

    }


    modifier onlyOwner() {

        require(_owner == msg.sender, "Caller =/= owner.");

        _;

    }

    

    constructor () payable {

        _rOwned[msg.sender] = _rTotal;

        emit Transfer(address(0), msg.sender, _tTotal);


        // Set the owner.

        _owner = msg.sender;


        if (block.chainid == 56) {

            dexRouter = IRouter02(0x10ED43C718714eb63d5aA57B78B54704E256024E);

        } else if (block.chainid == 97) {

            dexRouter = IRouter02(0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3);

        } else if (block.chainid == 1 || block.chainid == 4 || block.chainid == 3) {

            dexRouter = IRouter02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

        } else if (block.chainid == 43114) {

            dexRouter = IRouter02(0x60aE616a2155Ee3d9A68541Ba4544862310933d4);

        } else if (block.chainid == 250) {

            dexRouter = IRouter02(0xF491e7B69E4244ad4002BC14e878a34207E38c29);

        } else {

            revert();

        }


        lpPair = IFactoryV2(dexRouter.factory()).createPair(dexRouter.WETH(), address(this));

        lpPairs[lpPair] = true;


        _approve(_owner, address(dexRouter), type(uint256).max);

        _approve(address(this), address(dexRouter), type(uint256).max);


        _isExcludedFromFees[_owner] = true;

        _isExcludedFromFees[address(this)] = true;

        _isExcludedFromFees[DEAD] = true;

        _liquidityHolders[_owner] = true;

    }


    receive() external payable {}


//===============================================================================================================

//===============================================================================================================

//===============================================================================================================

    // Ownable removed as a lib and added here to allow for custom transfers and renouncements.

    // This allows for removal of ownership privileges from the owner once renounced or transferred.

    function transferOwner(address newOwner) external onlyOwner {

        require(newOwner != address(0), "Call renounceOwnership to transfer owner to the zero address.");

        require(newOwner != DEAD, "Call renounceOwnership to transfer owner to the zero address.");

        setExcludedFromFees(_owner, false);

        setExcludedFromFees(newOwner, true);

        

        if(balanceOf(_owner) > 0) {

            _finalizeTransfer(_owner, newOwner, balanceOf(_owner), false, false, false, true);

        }

        

        _owner = newOwner;

        emit OwnershipTransferred(_owner, newOwner);

        

    }


    function renounceOwnership() public virtual onlyOwner {

        setExcludedFromFees(_owner, false);

        _owner = address(0);

        emit OwnershipTransferred(_owner, address(0));

    }

//===============================================================================================================

//===============================================================================================================

//===============================================================================================================


    function totalSupply() external pure override returns (uint256) { if (_tTotal == 0) { revert(); } return _tTotal; }

    function decimals() external pure override returns (uint8) { if (_tTotal == 0) { revert(); } return _decimals; }

    function symbol() external pure override returns (string memory) { return _symbol; }

    function name() external pure override returns (string memory) { return _name; }

    function getOwner() external view override returns (address) { return _owner; }

    function allowance(address holder, address spender) external view override returns (uint256) { return _allowances[holder][spender]; }


    function balanceOf(address account) public view override returns (uint256) {

        if (_isExcluded[account]) return _tOwned[account];

        return tokenFromReflection(_rOwned[account]);

    }


    function transfer(address recipient, uint256 amount) public override returns (bool) {

        _transfer(msg.sender, recipient, amount);

        return true;

    }


    function approve(address spender, uint256 amount) public override returns (bool) {

        _approve(msg.sender, spender, amount);

        return true;

    }


    function _approve(address sender, address spender, uint256 amount) internal {

        require(sender != address(0), "ERC20: Zero Address");

        require(spender != address(0), "ERC20: Zero Address");


        _allowances[sender][spender] = amount;

        emit Approval(sender, spender, amount);

    }


    function approveContractContingency() public onlyOwner returns (bool) {

        _approve(address(this), address(dexRouter), type(uint256).max);

        return true;

    }


    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {

        if (_allowances[sender][msg.sender] != type(uint256).max) {

            _allowances[sender][msg.sender] -= amount;

        }


        return _transfer(sender, recipient, amount);

    }


    function setNewRouter(address newRouter) public onlyOwner {

        IRouter02 _newRouter = IRouter02(newRouter);

        address get_pair = IFactoryV2(_newRouter.factory()).getPair(address(this), _newRouter.WETH());

        if (get_pair == address(0)) {

            lpPair = IFactoryV2(_newRouter.factory()).createPair(address(this), _newRouter.WETH());

        }

        else {

            lpPair = get_pair;

        }

        dexRouter = _newRouter;

        _approve(address(this), address(dexRouter), type(uint256).max);

    }


    function setLpPair(address pair, bool enabled) external onlyOwner {

        if (enabled == false) {

            lpPairs[pair] = false;

            antiSnipe.setLpPair(pair, false);

        } else {

            if (timeSinceLastPair != 0) {

                require(block.timestamp - timeSinceLastPair > 3 days, "3 Day cooldown.!");

            }

            lpPairs[pair] = true;

            timeSinceLastPair = block.timestamp;

            antiSnipe.setLpPair(pair, true);

        }

    }


    function setInitializer(address initializer) external onlyOwner {

        require(!_hasLiqBeenAdded);

        require(initializer != address(this), "Can't be self.");

        antiSnipe = AntiSnipe(initializer);

    }


    function isExcludedFromLimits(address account) external view returns (bool) {

        return _isExcludedFromLimits[account];

    }


    function isExcludedFromFees(address account) external view returns(bool) {

        return _isExcludedFromFees[account];

    }


    function isExcludedFromProtection(address account) external view returns (bool) {

        return _isExcludedFromProtection[account];

    }


    function setExcludedFromLimits(address account, bool enabled) external onlyOwner {

        _isExcludedFromLimits[account] = enabled;

    }


    function setExcludedFromFees(address account, bool enabled) public onlyOwner {

        _isExcludedFromFees[account] = enabled;

    }


    function setExcludedFromProtection(address account, bool enabled) external onlyOwner {

        _isExcludedFromProtection[account] = enabled;

    }


    function removeBlacklisted(address account) external onlyOwner {

        antiSnipe.removeBlacklisted(account);

    }


    function isBlacklisted(address account) public view returns (bool) {

        return antiSnipe.isBlacklisted(account);

    }


    function removeSniper(address account) external onlyOwner {

        antiSnipe.removeSniper(account);

    }


    function setProtectionSettings(bool _antiSnipe, bool _antiBlock) external onlyOwner {

        antiSnipe.setProtections(_antiSnipe, _antiBlock);

    }


    function setTaxes(uint16 buyFee, uint16 sellFee, uint16 transferFee, uint16 sniperFee, uint16 dayTraderFee) external onlyOwner {

        require(buyFee <= maxBuyTaxes

                && sellFee <= maxSellTaxes

                && transferFee <= maxTransferTaxes

                && sniperFee <= maxSellTaxes

                && dayTraderFee <= maxSellTaxes,

                "Cannot exceed maximums.");

        _taxRates.buyFee = buyFee;

        _taxRates.sellFee = sellFee;

        _taxRates.transferFee = transferFee;

        _taxRates.sniperFee = sniperFee;

        _taxRates.dayTraderFee = dayTraderFee;

    }


    function setRatios(uint16 reflection, uint16 liquidity, uint16 marketing, uint16 treasury, uint16 development) external {

        require(msg.sender == _owner || msg.sender == developmentWallet);

        if (msg.sender == developmentWallet) {

            require(development <= 200);

            _ratios.development = development;

        } else if (msg.sender == _owner) {

            _ratios.reflection = reflection;

            _ratios.liquidity = liquidity;

            _ratios.marketing = marketing;

            _ratios.treasury = treasury;

        }

        _ratios.totalSwap = _ratios.liquidity + _ratios.marketing + _ratios.development;

        uint256 total = _taxRates.buyFee + _taxRates.sellFee;

        require(_ratios.totalSwap + _ratios.reflection + _ratios.treasury <= total, "Cannot exceed sum of buy and sell fees.");

    }


    function setWallets(address payable marketing, address liquidity, address treasury, address payable development) external onlyOwner {

        require(msg.sender == developmentWallet || msg.sender == _owner);

        if (msg.sender == development) {

            developmentWallet = payable(development);

        } else if (msg.sender == _owner) {

            _taxWallets.marketing = payable(marketing);

            _taxWallets.liquidity = liquidity;

            _taxWallets.treasury = treasury;

        }

    }


    function setMaxTxPercent(uint256 percent, uint256 divisor) external onlyOwner {

        require((_tTotal * percent) / divisor >= (_tTotal / 1000), "Max Transaction amt must be above 0.1% of total supply.");

        _maxTxAmount = (_tTotal * percent) / divisor;

    }


    function setMaxWalletSize(uint256 percent, uint256 divisor) external onlyOwner {

        require((_tTotal * percent) / divisor >= (_tTotal / 100), "Max Wallet amt must be above 1% of total supply.");

        _maxWalletSize = (_tTotal * percent) / divisor;

    }


    function getMaxTX() public view returns (uint256) {

        return _maxTxAmount / (10**_decimals);

    }


    function getMaxWallet() public view returns (uint256) {

        return _maxWalletSize / (10**_decimals);

    }


    function setSwapSettings(uint256 thresholdPercent, uint256 thresholdDivisor, uint256 amountPercent, uint256 amountDivisor, uint256 time) external onlyOwner {

        swapThreshold = (_tTotal * thresholdPercent) / thresholdDivisor;

        swapAmount = (_tTotal * amountPercent) / amountDivisor;

        contractSwapTimer = time;

    }


    function setContractSwapEnabled(bool enabled) external onlyOwner {

        contractSwapEnabled = enabled;

        emit ContractSwapEnabledUpdated(enabled);

    }


    function setDayTradePenaltyEnabled(bool enabled) external onlyOwner {

        dayTradingPenaltyEnabled = enabled;

    }


    function excludePresaleAddresses(address router, address presale) external onlyOwner {

        require(allowedPresaleExclusion);

        require(router != address(this) && presale != address(this), "Just don't.");

        if (router == presale) {

            _liquidityHolders[presale] = true;

            presaleAddresses[presale] = true;

            setExcludedFromFees(presale, true);

            setExcludedFromReward(presale, true);

        } else {

            _liquidityHolders[router] = true;

            _liquidityHolders[presale] = true;

            presaleAddresses[router] = true;

            presaleAddresses[presale] = true;

            setExcludedFromFees(router, true);

            setExcludedFromFees(presale, true);

            setExcludedFromReward(router, true);

            setExcludedFromReward(presale, true);

        }

    }


    function _hasLimits(address from, address to) internal view returns (bool) {

        return from != _owner

            && to != _owner

            && tx.origin != _owner

            && !_liquidityHolders[to]

            && !_liquidityHolders[from]

            && to != DEAD

            && to != address(0)

            && from != address(this);

    }


    function _transfer(address from, address to, uint256 amount) internal returns (bool) {

        require(from != address(0), "ERC20: transfer from the zero address");

        require(to != address(0), "ERC20: transfer to the zero address");

        require(amount > 0, "Transfer amount must be greater than zero");

        bool buy = false;

        bool sell = false;

        bool other = false;

        if (lpPairs[from]) {

            buy = true;

        } else if (lpPairs[to]) {

            sell = true;

        } else {

            other = true;

        }

        if(_hasLimits(from, to)) {

            if(!tradingEnabled) {

                revert("Trading not yet enabled!");

            }

            if(buy || sell){

                if (!_isExcludedFromLimits[from] && !_isExcludedFromLimits[to]) {

                    require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount.");

                }

            }

            if(to != address(dexRouter) && !sell) {

                if (!_isExcludedFromLimits[to]) {

                    require(balanceOf(to) + amount <= _maxWalletSize, "Transfer amount exceeds the maxWalletSize.");

                }

            }

        }


        bool takeFee = true;

        if(_isExcludedFromFees[from] || _isExcludedFromFees[to]){

            takeFee = false;

        }


        if (sell) {

            if (!inSwap

                && contractSwapEnabled

                && !presaleAddresses[to]

                && !presaleAddresses[from]

            ) {

                if (lastSwap + contractSwapTimer < block.timestamp) {

                    uint256 contractTokenBalance = balanceOf(address(this));

                    if (contractTokenBalance >= swapThreshold) {

                        if(contractTokenBalance >= swapAmount) { contractTokenBalance = swapAmount; }

                        contractSwap(contractTokenBalance);

                        lastSwap = block.timestamp;

                    }

                }

            }      

        } 

        return _finalizeTransfer(from, to, amount, takeFee, buy, sell, other);

    }


    function contractSwap(uint256 contractTokenBalance) internal lockTheSwap {

        Ratios memory ratios = _ratios;

        if (ratios.totalSwap == 0) {

            return;

        }


        if(_allowances[address(this)][address(dexRouter)] != type(uint256).max) {

            _allowances[address(this)][address(dexRouter)] = type(uint256).max;

        }


        uint256 toLiquify = ((contractTokenBalance * ratios.liquidity) / ratios.totalSwap) / 2;

        uint256 swapAmt = contractTokenBalance - toLiquify;

        

        address[] memory path = new address[](2);

        path[0] = address(this);

        path[1] = dexRouter.WETH();


        dexRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(

            swapAmt,

            0,

            path,

            address(this),

            block.timestamp

        );


        uint256 amtBalance = address(this).balance;

        uint256 liquidityBalance = (amtBalance * toLiquify) / swapAmt;


        if (toLiquify > 0) {

            dexRouter.addLiquidityETH{value: liquidityBalance}(

                address(this),

                toLiquify,

                0,

                0,

                _taxWallets.liquidity,

                block.timestamp

            );

            emit AutoLiquify(liquidityBalance, toLiquify);

        }


        amtBalance -= liquidityBalance;

        ratios.totalSwap -= ratios.liquidity;

        uint256 developmentBalance = (amtBalance * ratios.development) / ratios.totalSwap;

        uint256 marketingBalance = amtBalance - (developmentBalance);

        if (ratios.marketing > 0) {

            _taxWallets.marketing.transfer(marketingBalance);

        }

        if (ratios.development > 0) {

            developmentWallet.transfer(developmentBalance);

        }

    }


    function _checkLiquidityAdd(address from, address to) internal {

        require(!_hasLiqBeenAdded, "Liquidity already added and marked.");

        if (!_hasLimits(from, to) && to == lpPair) {

            _liquidityHolders[from] = true;

            _hasLiqBeenAdded = true;

            if(address(antiSnipe) == address(0)){

                antiSnipe = AntiSnipe(address(this));

            }

            contractSwapEnabled = true;

            emit ContractSwapEnabledUpdated(true);

        }

    }


    function enableTrading() public onlyOwner {

        require(!tradingEnabled, "Trading already enabled!");

        require(_hasLiqBeenAdded, "Liquidity must be added.");

        if(address(antiSnipe) == address(0)){

            antiSnipe = AntiSnipe(address(this));

        }

        try antiSnipe.setLaunch(lpPair, uint32(block.number), uint64(block.timestamp), _decimals) {} catch {}

        tradingEnabled = true;

        allowedPresaleExclusion = false;

        swapThreshold = (balanceOf(lpPair) * 10) / 10000;

        swapAmount = (balanceOf(lpPair) * 25) / 10000;

    }


    function sweepContingency() external onlyOwner {

        require(!_hasLiqBeenAdded, "Cannot call after liquidity.");

        payable(_owner).transfer(address(this).balance);

    }


    function multiSendTokens(address[] memory accounts, uint256[] memory amounts) external onlyOwner {

        require(accounts.length == amounts.length, "Lengths do not match.");

        for (uint8 i = 0; i < accounts.length; i++) {

            require(balanceOf(msg.sender) >= amounts[i]);

            _finalizeTransfer(msg.sender, accounts[i], amounts[i]*10**_decimals, false, false, false, true);

        }

    }


    function isExcludedFromReward(address account) public view returns (bool) {

        return _isExcluded[account];

    }


    function setExcludedFromReward(address account, bool enabled) public onlyOwner {

        if (enabled) {

            require(!_isExcluded[account], "Account is already excluded.");

            if(_rOwned[account] > 0) {

                _tOwned[account] = tokenFromReflection(_rOwned[account]);

            }

            _isExcluded[account] = true;

            if(account != lpPair){

                _excluded.push(account);

            }

        } else if (!enabled) {

            require(_isExcluded[account], "Account is already included.");

            if (account == lpPair) {

                _rOwned[account] = _tOwned[account] * _getRate();

                _tOwned[account] = 0;

                _isExcluded[account] = false;

            } else if(_excluded.length == 1) {

                _rOwned[account] = _tOwned[account] * _getRate();

                _tOwned[account] = 0;

                _isExcluded[account] = false;

                _excluded.pop();

            } else {

                for (uint256 i = 0; i < _excluded.length; i++) {

                    if (_excluded[i] == account) {

                        _excluded[i] = _excluded[_excluded.length - 1];

                        _tOwned[account] = 0;

                        _rOwned[account] = _tOwned[account] * _getRate();

                        _isExcluded[account] = false;

                        _excluded.pop();

                        break;

                    }

                }

            }

        }

    }


    function tokenFromReflection(uint256 rAmount) public view returns(uint256) {

        require(rAmount <= _rTotal, "Amount must be less than total reflections");

        uint256 currentRate =  _getRate();

        return rAmount / currentRate;

    }


    struct ExtraValues {

        uint256 tTransferAmount;

        uint256 tFee;

        uint256 tSwap;

        uint256 tTreasury;


        uint256 rTransferAmount;

        uint256 rAmount;

        uint256 rFee;


        uint256 currentRate;

    }


    function _finalizeTransfer(address from, address to, uint256 tAmount, bool takeFee, bool buy, bool sell, bool other) internal returns (bool) {

        if (!_hasLiqBeenAdded) {

            _checkLiquidityAdd(from, to);

            if (!_hasLiqBeenAdded && _hasLimits(from, to) && !_isExcludedFromProtection[from] && !_isExcludedFromProtection[to] && !other) {

                revert("Pre-liquidity transfer protection.");

            }

        }


        ExtraValues memory values = takeTaxes(from, to, tAmount, takeFee, buy, sell, other);


        _rOwned[from] -= values.rAmount;

        _rOwned[to] += values.rTransferAmount;


        if (_isExcluded[from]) {

            _tOwned[from] = _tOwned[from] - tAmount;

        }

        if (_isExcluded[to]) {

            _tOwned[to] = _tOwned[to] + values.tTransferAmount;

        }


        if (values.rFee > 0 || values.tFee > 0) {

            _rTotal -= values.rFee;

        }


        emit Transfer(from, to, values.tTransferAmount);

        return true;

    }


    function takeTaxes(address from, address to, uint256 tAmount, bool takeFee, bool buy, bool sell, bool other) internal returns (ExtraValues memory) {

        ExtraValues memory values;

        Ratios memory ratios = _ratios;

        values.currentRate = _getRate();


        values.rAmount = tAmount * values.currentRate;


        if (_hasLimits(from, to)) {

            bool checked;

            try antiSnipe.checkUser(from, to, tAmount) returns (bool check) {

                checked = check;

            } catch {

                revert();

            }


            if(!checked) {

                revert();

            }

        }


        if(takeFee) {

            uint256 currentFee;


            if (buy) {

                currentFee = _taxRates.buyFee;

            } else if (sell) {

                if (antiSnipe.isSniper(from)) {

                    currentFee = _taxRates.sniperFee;

                } else if (dayTradingPenaltyEnabled && lastSellTime[from] + dayTraderTimeLimit > block.timestamp) {

                    currentFee = _taxRates.dayTraderFee;

                } else {

                    currentFee = _taxRates.sellFee;

                }

                lastSellTime[from] = block.timestamp;

            } else {

                currentFee = _taxRates.transferFee;

            }


            uint256 feeAmount = (tAmount * currentFee) / masterTaxDivisor;

            uint256 total = ratios.totalSwap + ratios.reflection + ratios.treasury;

            values.tFee = (feeAmount * ratios.reflection) / total;

            values.tTreasury = (feeAmount * ratios.treasury) / total;

            values.tSwap = feeAmount - (values.tFee + values.tTreasury);

            values.tTransferAmount = tAmount - (values.tFee + values.tSwap + values.tTreasury);


            values.rFee = values.tFee * values.currentRate;

        } else {

            values.tFee = 0;

            values.tSwap = 0;

            values.tTreasury = 0;

            values.tTransferAmount = tAmount;


            values.rFee = 0;

        }


        if (values.tSwap > 0) {

            _rOwned[address(this)] += values.tSwap * values.currentRate;

            if(_isExcluded[address(this)]) {

                _tOwned[address(this)] += values.tSwap;

            }

            emit Transfer(from, address(this), values.tSwap);

        }


        if (values.tTreasury > 0) {

            _rOwned[_taxWallets.treasury] += values.tTreasury * values.currentRate;

            if(_isExcluded[_taxWallets.treasury]) {

                _tOwned[_taxWallets.treasury] += values.tTreasury;

            }

            emit Transfer(from, _taxWallets.treasury, values.tTreasury);

        }


        values.rTransferAmount = values.rAmount - (values.rFee + (values.tSwap * values.currentRate) + (values.tTreasury * values.currentRate));

        return values;

    }


    function _getRate() internal view returns(uint256) {

        uint256 rSupply = _rTotal;

        uint256 tSupply = _tTotal;

        if(_isExcluded[lpPair]) {

            if (_rOwned[lpPair] > rSupply || _tOwned[lpPair] > tSupply) return _rTotal / _tTotal;

            rSupply -= _rOwned[lpPair];

            tSupply -= _tOwned[lpPair];

        }

        if(_excluded.length > 0) {

            for (uint8 i = 0; i < _excluded.length; i++) {

                if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return _rTotal / _tTotal;

                rSupply = rSupply - _rOwned[_excluded[i]];

                tSupply = tSupply - _tOwned[_excluded[i]];

            }

        }

        if (rSupply < _rTotal / _tTotal) return _rTotal / _tTotal;

        return rSupply / tSupply;

    }


    function getNextSellTime(address account) external view returns (uint256) {

        uint256 nextSell = lastSellTime[account] + 24 hours;

        return nextSell - block.timestamp;

    }


    function setDayTraderTimeDelay(uint256 time) external {

        require(time <= 24 hours);

        dayTraderTimeLimit = time;

    }

}

Code Audit Findings

Audits Overview

Context
Project Name
NiFTi
Platform
Language
Codebase
Commit
About Xamer Audits
Delivery Date
Audit Methodology
Core Components
Vulnerability Summary
VULNERABILITY LEVEL PENDING DECLINED ACKNOWLEDGED PARTIALLY RESOLVED MITIGATED RESOLVED TOTAL
Critical 0 0 0 0 0 0 0
Major 0 0 0 0 0 0 0
Medium 0 0 0 0 0 4 4
Minor 0 0 0 0 0 1 1
Optimization 0 0 0 0 0 0 0
Informational 0 0 0 0 0 0 0
Discussion 0 0 0 0 0 0 0
Review Notes

Overview

The provided Solidity smart contract is designed for a token on the Ethereum blockchain. It includes functions to exclude addresses from certain restrictions, handle token transfers with specific conditions (e.g., trading limits, automatic liquidity provision on sells), and manage various taxes (swap, treasury, reflection). The contract supports features like enabling trading, sweeping ETH balances, and setting time delays for day traders.

It employs checks to ensure the security of transactions, and its functionality extends to liquidity management, token reflections, and treasury allocation. However, a complete understanding would require access to the full code, including definitions for variables such as `Ratios` and `ExtraValues`. It's crucial for such contracts to undergo thorough testing and auditing to mitigate potential risks.

Privileged Roles

The provided Solidity smart contract defines several privileged roles, typically restricted to the owner of the contract (the individual or entity deploying the contract on the Ethereum blockchain). Here are the privileged roles identified in the code:

Owner: The `_owner` variable represents the owner of the contract. The `onlyOwner` modifier ensures that certain functions can only be called by the owner, providing them with control over critical operations.

Exclusion Functions: The `excludePresaleAddresses` and `setExcludedFromReward` functions allow the owner to exclude specific addresses from fees or rewards, providing a level of control over tokenomics.

Trading Enabler: The `enableTrading` function, which can only be called by the owner, allows the activation of trading. It ensures that trading is enabled only once liquidity has been added, adding a layer of security.

Contingency Sweeper:
The `sweepContingency` function enables the owner to sweep the contract's ETH balance. This operation is allowed before liquidity is added, and it transfers the contract's ETH balance to the owner.

Token Sender: The `multiSendTokens` function allows the owner to send tokens to multiple addresses simultaneously. This is a bulk transfer function restricted to the owner.

These privileged roles provide the owner with control over critical aspects of the contract, such as liquidity activation, fee and reward exclusions, and fund management. It's important for the owner to use these capabilities responsibly to maintain the security and integrity of the token contract.

Audits Scope

ID FILE SHA256 CHECKSUM
NFT nifti.sol e6c5f33e1488424eeb3fcda5f77a86ce86ed6b4ee810f00e546d9e0d3402c186

NFT-01 | Input Validation Missing

CATEGORY SEVERITY LOCATIONS STATUS
privilege Medium

 function _hasLimits(address from, address to) internal view returns (bool) {
         return from != _owner
         && to != _owner
       && tx.origin != _owner
        && !_liquidityHolders[to]
       && !_liquidityHolders[from]
         && to != DEAD
        && to != address(0)
         && from != address(this);
   }

RESOLVED
Description

Location in code: Inside the _hasLimits function
Line number: 931-949
Description:
The _hasLimits function should perform thorough input validation to prevent unexpected behavior. Ensure that all relevant conditions are properly checked to avoid potential vulnerabilities.

NFT-02 | Access Control Issue

CATEGORY SEVERITY LOCATIONS STATUS
privilege Medium

  function excludePresaleAddresses(address router, address presale) external onlyOwner {
        require(allowedPresaleExclusion);
   require(router != address(this) && presale != address(this), "Just don't.");
        if (router == presale) {
     _liquidityHolders[presale] = true;
     presaleAddresses[presale] = true;
     setExcludedFromFees(presale, true);
      setExcludedFromReward(presale, true);
             } else {
       _liquidityHolders[router] = true;
       _liquidityHolders[presale] = true;
    presaleAddresses[router] = true;
     presaleAddresses[presale] = true;
       setExcludedFromFees(router, true);
      setExcludedFromFees(presale, true);
      setExcludedFromReward(router, true);
    setExcludedFromReward(presale, true);
               }
      }

RESOLVED
Description

Location in code: Inside the excludePresaleAddresses function
Line number: 892-928
Description:
The excludePresaleAddresses function should enforce proper access control to prevent unauthorized modifications. Consider adding appropriate access checks to ensure only authorized users can invoke this function.

NFT-03 | Gas Limit Consideration

CATEGORY SEVERITY LOCATIONS STATUS
privilege Minor

 function _finalizeTransfer(address from, address to, uint256 tAmount, bool takeFee, bool buy, bool sell, bool other) internal returns (bool) {
         if (!_hasLiqBeenAdded) {
  _checkLiquidityAdd(from, to);
  if (!_hasLiqBeenAdded && _hasLimits(from, to) && !_isExcludedFromProtection[from] && !_isExcludedFromProtection[to] && !other) {
  revert("Pre-liquidity transfer protection.");
             }
     }
 ExtraValues memory values = takeTaxes(from, to, tAmount, takeFee, buy, sell, other);
    _rOwned[from] -= values.rAmount;
   _rOwned[to] += values.rTransferAmount;
        if (_isExcluded[from]) {
      _tOwned[from] = _tOwned[from] - tAmount;
                    }
     if (_isExcluded[to]) {
  _tOwned[to] = _tOwned[to] + values.tTransferAmount;
           }
      if (values.rFee > 0 || values.tFee > 0) {
            _rTotal -= values.rFee;
              }
  emit Transfer(from, to, values.tTransferAmount);
       return true;
      }

RESOLVED
Description

Location in code: Inside the _finalizeTransfer function
Line number:  1340-1387
Description:
The _finalizeTransfer function may require gas optimization to ensure it doesn't exceed block gas limits. Evaluate the gas usage and optimize if necessary.

NFT-04 | Lack of Comprehensive Transfer Limits

CATEGORY SEVERITY LOCATIONS STATUS
privilege Medium

 function _transfer(address from, address to, uint256 amount) internal returns (bool) {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");
       require(amount > 0, "Transfer amount must be greater than zero");
       bool buy = false;  bool sell = false;
      bool other = false;
       if (lpPairs[from]) { buy = true; } else if (lpPairs[to]) { sell = true;} else { other = true; }
    if(_hasLimits(from, to)) {  if(!tradingEnabled) { revert("Trading not yet enabled!"); }
     if(buy || sell){ if (!_isExcludedFromLimits[from] && !_isExcludedFromLimits[to]) {
 require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount."); }
             } if(to != address(dexRouter) && !sell) { if (!_isExcludedFromLimits[to]) {
 require(balanceOf(to) + amount <= _maxWalletSize, "Transfer amount exceeds the maxWalletSize."); }
            }
  } bool takeFee = true;  if(_isExcludedFromFees[from] || _isExcludedFromFees[to]){ takeFee = false; }
        if (sell) { if (!inSwap  && contractSwapEnabled  && !presaleAddresses[to]  && !presaleAddresses[from]
   ) {  if (lastSwap + contractSwapTimer < block.timestamp) {  uint256 contractTokenBalance = balanceOf(address(this));
     if (contractTokenBalance >= swapThreshold) {    if(contractTokenBalance >= swapAmount) { contractTokenBalance = swapAmount; }
        contractSwap(contractTokenBalance);    lastSwap = block.timestamp;
                         }
                 }
                    }      
              }
  return _finalizeTransfer(from, to, amount, takeFee, buy, sell, other);
       }

RESOLVED
Description

Location in code: Inside the _transfer(address from, address to, uint256 amount) internal returns (bool)  function
Line number: 952-1054
Description:
While there are transfer limits in place, ensure that they cover all possible scenarios and adequately prevent potential exploits. Evaluate the logic in the _transfer function and verify that the limits are consistently enforced.

NFT-05 | Automated Liquidity Provision Control

CATEGORY SEVERITY LOCATIONS STATUS
privilege Medium

  function contractSwap(uint256 contractTokenBalance) internal lockTheSwap {
      Ratios memory ratios = _ratios;
      if (ratios.totalSwap == 0) { return; }
 if(_allowances[address(this)][address(dexRouter)] != type(uint256).max) {
 _allowances[address(this)][address(dexRouter)] = type(uint256).max; }
 uint256 toLiquify = ((contractTokenBalance * ratios.liquidity) / ratios.totalSwap) / 2;
   uint256 swapAmt = contractTokenBalance - toLiquify;
      address[] memory path = new address[](2);
        path[0] = address(this);
     path[1] = dexRouter.WETH();
    dexRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
            swapAmt, 0, path,  address(this),
           block.timestamp
           );
 uint256 amtBalance = address(this).balance;
  uint256 liquidityBalance = (amtBalance * toLiquify) / swapAmt;
      if (toLiquify > 0) {
   dexRouter.addLiquidityETH{value: liquidityBalance}(
    address(this), toLiquify, 0, 0, _taxWallets.liquidity,
      block.timestamp  ); emit AutoLiquify(liquidityBalance, toLiquify); }
   amtBalance -= liquidityBalance;  ratios.totalSwap -= ratios.liquidity;
   uint256 developmentBalance = (amtBalance * ratios.development) / ratios.totalSwap;
       uint256 marketingBalance = amtBalance - (developmentBalance);
      if (ratios.marketing > 0) { _taxWallets.marketing.transfer(marketingBalance); }
          if (ratios.development > 0) {
  developmentWallet.transfer(developmentBalance);
                }
      }

RESOLVED
Description

Location in code: Inside the function contractSwap(uint256 contractTokenBalance) internal lockTheSwap {
Line number: 1057-1151
Description:
The contractSwap function handles automated liquidity provision. Verify that this mechanism is secure, and assess the impact on liquidity pools. Consider implementing additional checks to enhance the security of this process.