• Base Contracts

Here is a full sample contract with all needed functions to use in the DETA Swap 2.0


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

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/IDETASwapFactory.sol";
import "./interfaces/IDETASwapRouter.sol";


contract DETASwap_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 = "DETASwap_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;

    IDETASwapRouter public DETASwapRouter;
    address public DETASwapPair;
    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(DETASwapRouter)
            || isPair
            , "DETA: 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;

        DETASwapRouter = IDETASwapRouter(_router);
        WBNB = DETASwapRouter.WETH();
        DETASwapPair = IDETASwapFactory(DETASwapRouter.factory())
        .createPair(address(this), WBNB, true, address(this));

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

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

        isTxLimitExempt[_msgSender()] = true;
        isTxLimitExempt[DETASwapPair] = true;
        isTxLimitExempt[address(DETASwapRouter)] = 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), "DETA: 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), "DETA: 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[DETASwapPair] = false;
        DETASwapRouter = IDETASwapRouter(_router);
        DETASwapPair = _pair;
        WBNB = DETASwapRouter.WETH();

        _isExcludedFromFee[DETASwapPair] = true;

        _isPairAddress[DETASwapPair] = true;

        isTxLimitExempt[DETASwapPair] = true;
        isTxLimitExempt[address(DETASwapRouter)] = true;

        pairs[0] = DETASwapPair;
        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 DETARouter 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(DETASwapRouter) && !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 = DETASwapRouter.factory();
        require(
            msg.sender == factory
            || msg.sender == address(DETASwapRouter)
            || msg.sender == address(this)
        , "DETA: 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