๐Ÿ–ฅ๏ธSwap 2.0

Swap 2.0 Smart Contract Guide

Swap 2.0 Contract Upgrade Intro

Typical Automated Market Makers (AMMโ€™s) and Exchanges sell project tokens to collect requisite fees and taxes for every transaction. As a result, each swap incurs negative sell pressure, subsequently hampering the projectโ€™s momentum over time. PYESwap, the only Swap 2.0 compatible exchange, and Swap 2.0 smart contracts eliminate this significant drawback by instead collecting taxes and fees in the trading pairs base coin or token, such as BNB, ETH, BUSD, or USDC. By mitigating unnecessary sells in each transaction, Swap 2.0 technology directly promotes authentic markets and project longevity. There are two ways to incorporate Swap 2.0 capability in your token smart contract:

  1. Utilize PYELabโ€™s Token Creator feature to generate a Swap 2.0 compatible token contract quickly and easily - no programming required. Select from a pre-defined list of contracts with optional tokenomics such as automatic buybacks and liquidity contributions to mitigate sell pressure.

  2. Manually add the following necessary logic to your token contract:

Existing Smart Contract Upgrade Process

If you already have token smart contract that you would like to build off of and make Swap 2.0 compatible, there are two primary sections that must be added to your token contractโ€™s code:

  • Router/Pair Info

  • Fee Structuring

Router and Pair Setup

1. Begin by importing the PYESwapRouter and PYESwapFactory from:

import โ€œ@PYELibrary/../../IPYESwapFactory.solโ€; (need actual public repos here)
import โ€œ@PYELibrary/../../IPYESwapRouter.solโ€;

2. Now, instantiate the pyeSwapRouter and pyeSwapPair address in your contract as such:

IPYESwapRouter public pyeSwapRouter;
address public pyeSwapPair;

3. In the constructor function for your contract, pass the pyeSwapRouter address and cast the address as an interface. Additionally, deploy your new trading pair:

pyeSwapRouter = IPYESwapRouter(_router);         
WBNB = pyeSwapRouter.WETH();         
pyeSwapPair = IPYESwapFactory(pyeSwapRouter.factory())
.createPair(address(this), WBNB, true, address(this));

tokens[pairsLength] = WBNB;         
pairs[pairsLength] = pyeSwapPair;         
pairsLength += 1;         
_isPairAddress[pyeSwapPair] = true;

4. If you plan on adding your token pair to an exchange other than PYESwap, you can do so by adding the following functions to your contract:

function addOutsideSwapPair(address account) public onlyOwner {         
     _includeSwapFee[account] = true;     
}     
 
function removeOutsideSwapPair(address account) public onlyOwner {
     _includeSwapFee[account] = false;     
}

These functions take a pair contract address โ€œaccountโ€ as a parameter and includes or excludes them from swap fees accordingly. Also include the following functions to add token pairs to the pair list:

// adds a token pair to the factory pair list.
function addPair(address _pair, address _token) public {         
    address factory = pyeSwapRouter.factory();         
    require( msg.sender == factory || msg.sender == address(pyeSwapRouter) || msg.sender == address(this) , "PYE: NOT_ALLOWED");          
    if(!_checkPairRegistered(_pair)) {             
        _isExcludedFromFee[_pair] = true;             
        _isPairAddress[_pair] = true;              
        pairs[pairsLength] = _pair;             
        tokens[pairsLength] = _token;              
        pairsLength += 1;         
    }     
}

// internal function to check if a pair address is already registered.
function _checkPairRegistered(address _pair) internal view returns (bool) {         
    bool isPair = false;         
    for(uint i = 0; i < pairsLength; i++) {             
        if(pairs[i] == _pair) isPair = true;         
    }          
    return isPair;     
}

// internal function to return the index of a pair address 
function _getTokenIndex(address _token) internal view returns (uint256) {         
    uint256 index = pairsLength + 1;         
    for(uint256 i = 0; i < pairsLength; i++) {             
        if(tokens[i] == _token) index = i;         
    }          
    return index;     
}

// Crucially, you should add this function to update the PYESwapRouter address should a new version come out. This function also affords you the ability to update your tokenโ€™s pair contract:

function updateRouterAndPair(address _router, address _pair) public onlyOwner {         
    _isExcludedFromFee[pyeSwapPair] = false;         
    pyeSwapRouter = IPYESwapRouter(_router);         
    pyeSwapPair = _pair;         
    WBNB = pyeSwapRouter.WETH();          
    _isExcludedFromFee[pyeSwapPair] = true;          
    _isPairAddress[pyeSwapPair] = true;          
    pairs[0] = pyeSwapPair;        
    tokens[0] = WBNB;     
}

// lastly, add the onlyExchange modifier to restrict the set of addresses which can execute certain swap 2.0 functions:

modifier onlyExchange() {         
    bool isPair = false;         
    for(uint i = 0; i < pairsLength; i++) {             
        if(pairs[i] == msg.sender) isPair = true;         
    }         
    require(msg.sender == address(pyeSwapRouter) || isPair, "PYE: NOT_ALLOWED");         
    olid_;     
}

Fee Structure

1. Begin your fee structuring by declaring two structs: Fees and FeeValues. The Fees struct contains the numeric fee value corresponding to a particular fee. For example, a 2% marketing fee would be entered as โ€œ200โ€. The FeeValues struct contains the token amounts corresponding to the fees for a particular tx.

The Fees struct should contain the fee value and the associated address in which that fee is collected. As an example, a token contract with one fee would be declared as:

struct Fees {         
    uint256 wallet1Fee;         
    address wallet1Address;     
}

You can add as many fees as youโ€™d like, as long as you instantiate the fee and its collection address in the Fees struct. A FeeValues struct for the above example would look like:

struct FeeValues {         
    uint256 transferAmount;         
    uint256 wallet1;     
}

2. Create structs for each fee class as such:

Fees private _defaultFees;
Fees public _buyFees;
Fees private _previousFees;
Fees private _emptyFees;
Fees public _sellFees;
Fees private _outsideBuyFees;
Fees private _outsideSellFees;

3. Include a mapping to set certain addresses (ex: routers, wallets) as being excluded from fees.

mapping (address => bool) private _isExcludedFromFee;

4. In the constructor function in your contract, pass the fee values for buys and sells (ex: 200 for 2%) and associated collection addresses as deployment parameters along with any other necessary values:

// Edit the constructor in order to declare default fees on deployment
constructor( existingParams..., address _wallet1, uint256 _wallet1FeeBuy, uint256 _wallet1FeeSell) {
    // ...
    // existing contructor code
    // ...
    
    _defaultFees = Fees(
        _wallet1FeeBuy,
        _wallet1
    );

    _buyFees = Fees(
        _wallet1FeeBuy,
        _wallet1
    );

    _sellFees = Fees(
        _wallet1FeeSell,
        _wallet1
    );

    _outsideBuyFees = Fees(
        _wallet1FeeBuy,
        _wallet1
    );

    _outsideSellFees = Fees(
        _wallet1FeeSell,
        _wallet1
    );
}

These structs contain the values passed for the fee amounts and wallets passed in the constructor.

5. Include functions in the body of your contract to adjust the various buy and sell fees as necessary. Also add two functions to set the _isExcludedFromFee mapping detailed above.

SetBuyFees and setSellFees are used to manually change the associated fees in your contract. This gives you the flexibility to control how fees are collected based on the nature of the transaction.

Use the setWalletAddress functions to change the collection location for the wallet receiving the fees.


function excludeFromFee(address account) public onlyOwner {
    _isExcludedFromFee[account] = true;
}

function includeInFee(address account) public onlyOwner {
    _isExcludedFromFee[account] = false;
}

// Functions to update fees and addresses 

// set fee values on buys
function setBuyFees(uint256 _wallet1Fee) external onlyOwner {
    _defaultFees.wallet1Fee = _wallet1Fee;
    _buyFees.wallet1Fee = _wallet1Fee;
    _outsideBuyFees.wallet1Fee = _wallet1Fee;
}

// set fee values on sells
function setSellFees(uint256 _wallet1Fee) external onlyOwner {
    _defaultFees.wallet1Fee = _wallet1Fee;
    _sellFees.wallet1Fee = _wallet1Fee;
    _outsideSellFees.wallet1Fee = _wallet1Fee;
}

function setwallet1Address(address _wallet1) external onlyOwner {
    require(_wallet1 != address(0), "PYE: Address Zero is not allowed");
    _defaultFees.wallet1Address = _wallet1;
    _buyFees.wallet1Address = _wallet1;
    _sellFees.wallet1Address = _wallet1;
    _outsideBuyFees.wallet1Address = _wallet1;
    _outsideSellFees.wallet1Address = _wallet1;
}   

6. If you want to list your token on an additional exchange, such as PancakeSwap, include the following function to add outside pair contracts:

function addOutsideSwapPair(address account) public onlyOwner {
    _includeSwapFee[account] = true;
}

function removeOutsideSwapPair(address account) public onlyOwner {
    _includeSwapFee[account] = false;
}   

7. Include the following private helper functions; these are required for internal calls within the contract to correctly calculate fees.

_getValues and _calculateFee are internal helper functions to fetch fees for calculations.

function _getValues(uint256 tAmount) private view returns (FeeValues memory) {
    FeeValues memory values = FeeValues(
        0,
        calculateFee(tAmount, _defaultFees.marketingFee),
        calculateFee(tAmount, _defaultFees.developmentFee)
    );

    values.transferAmount = tAmount.sub(values.marketing).sub(values.development);
    return values;
}

function calculateFee(uint256 _amount, uint256 _fee) private pure returns (uint256) {
    if(_fee == 0) return 0;
    return _amount.mul(_fee).div(
        10**4
    );
}

function removeAllFee() private {
    _previousFees = _defaultFees;
    _defaultFees = _emptyFees;
}

function setSellFee() private {
    _defaultFees = _sellFees;
}

function setOutsideBuyFee() private {
    _previousFees = _defaultFees;
    _defaultFees = _outsideBuyFees;
}

function setOutsideSellFee() private {
    _previousFees = _defaultFees;
    _defaultFees = _outsideSellFees;
}

function restoreAllFee() private {
    _defaultFees = _previousFees;
}

function getTotalFee(address account) public view returns (uint256) {
    if(_isExcludedFromFee[account]) {
        return 0;
    } else {
    return _defaultFees.marketingFee
        .add(_defaultFees.developmentFee);
    }
}

function getFee() public view returns (uint256) {
    return _defaultFees.marketingFee
        .add(_defaultFees.developmentFee);
}

function _takeFees(FeeValues memory values) private {
    _takeFee(values.marketing, _defaultFees.marketingAddress);
    _takeFee(values.development, _defaultFees.developmentAddress);
}

function _takeFee(uint256 tAmount, address recipient) private {
    if(recipient == address(0)) return;
    if(tAmount == 0) return;

    _balances[address(this)] = _balances[address(this)].add(tAmount);
}

8. In your tokenโ€™s transfer function, include the following logic to ensure fees are take appropriately depending on the transaction details:

//indicates if fee should be deducted from transfer of tokens
uint8 takeFee = 0;
if(_isPairAddress[to] && from != address(pyeSwapRouter) && !isExcludedFromFee(from)) {
    takeFee = 1;
} else if(_includeSwapFee[from]) {
    takeFee = 2;
} else if(_includeSwapFee[to]) {
    takeFee = 3;
}

//transfer amount, it will take tax
_tokenTransfer(from, to, amount, takeFee);

9. Create a new function in your contract called _tokenTransfer:

//this method is responsible for taking all fee, if takeFee is true
function _tokenTransfer(address sender, address recipient, uint256 amount, uint8 takeFee) private {
    if(takeFee == 0 || takeFee == 1) {
        removeAllFee();
    } else if(takeFee == 2) {
        setOutsideBuyFee();
    } else if(takeFee == 3) {
        setOutsideSellFee();
    }


    FeeValues memory _values = _getValues(amount);
    _balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
    _balances[recipient] = _balances[recipient].add(_values.transferAmount);
    _takeFees(_values);

    emit Transfer(sender, recipient, _values.transferAmount);

    if(takeFee == 0) {
        restoreAllFee();
    } else if(takeFee == 1) {
        setSellFee();
    } else if(takeFee == 2 || takeFee == 3) {
        restoreAllFee();
        emit Transfer(sender, _defaultFees.developmentAddress, _values.development);
        emit Transfer(sender, _defaultFees.marketingAddress, _values.marketing);
    } 
}

10. To actually transfer your fees to the contract and distribute them, include the handleFee() function:

// This function transfers the fees to the correct addresses. 
function handleFee(uint256 amount, address token) public onlyExchange {
    uint256 tokenIndex = _getTokenIndex(token);
    if(tokenIndex < pairsLength) {
        uint256 allowanceT = IERC20(token).allowance(msg.sender, address(this));
        if(allowanceT >= amount) {
            IERC20(token).transferFrom(msg.sender, address(this), amount);

            // All fees to be declared here in order to be calculated and sent
            uint256 totalFee = getFee();
            uint256 wallet1FeeAmount = amount.mul(_defaultFees.wallet1Fee).div(totalFee);

            IERC20(token).transfer(_defaultFees.wallet1Address, wallet1FeeAmount);

            restoreAllFee();
        }
    }
}
Full Sample Contract

Here is a full sample contract with all needed functions

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IPYESwapFactory.sol";
import "./interfaces/IPYESwapRouter.sol";


contract PYESwap_Base is IERC20, Ownable {
    using SafeMath for uint256;
    using Address for address;

    
    // Fees
    // Add and remove fee types and destinations here as needed
    struct Fees {
        uint256 marketingFee;
        uint256 developmentFee;
        address marketingAddress;
        address developmentAddress;
    }

    // Transaction fee values
    // Add and remove fee value types here as needed
    struct FeeValues {
        uint256 transferAmount;
        uint256 marketing;
        uint256 development;
    }

    // Token details
    mapping (address => uint256) _balances;
    mapping (address => mapping (address => uint256)) private _allowances;
    // Set total supply here
    uint256 private _tTotal = 10 * 10**9 * 10**9;



    // Users states
    mapping (address => bool) private _isExcludedFromFee;
    mapping (address => bool) isTxLimitExempt;


    // Pair Details
    mapping (uint256 => address) private pairs;
    mapping (uint256 => address) private tokens;
    uint256 private pairsLength;
    mapping (address => bool) public _isPairAddress;
    // Outside Swap Pairs
    mapping (address => bool) private _includeSwapFee;


    // Set the name, symbol, and decimals here
    string constant _name = "PYESwap_Base";
    string constant _symbol = "BASE";
    uint8 constant _decimals = 9;

    Fees private _defaultFees;
    Fees public _buyFees;
    Fees private _previousFees;
    Fees private _emptyFees;
    Fees public _sellFees;
    Fees private _outsideBuyFees;
    Fees private _outsideSellFees;

    IPYESwapRouter public pyeSwapRouter;
    address public pyeSwapPair;
    address public WBNB;
    address public _burnAddress = 0x000000000000000000000000000000000000dEaD;
    uint256 public _maxTxAmount = 5 * 10**8 * 10**9;

    bool public swapEnabled = true;
    uint256 public swapThreshold = 5 * 10**14; // 0.0005 WBNB
    bool inSwap;

    modifier swapping() { inSwap = true; _; inSwap = false; }
    modifier onlyExchange() {
        bool isPair = false;
        for(uint i = 0; i < pairsLength; i++) {
            if(pairs[i] == msg.sender) isPair = true;
        }
        require(
            msg.sender == address(pyeSwapRouter)
            || isPair
            , "PYE: NOT_ALLOWED"
        );
        _;
    }

    // Edit the constructor in order to declare default fees on deployment
    constructor(address _router, address _marketing, uint256 _marketingFeeBuy, uint256 _marketingFeeSell, address _development, uint256 _developmentFeeBuy, uint256 _developmentFeeSell) {
        _balances[_msgSender()] = _tTotal;

        pyeSwapRouter = IPYESwapRouter(_router);
        WBNB = pyeSwapRouter.WETH();
        pyeSwapPair = IPYESwapFactory(pyeSwapRouter.factory())
        .createPair(address(this), WBNB, true, address(this));

        tokens[pairsLength] = WBNB;
        pairs[pairsLength] = pyeSwapPair;
        pairsLength += 1;
        _isPairAddress[pyeSwapPair] = true;

        _isExcludedFromFee[_msgSender()] = true;
        _isExcludedFromFee[pyeSwapPair] = true;

        isTxLimitExempt[_msgSender()] = true;
        isTxLimitExempt[pyeSwapPair] = true;
        isTxLimitExempt[address(pyeSwapRouter)] = true;

        // This should match the struct Fee
        _defaultFees = Fees(
            _marketingFeeBuy,
            _developmentFeeBuy,
            _marketing,
            _development
        );

        _buyFees = Fees(
            _marketingFeeBuy,
            _developmentFeeBuy,
            _marketing,
            _development
        );

        _sellFees = Fees(
            _marketingFeeSell,
            _developmentFeeSell,
            _marketing,
            _development
        );

        _outsideBuyFees = Fees(
            _marketingFeeBuy,
            _developmentFeeBuy,
            _marketing,
            _development
        );

        _outsideSellFees = Fees(
            _marketingFeeSell,
            _developmentFeeSell,
            _marketing,
            _development
        );
        
        emit Transfer(address(0), _msgSender(), _tTotal);
    }

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

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

    function decimals() public pure returns (uint8) {
        return _decimals;
    }

    function totalSupply() public view override returns (uint256) {
        return _tTotal;
    }

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    function transfer(address recipient, uint256 amount) public override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

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

    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "BEP20: transfer amount exceeds allowance"));
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "BEP20: decreased allowance below zero"));
        return true;
    }

    function excludeFromFee(address account) public onlyOwner {
        _isExcludedFromFee[account] = true;
    }

    function includeInFee(address account) public onlyOwner {
        _isExcludedFromFee[account] = false;
    }

    // Functions to update fees and addresses 

     // set fee values on buys
    function setBuyFees(uint256 _marketingFee, uint256 _developmentFee) external onlyOwner {
        _defaultFees.marketingFee = _marketingFee;
        _defaultFees.developmentFee = _developmentFee;

        _buyFees.marketingFee = _marketingFee;
        _buyFees.developmentFee = _developmentFee;

        _outsideBuyFees.marketingFee = _marketingFee;
        _outsideBuyFees.developmentFee = _developmentFee;
    }

    // set fee values on sells
    function setSellFees(uint256 _marketingFee, uint256 _developmentFee) external onlyOwner {
        _sellFees.marketingFee = _marketingFee;
        _sellFees.developmentFee = _developmentFee;

        _outsideSellFees.marketingFee = _marketingFee;
        _outsideSellFees.developmentFee = _developmentFee;  
    }

    function setDevelopmentAddress(address _development) external onlyOwner {
        require(_development != address(0), "PYE: Address Zero is not allowed");
        _defaultFees.developmentAddress = _development;
        _buyFees.developmentAddress = _development;
        _sellFees.developmentAddress = _development;
        _outsideBuyFees.developmentAddress = _development;
        _outsideSellFees.developmentAddress = _development;
    }

    function setMarketingAddress(address _marketing) external onlyOwner {
        require(_marketing != address(0), "PYE: Address Zero is not allowed");
        _defaultFees.marketingAddress = _marketing;
        _buyFees.marketingAddress = _marketing;
        _sellFees.marketingAddress = _marketing;
        _outsideBuyFees.marketingAddress = _marketing;
        _outsideSellFees.marketingAddress = _marketing;
    }



    function updateRouterAndPair(address _router, address _pair) public onlyOwner {
        _isExcludedFromFee[pyeSwapPair] = false;
        pyeSwapRouter = IPYESwapRouter(_router);
        pyeSwapPair = _pair;
        WBNB = pyeSwapRouter.WETH();

        _isExcludedFromFee[pyeSwapPair] = true;

        _isPairAddress[pyeSwapPair] = true;

        isTxLimitExempt[pyeSwapPair] = true;
        isTxLimitExempt[address(pyeSwapRouter)] = true;

        pairs[0] = pyeSwapPair;
        tokens[0] = WBNB;
    }

    function addOutsideSwapPair(address account) public onlyOwner {
        _includeSwapFee[account] = true;
    }

    function removeOutsideSwapPair(address account) public onlyOwner {
        _includeSwapFee[account] = false;
    }

    // To update the max tx amount
    function setMaxTxPercent(uint256 maxTxPercent) external onlyOwner {
        _maxTxAmount = _tTotal.mul(maxTxPercent).div(
            10**4
        );
    }

    //to receive BNB from pyeRouter when swapping
    receive() external payable {}

    function _getValues(uint256 tAmount) private view returns (FeeValues memory) {
        FeeValues memory values = FeeValues(
            0,
            calculateFee(tAmount, _defaultFees.marketingFee),
            calculateFee(tAmount, _defaultFees.developmentFee)
        );

        values.transferAmount = tAmount.sub(values.marketing).sub(values.development);
        return values;
    }

    function calculateFee(uint256 _amount, uint256 _fee) private pure returns (uint256) {
        if(_fee == 0) return 0;
        return _amount.mul(_fee).div(
            10**4
        );
    }

    function removeAllFee() private {
        _previousFees = _defaultFees;
        _defaultFees = _emptyFees;
    }

    function setSellFee() private {
        _defaultFees = _sellFees;
    }

    function setOutsideBuyFee() private {
        _previousFees = _defaultFees;
        _defaultFees = _outsideBuyFees;
    }

    function setOutsideSellFee() private {
        _previousFees = _defaultFees;
        _defaultFees = _outsideSellFees;
    }

    function restoreAllFee() private {
        _defaultFees = _previousFees;
    }

    function isExcludedFromFee(address account) public view returns(bool) {
        return _isExcludedFromFee[account];
    }

    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) private {
        require(owner != address(0), "BEP20: approve from the zero address");
        require(spender != address(0), "BEP20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function getBalance(address keeper) public view returns (uint256){
        return _balances[keeper];
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) private {
        require(from != address(0), "BEP20: transfer from the zero address");
        require(to != address(0), "BEP20: transfer to the zero address");
        require(amount > 0, "Transfer amount must be greater than zero");

        checkTxLimit(from, amount);

        //indicates if fee should be deducted from transfer of tokens
        uint8 takeFee = 0;
        if(_isPairAddress[to] && from != address(pyeSwapRouter) && !isExcludedFromFee(from)) {
            takeFee = 1;
        } else if(_includeSwapFee[from]) {
            takeFee = 2;
        } else if(_includeSwapFee[to]) {
            takeFee = 3;
        }

        //transfer amount, it will take tax
        _tokenTransfer(from, to, amount, takeFee);
    }

    function getCirculatingSupply() public view returns (uint256) {
        return _tTotal.sub(balanceOf(_burnAddress)).sub(balanceOf(address(0)));
    }

    function getTotalFee(address account) public view returns (uint256) {
        if(_isExcludedFromFee[account]) {
            return 0;
        } else {
        return _defaultFees.marketingFee
            .add(_defaultFees.developmentFee);
        }
    }

    function getFee() public view returns (uint256) {
        return _defaultFees.marketingFee
            .add(_defaultFees.developmentFee);
    }

    //this method is responsible for taking all fee, if takeFee is true
    function _tokenTransfer(address sender, address recipient, uint256 amount, uint8 takeFee) private {
        if(takeFee == 0 || takeFee == 1) {
            removeAllFee();
        } else if(takeFee == 2) {
            setOutsideBuyFee();
        } else if(takeFee == 3) {
            setOutsideSellFee();
        }


        FeeValues memory _values = _getValues(amount);
        _balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
        _balances[recipient] = _balances[recipient].add(_values.transferAmount);
        _takeFees(_values);

        emit Transfer(sender, recipient, _values.transferAmount);

        if(takeFee == 0) {
            restoreAllFee();
        } else if(takeFee == 1) {
            setSellFee();
        } else if(takeFee == 2 || takeFee == 3) {
            restoreAllFee();
            emit Transfer(sender, _defaultFees.developmentAddress, _values.development);
            emit Transfer(sender, _defaultFees.marketingAddress, _values.marketing);
        } 
    }

    function _takeFees(FeeValues memory values) private {
        _takeFee(values.marketing, _defaultFees.marketingAddress);
        _takeFee(values.development, _defaultFees.developmentAddress);
    }

    function _takeFee(uint256 tAmount, address recipient) private {
        if(recipient == address(0)) return;
        if(tAmount == 0) return;

        _balances[address(this)] = _balances[address(this)].add(tAmount);
    }

    function setIsTxLimitExempt(address holder, bool exempt) external onlyOwner {
        isTxLimitExempt[holder] = exempt;
    }

    function checkTxLimit(address sender, uint256 amount) internal view {
        require(amount <= _maxTxAmount || isTxLimitExempt[sender], "TX Limit Exceeded");
    }

    // This function transfers the fees to the correct addresses. 
    function handleFee(uint256 amount, address token) public onlyExchange {
        uint256 tokenIndex = _getTokenIndex(token);
        if(tokenIndex < pairsLength) {
            uint256 allowanceT = IERC20(token).allowance(msg.sender, address(this));
            if(allowanceT >= amount) {
                IERC20(token).transferFrom(msg.sender, address(this), amount);

                // All fees to be declared here in order to be calculated and sent
                uint256 totalFee = getFee();
                uint256 marketingFeeAmount = amount.mul(_defaultFees.marketingFee).div(totalFee);
                uint256 developmentFeeAmount = amount.mul(_defaultFees.developmentFee).div(totalFee);

                IERC20(token).transfer(_defaultFees.marketingAddress, marketingFeeAmount);
                IERC20(token).transfer(_defaultFees.developmentAddress, developmentFeeAmount);

                restoreAllFee();
            }
        }
    }

    function _getTokenIndex(address _token) internal view returns (uint256) {
        uint256 index = pairsLength + 1;
        for(uint256 i = 0; i < pairsLength; i++) {
            if(tokens[i] == _token) index = i;
        }

        return index;
    }

    function addPair(address _pair, address _token) public {
        address factory = pyeSwapRouter.factory();
        require(
            msg.sender == factory
            || msg.sender == address(pyeSwapRouter)
            || msg.sender == address(this)
        , "PYE: NOT_ALLOWED"
        );

        if(!_checkPairRegistered(_pair)) {
            _isExcludedFromFee[_pair] = true;
            _isPairAddress[_pair] = true;
            isTxLimitExempt[_pair] = true;

            pairs[pairsLength] = _pair;
            tokens[pairsLength] = _token;

            pairsLength += 1;
        }
    }

    function _checkPairRegistered(address _pair) internal view returns (bool) {
        bool isPair = false;
        for(uint i = 0; i < pairsLength; i++) {
            if(pairs[i] == _pair) isPair = true;
        }

        return isPair;
    }

    // Rescue bnb that is sent here by mistake
    function rescueBNB(uint256 amount, address to) external onlyOwner{
        payable(to).transfer(amount);
      }

    // Rescue tokens that are sent here by mistake
    function rescueToken(IERC20 token, uint256 amount, address to) external onlyOwner {
        if( token.balanceOf(address(this)) < amount ) {
            amount = token.balanceOf(address(this));
        }
        token.transfer(to, amount);
    }
}

Last updated