ETH Price: $2,241.90 (-2.01%)

Transaction Decoder

Block:
12944276 at Aug-02-2021 06:04:40 AM +UTC
Transaction Fee:
0.006718272 ETH $15.06
Gas Used:
279,928 Gas / 24 Gwei

Emitted Events:

110 FEG.Transfer( from=[Sender] 0x8482741006f65270655ff08d704126028207bdb6, to=[Receiver] FEGstakeV2, value=59945293151192154604 )
111 FEG.Approval( owner=[Sender] 0x8482741006f65270655ff08d704126028207bdb6, spender=[Receiver] FEGstakeV2, value=999999999999999938831333519191678976 )
112 FEGstakeV2.Transfer( src=0x0000000000000000000000000000000000000000, dst=[Receiver] FEGstakeV2, amt=59890233447565450162 )
113 FEGstakeV2.Transfer( src=[Receiver] FEGstakeV2, dst=[Sender] 0x8482741006f65270655ff08d704126028207bdb6, amt=59890233447565450162 )
114 FEGstakeV2.STAKED( staker=[Sender] 0x8482741006f65270655ff08d704126028207bdb6, tokens=61168666480808321024 )

Account State Difference:

  Address   Before After State Difference Code
(zhizhu.top)
148.3306789230705458 Eth148.3373971950705458 Eth0.006718272
0x38999921...52522C945
0x4a9D6b95...b20fa2358
0x84827410...28207Bdb6
0.020355436030053241 Eth
Nonce: 66
0.013637164030053241 Eth
Nonce: 67
0.006718272

Execution Trace

FEGstakeV2.STAKE( tokens=61168666480808321024 ) => ( poolAmountOut=59890233447565450162 )
  • FEG.balanceOf( account=0x8482741006F65270655ff08d704126028207Bdb6 ) => ( 61168710610916826870 )
  • FEG.balanceOf( account=0x4a9D6b95459eb9532B7E4d82Ca214a3b20fa2358 ) => ( 3189644726870568276972930 )
  • FEGstakeV2.balanceOf( whom=0x8482741006F65270655ff08d704126028207Bdb6 ) => ( 0 )
  • FEGstakeV2.balanceOf( whom=0x8482741006F65270655ff08d704126028207Bdb6 ) => ( 0 )
  • FEGstakeV2.balanceOf( whom=0x8482741006F65270655ff08d704126028207Bdb6 ) => ( 0 )
  • FEG.transferFrom( sender=0x8482741006F65270655ff08d704126028207Bdb6, recipient=0x4a9D6b95459eb9532B7E4d82Ca214a3b20fa2358, amount=61168666480808321024 ) => ( True )
  • FEGstakeV2.transfer( dst=0x8482741006F65270655ff08d704126028207Bdb6, amt=59890233447565450162 ) => ( True )
    STAKE[FEGstakeV2 (ln:844)]
    File 1 of 2: FEGstakeV2
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity 0.7.6;
    
    
    
    abstract contract ReentrancyGuard {
    
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
    
        uint256 private _status;
    
        constructor () {
            _status = _NOT_ENTERED;
        }
    
        modifier nonReentrant() {
    
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
    
            _status = _ENTERED;
    
            _;
    
            _status = _NOT_ENTERED;
        }
    }
    
    // ----------------------------------------------------------------------------
    // SafeMath library
    // ----------------------------------------------------------------------------
    
    
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
    
            return c;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
                return 0;
            }
    
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be 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); // There is no case in which this doesn't hold
    
            return c;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts with custom message when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
        
        function ceil(uint a, uint m) internal pure returns (uint r) {
            return (a + m - 1) / m * m;
        }
    }
    
    // ----------------------------------------------------------------------------
    // Owned contract
    // ----------------------------------------------------------------------------
    contract Owned {
        address public owner;
    
        event OwnershipTransferred(address indexed _from, address indexed _to);
    
        constructor() {
            owner = msg.sender;
        }
    
        modifier onlyOwner {
            require(msg.sender == owner);
            _;
        }
    
        function transferOwnership(address payable _newOwner) public onlyOwner {
            require(_newOwner != address(0), "ERC20: sending to the zero address");
            owner = _newOwner;
            emit OwnershipTransferred(msg.sender, _newOwner);
        }
    }
    
    // ----------------------------------------------------------------------------
    // ERC Token Standard #20 Interface
    // ----------------------------------------------------------------------------
    interface IERC20 {
        function totalSupply() external view returns (uint256);
        function balanceOf(address tokenOwner) external view returns (uint256 balance);
        function allowance(address tokenOwner, address spender) external view returns (uint256 remaining);
        function transfer(address to, uint256 tokens) external returns (bool success);
        function approve(address spender, uint256 tokens) external returns (bool success);
        function transferFrom(address from, address to, uint256 tokens) external returns (bool success);
        function burnTokens(uint256 _amount) external;
        
        function calculateFeesBeforeSend(
            address sender,
            address recipient,
            uint256 amount
        ) external view returns (uint256, uint256);
        
        
        event Transfer(address indexed from, address indexed to, uint256 tokens);
        event Approval(address indexed tokenOwner, address indexed spender, uint256 tokens);
    }
    
    interface regreward {
        function distributeV2() external;
    }
    
    interface FEGex2 {
        function BUY(
            address to,
            uint minAmountOut
        ) 
            external payable
            returns (uint tokenAmountOut, uint spotPriceAfter);
    }
    
    // ----------------------------------------------------------------------------
    // ERC20 Token, with the addition of symbol, name and decimals and assisted
    // token transfers
    // ----------------------------------------------------------------------------
    
    library Roles {
        struct Role {
            mapping (address => bool) bearer;
        }
    
        function add(Role storage role, address account) internal {
            require(!has(role, account), "Roles: account already has role");
            role.bearer[account] = true;
        }
    
        function remove(Role storage role, address account) internal {
            require(has(role, account), "Roles: account does not have role");
            role.bearer[account] = false;
        }
    
        function has(Role storage role, address account) internal view returns (bool) {
            require(account != address(0), "Roles: account is the zero address");
            return role.bearer[account];
        }
    }
    
    contract WhitelistAdminRole is Owned  {
        using Roles for Roles.Role;
    
        event WhitelistAdminAdded(address indexed account);
        event WhitelistAdminRemoved(address indexed account);
    
        Roles.Role private _whitelistAdmins;
    
       constructor () {
            _addWhitelistAdmin(msg.sender);
        }
        
        modifier onlyWhitelistAdmin() {
            require(isWhitelistAdmin(msg.sender), "WhitelistAdminRole: caller does not have the WhitelistAdmin role");
            _;
        }
    
        function isWhitelistAdmin(address account) public view returns (bool) {
            return _whitelistAdmins.has(account);
        }
        function addWhitelistAdmin(address account) public onlyWhitelistAdmin {
            _addWhitelistAdmin(account);
        }
    
        function renounceWhitelistAdmin() public {
            _removeWhitelistAdmin(msg.sender);
        }
    
        function _addWhitelistAdmin(address account) internal {
            _whitelistAdmins.add(account);
            emit WhitelistAdminAdded(account);
        } 
    
        function _removeWhitelistAdmin(address account) internal {
            _whitelistAdmins.remove(account);
            emit WhitelistAdminRemoved(account);
        }
    }
    
    contract FNum is ReentrancyGuard{
    
        uint public constant BASE              = 10**18;
        
        function badd(uint a, uint b)
            internal pure
            returns (uint)
        {
            uint c = a + b;
            require(c >= a, "ERR_ADD_OVERFLOW");
            return c;
        }
    
        function bsub(uint a, uint b)
            internal pure
            returns (uint)
        {
            (uint c, bool flag) = bsubSign(a, b);
            require(!flag, "ERR_SUB_UNDERFLOW");
            return c;
        }
    
        function bsubSign(uint a, uint b)
            internal pure
            returns (uint, bool)
        {
            if (a >= b) {
                return (a - b, false);
            } else {
                return (b - a, true);
            }
        }
    
        function bmul(uint a, uint b)
            internal pure
            returns (uint)
        {
            uint c0 = a * b;
            require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW");
            uint c1 = c0 + (BASE / 2);
            require(c1 >= c0, "ERR_MUL_OVERFLOW");
            uint c2 = c1 / BASE;
            return c2;
        }
    
        function bdiv(uint a, uint b)
            internal pure
            returns (uint)
        {
            require(b != 0, "ERR_DIV_ZERO");
            uint c0 = a * BASE;
            require(a == 0 || c0 / a == BASE, "ERR_DIV_INTERNAL"); // bmul overflow
            uint c1 = c0 + (b / 2);
            require(c1 >= c0, "ERR_DIV_INTERNAL"); //  badd require
            uint c2 = c1 / b;
            return c2;
        }
        
    function btoi(uint a)
            internal pure
            returns (uint)
        {
            return a / BASE;
        }
    
        function bfloor(uint a)
            internal pure
            returns (uint)
        {
            return btoi(a) * BASE;
        }
        
    function bpowi(uint a, uint n)
            internal pure
            returns (uint)
        {
            uint z = n % 2 != 0 ? a : BASE;
    
            for (n /= 2; n != 0; n /= 2) {
                a = bmul(a, a);
    
                if (n % 2 != 0) {
                    z = bmul(z, a);
                }
            }
            return z;
        }
    
        function bpow(uint base, uint exp)
            internal pure
            returns (uint)
        {
    
            uint whole  = bfloor(exp);
            uint remain = bsub(exp, whole);
    
            uint wholePow = bpowi(base, btoi(whole));
    
            if (remain == 0) {
                return wholePow;
            }
            uint BPOW_PRECISION = BASE / 10**10;
            uint partialResult = bpowApprox(base, remain, BPOW_PRECISION);
            return bmul(wholePow, partialResult);
        }
    
        function bpowApprox(uint base, uint exp, uint precision)
            internal pure
            returns (uint)
        {
            // term 0:
            uint a     = exp;
            (uint x, bool xneg)  = bsubSign(base, BASE);
            uint term = BASE;
            uint sum   = term;
            bool negative = false;
    
    
            for (uint i = 1; term >= precision; i++) {
                uint bigK = i * BASE;
                (uint c, bool cneg) = bsubSign(a, bsub(bigK, BASE));
                term = bmul(term, bmul(c, x));
                term = bdiv(term, bigK);
                if (term == 0) break;
    
                if (xneg) negative = !negative;
                if (cneg) negative = !negative;
                if (negative) {
                    sum = bsub(sum, term);
                } else {
                    sum = badd(sum, term);
                }
            }
    
            return sum;
        }
    
    
    }
    
    contract FTokenBase is FNum {
    
        mapping(address => uint)                   internal _balance;
        mapping(address => mapping(address=>uint)) internal _allowance;
        uint public _totalSupply;
    
        event Approval(address indexed src, address indexed dst, uint amt);
        event Transfer(address indexed src, address indexed dst, uint amt);
    
        function _mint(uint amt) internal {
            _balance[address(this)] = badd(_balance[address(this)], amt);
            _totalSupply = badd(_totalSupply, amt);
            emit Transfer(address(0), address(this), amt);
        }
    
        function _burn(uint amt) internal {
            require(_balance[address(this)] >= amt);
            _balance[address(this)] = bsub(_balance[address(this)], amt);
            _totalSupply = bsub(_totalSupply, amt);
            emit Transfer(address(this), address(0), amt);
        }
        
        function _move(address src, address dst, uint amt) internal {
            require(_balance[src] >= amt);
            _balance[src] = bsub(_balance[src], amt);
            _balance[dst] = badd(_balance[dst], amt);
            emit Transfer(src, dst, amt);
        }
    
        function _push(address to, uint amt) internal {
            _move(address(this), to, amt);
        }
    
        function _pull(address from, uint amt) internal {
            _move(from, address(this), amt);
        }
    }
    
    contract FToken is FTokenBase {
    
        string  private _name     = "FEG Stake Shares";
        string  private _symbol   = "FSS";
        uint8   private _decimals = 18;
    
        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 allowance(address src, address dst) external view returns (uint) {
            return _allowance[src][dst];
        }
    
        function balanceOf(address whom) external view returns (uint) {
            return _balance[whom];
        }
    
        function totalSupply() public view returns (uint) {
            return _totalSupply;
        }
    
        function approve(address dst, uint amt) external returns (bool) {
            _allowance[msg.sender][dst] = amt;
            emit Approval(msg.sender, dst, amt);
            return true;
        }
    
        function increaseApproval(address dst, uint amt) external returns (bool) {
            _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt);
            emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
            return true;
        }
    
        function decreaseApproval(address dst, uint amt) external returns (bool) {
            uint oldValue = _allowance[msg.sender][dst];
            if (amt > oldValue) {
                _allowance[msg.sender][dst] = 0;
            } else {
                _allowance[msg.sender][dst] = bsub(oldValue, amt);
            }
            emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
            return true;
        }
    
        function transfer(address dst, uint amt) external returns (bool) {
            _move(msg.sender, dst, amt);
            return true;
        }
    
        function transferFrom(address src, address dst, uint amt) external returns (bool) {
            require(msg.sender == src || amt <= _allowance[src][msg.sender]);
         
            _move(src, dst, amt);
            if (msg.sender != src && _allowance[src][msg.sender] != uint256(-1)) {
                _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt);
                emit Approval(msg.sender, dst, _allowance[src][msg.sender]);
            }
            return true;
        }
    }
    
    contract FEGstakeV2 is Owned, ReentrancyGuard, WhitelistAdminRole, FNum, FTokenBase, FToken{
        using SafeMath for uint256;
        
        address public FEG   = 0x389999216860AB8E0175387A0c90E5c52522C945;
        address public fETH  = 0xf786c34106762Ab4Eeb45a51B42a62470E9D5332;
        address public USDT  = 0x979838c9C16FD365C9fE028B0bEa49B1750d86e9;
        address public TRY   = 0xc12eCeE46ed65D970EE5C899FCC7AE133AfF9b03;
        address public FETP  = 0xa40462266dC28dB1d570FC8F8a0F4B72B8618f7a;
        address public BTC   = 0xe3cDB92b094a3BeF3f16103b53bECfb17A3558ad;
        address public poolShares = address(this);
        address public regrewardContract; //Signs The Checks
        
        bool public live = false;
        bool public perform = false; //if true then distribution of rewards from the pool to stakers via the withdraw function is enabled
        bool public perform2 = true; //if true then distribution of TX rewards from unclaimed 1 and 2 wrap's will distribute to stakers
        bool public perform3 = true; //if true then distribution of TX rewards from unclaimed 3rd wrap's will distribute to stakers
        uint256 public scailment = 20; // FEG has TX fee, deduct this fee to not break maths
        
        uint256 public totalDividends = 0;
        uint256 public must = 3e15;
        uint256 public scaleatize = 99;
        uint256 private scaledRemainder = 0;
        uint256 private scaling = uint256(10) ** 12;
        uint public round = 1;
        uint256 public totalDividends1 = 0;
        uint256 private scaledRemainder1 = 0;
        uint256 private scaling1 = uint256(10) ** 12;
        uint public round1 = 1;
        uint256 public totalDividends2 = 0;
        uint256 private scaledRemainder2 = 0;
        uint256 private scaling2 = uint256(10) ** 12;
        uint public round2 = 1;
        
        mapping(address => uint) public farmTime; // When you staked
        
        struct USER{
            uint256 lastDividends;
            uint256 fromTotalDividend;
            uint round;
            uint256 remainder;
            uint256 lastDividends1;
            uint256 fromTotalDividend1;
            uint round1;
            uint256 remainder1;
            uint256 lastDividends2;
            uint256 fromTotalDividend2;
            uint round2;
            uint256 remainder2;
            bool initialized;
            bool activated;
        } 
        
        address[] internal stakeholders;
        uint public scalerize = 98;
        uint256 public scaletor = 1e17;
        uint256 public scaletor1 = 20e18;
        uint256 public scaletor2 = 1e15;
        uint256 public totalWrap; //  total unclaimed fETH rewards
        uint256 public totalWrap1; //  total unclaimed usdt rewards
        uint256 public totalWrap2; //  total unclaimed btc rewards
        uint256 public totalWrapRef  = bsub(IERC20(fETH).balanceOf(address(this)), totalWrap); //total fETH reflections unclaimed
        uint256 public totalWrapRef1 = bsub(IERC20(USDT).balanceOf(address(this)), totalWrap1); //total usdt reflections unclaimed
        uint256 public totalWrapRef2 = bsub(IERC20(BTC).balanceOf(address(this)), totalWrap2); //total BTC reflections unclaimed
        mapping(address => USER) stakers;
        mapping (uint => uint256) public payouts;                   // keeps record of each payout
        mapping (uint => uint256) public payouts1;                   // keeps record of each payout
        mapping (uint => uint256) public payouts2;                   // keeps record of each payout
        FEGex2 fegexpair;
        event STAKED(address staker, uint256 tokens);
        event ACTIVATED(address staker, uint256 cost);
        event START(address staker, uint256 tokens);
        event EARNED(address staker, uint256 tokens);
        event UNSTAKED(address staker, uint256 tokens);
        event PAYOUT(uint256 round, uint256 tokens, address sender);
        event PAYOUT1(uint256 round, uint256 tokens, address sender);
        event PAYOUT2(uint256 round, uint256 tokens, address sender);
        event CLAIMEDREWARD(address staker, uint256 reward);
        event CLAIMEDREWARD1(address staker, uint256 reward);
        event CLAIMEDREWARD2(address staker, uint256 reward);
        
        constructor(){
        fegexpair = FEGex2(FETP);
        }
        
        receive() external payable {
        }
    
        function changeFEGExPair(FEGex2 _fegexpair, address addy) external onlyOwner{ // Incase FEGex updates in future
            require(address(_fegexpair) != address(0), "setting 0 to contract");
            fegexpair = _fegexpair;
            FETP = addy;
        }
        
        function changeTRY(address _try) external onlyOwner{ // Incase TRY updates in future
            TRY = _try;
        }
        
        function changeScalerize(uint _sca) public onlyOwner{
            require(_sca != 0, "You cannot turn off");
            scalerize = _sca;
        }
        
        function changeScalatize(uint _scm) public onlyOwner {
            require(_scm != 0, "You cannot turn off");
            scaleatize = _scm;
        }
        
        function isStakeholder(address _address)
           public
           view
           returns(bool)
       {
           
           if(stakers[_address].initialized) return true;
           else return false;
       }
       
       function addStakeholder(address _stakeholder)
           internal
       {
           (bool _isStakeholder) = isStakeholder(_stakeholder);
           if(!_isStakeholder) {
               farmTime[msg.sender] =  block.timestamp;
               stakers[_stakeholder].initialized = true;
           }
       }
       
       // ------------------------------------------------------------------------
        // Token holders can stake their tokens using this function
        // @param tokens number of tokens to stake
        // ------------------------------------------------------------------------
    
        function calcPoolInGivenSingleOut(
            uint tokenBalanceOut,
            uint tokenWeightOut,
            uint poolSupply,
            uint totalWeight,
            uint tokenAmountOut,
            uint swapFee
        )
            public pure
            returns (uint poolAmountIn)
        {
    
    
            uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);
            uint zar = bmul(bsub(BASE, normalizedWeight), swapFee);
            uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BASE, zar));
    
            uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee);
            uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);
    
    
            uint poolRatio = bpow(tokenOutRatio, normalizedWeight);
            uint newPoolSupply = bmul(poolRatio, poolSupply);
            uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply);
    
    
            poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BASE, 0));
            return (poolAmountIn);
        }
        
        function calcSingleOutGivenPoolIn(
            uint tokenBalanceOut,
            uint tokenWeightOut,
            uint poolSupply,
            uint totalWeight,
            uint poolAmountIn,
            uint swapFee
        )
            public pure
            returns (uint tokenAmountOut)
        {
            uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);
    
            uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BASE, 0));
            uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee);
            uint poolRatio = bdiv(newPoolSupply, poolSupply);
    
    
            uint tokenOutRatio = bpow(poolRatio, bdiv(BASE, normalizedWeight));
            uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);
    
            uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut);
            uint zaz = bmul(bsub(BASE, normalizedWeight), swapFee);
            tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BASE, zaz));
            return tokenAmountOut;
        }
    
        function calcPoolOutGivenSingleIn(
            uint tokenBalanceIn,
            uint tokenWeightIn,
            uint poolSupply,
            uint totalWeight,
            uint tokenAmountIn,
            uint swapFee
        )
            public pure
            returns (uint poolAmountOut)
        {
    
            uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);
            uint zaz = bmul(bsub(BASE, normalizedWeight), swapFee);
            uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BASE, zaz));
    
            uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);
            uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);
    
     
            uint poolRatio = bpow(tokenInRatio, normalizedWeight);
            uint newPoolSupply = bmul(poolRatio, poolSupply);
            poolAmountOut = bsub(newPoolSupply, poolSupply);
            return (poolAmountOut);
        }
         
        function calcOutGivenIn(
            uint tokenBalanceIn,
            uint tokenWeightIn,
            uint tokenBalanceOut,
            uint tokenWeightOut,
            uint tokenAmountIn,
            uint swapFee
        )
            public pure
            returns (uint tokenAmountOut, uint tokenInFee)
        {
            uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut);
            uint adjustedIn = bsub(BASE, swapFee);
            adjustedIn = bmul(tokenAmountIn, adjustedIn);
            uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));
            uint foo = bpow(y, weightRatio);
            uint bar = bsub(BASE, foo);
            tokenAmountOut = bmul(tokenBalanceOut, bar);
            tokenInFee = bsub(tokenAmountIn, adjustedIn);
            return (tokenAmountOut, tokenInFee);
        }
    
        function calcInGivenOut(
            uint tokenBalanceIn,
            uint tokenWeightIn,
            uint tokenBalanceOut,
            uint tokenWeightOut,
            uint tokenAmountOut,
            uint swapFee
        )
            public pure
            returns (uint tokenAmountIn)
        {
            uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn);
            uint diff = bsub(tokenBalanceOut, tokenAmountOut);
            uint y = bdiv(tokenBalanceOut, diff);
            uint foo = bpow(y, weightRatio);
            foo = bsub(foo, BASE);
            foo = bmul(tokenBalanceIn, foo);
            tokenAmountIn = bsub(BASE, swapFee);
            tokenAmountIn = bdiv(foo, tokenAmountIn);
            return (tokenAmountIn);
        }
    
        function activateUserStaking() public payable{ // Activation of FEGstake costs 0.02 fETH which is automatically refunded to your wallet in the form of TRY.
            require(msg.value == must, "You must deposit the right amount to activate");
          
            fegexpair.BUY{value: msg.value }(msg.sender, 100);
            stakers[msg.sender].activated = true;
            
            emit ACTIVATED(msg.sender, msg.value);
        }
    
        function isActivated(address staker) public view returns(bool){
            if(stakers[staker].activated) return true;
           else return false;
        }
        
        function Start(uint256 tokens) public onlyOwner returns(uint poolAmountOut){
            require(live == false, "Can only use once");
            require(IERC20(FEG).transferFrom(msg.sender, address(this), tokens), "Tokens cannot be transferred from user for locking");
            uint256 transferTxFee = (onePercent(tokens).mul(scailment)).div(10);
            uint256 tokensToStake = (tokens.sub(transferTxFee));
            addStakeholder(msg.sender);
    
            _mint(tokensToStake);
            live = true;
            IERC20(poolShares).transfer(msg.sender, tokensToStake);
            IERC20(address(fETH)).approve(address(FETP), 1000000000000000000000e18);        
        
            emit START(msg.sender, tokensToStake);    
            
            return poolAmountOut;
        }
        
        function STAKE(uint256 tokens) public returns(uint poolAmountOut){ 
            require(IERC20(FEG).balanceOf(msg.sender) >= tokens, "You do not have enough FEG");
            require(stakers[msg.sender].activated == true);
            require(live == true);
            uint256 transferTxFee = (onePercent(tokens).mul(scailment)).div(10);
            uint256 tokensToStake = (tokens.sub(transferTxFee));
            uint256 totalFEG = IERC20(FEG).balanceOf(address(this));
            addStakeholder(msg.sender);
            
            // add pending rewards to remainder to be claimed by user later, if there is any existing stake
                uint256 owing = pendingReward(msg.sender);
                stakers[msg.sender].remainder += owing;
                stakers[msg.sender].lastDividends = owing;
                stakers[msg.sender].fromTotalDividend = totalDividends;
                stakers[msg.sender].round =  round;
                
                uint256 owing1 = pendingReward1(msg.sender);
                stakers[msg.sender].remainder1 += owing1;
                stakers[msg.sender].lastDividends1 = owing1;
                stakers[msg.sender].fromTotalDividend1 = totalDividends1;
                stakers[msg.sender].round1 =  round1;
                
                uint256 owing2 = pendingReward2(msg.sender);
                stakers[msg.sender].remainder2 += owing2;
                stakers[msg.sender].lastDividends2 = owing2;
                stakers[msg.sender].fromTotalDividend2 = totalDividends2;
                stakers[msg.sender].round2 =  round2;
                
            poolAmountOut = calcPoolOutGivenSingleIn(
                                totalFEG,
                                bmul(BASE, 25),
                                _totalSupply,
                                bmul(BASE, 25),
                                tokensToStake,
                                0
                            );
                            
            require(IERC20(FEG).transferFrom(msg.sender, address(this), tokens), "Tokens cannot be transferred from user for locking");                
            _mint(poolAmountOut);
            IERC20(poolShares).transfer(msg.sender, poolAmountOut);
                
            emit STAKED(msg.sender, tokens); 
                
            return poolAmountOut;
            
        }
    
        
        // ------------------------------------------------------------------------
        // Owners can send the funds to be distributed to stakers using this function
        // @param tokens number of tokens to distribute
        // ------------------------------------------------------------------------
    
        function ADDFUNDS1(uint256 tokens) public onlyWhitelistAdmin{
            require(IERC20(fETH).transferFrom(msg.sender, address(this), tokens), "Tokens cannot be transferred from funder account");
            
            uint256 tokens_ = bmul(tokens, bdiv(99, 100));
            totalWrap = badd(totalWrap, tokens_);
            _addPayout(tokens_);
        }
        
        function ADDFUNDS2(uint256 tokens) public onlyWhitelistAdmin{
            require(IERC20(USDT).transferFrom(msg.sender, address(this), tokens), "Tokens cannot be transferred from funder account");
            
            uint256 tokens_ = bmul(tokens, bdiv(99, 100));
            totalWrap1 = badd(totalWrap1, tokens_);
            _addPayout1(tokens_);
        }
        
        function ADDFUNDS3(uint256 tokens) public onlyWhitelistAdmin{
            require(IERC20(BTC).transferFrom(msg.sender, address(this), tokens), "Tokens cannot be transferred from funder account");
            uint256 tokens_ = bmul(tokens, bdiv(99, 100));
            totalWrap2 = badd(totalWrap2, tokens_);
            _addPayout2(tokens_);
        }
        
        // ------------------------------------------------------------------------
        // Private function to register payouts
        // ------------------------------------------------------------------------
        function _addPayout(uint256 tokens_) private {
             // divide the funds among the currently staked tokens
            // scale the deposit and add the previous remainder
            uint256 totalShares = _totalSupply;
            uint256 available = (tokens_.mul(scaling)).add(scaledRemainder); 
            uint256 dividendPerToken = available.div(totalShares);
            scaledRemainder = available.mod(totalShares);
            totalDividends = totalDividends.add(dividendPerToken);
            payouts[round] = payouts[round - 1].add(dividendPerToken);
            emit PAYOUT(round, tokens_, msg.sender);
            round++;
            
        }
        
        function _addPayout1(uint256 tokens_1) private{
            // divide the funds among the currently staked tokens
            // scale the deposit and add the previous remainder
            uint256 totalShares = _totalSupply;
            uint256 available = (tokens_1.mul(scaling)).add(scaledRemainder1); 
            uint256 dividendPerToken = available.div(totalShares);
            scaledRemainder1 = available.mod(totalShares);
            totalDividends1 = totalDividends1.add(dividendPerToken);
            payouts1[round1] = payouts1[round1 - 1].add(dividendPerToken);
            emit PAYOUT1(round1, tokens_1, msg.sender);
            round1++;
        }
        
        function _addPayout2(uint256 tokens_2) private{
            // divide the funds among the currently staked tokens
            // scale the deposit and add the previous remainder
            uint256 totalShares = _totalSupply;
            uint256 available = (tokens_2.mul(scaling)).add(scaledRemainder2); 
            uint256 dividendPerToken = available.div(totalShares);
            scaledRemainder2 = available.mod(totalShares);
            totalDividends2 = totalDividends2.add(dividendPerToken);
            payouts2[round2] = payouts2[round2 - 1].add(dividendPerToken);
            emit PAYOUT2(round2, tokens_2, msg.sender);
            round2++;
        }
        
        // ------------------------------------------------------------------------
        // Stakers can claim their pending rewards using this function
        // ------------------------------------------------------------------------
        function CLAIMREWARD() public nonReentrant{
            
                uint256 owing = pendingReward(msg.sender);
            if(owing > 0){
                owing = owing.add(stakers[msg.sender].remainder);
                stakers[msg.sender].remainder = 0;
            
                require(IERC20(fETH).transfer(msg.sender,owing), "ERROR: error in sending reward from contract");
            
                emit CLAIMEDREWARD(msg.sender, owing);
                totalWrap = bsub(totalWrap, owing);
                stakers[msg.sender].lastDividends = owing; // unscaled
                stakers[msg.sender].round = round; // update the round
                stakers[msg.sender].fromTotalDividend = totalDividends; // scaled
            }
        }
        
        function CLAIMREWARD1() public nonReentrant {
            
                uint256 owing1 = pendingReward1(msg.sender);
            if(owing1 > 0){
                owing1 = owing1.add(stakers[msg.sender].remainder1);
                stakers[msg.sender].remainder1 = 0;
            
                require(IERC20(USDT).transfer(msg.sender,owing1), "ERROR: error in sending reward from contract");
            
                emit CLAIMEDREWARD1(msg.sender, owing1);
                totalWrap1 = bsub(totalWrap1, owing1);
                stakers[msg.sender].lastDividends1 = owing1; // unscaled
                stakers[msg.sender].round1 = round1; // update the round
                stakers[msg.sender].fromTotalDividend1 = totalDividends1; // scaled
            }
        }
        
        function CLAIMREWARD2() public nonReentrant {
          
                uint256 owing2 = pendingReward2(msg.sender);
            if(owing2 > 0){
                owing2 = owing2.add(stakers[msg.sender].remainder2);
                stakers[msg.sender].remainder2 = 0;
            
                require(IERC20(BTC).transfer(msg.sender, owing2), "ERROR: error in sending reward from contract");
            
                emit CLAIMEDREWARD2(msg.sender, owing2);
                totalWrap2 = bsub(totalWrap2, owing2);
                stakers[msg.sender].lastDividends2 = owing2; // unscaled
                stakers[msg.sender].round2 = round2; // update the round
                stakers[msg.sender].fromTotalDividend2 = totalDividends2; // scaled
            }
        }
        
        function CLAIMALLREWARD() public { 
            distribute12();
            CLAIMREWARD();
            CLAIMREWARD1();
            
            if(perform3==true){
            distribute23();    
            CLAIMREWARD2();   
            }
        }
        
        // ------------------------------------------------------------------------
        // Get the pending rewards of the staker
        // @param _staker the address of the staker
        // ------------------------------------------------------------------------    
    
        function pendingReward(address staker) private returns (uint256) {
            require(staker != address(0), "ERC20: sending to the zero address");
            uint256 yourBase = IERC20(poolShares).balanceOf(msg.sender);
            uint stakersRound = stakers[staker].round;
            uint256 amount =  ((totalDividends.sub(payouts[stakersRound - 1])).mul(yourBase)).div(scaling);
            stakers[staker].remainder += ((totalDividends.sub(payouts[stakersRound - 1])).mul(yourBase)) % scaling;
            return (bmul(amount, bdiv(scalerize, 100)));
        }
        
        function pendingReward1(address staker) private returns (uint256) {
            require(staker != address(0), "ERC20: sending to the zero address");
            uint256 yourBase = IERC20(poolShares).balanceOf(msg.sender);
            uint stakersRound = stakers[staker].round1;
            uint256 amount1 =  ((totalDividends1.sub(payouts1[stakersRound - 1])).mul(yourBase)).div(scaling);
            stakers[staker].remainder1 += ((totalDividends1.sub(payouts1[stakersRound - 1])).mul(yourBase)) % scaling;
            return (bmul(amount1, bdiv(scalerize, 100)));
        }
        
        function pendingReward2(address staker) private returns (uint256) {
            require(staker != address(0), "ERC20: sending to the zero address");
            uint256 yourBase = IERC20(poolShares).balanceOf(msg.sender);
            uint stakersRound = stakers[staker].round2;
            uint256 amount2 =  ((totalDividends2.sub(payouts2[stakersRound - 1])).mul(yourBase)).div(scaling);
            stakers[staker].remainder2 += ((totalDividends2.sub(payouts2[stakersRound - 1])).mul(yourBase)) % scaling;
            return (bmul(amount2, bdiv(scalerize, 100)));
        }
        
        function getPending1(address staker) public view returns(uint256 _pendingReward) {
            require(staker != address(0), "ERC20: sending to the zero address");
            uint256 yourBase = IERC20(poolShares).balanceOf(staker);
            uint stakersRound = stakers[staker].round; 
            uint256 amount =  ((totalDividends.sub(payouts[stakersRound - 1])).mul(yourBase)).div(scaling);
            amount += ((totalDividends.sub(payouts[stakersRound - 1])).mul(yourBase)) % scaling;
            return (bmul(amount.add(stakers[staker].remainder), bdiv(scalerize, 100)));
        }
        
        function getPending2(address staker) public view returns(uint256 _pendingReward) {
            require(staker != address(0), "ERC20: sending to the zero address");
            uint256 yourBase = IERC20(poolShares).balanceOf(staker);
            uint stakersRound = stakers[staker].round1;
            uint256 amount1 = ((totalDividends1.sub(payouts1[stakersRound - 1])).mul(yourBase)).div(scaling);
            amount1 += ((totalDividends1.sub(payouts1[stakersRound - 1])).mul(yourBase)) % scaling;
            return (bmul(amount1.add(stakers[staker].remainder1), bdiv(scalerize, 100)));
        }
        
        function getPending3(address staker) public view returns(uint256 _pendingReward) {
            require(staker != address(0), "ERC20: sending to the zero address");
            uint256 yourBase = IERC20(poolShares).balanceOf(staker);
            uint stakersRound = stakers[staker].round2;
            uint256 amount2 =  ((totalDividends2.sub(payouts2[stakersRound - 1])).mul(yourBase)).div(scaling);
            amount2 += ((totalDividends2.sub(payouts2[stakersRound - 1])).mul(yourBase)) % scaling;
            return (bmul(amount2.add(stakers[staker].remainder2), bdiv(scalerize, 100)));
        
        }
            // ------------------------------------------------------------------------
        // Get the FEG balance of the token holder
        // @param user the address of the token holder
        // ------------------------------------------------------------------------
        function userStakedFEG(address user) external view returns(uint256 StakedFEG){
            require(user != address(0), "ERC20: sending to the zero address");
            uint256 totalFEG = IERC20(FEG).balanceOf(address(this));
            uint256 yourStakedFEG = calcSingleOutGivenPoolIn(
                                totalFEG, 
                                bmul(BASE, 25),
                                _totalSupply,
                                bmul(BASE, 25),
                                IERC20(poolShares).balanceOf(address(user)),
                                0
                            );
            
            return yourStakedFEG;
        }
        
        // ------------------------------------------------------------------------
        // Stakers can un stake the staked tokens using this function
        // @param tokens the number of tokens to withdraw
        // ------------------------------------------------------------------------
        function WITHDRAW(address to, uint256 _tokens) external returns (uint tokenAmountOut) {
            uint256 totalFEG = IERC20(FEG).balanceOf(address(this));
            require(stakers[msg.sender].activated == true);
            
            if(perform==true) {
            regreward(regrewardContract).distributeV2();
            }
            
            CLAIMALLREWARD();
    
            uint256 tokens = calcPoolInGivenSingleOut(
                                totalFEG,
                                bmul(BASE, 25),
                                _totalSupply,
                                bmul(BASE, 25),
                                _tokens,
                                0
                            );
                            
            tokenAmountOut = calcSingleOutGivenPoolIn(
                                totalFEG, 
                                bmul(BASE, 25),
                                _totalSupply,
                                bmul(BASE, 25),
                                tokens,
                                0
                            ); 
            require(tokens <= IERC20(poolShares).balanceOf(msg.sender), "You don't have enough FEG");
            _pullPoolShare(tokens);
            _burn(tokens);
            require(IERC20(FEG).transfer(to, tokenAmountOut), "Error in un-staking tokens");
            
            emit UNSTAKED(msg.sender, tokens);
            
            return tokenAmountOut;
        }
        
        function _pullPoolShare(uint amount)
            internal
        {
            bool xfer = IERC20(poolShares).transferFrom(msg.sender, address(this), amount);
            require(xfer, "ERR_ERC20_FALSE");
        }    
    
        // ------------------------------------------------------------------------
        // Private function to calculate 1% percentage
        // ------------------------------------------------------------------------
        function onePercent(uint256 _tokens) private pure returns (uint256){
            uint256 roundValue = _tokens.ceil(100);
            uint onePercentofTokens = roundValue.mul(100).div(100 * 10**uint(2));
            return onePercentofTokens;
        }
        
        function emergencySaveLostTokens(address to, address _token, uint256 _amt) public onlyOwner {
            require(_token != FEG, "Cannot remove users FEG");
            require(_token != fETH, "Cannot remove users fETH");
            require(_token != USDT, "Cannot remove users fUSDT");
            require(_token != BTC, "Cannot remove users fBTC");
            require(IERC20(_token).transfer(to, _amt), "Error in retrieving tokens");
            payable(owner).transfer(address(this).balance);
        }
        
        function changeregrewardContract(address _regrewardContract) external onlyOwner{
            require(address(_regrewardContract) != address(0), "setting 0 to contract");
            regrewardContract = _regrewardContract;
        }
       
        function changePerform(bool _bool) external onlyOwner{
            perform = _bool;
        }
    
        function changePerform2(bool _bool) external onlyOwner{
            perform2 = _bool;
        }
        
        function changePerform3(bool _bool) external onlyOwner{
            perform3 = _bool;
        }
        
        function changeMust(uint256 _must) external onlyOwner{
            require(must !=0, "Cannot set to 0");
            require(must <= 3e15, "Cannot set over 0.003 fETH");
            must = _must;
        }
        
        function updateBase(address _BTC, address _ETH, address _USDT) external onlyOwner{ // Incase wraps ever update
            BTC = _BTC;
            fETH = _ETH;
            USDT = _USDT;
        }
        
        function distribute12() public {
            if (IERC20(fETH).balanceOf(address(this)) > badd(totalWrap, scaletor))  {
            distributeWrap1();
            }
            
            if(IERC20(USDT).balanceOf(address(this)) > badd(totalWrap1, scaletor1)){
            distributeWrap2();
            }
        }
        
        function distribute23() public {    
            if(perform3==true){
                if(IERC20(BTC).balanceOf(address(this)) > badd(totalWrap2, scaletor2)){
            distributeWrap3();}
            }
        }
        
        function changeScaletor(uint256 _sca, uint256 _sca1, uint256 _sca2) public onlyOwner {
            require(_sca !=0 && _sca1 !=0 && _sca2 !=0, "You cannot turn off");
            require(_sca >= 5e17 && _sca1 >= 20e18 && _sca2 >= 1e15, "Must be over minimum");
            scaletor = _sca;
            scaletor1 = _sca1;
            scaletor2 = _sca2;
        }
        
        function distributeWrap1() internal {
            uint256 wrapped = bsub(IERC20(fETH).balanceOf(address(this)), totalWrap);
            totalWrap = badd(totalWrap, wrapped);
            _addPayout(wrapped);
        }
    
        function distributeWrap2() internal {
            uint256 wrapped = bsub(IERC20(USDT).balanceOf(address(this)), totalWrap1);
            totalWrap1 = badd(totalWrap1, wrapped);
            _addPayout1(wrapped);
        }
        
        function distributeWrap3() internal {
            uint256 wrapped = bsub(IERC20(BTC).balanceOf(address(this)), totalWrap2);
            totalWrap2 = badd(totalWrap2, wrapped);
            _addPayout2(wrapped);
        }
        }

    File 2 of 2: FEG
    // FEG (Fuck Emily Goetz Token)
    // Why?  Because fuck you thats why!
    // The best way to say FUCK YOU EMILY GOETZ is to blow up a token with her code with FEG as the ticker!
    // Why 100,000,000,000,000,000 token supply? That's how many times she's had VD!  hahaha  Fuck Emily Goetz!
    
    
    // SPDX-License-Identifier: Unlicensed
    
    pragma solidity ^0.6.12;
    
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
    
            return c;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
                return 0;
            }
    
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be 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); // There is no case in which this doesn't hold
    
            return c;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts with custom message when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            return _functionCallWithValue(target, data, value, errorMessage);
        }
    
        function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
    
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    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 () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view 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");
            _;
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    
    
    contract FEG is Context, IERC20, Ownable {
        using SafeMath for uint256;
        using Address for address;
    
        mapping (address => uint256) private _rOwned;
        mapping (address => uint256) private _tOwned;
        mapping (address => mapping (address => uint256)) private _allowances;
    
        mapping (address => bool) private _isExcluded;
        address[] private _excluded;
       
        uint256 private constant MAX = ~uint256(0);
        uint256 private constant _tTotal = 100000000000 * 10**6 * 10**9;
        uint256 private _rTotal = (MAX - (MAX % _tTotal));
        uint256 private _tFeeTotal;
    
        string private _name = 'FEGtoken';
        string private _symbol = 'FEG';
        uint8 private _decimals = 9;
    
        constructor () public {
            _rOwned[_msgSender()] = _rTotal;
            emit Transfer(address(0), _msgSender(), _tTotal);
        }
    
        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 override returns (uint256) {
            return _tTotal;
        }
    
        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(_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, "ERC20: 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, "ERC20: decreased allowance below zero"));
            return true;
        }
    
        function isExcluded(address account) public view returns (bool) {
            return _isExcluded[account];
        }
    
        function totalFees() public view returns (uint256) {
            return _tFeeTotal;
        }
    
        function reflect(uint256 tAmount) public {
            address sender = _msgSender();
            require(!_isExcluded[sender], "Excluded addresses cannot call this function");
            (uint256 rAmount,,,,) = _getValues(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _rTotal = _rTotal.sub(rAmount);
            _tFeeTotal = _tFeeTotal.add(tAmount);
        }
    
        function reflectionFromToken(uint256 tAmount, bool deductTransferFee) public view returns(uint256) {
            require(tAmount <= _tTotal, "Amount must be less than supply");
            if (!deductTransferFee) {
                (uint256 rAmount,,,,) = _getValues(tAmount);
                return rAmount;
            } else {
                (,uint256 rTransferAmount,,,) = _getValues(tAmount);
                return rTransferAmount;
            }
        }
    
        function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
            require(rAmount <= _rTotal, "Amount must be less than total reflections");
            uint256 currentRate =  _getRate();
            return rAmount.div(currentRate);
        }
    
        function excludeAccount(address account) external onlyOwner() {
            require(!_isExcluded[account], "Account is already excluded");
            if(_rOwned[account] > 0) {
                _tOwned[account] = tokenFromReflection(_rOwned[account]);
            }
            _isExcluded[account] = true;
            _excluded.push(account);
        }
    
        function includeAccount(address account) external onlyOwner() {
            require(_isExcluded[account], "Account is already excluded");
            for (uint256 i = 0; i < _excluded.length; i++) {
                if (_excluded[i] == account) {
                    _excluded[i] = _excluded[_excluded.length - 1];
                    _tOwned[account] = 0;
                    _isExcluded[account] = false;
                    _excluded.pop();
                    break;
                }
            }
        }
    
        function _approve(address owner, address spender, uint256 amount) private {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        function _transfer(address sender, address recipient, uint256 amount) private {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            require(amount > 0, "Transfer amount must be greater than zero");
            if (_isExcluded[sender] && !_isExcluded[recipient]) {
                _transferFromExcluded(sender, recipient, amount);
            } else if (!_isExcluded[sender] && _isExcluded[recipient]) {
                _transferToExcluded(sender, recipient, amount);
            } else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
                _transferStandard(sender, recipient, amount);
            } else if (_isExcluded[sender] && _isExcluded[recipient]) {
                _transferBothExcluded(sender, recipient, amount);
            } else {
                _transferStandard(sender, recipient, amount);
            }
        }
    
        function _transferStandard(address sender, address recipient, uint256 tAmount) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);       
            _reflectFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _transferToExcluded(address sender, address recipient, uint256 tAmount) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);           
            _reflectFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _transferFromExcluded(address sender, address recipient, uint256 tAmount) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
            _tOwned[sender] = _tOwned[sender].sub(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);   
            _reflectFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _transferBothExcluded(address sender, address recipient, uint256 tAmount) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
            _tOwned[sender] = _tOwned[sender].sub(tAmount);
            _rOwned[sender] = _rOwned[sender].sub(rAmount);
            _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);        
            _reflectFee(rFee, tFee);
            emit Transfer(sender, recipient, tTransferAmount);
        }
    
        function _reflectFee(uint256 rFee, uint256 tFee) private {
            _rTotal = _rTotal.sub(rFee);
            _tFeeTotal = _tFeeTotal.add(tFee);
        }
    
        function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256) {
            (uint256 tTransferAmount, uint256 tFee) = _getTValues(tAmount);
            uint256 currentRate =  _getRate();
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, currentRate);
            return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee);
        }
    
        function _getTValues(uint256 tAmount) private pure returns (uint256, uint256) {
            uint256 tFee = tAmount.div(100).mul(2);
            uint256 tTransferAmount = tAmount.sub(tFee);
            return (tTransferAmount, tFee);
        }
    
        function _getRValues(uint256 tAmount, uint256 tFee, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
            uint256 rAmount = tAmount.mul(currentRate);
            uint256 rFee = tFee.mul(currentRate);
            uint256 rTransferAmount = rAmount.sub(rFee);
            return (rAmount, rTransferAmount, rFee);
        }
    
        function _getRate() private view returns(uint256) {
            (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
            return rSupply.div(tSupply);
        }
    
        function _getCurrentSupply() private view returns(uint256, uint256) {
            uint256 rSupply = _rTotal;
            uint256 tSupply = _tTotal;      
            for (uint256 i = 0; i < _excluded.length; i++) {
                if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);
                rSupply = rSupply.sub(_rOwned[_excluded[i]]);
                tSupply = tSupply.sub(_tOwned[_excluded[i]]);
            }
            if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
            return (rSupply, tSupply);
        }
    }