Bankroll Network - Smart Contract Audit Report

Summary

bankroll.network Bankroll is the best way to HODL and grow your crypto!

Bankroll is a premiere decentralized finance network on TRON and Ethereum. It implements a voluntary, sustainable, and permissionless global economic engine. Through a network of financial contracts the platform provides rewards in TRX, ETH, BTT, VLT and BNKR. Bankroll... play to win!!!

Notable features included in the contract suite:
  • The token contracts contain mint and burn functions, mostly related to the distribution of rewards.
  • Ownership - Some functions are protected and can only be called by the contract owner. The deployer and future owners can transfer ownership to any address.
  • Utilization of SafeMath to prevent overflows.
Audit Findings Summary
  • No impactful security issues were identified.

We ran over 400,000 transactions interacting with this suite of contracts on a test blockchain to determine these results.
Vulnerability Category Notes Result
Arbitrary Storage Write N/A PASS
Arbitrary Jump N/A PASS
Delegate Call to Untrusted Contract N/A PASS
Dependence on Predictable Variables N/A PASS
Deprecated Opcodes N/A PASS
Ether Thief N/A PASS
Exceptions N/A PASS
External Calls N/A PASS
Integer Over/Underflow N/A PASS
Multiple Sends N/A PASS
Suicide N/A PASS
State Change External Calls The state of mintedSupply_ , mintingFinished , and totalSupply_ is accessed after a call to a user-defined address. This is not a risk as the affected
functions revert if not completed successfully, or if that is not the case, they can only be called by the owner.
Warning
Unchecked Retval N/A PASS
User Supplied Assertion N/A PASS
Critical Solidity Compiler N/A PASS
Overall Contract Safety   PASS

Function Graph

Smart Contract Graph

Inheritence Chart

Smart Contract Inheritance

Functions Overview



 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public

 +  Ownable 
    - [Pub]  #
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 +  Whitelist (Ownable)
    - [Pub] addAddressToWhitelist #
       - modifiers: onlyOwner
    - [Pub] addAddressesToWhitelist #
       - modifiers: onlyOwner
    - [Pub] removeAddressFromWhitelist #
       - modifiers: onlyOwner
    - [Pub] removeAddressesFromWhitelist #
       - modifiers: onlyOwner

 +  Swap 
    - [Pub] getInputPrice
    - [Pub] getOutputPrice
    - [Pub] trxToTokenSwapInput ($)
    - [Pub] trxToTokenSwapOutput ($)
    - [Pub] tokenToTrxSwapInput #
    - [Pub] tokenToTrxSwapOutput #
    - [Pub] getTrxToTokenInputPrice
    - [Pub] getTrxToTokenOutputPrice
    - [Pub] getTokenToTrxInputPrice
    - [Pub] getTokenToTrxOutputPrice
    - [Pub] tokenAddress
    - [Pub] tronBalance
    - [Pub] tokenBalance
    - [Pub] getTrxToLiquidityInputPrice
    - [Pub] getLiquidityToReserveInputPrice
    - [Pub] txs
    - [Pub] addLiquidity ($)
    - [Pub] removeLiquidity #

 +  Exchange 
    - [Ext] getTrxToTokenInputPrice
    - [Ext] getTokenToTrxInputPrice

 +  Token 
    - [Pub] remainingMintableSupply
    - [Pub] transferFrom #
    - [Pub] transfer #
    - [Pub] balanceOf
    - [Pub] burn #
    - [Pub] mintedSupply #
    - [Pub] allowance
    - [Pub] approve #

 +  TokenMint 
    - [Pub] mint #
    - [Pub] sponsorFor ($)
    - [Pub] mintingDifficulty
    - [Pub] estimateMint #

 +  BankrollFarm (Whitelist)
    - [Pub]  #
       - modifiers: Ownable
    - [Pub] freeze #
    - [Pub] unfreeze #
    - [Pub] claim #
    - [Pub] baseAvailable
    - [Pub] counterToBaseAmount
    - [Pub] counterToTrx
    - [Pub] baseToTrx
    - [Pub] availableMint
    - [Pub] availableStake
    - [Pub] dailyEstimate
    - [Pub] balanceOf
    - [Pub] balanceOfBase
    - [Pub] balanceOfCounter
    - [Pub] totalReferralOf
    - [Pub] totalMintedOf
    - [Pub] txsOf
    - [Pub] statsOf
    - [Pub] ready
    - [Pub] isOpen
    - [Pub] lastUpdated
    - [Pub] bonusFactor
    - [Pub] totalTronBalance
    - [Pub] totalDailyEstimate
    - [Pub] baseBalance
    - [Pub] counterBalance
    - [Pub] close #
       - modifiers: onlyWhitelisted

 + [Lib] SafeMath 
    - [Int] mul
    - [Int] div
    - [Int] sub
    - [Int] safeSub
    - [Int] add
    - [Int] max
    - [Int] min

 + [Lib] Address 
    - [Int] isContract

							

Source Code

Click here to download the source code as a .sol file. Note there are two BankrollFarm contracts - One for JustSwap and one for UniFi. This contract is deployed at TQ4zMrXKmWDyG3EV26pMuToQXsntztDGAX.


// Deployed at TQ4zMrXKmWDyG3EV26pMuToQXsntztDGAX
/*
    SPDX-License-Identifier: MIT
    A Bankteller Production
    Bankroll Network
    Copyright 2020
*/

pragma solidity ^0.4.25;


// File: openzeppelin-solidity/contracts/ownership/Ownable.sol

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address public owner;


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


    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor() public {
        owner = msg.sender;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

}

// File: openzeppelin-solidity/contracts/ownership/Whitelist.sol

/**
 * @title Whitelist
 * @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions.
 * @dev This simplifies the implementation of "user permissions".
 */
contract Whitelist is Ownable {
    mapping(address => bool) public whitelist;

    event WhitelistedAddressAdded(address addr);
    event WhitelistedAddressRemoved(address addr);

    /**
     * @dev Throws if called by any account that's not whitelisted.
     */
    modifier onlyWhitelisted() {
        require(whitelist[msg.sender]);
        _;
    }

    /**
     * @dev add an address to the whitelist
     * @param addr address
     * @return true if the address was added to the whitelist, false if the address was already in the whitelist
     */
    function addAddressToWhitelist(address addr) onlyOwner public returns(bool success) {
        if (!whitelist[addr]) {
            whitelist[addr] = true;
            emit WhitelistedAddressAdded(addr);
            success = true;
        }
    }

    /**
     * @dev add addresses to the whitelist
     * @param addrs addresses
     * @return true if at least one address was added to the whitelist,
     * false if all addresses were already in the whitelist
     */
    function addAddressesToWhitelist(address[] addrs) onlyOwner public returns(bool success) {
        for (uint256 i = 0; i < addrs.length; i++) {
            if (addAddressToWhitelist(addrs[i])) {
                success = true;
            }
        }
    }

    /**
     * @dev remove an address from the whitelist
     * @param addr address
     * @return true if the address was removed from the whitelist,
     * false if the address wasn't in the whitelist in the first place
     */
    function removeAddressFromWhitelist(address addr) onlyOwner public returns(bool success) {
        if (whitelist[addr]) {
            whitelist[addr] = false;
            emit WhitelistedAddressRemoved(addr);
            success = true;
        }
    }

    /**
     * @dev remove addresses from the whitelist
     * @param addrs addresses
     * @return true if at least one address was removed from the whitelist,
     * false if all addresses weren't in the whitelist in the first place
     */
    function removeAddressesFromWhitelist(address[] addrs) onlyOwner public returns(bool success) {
        for (uint256 i = 0; i < addrs.length; i++) {
            if (removeAddressFromWhitelist(addrs[i])) {
                success = true;
            }
        }
    }

}

contract Swap {

    /**
      * @dev Pricing function for converting between TRX && Tokens.
      * @param input_amount Amount of TRX or Tokens being sold.
      * @param input_reserve Amount of TRX or Tokens (input type) in exchange reserves.
      * @param output_reserve Amount of TRX or Tokens (output type) in exchange reserves.
      * @return Amount of TRX or Tokens bought.
      */
    function getInputPrice(uint256 input_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256);

    /**
      * @dev Pricing function for converting between TRX && Tokens.
      * @param output_amount Amount of TRX or Tokens being bought.
      * @param input_reserve Amount of TRX or Tokens (input type) in exchange reserves.
      * @param output_reserve Amount of TRX or Tokens (output type) in exchange reserves.
      * @return Amount of TRX or Tokens sold.
      */
    function getOutputPrice(uint256 output_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256);
    /**
     * @notice Convert TRX to Tokens.
     * @dev User specifies exact input (msg.value) && minimum output.
     * @param min_tokens Minimum Tokens bought.
     * @return Amount of Tokens bought.
     */
    function trxToTokenSwapInput(uint256 min_tokens) public payable returns (uint256);

    /**
     * @notice Convert TRX to Tokens.
     * @dev User specifies maximum input (msg.value) && exact output.
     * @param tokens_bought Amount of tokens bought.
     * @return Amount of TRX sold.
     */
    function trxToTokenSwapOutput(uint256 tokens_bought) public payable returns (uint256);

    /**
     * @notice Convert Tokens to TRX.
     * @dev User specifies exact input && minimum output.
     * @param tokens_sold Amount of Tokens sold.
     * @param min_trx Minimum TRX purchased.
     * @return Amount of TRX bought.
     */
    function tokenToTrxSwapInput(uint256 tokens_sold, uint256 min_trx) public returns (uint256);

    /**
     * @notice Convert Tokens to TRX.
     * @dev User specifies maximum input && exact output.
     * @param trx_bought Amount of TRX purchased.
     * @param max_tokens Maximum Tokens sold.
     * @return Amount of Tokens sold.
     */
    function tokenToTrxSwapOutput(uint256 trx_bought, uint256 max_tokens) public returns (uint256);

    /***********************************|
    |         Getter Functions          |
    |__________________________________*/

    /**
     * @notice Public price function for TRX to Token trades with an exact input.
     * @param trx_sold Amount of TRX sold.
     * @return Amount of Tokens that can be bought with input TRX.
     */
    function getTrxToTokenInputPrice(uint256 trx_sold) public view returns (uint256);

    /**
     * @notice Public price function for TRX to Token trades with an exact output.
     * @param tokens_bought Amount of Tokens bought.
     * @return Amount of TRX needed to buy output Tokens.
     */
    function getTrxToTokenOutputPrice(uint256 tokens_bought) public view returns (uint256);

    /**
     * @notice Public price function for Token to TRX trades with an exact input.
     * @param tokens_sold Amount of Tokens sold.
     * @return Amount of TRX that can be bought with input Tokens.
     */
    function getTokenToTrxInputPrice(uint256 tokens_sold) public view returns (uint256);

    /**
     * @notice Public price function for Token to TRX trades with an exact output.
     * @param trx_bought Amount of output TRX.
     * @return Amount of Tokens needed to buy output TRX.
     */
    function getTokenToTrxOutputPrice(uint256 trx_bought) public view returns (uint256) ;

    /**
     * @return Address of Token that is sold on this exchange.
     */
    function tokenAddress() public view returns (address) ;


    function tronBalance() public view returns (uint256);

    function tokenBalance() public view returns (uint256);

    function getTrxToLiquidityInputPrice(uint256 trx_sold) public view returns (uint256);

    function getLiquidityToReserveInputPrice(uint amount) public view returns (uint256, uint256);

    function txs(address owner) public view returns (uint256) ;


    /***********************************|
    |        Liquidity Functions        |
    |__________________________________*/

    /**
     * @notice Deposit TRX && Tokens (token) at current ratio to mint SWAP tokens.
     * @dev min_liquidity does nothing when total SWAP supply is 0.
     * @param min_liquidity Minimum number of SWAP sender will mint if total SWAP supply is greater than 0.
     * @param max_tokens Maximum number of tokens deposited. Deposits max amount if total SWAP supply is 0.
     * @return The amount of SWAP minted.
     */
    function addLiquidity(uint256 min_liquidity, uint256 max_tokens) public payable returns (uint256) ;

    /**
     * @dev Burn SWAP tokens to withdraw TRX && Tokens at current ratio.
     * @param amount Amount of SWAP burned.
     * @param min_trx Minimum TRX withdrawn.
     * @param min_tokens Minimum Tokens withdrawn.
     * @return The amount of TRX && Tokens withdrawn.
     */
    function removeLiquidity(uint256 amount, uint256 min_trx, uint256 min_tokens) public returns (uint256, uint256);
}

contract Exchange {
    function getTrxToTokenInputPrice(uint256 trx_sold) external view returns (uint256);
    function getTokenToTrxInputPrice(uint256 tokens_sold) external view returns (uint256);
}



contract Token {
    function remainingMintableSupply() public view returns (uint256) {}
    function transferFrom(address from, address to, uint256 value) public returns (bool){}
    function transfer(address to, uint256 value) public returns (bool){}
    function balanceOf(address who) public view returns (uint256){}
    function burn(uint256 _value) public {}
    function mintedSupply() public returns (uint256) {}
    function allowance(address owner, address spender) public view returns (uint256);
    function approve(address spender, uint256 value) public returns (bool);
}


contract TokenMint {
    function mint(address beneficiary, uint256 tokenAmount) public returns (uint256){}
    function sponsorFor(address _sender, address _beneficiary) public payable {}
    function mintingDifficulty() public view returns (uint256) {}
    function estimateMint(uint256 _amount) public returns (uint256){}
}

contract BankrollFarm is Whitelist {

    using Address for address;
    using SafeMath for uint;

    /**
    * No bloody contracts
    *
    */
    modifier isHuman {
        //No contracts
        require(msg.sender == tx.origin && !msg.sender.isContract());
        _;
    }


    struct Stats {
        uint balance; //current BNKR balance
        uint counterBalance; //current balance off farmable token
        uint totalMinted; //total minted BNKR
        uint totalDeposited; //total ever deposited TRON
        uint totalWithdrawn; //total withdrawn
        uint totalReferral; //total referrals
        uint lastUpdated; //last tx time used for calculating minted BNKR
        uint xMinted; //times claim has been called
        uint xDeposited; //times a deposit has been made
        uint xWithdrawn; //times a withdrawal was made
    }

    event onClose(
        uint256 closed
    );

    event onFreeze(
        address indexed customerAddress,
        uint256 tron
    );

    event onUnfreeze(
        address indexed customerAddress,
        uint256 tron
    );

    event onClaim(
        address indexed customerAddress,
        uint256 bnkr
    );

    event onBalance(
        address indexed customerAddress,
        uint256 tronBalance,
        uint256 bnkrMinted
    );

    event onContractBalance(
        uint256 balance
    );


    mapping(address => Stats) internal stats;
    address public mintAddress = address(0x413b155e2c501254567913a1d15e2fab4b9abea6aa); //TFMcU3QBGVB5ghtYw8g9wMV3rTFdkH2avv
    address public tokenAddress = address(0x418caeea9c7ebb8840ee4b49d10542b99cec6ffbc6); //TNo59Khpq46FGf4sD7XSWYFNfYfbc8CqNK
    address public swapAddress = address(0x41aaa7d283fa8ff534ca65a5a311e376b63411981a); //TRXYvAoYvCqmvZWpFCTLc4rdQ7KxbLsUSj
    address public wtrxAddress = address(0x41891cdb91d149f23b1a45d9c5ca78a88d0cb44c18); //TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR
    address public counterAddress;
    address public exchangeAddress;
    TokenMint private tokenMint;
    Token private token;
    Token private counterToken;
    Exchange private exchange;
    Swap private swap;

    uint256 public totalMinted;
    uint256 public totalDeposits;
    uint256 public totalTxs;
    uint256 public players;
    uint256 public closed = 0;
    uint256 public launched;

    

    uint256 internal lastBalance_;

    uint256 internal balanceIncrement_ = 50e6;
    uint256 internal trackingInterval_ = 6 hours;
    uint256 internal bonusPeriod = 24 hours * 365;

    /**
    * @dev 
    * @param _counterAddress The address of the TRC20 to stake vs BNKR
    * @param _exchangeAddress The Justswap pair contract used as a  price oracle
    */
    constructor(address _counterAddress, address _exchangeAddress) Ownable() public {

       
        counterAddress = _counterAddress;
        exchangeAddress = _exchangeAddress;

        //Only the mint should own its paired token
        tokenMint = TokenMint(mintAddress);
        token = Token(tokenAddress);
        swap = Swap(swapAddress);
        counterToken = Token(counterAddress);
        exchange = Exchange(exchangeAddress);

        //add creator to whitelist
        addAddressToWhitelist(msg.sender);

        launched = now;

    }

    // @dev Stake counter and base tokens with counter amount as input; base is calculated
    function freeze(address referrer, uint _counterAmount) public {

        //If closed then don't accept new funds
        if (closed > 0){
            return;
        }

        //No double spend
        claim(referrer);

        //Got to be able to mint
        require(isOpen(), "Mint is closed");

        address _customerAddress = msg.sender;

        require(_counterAmount > 0, "Deposit zero");
        require(counterToken.transferFrom(_customerAddress, address(this), _counterAmount), "Counter token transfer failed");
        uint _baseAmount = counterToBaseAmount(_counterAmount);

        //As long as we have the balance lets go for it
        require(_baseAmount <= token.balanceOf(_customerAddress), "Base amount required > balance");
        require(token.transferFrom(_customerAddress, address(this), _baseAmount), "Base token transfer failed");

        //Count players
        if (stats[_customerAddress].totalDeposited == 0 ){
            players += 1;
        }

        uint trxValue = counterToTrx(_counterAmount) * 2;
        //Increase the amount staked
        stats[_customerAddress].balance += _baseAmount;
        stats[_customerAddress].counterBalance += _counterAmount;
        stats[_customerAddress].lastUpdated = now;
        stats[_customerAddress].xDeposited += 1;
        stats[_customerAddress].totalDeposited += trxValue;

        totalDeposits += trxValue;
        totalTxs += 1;


        emit onFreeze(_customerAddress, trxValue);
    }

    // @dev Unfreeze staked tokens
    function unfreeze(address referrer) public  {

        //No double spend
        claim(referrer);

        address _customerAddress = msg.sender;

        uint balance = stats[_customerAddress].balance;
        uint counterBalance = stats[_customerAddress].counterBalance;
        uint trxValue = counterToTrx(counterBalance) + baseToTrx(balance);
        
        //Lets always update time on any modification
        stats[_customerAddress].balance = 0;
        stats[_customerAddress].counterBalance = 0;
        stats[_customerAddress].lastUpdated = now;
        stats[_customerAddress].xWithdrawn += 1;
        stats[_customerAddress].totalWithdrawn += trxValue;

        totalTxs += 1;

        //Transfer the coins, thank you
        token.transfer(_customerAddress, balance);
        counterToken.transfer(_customerAddress, counterBalance);

        emit onUnfreeze(_customerAddress, trxValue);

    }

    // @dev Claim available base tokens
    function claim(address referrer) public {

        //No work to do, just return and this is pause aware
        //Pause only impacts a user after they claim after the pause
        if (availableMint() == 0){
            return;
        }

        if (now.safeSub(lastBalance_) > trackingInterval_) {
            emit onContractBalance(totalTronBalance());
            lastBalance_ = now;
        }

        address _customerAddress = msg.sender;


        //This has already been validated with availableMint
        //If we are here _stakeAmount will be greater than zero
        uint _stakeAmount = availableStake();

        //Minimum of 50 deposited to receive a referral; 5% referral
        if (referrer != address(0) && referrer != _customerAddress && stats[referrer].balance >= balanceIncrement_){
            uint _referrerMinted = tokenMint.mint(referrer,  _stakeAmount / 10);
            stats[referrer].totalReferral += _referrerMinted;
            totalMinted += _referrerMinted;
            emit onClaim(referrer, _referrerMinted);
        }

        //Update stats; time is updated only
        uint _minted = tokenMint.mint(_customerAddress,  _stakeAmount);
        stats[_customerAddress].lastUpdated = now;
        stats[_customerAddress].xMinted += 1;
        stats[_customerAddress].totalMinted += _minted;
        totalMinted += _minted;

        //Mint to the customer directly
        uint _ownerMinted = tokenMint.mint(owner,  _stakeAmount);
        stats[owner].totalReferral += _ownerMinted;
        totalMinted += _ownerMinted;
        emit onClaim(owner, _ownerMinted);

        totalTxs += 1;

        emit onClaim(_customerAddress, _minted);
        emit onBalance(_customerAddress, balanceOf(_customerAddress), stats[_customerAddress].totalMinted);
    }

    //@dev Sanity check to assure we have adequate balance of base tokens and allowance based on counter token amount
    function  baseAvailable(uint _counterAmount) public view returns (bool){
        address _customerAddress = msg.sender;

        uint _baseAmount = counterToBaseAmount(_counterAmount);

        //As long as we have the balance lets go for it
        return _baseAmount <= token.balanceOf(_customerAddress) && _baseAmount <= token.allowance(_customerAddress, address(this));
    }

    // @dev Calculate base tokens based on the counter token using both price oracles from Swap / Justswap
    function counterToBaseAmount(uint _amount) public view returns (uint){
        if (_amount > 0) {
            uint _trxValue = 0;
            if (counterAddress != wtrxAddress){
                _trxValue = exchange.getTokenToTrxInputPrice(_amount);
            } else {
                _trxValue = _amount;
            }
            return swap.getTrxToTokenInputPrice(_trxValue); 
        } else {
            return 0;
        }
    }

    // @dev Return the amount of TR based on price from JustSwap exchange
    function counterToTrx(uint _amount) public view returns (uint){
        if (counterAddress != wtrxAddress){
            return (_amount > 0) ? exchange.getTokenToTrxInputPrice(_amount) : 0;
        } else {
            return _amount;
        }
    }

    // @dev Return the amount of TRX based on price from Swap
    function baseToTrx(uint _amount) public view returns (uint){
        return (_amount > 0) ? swap.getTokenToTrxInputPrice(_amount) : 0;
    }

    // @dev Return estimate to mint based on available stake and minter
    function availableMint() public view returns (uint256){

        return tokenMint.estimateMint(availableStake());

    }

    // @dev Return available stake that can be used against the minter based on time
    function availableStake() public view returns (uint256){
        address _customerAddress = msg.sender;

        //Use simple balance for sanity checking
        uint balance = stats[_customerAddress].balance;

        //lastUpdated should always be greater than zero, but for safety we'll check
        if (balance == 0 || stats[_customerAddress].lastUpdated == 0){
            return 0;
        }

        //If closed and a claim has happened since
        if (closed > 0){
            if (stats[_customerAddress].lastUpdated > closed){
                return 0;
            }
        }

        //Grab the calculate full TRX balance
        balance = balanceOf(_customerAddress);

        uint lapsed = now.safeSub(stats[_customerAddress].lastUpdated);

        //Daily staked amount times the bonus factor
        uint _stakeAmount  = balance.div(86400) * lapsed * bonusFactor();

        //We are done
        return _stakeAmount;

    }

    // @dev Return estimate of daily returns based on calculate TRX balance
    function dailyEstimate(address _customerAddress) public view returns (uint256){

        //Use simple balance for sanity checking
        uint balance = stats[_customerAddress].balance;

        //lastUpdated should always be greater than zero, but for safety we'll check
        if (balance == 0 || stats[_customerAddress].lastUpdated == 0){
            return 0;
        }

        //Grab the calculate full TRX balance
        balance = balanceOf(_customerAddress);

        return tokenMint.estimateMint(balance * bonusFactor());

    }

    // @dev Returns the calculated TRX balance based on swap/exchange price oracles
    function balanceOf(address _customerAddress) public view returns (uint256){
        return counterToTrx(stats[_customerAddress].counterBalance) + baseToTrx(stats[_customerAddress].balance);
    }

    // @dev Returns the base tokens for a customer
    function balanceOfBase(address _customerAddress) public view returns (uint256){
        return stats[_customerAddress].balance;
    }

    // @dev Returns the balance of the counter tokens for  customer
    function balanceOfCounter(address _customerAddress) public view returns (uint256){
        return stats[_customerAddress].counterBalance;
    }

    // @dev Returns the total referral income for a given customer
    function totalReferralOf(address _customerAddress) public view returns (uint256) {
        return stats[_customerAddress].totalReferral;
    }

    //@dev Returns the total number of coins minted for a given customer
    function totalMintedOf(address _customerAddress) public view returns (uint256) {
        return stats[_customerAddress].totalMinted;
    }

    // @dev Returns tx count across deposts, withdraws, and claims
    function txsOf(address _customerAddress) public view returns (uint256){
        Stats stat = stats[_customerAddress];
        return stat.xDeposited + stat.xWithdrawn + stat.xMinted;
    }

    // @dev Returns bulk stats for a given customer
    function statsOf(address _customerAddress) public view returns (uint, uint, uint, uint,uint, uint, uint, uint, uint, uint,uint) {

        Stats stat = stats[_customerAddress];

        return
        (stat.balance,
        stat.totalDeposited,
        stat.totalWithdrawn,
        stat.totalMinted,
        stat.totalReferral,
        stat.lastUpdated,
        stat.xDeposited,
        stat.xWithdrawn,
        stat.xMinted,
        stat.xDeposited + stat.xWithdrawn + stat.xMinted,
        stat.counterBalance);
    }

    // @dev Returns true when balance and lastUpdate are positive and pat the current block time
    function ready() public view returns (bool){
        //Requirements: non zero balance, lapsed time
        return stats[msg.sender].balance > 0 && now.safeSub(stats[msg.sender].lastUpdated) > 0 && stats[msg.sender].lastUpdated > 0;
    }

    // @dev Returns true if the base token can still be mined
    function isOpen() public view returns (bool){
        return token.remainingMintableSupply() > 0;
    }

    // @dev Returns the last time the user interacted with the contract
    function lastUpdated() public view returns (uint){
        return stats[msg.sender].lastUpdated;
    }

    // @dev Graceful step for 10 down to 1 over the bonusperiod 
    function bonusFactor() public view returns (uint){
        uint elapsed = now.safeSub(launched);
        return  1 + bonusPeriod.safeSub(elapsed).mul(10).div(bonusPeriod);
    }

    /**
     * @dev Method to view the current tron stored in the contract as calculated from price oracles
     *  Example: totaltronBalance()
     */
    function totalTronBalance() public view returns (uint256) {
        return counterToTrx(counterBalance()) + baseToTrx(baseBalance());
    }

    //@dev Returns the daily estimate based on the total contract balance and bonusfactor
    function totalDailyEstimate() public view returns (uint){
        return tokenMint.estimateMint(totalTronBalance() * bonusFactor());
    }

    //@dev Returns the total balance of base tokens in the contract
    function baseBalance() public view returns (uint) {
        return token.balanceOf(address(this));
    }

    //@dev Returns the total balance of all counter tokens in the contract
    function counterBalance() public view returns (uint){
        return counterToken.balanceOf(address(this));
    }

    /* Admin functions */

    //@dev Closes a pool.  Once a pool is closed a user can claim one last time and then withdraw funds  
    function close() onlyWhitelisted public returns (uint){
        if (closed == 0){
            closed = now;
            emit onClose(closed);
        }

        return closed;
    }

}

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

    /**
    * @dev Multiplies two numbers, throws on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
            return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
    }

    /**
    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /* @dev Subtracts two numbers, else returns zero */
    function safeSub(uint a, uint b) internal pure returns (uint) {
        if (b > a) {
            return 0;
        } else {
            return a - b;
        }
    }

    /**
    * @dev Adds two numbers, throws on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

/**
 * Utility library of inline functions on addresses
 */
library Address {
    /**
     * Returns whether the target address is a contract
     * @dev This function will return false if invoked during the constructor of a contract,
     * as the code is not actually created until after the constructor finishes.
     * @param account address of the account to check
     * @return whether the target address is a contract
     */
    function isContract(address account) internal view returns (bool) {
        uint size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solhint-disable-next-line no-inline-assembly
        assembly {size := extcodesize(account)}
        return size > 0;
    }
}
			// (This comment serves to fix an HTML issue on Solidity.finance)   "


Function Graph

Smart Contract Graph

Inheritence Chart

Smart Contract Inheritance

Functions Overview



 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public

 +  Ownable 
    - [Pub]  #
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 +  Whitelist (Ownable)
    - [Pub] addAddressToWhitelist #
       - modifiers: onlyOwner
    - [Pub] addAddressesToWhitelist #
       - modifiers: onlyOwner
    - [Pub] removeAddressFromWhitelist #
       - modifiers: onlyOwner
    - [Pub] removeAddressesFromWhitelist #
       - modifiers: onlyOwner

 +  Swap 
    - [Pub] getInputPrice
    - [Pub] getOutputPrice
    - [Pub] trxToTokenSwapInput ($)
    - [Pub] trxToTokenSwapOutput ($)
    - [Pub] tokenToTrxSwapInput #
    - [Pub] tokenToTrxSwapOutput #
    - [Pub] getTrxToTokenInputPrice
    - [Pub] getTrxToTokenOutputPrice
    - [Pub] getTokenToTrxInputPrice
    - [Pub] getTokenToTrxOutputPrice
    - [Pub] tokenAddress
    - [Pub] tronBalance
    - [Pub] tokenBalance
    - [Pub] getTrxToLiquidityInputPrice
    - [Pub] getLiquidityToReserveInputPrice
    - [Pub] txs
    - [Pub] addLiquidity ($)
    - [Pub] removeLiquidity #

 +  Exchange 
    - [Ext] getEstimatedSellReceiveAmount

 +  Token 
    - [Pub] remainingMintableSupply
    - [Pub] transferFrom #
    - [Pub] transfer #
    - [Pub] balanceOf
    - [Pub] burn #
    - [Pub] mintedSupply #
    - [Pub] allowance
    - [Pub] approve #

 +  TokenMint 
    - [Pub] mint #
    - [Pub] sponsorFor ($)
    - [Pub] mintingDifficulty
    - [Pub] estimateMint #

 +  BankrollFarm (Whitelist)
    - [Pub]  #
       - modifiers: Ownable
    - [Pub] freeze #
    - [Pub] unfreeze #
    - [Pub] claim #
    - [Pub] baseAvailable
    - [Pub] counterToBaseAmount
    - [Pub] counterToTrx
    - [Pub] baseToTrx
    - [Pub] availableMint
    - [Pub] availableStake
    - [Pub] dailyEstimate
    - [Pub] balanceOf
    - [Pub] balanceOfBase
    - [Pub] balanceOfCounter
    - [Pub] totalReferralOf
    - [Pub] totalMintedOf
    - [Pub] txsOf
    - [Pub] statsOf
    - [Pub] ready
    - [Pub] isOpen
    - [Pub] lastUpdated
    - [Pub] bonusFactor
    - [Pub] totalTronBalance
    - [Pub] totalDailyEstimate
    - [Pub] baseBalance
    - [Pub] counterBalance
    - [Pub] close #
       - modifiers: onlyWhitelisted

 + [Lib] SafeMath 
    - [Int] mul
    - [Int] div
    - [Int] sub
    - [Int] safeSub
    - [Int] add
    - [Int] max
    - [Int] min

 + [Lib] Address 
    - [Int] isContract

							

Source Code

Click here to download the source code as a .sol file. Note there are two BankrollFarm contracts - One for JustSwap and one for UniFi. This contract is deployed at TQ5ZVjbJwYk6a9n6RrpsYVuFaiVK2r1GAb.


// Deployed at - TQ5ZVjbJwYk6a9n6RrpsYVuFaiVK2r1GAb

/*
    SPDX-License-Identifier: MIT
    A Bankteller Production
    Bankroll Network
    Copyright 2020
*/

pragma solidity ^0.4.25;


// File: openzeppelin-solidity/contracts/ownership/Ownable.sol

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address public owner;


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


    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor() public {
        owner = msg.sender;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

}

// File: openzeppelin-solidity/contracts/ownership/Whitelist.sol

/**
 * @title Whitelist
 * @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions.
 * @dev This simplifies the implementation of "user permissions".
 */
contract Whitelist is Ownable {
    mapping(address => bool) public whitelist;

    event WhitelistedAddressAdded(address addr);
    event WhitelistedAddressRemoved(address addr);

    /**
     * @dev Throws if called by any account that's not whitelisted.
     */
    modifier onlyWhitelisted() {
        require(whitelist[msg.sender]);
        _;
    }

    /**
     * @dev add an address to the whitelist
     * @param addr address
     * @return true if the address was added to the whitelist, false if the address was already in the whitelist
     */
    function addAddressToWhitelist(address addr) onlyOwner public returns(bool success) {
        if (!whitelist[addr]) {
            whitelist[addr] = true;
            emit WhitelistedAddressAdded(addr);
            success = true;
        }
    }

    /**
     * @dev add addresses to the whitelist
     * @param addrs addresses
     * @return true if at least one address was added to the whitelist,
     * false if all addresses were already in the whitelist
     */
    function addAddressesToWhitelist(address[] addrs) onlyOwner public returns(bool success) {
        for (uint256 i = 0; i < addrs.length; i++) {
            if (addAddressToWhitelist(addrs[i])) {
                success = true;
            }
        }
    }

    /**
     * @dev remove an address from the whitelist
     * @param addr address
     * @return true if the address was removed from the whitelist,
     * false if the address wasn't in the whitelist in the first place
     */
    function removeAddressFromWhitelist(address addr) onlyOwner public returns(bool success) {
        if (whitelist[addr]) {
            whitelist[addr] = false;
            emit WhitelistedAddressRemoved(addr);
            success = true;
        }
    }

    /**
     * @dev remove addresses from the whitelist
     * @param addrs addresses
     * @return true if at least one address was removed from the whitelist,
     * false if all addresses weren't in the whitelist in the first place
     */
    function removeAddressesFromWhitelist(address[] addrs) onlyOwner public returns(bool success) {
        for (uint256 i = 0; i < addrs.length; i++) {
            if (removeAddressFromWhitelist(addrs[i])) {
                success = true;
            }
        }
    }

}

contract Swap {

    /**
      * @dev Pricing function for converting between TRX && Tokens.
      * @param input_amount Amount of TRX or Tokens being sold.
      * @param input_reserve Amount of TRX or Tokens (input type) in exchange reserves.
      * @param output_reserve Amount of TRX or Tokens (output type) in exchange reserves.
      * @return Amount of TRX or Tokens bought.
      */
    function getInputPrice(uint256 input_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256);

    /**
      * @dev Pricing function for converting between TRX && Tokens.
      * @param output_amount Amount of TRX or Tokens being bought.
      * @param input_reserve Amount of TRX or Tokens (input type) in exchange reserves.
      * @param output_reserve Amount of TRX or Tokens (output type) in exchange reserves.
      * @return Amount of TRX or Tokens sold.
      */
    function getOutputPrice(uint256 output_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256);
    /**
     * @notice Convert TRX to Tokens.
     * @dev User specifies exact input (msg.value) && minimum output.
     * @param min_tokens Minimum Tokens bought.
     * @return Amount of Tokens bought.
     */
    function trxToTokenSwapInput(uint256 min_tokens) public payable returns (uint256);

    /**
     * @notice Convert TRX to Tokens.
     * @dev User specifies maximum input (msg.value) && exact output.
     * @param tokens_bought Amount of tokens bought.
     * @return Amount of TRX sold.
     */
    function trxToTokenSwapOutput(uint256 tokens_bought) public payable returns (uint256);

    /**
     * @notice Convert Tokens to TRX.
     * @dev User specifies exact input && minimum output.
     * @param tokens_sold Amount of Tokens sold.
     * @param min_trx Minimum TRX purchased.
     * @return Amount of TRX bought.
     */
    function tokenToTrxSwapInput(uint256 tokens_sold, uint256 min_trx) public returns (uint256);

    /**
     * @notice Convert Tokens to TRX.
     * @dev User specifies maximum input && exact output.
     * @param trx_bought Amount of TRX purchased.
     * @param max_tokens Maximum Tokens sold.
     * @return Amount of Tokens sold.
     */
    function tokenToTrxSwapOutput(uint256 trx_bought, uint256 max_tokens) public returns (uint256);

    /***********************************|
    |         Getter Functions          |
    |__________________________________*/

    /**
     * @notice Public price function for TRX to Token trades with an exact input.
     * @param trx_sold Amount of TRX sold.
     * @return Amount of Tokens that can be bought with input TRX.
     */
    function getTrxToTokenInputPrice(uint256 trx_sold) public view returns (uint256);

    /**
     * @notice Public price function for TRX to Token trades with an exact output.
     * @param tokens_bought Amount of Tokens bought.
     * @return Amount of TRX needed to buy output Tokens.
     */
    function getTrxToTokenOutputPrice(uint256 tokens_bought) public view returns (uint256);

    /**
     * @notice Public price function for Token to TRX trades with an exact input.
     * @param tokens_sold Amount of Tokens sold.
     * @return Amount of TRX that can be bought with input Tokens.
     */
    function getTokenToTrxInputPrice(uint256 tokens_sold) public view returns (uint256);

    /**
     * @notice Public price function for Token to TRX trades with an exact output.
     * @param trx_bought Amount of output TRX.
     * @return Amount of Tokens needed to buy output TRX.
     */
    function getTokenToTrxOutputPrice(uint256 trx_bought) public view returns (uint256) ;

    /**
     * @return Address of Token that is sold on this exchange.
     */
    function tokenAddress() public view returns (address) ;


    function tronBalance() public view returns (uint256);

    function tokenBalance() public view returns (uint256);

    function getTrxToLiquidityInputPrice(uint256 trx_sold) public view returns (uint256);

    function getLiquidityToReserveInputPrice(uint amount) public view returns (uint256, uint256);

    function txs(address owner) public view returns (uint256) ;


    /***********************************|
    |        Liquidity Functions        |
    |__________________________________*/

    /**
     * @notice Deposit TRX && Tokens (token) at current ratio to mint SWAP tokens.
     * @dev min_liquidity does nothing when total SWAP supply is 0.
     * @param min_liquidity Minimum number of SWAP sender will mint if total SWAP supply is greater than 0.
     * @param max_tokens Maximum number of tokens deposited. Deposits max amount if total SWAP supply is 0.
     * @return The amount of SWAP minted.
     */
    function addLiquidity(uint256 min_liquidity, uint256 max_tokens) public payable returns (uint256) ;

    /**
     * @dev Burn SWAP tokens to withdraw TRX && Tokens at current ratio.
     * @param amount Amount of SWAP burned.
     * @param min_trx Minimum TRX withdrawn.
     * @param min_tokens Minimum Tokens withdrawn.
     * @return The amount of TRX && Tokens withdrawn.
     */
    function removeLiquidity(uint256 amount, uint256 min_trx, uint256 min_tokens) public returns (uint256, uint256);
}

contract Exchange {
    function getEstimatedSellReceiveAmount(uint256 tokens_sold) external view returns (uint256);
}



contract Token {
    function remainingMintableSupply() public view returns (uint256) {}
    function transferFrom(address from, address to, uint256 value) public returns (bool){}
    function transfer(address to, uint256 value) public returns (bool){}
    function balanceOf(address who) public view returns (uint256){}
    function burn(uint256 _value) public {}
    function mintedSupply() public returns (uint256) {}
    function allowance(address owner, address spender) public view returns (uint256);
    function approve(address spender, uint256 value) public returns (bool);
}


contract TokenMint {
    function mint(address beneficiary, uint256 tokenAmount) public returns (uint256){}
    function sponsorFor(address _sender, address _beneficiary) public payable {}
    function mintingDifficulty() public view returns (uint256) {}
    function estimateMint(uint256 _amount) public returns (uint256){}
}

contract BankrollFarm is Whitelist {

    using Address for address;
    using SafeMath for uint;

    /**
    * No bloody contracts
    *
    */
    modifier isHuman {
        //No contracts
        require(msg.sender == tx.origin && !msg.sender.isContract());
        _;
    }


    struct Stats {
        uint balance; //current BNKR balance
        uint counterBalance; //current balance off farmable token
        uint totalMinted; //total minted BNKR
        uint totalDeposited; //total ever deposited TRON
        uint totalWithdrawn; //total withdrawn
        uint totalReferral; //total referrals
        uint lastUpdated; //last tx time used for calculating minted BNKR
        uint xMinted; //times claim has been called
        uint xDeposited; //times a deposit has been made
        uint xWithdrawn; //times a withdrawal was made
    }

    event onClose(
        uint256 closed
    );

    event onFreeze(
        address indexed customerAddress,
        uint256 tron
    );

    event onUnfreeze(
        address indexed customerAddress,
        uint256 tron
    );

    event onClaim(
        address indexed customerAddress,
        uint256 bnkr
    );

    event onBalance(
        address indexed customerAddress,
        uint256 tronBalance,
        uint256 bnkrMinted
    );

    event onContractBalance(
        uint256 balance
    );


    mapping(address => Stats) internal stats;
    address public mintAddress = address(0x413b155e2c501254567913a1d15e2fab4b9abea6aa); //TFMcU3QBGVB5ghtYw8g9wMV3rTFdkH2avv
    address public tokenAddress = address(0x418caeea9c7ebb8840ee4b49d10542b99cec6ffbc6); //TNo59Khpq46FGf4sD7XSWYFNfYfbc8CqNK
    address public swapAddress = address(0x41aaa7d283fa8ff534ca65a5a311e376b63411981a); //TRXYvAoYvCqmvZWpFCTLc4rdQ7KxbLsUSj
    address public wtrxAddress = address(0x41891cdb91d149f23b1a45d9c5ca78a88d0cb44c18); //TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR
    address public counterAddress;
    address public exchangeAddress;
    TokenMint private tokenMint;
    Token private token;
    Token private counterToken;
    Exchange private exchange;
    Swap private swap;

    uint256 public totalMinted;
    uint256 public totalDeposits;
    uint256 public totalTxs;
    uint256 public players;
    uint256 public closed = 0;
    uint256 public launched;

    

    uint256 internal lastBalance_;

    uint256 internal balanceIncrement_ = 50e6;
    uint256 internal trackingInterval_ = 6 hours;
    uint256 internal bonusPeriod = 24 hours * 365;

    /**
    * @dev 
    * @param _counterAddress The address of the TRC20 to stake vs BNKR
    * @param _exchangeAddress The Justswap pair contract used as a  price oracle
    */
    constructor(address _counterAddress, address _exchangeAddress) Ownable() public {

       
        counterAddress = _counterAddress;
        exchangeAddress = _exchangeAddress;

        //Only the mint should own its paired token
        tokenMint = TokenMint(mintAddress);
        token = Token(tokenAddress);
        swap = Swap(swapAddress);
        counterToken = Token(counterAddress);
        exchange = Exchange(exchangeAddress);

        //add creator to whitelist
        addAddressToWhitelist(msg.sender);

        launched = now;

    }

    // @dev Stake counter and base tokens with counter amount as input; base is calculated
    function freeze(address referrer, uint _counterAmount) public {

        //If closed then don't accept new funds
        if (closed > 0){
            return;
        }

        //No double spend
        claim(referrer);

        //Got to be able to mint
        require(isOpen(), "Mint is closed");

        address _customerAddress = msg.sender;

        require(_counterAmount > 0, "Deposit zero");
        require(counterToken.transferFrom(_customerAddress, address(this), _counterAmount), "Counter token transfer failed");
        uint _baseAmount = counterToBaseAmount(_counterAmount);

        //As long as we have the balance lets go for it
        require(_baseAmount <= token.balanceOf(_customerAddress), "Base amount required > balance");
        require(token.transferFrom(_customerAddress, address(this), _baseAmount), "Base token transfer failed");

        //Count players
        if (stats[_customerAddress].totalDeposited == 0 ){
            players += 1;
        }

        uint trxValue = counterToTrx(_counterAmount) * 2;
        //Increase the amount staked
        stats[_customerAddress].balance += _baseAmount;
        stats[_customerAddress].counterBalance += _counterAmount;
        stats[_customerAddress].lastUpdated = now;
        stats[_customerAddress].xDeposited += 1;
        stats[_customerAddress].totalDeposited += trxValue;

        totalDeposits += trxValue;
        totalTxs += 1;


        emit onFreeze(_customerAddress, trxValue);
    }

    // @dev Unfreeze staked tokens
    function unfreeze(address referrer) public  {

        //No double spend
        claim(referrer);

        address _customerAddress = msg.sender;

        uint balance = stats[_customerAddress].balance;
        uint counterBalance = stats[_customerAddress].counterBalance;
        uint trxValue = counterToTrx(counterBalance) + baseToTrx(balance);
        
        //Lets always update time on any modification
        stats[_customerAddress].balance = 0;
        stats[_customerAddress].counterBalance = 0;
        stats[_customerAddress].lastUpdated = now;
        stats[_customerAddress].xWithdrawn += 1;
        stats[_customerAddress].totalWithdrawn += trxValue;

        totalTxs += 1;

        //Transfer the coins, thank you
        token.transfer(_customerAddress, balance);
        counterToken.transfer(_customerAddress, counterBalance);

        emit onUnfreeze(_customerAddress, trxValue);

    }

    // @dev Claim available base tokens
    function claim(address referrer) public {

        //No work to do, just return and this is pause aware
        //Pause only impacts a user after they claim after the pause
        if (availableMint() == 0){
            return;
        }

        if (now.safeSub(lastBalance_) > trackingInterval_) {
            emit onContractBalance(totalTronBalance());
            lastBalance_ = now;
        }

        address _customerAddress = msg.sender;


        //This has already been validated with availableMint
        //If we are here _stakeAmount will be greater than zero
        uint _stakeAmount = availableStake();

        //Minimum of 50 deposited to receive a referral; 5% referral
        if (referrer != address(0) && referrer != _customerAddress && stats[referrer].balance >= balanceIncrement_){
            uint _referrerMinted = tokenMint.mint(referrer,  _stakeAmount / 10);
            stats[referrer].totalReferral += _referrerMinted;
            totalMinted += _referrerMinted;
            emit onClaim(referrer, _referrerMinted);
        }

        //Update stats; time is updated only
        uint _minted = tokenMint.mint(_customerAddress,  _stakeAmount);
        stats[_customerAddress].lastUpdated = now;
        stats[_customerAddress].xMinted += 1;
        stats[_customerAddress].totalMinted += _minted;
        totalMinted += _minted;

        //Mint to the customer directly
        uint _ownerMinted = tokenMint.mint(owner,  _stakeAmount);
        stats[owner].totalReferral += _ownerMinted;
        totalMinted += _ownerMinted;
        emit onClaim(owner, _ownerMinted);

        totalTxs += 1;

        emit onClaim(_customerAddress, _minted);
        emit onBalance(_customerAddress, balanceOf(_customerAddress), stats[_customerAddress].totalMinted);
    }

    //@dev Sanity check to assure we have adequate balance of base tokens and allowance based on counter token amount
    function  baseAvailable(uint _counterAmount) public view returns (bool){
        address _customerAddress = msg.sender;

        uint _baseAmount = counterToBaseAmount(_counterAmount);

        //As long as we have the balance lets go for it
        return _baseAmount <= token.balanceOf(_customerAddress) && _baseAmount <= token.allowance(_customerAddress, address(this));
    }

    // @dev Calculate base tokens based on the counter token using both price oracles from Swap / Justswap
    function counterToBaseAmount(uint _amount) public view returns (uint){
        if (_amount > 0) {
            uint _trxValue = counterToTrx(_amount);
            return swap.getTrxToTokenInputPrice(_trxValue); 
        } else {
            return 0;
        }
    }

    // @dev Return the amount of TR based on price from JustSwap exchange
    function counterToTrx(uint _amount) public view returns (uint){
        if (counterAddress != wtrxAddress){
            if (_amount > 0) {
                return exchange.getEstimatedSellReceiveAmount(_amount);
             } else {
                 return 0;
             }
        } else {
            return _amount;
        }
    }

    // @dev Return the amount of TRX based on price from Swap
    function baseToTrx(uint _amount) public view returns (uint){
        return (_amount > 0) ? swap.getTokenToTrxInputPrice(_amount) : 0;
    }

    // @dev Return estimate to mint based on available stake and minter
    function availableMint() public view returns (uint256){

        return tokenMint.estimateMint(availableStake());

    }

    // @dev Return available stake that can be used against the minter based on time
    function availableStake() public view returns (uint256){
        address _customerAddress = msg.sender;

        //Use simple balance for sanity checking
        uint balance = stats[_customerAddress].balance;

        //lastUpdated should always be greater than zero, but for safety we'll check
        if (balance == 0 || stats[_customerAddress].lastUpdated == 0){
            return 0;
        }

        //If closed and a claim has happened since
        if (closed > 0){
            if (stats[_customerAddress].lastUpdated > closed){
                return 0;
            }
        }

        //Grab the calculate full TRX balance
        balance = balanceOf(_customerAddress);

        uint lapsed = now.safeSub(stats[_customerAddress].lastUpdated);

        //Daily staked amount times the bonus factor
        uint _stakeAmount  = balance.div(86400) * lapsed * bonusFactor();

        //We are done
        return _stakeAmount;

    }

    // @dev Return estimate of daily returns based on calculate TRX balance
    function dailyEstimate(address _customerAddress) public view returns (uint256){

        //Use simple balance for sanity checking
        uint balance = stats[_customerAddress].balance;

        //lastUpdated should always be greater than zero, but for safety we'll check
        if (balance == 0 || stats[_customerAddress].lastUpdated == 0){
            return 0;
        }

        //Grab the calculate full TRX balance
        balance = balanceOf(_customerAddress);

        return tokenMint.estimateMint(balance * bonusFactor());

    }

    // @dev Returns the calculated TRX balance based on swap/exchange price oracles
    function balanceOf(address _customerAddress) public view returns (uint256){
        return counterToTrx(stats[_customerAddress].counterBalance) + baseToTrx(stats[_customerAddress].balance);
    }

    // @dev Returns the base tokens for a customer
    function balanceOfBase(address _customerAddress) public view returns (uint256){
        return stats[_customerAddress].balance;
    }

    // @dev Returns the balance of the counter tokens for  customer
    function balanceOfCounter(address _customerAddress) public view returns (uint256){
        return stats[_customerAddress].counterBalance;
    }

    // @dev Returns the total referral income for a given customer
    function totalReferralOf(address _customerAddress) public view returns (uint256) {
        return stats[_customerAddress].totalReferral;
    }

    //@dev Returns the total number of coins minted for a given customer
    function totalMintedOf(address _customerAddress) public view returns (uint256) {
        return stats[_customerAddress].totalMinted;
    }

    // @dev Returns tx count across deposts, withdraws, and claims
    function txsOf(address _customerAddress) public view returns (uint256){
        Stats stat = stats[_customerAddress];
        return stat.xDeposited + stat.xWithdrawn + stat.xMinted;
    }

    // @dev Returns bulk stats for a given customer
    function statsOf(address _customerAddress) public view returns (uint, uint, uint, uint,uint, uint, uint, uint, uint, uint,uint) {

        Stats stat = stats[_customerAddress];

        return
        (stat.balance,
        stat.totalDeposited,
        stat.totalWithdrawn,
        stat.totalMinted,
        stat.totalReferral,
        stat.lastUpdated,
        stat.xDeposited,
        stat.xWithdrawn,
        stat.xMinted,
        stat.xDeposited + stat.xWithdrawn + stat.xMinted,
        stat.counterBalance);
    }

    // @dev Returns true when balance and lastUpdate are positive and pat the current block time
    function ready() public view returns (bool){
        //Requirements: non zero balance, lapsed time
        return stats[msg.sender].balance > 0 && now.safeSub(stats[msg.sender].lastUpdated) > 0 && stats[msg.sender].lastUpdated > 0;
    }

    // @dev Returns true if the base token can still be mined
    function isOpen() public view returns (bool){
        return token.remainingMintableSupply() > 0;
    }

    // @dev Returns the last time the user interacted with the contract
    function lastUpdated() public view returns (uint){
        return stats[msg.sender].lastUpdated;
    }

    // @dev Graceful step for 10 down to 1 over the bonusperiod 
    function bonusFactor() public view returns (uint){
        uint elapsed = now.safeSub(launched);
        return  1 + bonusPeriod.safeSub(elapsed).mul(10).div(bonusPeriod);
    }

    /**
     * @dev Method to view the current tron stored in the contract as calculated from price oracles
     *  Example: totaltronBalance()
     */
    function totalTronBalance() public view returns (uint256) {
        return counterToTrx(counterBalance()) + baseToTrx(baseBalance());
    }

    //@dev Returns the daily estimate based on the total contract balance and bonusfactor
    function totalDailyEstimate() public view returns (uint){
        return tokenMint.estimateMint(totalTronBalance() * bonusFactor());
    }

    //@dev Returns the total balance of base tokens in the contract
    function baseBalance() public view returns (uint) {
        return token.balanceOf(address(this));
    }

    //@dev Returns the total balance of all counter tokens in the contract
    function counterBalance() public view returns (uint){
        return counterToken.balanceOf(address(this));
    }

    /* Admin functions */

    //@dev Closes a pool.  Once a pool is closed a user can claim one last time and then withdraw funds  
    function close() onlyWhitelisted public returns (uint){
        if (closed == 0){
            closed = now;
            emit onClose(closed);
        }

        return closed;
    }

}

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

    /**
    * @dev Multiplies two numbers, throws on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
            return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
    }

    /**
    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /* @dev Subtracts two numbers, else returns zero */
    function safeSub(uint a, uint b) internal pure returns (uint) {
        if (b > a) {
            return 0;
        } else {
            return a - b;
        }
    }

    /**
    * @dev Adds two numbers, throws on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

/**
 * Utility library of inline functions on addresses
 */
library Address {
    /**
     * Returns whether the target address is a contract
     * @dev This function will return false if invoked during the constructor of a contract,
     * as the code is not actually created until after the constructor finishes.
     * @param account address of the account to check
     * @return whether the target address is a contract
     */
    function isContract(address account) internal view returns (bool) {
        uint size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solhint-disable-next-line no-inline-assembly
        assembly {size := extcodesize(account)}
        return size > 0;
    }
}		// (This comment serves to fix an HTML issue on Solidity.finance) "


Function Graph

Smart Contract Graph

Inheritence Chart

Smart Contract Inheritance

Functions Overview



 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public

 +  Ownable 
    - [Pub]  #
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 + [Lib] SafeMath 
    - [Int] mul
    - [Int] div
    - [Int] sub
    - [Int] add

 +  TRC20Basic 
    - [Pub] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #

 +  BasicToken (TRC20Basic)
    - [Pub] totalSupply
    - [Pub] transfer #
    - [Pub] balanceOf

 +  TRC20 (TRC20Basic)
    - [Pub] allowance
    - [Pub] transferFrom #
    - [Pub] approve #

 +  StandardToken (TRC20, BasicToken)
    - [Pub] transferFrom #
    - [Pub] approve #
    - [Pub] allowance
    - [Pub] increaseApproval #
    - [Pub] decreaseApproval #

 +  MintableToken (StandardToken, Ownable)
    - [Pub] mint #
       - modifiers: onlyOwner,canMint
    - [Pub] finishMinting #
       - modifiers: onlyOwner,canMint

 +  Token 
    - [Pub] remainingMintableSupply
    - [Pub] transferFrom #
    - [Pub] transfer #
    - [Pub] balanceOf
    - [Pub] burn #
    - [Pub] mintedSupply #

 +  HyperToken (MintableToken)
    - [Pub]  #
       - modifiers: Ownable
    - [Pub] swap #
    - [Pub] airdrop #
    - [Pub] mint #
    - [Pub] finishMinting #
       - modifiers: onlyOwner,canMint
    - [Pub] transferFrom #
    - [Pub] transfer #
    - [Pub] remainingMintableSupply
    - [Pub] cap
    - [Pub] mintedSupply
    - [Pub] statsOf
    - [Pub] airdropEligible
    - [Pub] mintedBy

  
							

Source Code

Click here to download the source code as a .sol file.


pragma solidity ^0.4.25;


// File: openzeppelin-solidity/contracts/ownership/Ownable.sol

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address public owner;


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


    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor() public {
        owner = msg.sender;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

}

// File: openzeppelin-solidity/contracts/math/SafeMath.sol

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

    /**
    * @dev Multiplies two numbers, throws on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
            return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
    }

    /**
    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /**
    * @dev Adds two numbers, throws on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }
}

// File: openzeppelin-solidity/contracts/token/TRC20/TRC20Basic.sol

/**
 * @title TRC20Basic
 * @dev Simpler version of TRC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/179
 */
contract TRC20Basic {
    function totalSupply() public view returns (uint256);

    function balanceOf(address who) public view returns (uint256);

    function transfer(address to, uint256 value) public returns (bool);

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

// File: openzeppelin-solidity/contracts/token/TRC20/BasicToken.sol

/**
 * @title Basic token
 * @dev Basic version of StandardToken, with no allowances.
 */
contract BasicToken is TRC20Basic {
    using SafeMath for uint256;

    mapping(address => uint256) balances;

    uint256 totalSupply_;

    /**
    * @dev total number of tokens in existence
    */
    function totalSupply() public view returns (uint256) {
        return totalSupply_;
    }

    /**
    * @dev transfer token for a specified address
    * @param _to The address to transfer to.
    * @param _value The amount to be transferred.
    */
    function transfer(address _to, uint256 _value) public returns (bool) {
        require(_to != address(0));
        require(_value <= balances[msg.sender]);

        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    /**
    * @dev Gets the balance of the specified address.
    * @param _owner The address to query the the balance of.
    * @return An uint256 representing the amount owned by the passed address.
    */
    function balanceOf(address _owner) public view returns (uint256) {
        return balances[_owner];
    }

}

// File: openzeppelin-solidity/contracts/token/TRC20/TRC20.sol

/**
 * @title TRC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract TRC20 is TRC20Basic {
    function allowance(address owner, address spender) public view returns (uint256);

    function transferFrom(address from, address to, uint256 value) public returns (bool);

    function approve(address spender, uint256 value) public returns (bool);

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

// File: openzeppelin-solidity/contracts/token/TRC20/StandardToken.sol

/**
 * @title Standard TRC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract StandardToken is TRC20, BasicToken {

    mapping(address => mapping(address => uint256)) internal allowed;


    /**
     * @dev Transfer tokens from one address to another
     * @param _from address The address which you want to send tokens from
     * @param _to address The address which you want to transfer to
     * @param _value uint256 the amount of tokens to be transferred
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        require(_to != address(0));
        require(_value <= balances[_from]);
        require(_value <= allowed[_from][msg.sender]);

        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        emit Transfer(_from, _to, _value);
        return true;
    }

    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
     *
     * 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
     * @param _spender The address which will spend the funds.
     * @param _value The amount of tokens to be spent.
     */
    function approve(address _spender, uint256 _value) public returns (bool) {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
     * @dev Function to check the amount of tokens that an owner allowed to a spender.
     * @param _owner address The address which owns the funds.
     * @param _spender address The address which will spend the funds.
     * @return A uint256 specifying the amount of tokens still available for the spender.
     */
    function allowance(address _owner, address _spender) public view returns (uint256) {
        return allowed[_owner][_spender];
    }

    /**
     * @dev Increase the amount of tokens that an owner allowed to a spender.
     *
     * approve should be called when allowed[_spender] == 0. To increment
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * @param _spender The address which will spend the funds.
     * @param _addedValue The amount of tokens to increase the allowance by.
     */
    function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
        allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
        emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     *
     * approve should be called when allowed[_spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * @param _spender The address which will spend the funds.
     * @param _subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
        uint oldValue = allowed[msg.sender][_spender];
        if (_subtractedValue > oldValue) {
            allowed[msg.sender][_spender] = 0;
        } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
        }
        emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

}

// File: openzeppelin-solidity/contracts/token/TRC20/MintableToken.sol

/**
 * @title Mintable token
 * @dev Simple TRC20 Token example, with mintable token creation
 * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
 * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
 */
contract MintableToken is StandardToken, Ownable {
    event Mint(address indexed to, uint256 amount);
    event MintFinished();

    bool public mintingFinished = false;


    modifier canMint() {
        require(!mintingFinished);
        _;
    }

    /**
     * @dev Function to mint tokens
     * @param _to The address that will receive the minted tokens.
     * @param _amount The amount of tokens to mint.
     * @return A boolean that indicates if the operation was successful.
     */
    function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
        totalSupply_ = totalSupply_.add(_amount);
        balances[_to] = balances[_to].add(_amount);
        emit Mint(_to, _amount);
        emit Transfer(address(0), _to, _amount);
        return true;
    }

    /**
     * @dev Function to stop minting new tokens.
     * @return True if the operation was successful.
     */
    function finishMinting() onlyOwner canMint public returns (bool) {
        mintingFinished = true;
        emit MintFinished();
        return true;
    }


}

contract Token {
    function remainingMintableSupply() public view returns (uint256) {}
    function transferFrom(address from, address to, uint256 value) public returns (bool){}
    function transfer(address to, uint256 value) public returns (bool){}
    function balanceOf(address who) public view returns (uint256){}
    function burn(uint256 _value) public {}
    function mintedSupply() public returns (uint256) {}
}



/**
 * @dev Very simple TRC20 Token that can be minted.
 * It is meant to be used in a crowdsale contract.
 */
contract HyperToken is MintableToken {

    struct Stats {
        uint256 txs;
        uint256 minted;
        bool receivedAirdrop;
    }


    // solium-disable-next-line uppercase
    string public constant name = "Bankroll Token";
    string public constant symbol = "BNKR"; // solium-disable-line uppercase
    uint8 public constant decimals = 6; // solium-disable-line uppercase
    uint256  private constant targetSupply = 21e6 * 1e6; //21M supply
    uint256 public totalTxs;
    uint256 public players;
    uint256  private mintedSupply_;

    //Old token
    address public tokenAddress;
    Token private token;

    mapping(address => Stats) private stats;



    /**
     * @dev default constructor
     */
    constructor(address _tokenAddress) Ownable() public {

        //Old token
        tokenAddress = _tokenAddress;
        token = Token(tokenAddress);

    }

    /**
     * @dev Swaps the old token for the new one if approval and amount is available (onlyOwner)
     */
    function swap(address _to, uint256 _amount) public {

        require(_amount > 0);

        //Transfer requires approval
        require(token.transferFrom(_to, address(this), _amount));

        //Burn whatever is collected; make no assumptions about former tokens calcs
        token.burn(token.balanceOf(address(this)));

        //Mint the new token
        require(mint(_to,_amount));
    }

    /** @dev does a one time airdrop; subject to (onlyOwner) */
    function airdrop(address _to, uint256 _amount) public returns (bool) {
        require(!stats[_to].receivedAirdrop);
        stats[_to].receivedAirdrop = mint(_to, _amount);

        return stats[_to].receivedAirdrop;
    }


    /**
     * @dev Function to mint tokens (onlyOwner)
     * @param _to The address that will receive the minted tokens.
     * @param _amount The amount of tokens to mint.
     * @return A boolean that indicates if the operation was successful.
     */
    function mint(address _to, uint256 _amount) public returns (bool) {

        //Never fail, just don't mint if over
        if (_amount == 0 || mintedSupply_.add(_amount) > targetSupply) {
            return false;
        }

        //Mint
        super.mint(_to, _amount);
        mintedSupply_ = mintedSupply_.add(_amount);

        if (mintedSupply_ == targetSupply) {
            mintingFinished = true;
        }

        /* Members */
        if (stats[_to].txs == 0) {
            players += 1;
        }

        stats[_to].txs += 1;
        stats[_to].minted += _amount;

        totalTxs += 1;


        return true;

    }



    /**
     * @dev Override so that minting cannot be accidentally terminated
     */
    function finishMinting() onlyOwner canMint public returns (bool) {
        return false;
    }

    /** @dev Transfers (using transferFrom) */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {

        super.transferFrom(_from, _to, _value);

        /* Members */
        if (stats[_to].txs == 0) {
            players += 1;
        }

        stats[_to].txs += 1;
        stats[_from].txs += 1;

        totalTxs += 1;

        return true;


    }

    /** @dev Transfers */
    function transfer(address _to, uint256 _value) public returns (bool) {

        super.transfer(_to, _value);

        /* Members */
        if (stats[_to].txs == 0) {
            players += 1;
        }

        stats[_to].txs += 1;
        stats[msg.sender].txs += 1;

        totalTxs += 1;

        return true;
    }

    /** @dev Returns the supply still available to mint */
    function remainingMintableSupply() public view returns (uint256) {
        return targetSupply.sub(mintedSupply_);
    }

    /**
     * @dev Returns the cap for the token minting.
     */
    function cap() public view returns (uint256) {
        return targetSupply;
    }

    /**
    * @dev total number of minted tokens
    */
    function mintedSupply() public view returns (uint256) {
        return mintedSupply_;
    }

    /** @dev stats of player, (txs, minted) */
    function statsOf(address player) public view returns (uint256, uint256, uint256){
        return (balanceOf(player), stats[player].txs, stats[player].minted);
    }

    /** @dev check eligibiity for a given player to receive a one time airdrop */
    function airdropEligible(address player) public view returns (bool){
        return stats[player].receivedAirdrop == false;
    }

    ///** @dev Returns the number of tokens minted by the player */
    function mintedBy(address player) public view returns (uint256){
        return stats[player].minted;
    }


}

					   // (This comment serves to fix an HTML issue on Solidity.finance)    >>"


Function Graph

Smart Contract Graph

Inheritence Chart

Smart Contract Inheritance

Functions Overview



 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public

 +  Token 
    - [Pub] approve #
    - [Pub] allowance
    - [Pub] transferFrom #
    - [Pub] transfer #
    - [Pub] balanceOf
    - [Pub] totalSupply

 +  Swap 
    - [Pub] getInputPrice
    - [Pub] getOutputPrice
    - [Pub] trxToTokenSwapInput ($)
    - [Pub] trxToTokenSwapOutput ($)
    - [Pub] tokenToTrxSwapInput #
    - [Pub] tokenToTrxSwapOutput #
    - [Pub] getTrxToTokenInputPrice
    - [Pub] getTrxToTokenOutputPrice
    - [Pub] getTokenToTrxInputPrice
    - [Pub] getTokenToTrxOutputPrice
    - [Pub] tokenAddress
    - [Pub] tronBalance
    - [Pub] tokenBalance
    - [Pub] getTrxToLiquidityInputPrice
    - [Pub] getLiquidityToReserveInputPrice
    - [Pub] txs
    - [Pub] addLiquidity ($)
    - [Pub] removeLiquidity #

 +  BankrollStronghold 
    - [Pub]  #
    - [Pub] buy ($)
    - [Int] buyFor #
    - [Pub]  ($)
    - [Pub] reinvest #
       - modifiers: onlyStronghands
    - [Pub] withdraw #
       - modifiers: onlyStronghands
    - [Pub] sell #
       - modifiers: onlyBagholders
    - [Ext] transfer #
       - modifiers: onlyBagholders
    - [Pub] totalTokenBalance
    - [Pub] lockedTokenBalance
    - [Pub] collateralBalance
    - [Pub] totalSupply
    - [Pub] myTokens
    - [Pub] myDividends
    - [Pub] balanceOf
    - [Pub] trxBalance
    - [Pub] dividendsOf
    - [Int] approveSwap #
    - [Int] sellTokens #
    - [Int] sellTrx #
    - [Pub] calculateLiquidityToTrx
    - [Pub] calculateTaxedTrxToTokenLiquidity
    - [Pub] calculateTaxedLiquidityToTrx
    - [Pub] sweep #
    - [Pub] statsOf
    - [Pub] dailyEstimateTrx
    - [Pub] dailyEstimate
    - [Prv] allocateFees #
    - [Prv] distribute #
    - [Int] purchaseTokens #

 + [Lib] SafeMath 
    - [Int] mul
    - [Int] div
    - [Int] sub
    - [Int] safeSub
    - [Int] add
    - [Int] max
    - [Int] min
							

Source Code

Click here to download the source code as a .sol file.


/*
    SPDX-License-Identifier: MIT
    A Bankteller Production
    Bankroll Network
    Copyright 2020
*/
pragma solidity ^0.4.25;


contract Token {
    function approve(address spender, uint256 value) public returns (bool);

    function allowance(address owner, address spender) public view returns (uint256);

    function transferFrom(address from, address to, uint256 value) public returns (bool);

    function transfer(address to, uint256 value) public returns (bool);

    function balanceOf(address who) public view returns (uint256);

    function totalSupply() public view returns (uint256);
}

contract Swap {

    /**
      * @dev Pricing function for converting between TRX && Tokens.
      * @param input_amount Amount of TRX or Tokens being sold.
      * @param input_reserve Amount of TRX or Tokens (input type) in exchange reserves.
      * @param output_reserve Amount of TRX or Tokens (output type) in exchange reserves.
      * @return Amount of TRX or Tokens bought.
      */
    function getInputPrice(uint256 input_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256);

    /**
      * @dev Pricing function for converting between TRX && Tokens.
      * @param output_amount Amount of TRX or Tokens being bought.
      * @param input_reserve Amount of TRX or Tokens (input type) in exchange reserves.
      * @param output_reserve Amount of TRX or Tokens (output type) in exchange reserves.
      * @return Amount of TRX or Tokens sold.
      */
    function getOutputPrice(uint256 output_amount, uint256 input_reserve, uint256 output_reserve) public view returns (uint256);
    /**
     * @notice Convert TRX to Tokens.
     * @dev User specifies exact input (msg.value) && minimum output.
     * @param min_tokens Minimum Tokens bought.
     * @return Amount of Tokens bought.
     */
    function trxToTokenSwapInput(uint256 min_tokens) public payable returns (uint256);

    /**
     * @notice Convert TRX to Tokens.
     * @dev User specifies maximum input (msg.value) && exact output.
     * @param tokens_bought Amount of tokens bought.
     * @return Amount of TRX sold.
     */
    function trxToTokenSwapOutput(uint256 tokens_bought) public payable returns (uint256);

    /**
     * @notice Convert Tokens to TRX.
     * @dev User specifies exact input && minimum output.
     * @param tokens_sold Amount of Tokens sold.
     * @param min_trx Minimum TRX purchased.
     * @return Amount of TRX bought.
     */
    function tokenToTrxSwapInput(uint256 tokens_sold, uint256 min_trx) public returns (uint256);

    /**
     * @notice Convert Tokens to TRX.
     * @dev User specifies maximum input && exact output.
     * @param trx_bought Amount of TRX purchased.
     * @param max_tokens Maximum Tokens sold.
     * @return Amount of Tokens sold.
     */
    function tokenToTrxSwapOutput(uint256 trx_bought, uint256 max_tokens) public returns (uint256);

    /***********************************|
    |         Getter Functions          |
    |__________________________________*/

    /**
     * @notice Public price function for TRX to Token trades with an exact input.
     * @param trx_sold Amount of TRX sold.
     * @return Amount of Tokens that can be bought with input TRX.
     */
    function getTrxToTokenInputPrice(uint256 trx_sold) public view returns (uint256);

    /**
     * @notice Public price function for TRX to Token trades with an exact output.
     * @param tokens_bought Amount of Tokens bought.
     * @return Amount of TRX needed to buy output Tokens.
     */
    function getTrxToTokenOutputPrice(uint256 tokens_bought) public view returns (uint256);

    /**
     * @notice Public price function for Token to TRX trades with an exact input.
     * @param tokens_sold Amount of Tokens sold.
     * @return Amount of TRX that can be bought with input Tokens.
     */
    function getTokenToTrxInputPrice(uint256 tokens_sold) public view returns (uint256);

    /**
     * @notice Public price function for Token to TRX trades with an exact output.
     * @param trx_bought Amount of output TRX.
     * @return Amount of Tokens needed to buy output TRX.
     */
    function getTokenToTrxOutputPrice(uint256 trx_bought) public view returns (uint256) ;

    /**
     * @return Address of Token that is sold on this exchange.
     */
    function tokenAddress() public view returns (address) ;


    function tronBalance() public view returns (uint256);

    function tokenBalance() public view returns (uint256);

    function getTrxToLiquidityInputPrice(uint256 trx_sold) public view returns (uint256);

    function getLiquidityToReserveInputPrice(uint amount) public view returns (uint256, uint256);

    function txs(address owner) public view returns (uint256) ;


    /***********************************|
    |        Liquidity Functions        |
    |__________________________________*/

    /**
     * @notice Deposit TRX && Tokens (token) at current ratio to mint SWAP tokens.
     * @dev min_liquidity does nothing when total SWAP supply is 0.
     * @param min_liquidity Minimum number of SWAP sender will mint if total SWAP supply is greater than 0.
     * @param max_tokens Maximum number of tokens deposited. Deposits max amount if total SWAP supply is 0.
     * @return The amount of SWAP minted.
     */
    function addLiquidity(uint256 min_liquidity, uint256 max_tokens) public payable returns (uint256) ;

    /**
     * @dev Burn SWAP tokens to withdraw TRX && Tokens at current ratio.
     * @param amount Amount of SWAP burned.
     * @param min_trx Minimum TRX withdrawn.
     * @param min_tokens Minimum Tokens withdrawn.
     * @return The amount of TRX && Tokens withdrawn.
     */
    function removeLiquidity(uint256 amount, uint256 min_trx, uint256 min_tokens) public returns (uint256, uint256);
}

/*
 * @dev Life is a perpetual rewards contract the collects 9% fee for a dividend pool that drips 2% daily.
 * A 1% fee is used to buy back a specified ERC20/TRC20 token and distribute to LYF holders via a 2% drip
*/


contract BankrollStronghold {

    using SafeMath for uint;

    /*=================================
    =            MODIFIERS            =
    =================================*/

    /// @dev Only people with tokens
    modifier onlyBagholders {
        require(myTokens() > 0);
        _;
    }

    /// @dev Only people with profits
    modifier onlyStronghands {
        require(myDividends() > 0);
        _;
    }



    /*==============================
    =            EVENTS            =
    ==============================*/


    event onLeaderBoard(
        address indexed customerAddress,
        uint256 invested,
        uint256 tokens,
        uint256 soldTokens,
        uint256 timestamp
    );

    event onTokenPurchase(
        address indexed customerAddress,
        uint256 incomingeth,
        uint256 tokensMinted,
        uint timestamp
    );

    event onTokenSell(
        address indexed customerAddress,
        uint256 tokensBurned,
        uint256 ethEarned,
        uint timestamp
    );

    event onReinvestment(
        address indexed customerAddress,
        uint256 ethReinvested,
        uint256 tokensMinted,
        uint256 timestamp
    );

    event onWithdraw(
        address indexed customerAddress,
        uint256 ethWithdrawn,
        uint256 timestamp
    );

    event onClaim(
        address indexed customerAddress,
        uint256 tokens,
        uint256 timestamp
    );

    event onTransfer(
        address indexed from,
        address indexed to,
        uint256 tokens,
        uint256 timestamp
    );

    event onBuyBack(
        uint ethAmount,
        uint tokenAmount,
        uint256 timestamp
    );

    event onBalance(
        uint256 trxBalance,
        uint256 tokenBalance,
        uint256 timestamp
    );

    event onLiquiditySweep(
        uint amount
    );

    event onLiquidityProviderReward(
        uint amount
    );

    // Onchain Stats!!!
    struct Stats {
        uint invested;
        uint reinvested;
        uint withdrawn;
        uint rewarded;
        uint contributed;
        uint transferredTokens;
        uint receivedTokens;
        uint xInvested;
        uint xReinvested;
        uint xRewarded;
        uint xContributed;
        uint xWithdrawn;
        uint xTransferredTokens;
        uint xReceivedTokens;
    }


    /*=====================================
    =            CONFIGURABLES            =
    =====================================*/

    /// @dev 15% dividends for token purchase
    uint8 constant internal entryFee_ = 10;


    /// @dev 5% dividends for token selling
    uint8 constant internal exitFee_ = 10;

    uint8 constant internal dripFee = 40;  //80% of fees go to drip/instant, the rest, 20%,  to lock into token liquidity

    uint8 constant internal instantFee = 40;

    uint8 constant payoutRate_ = 2;

    uint256 constant internal magnitude = 2 ** 64;

    uint constant MAX_UINT = 2**256 - 1;

    /*=================================
     =            DATASETS            =
     ================================*/

    // amount of shares for each address (scaled number)
    mapping(address => uint256) private tokenBalanceLedger_;
    mapping(address => int256) private payoutsTo_;
    mapping(address => Stats) private stats;
    //on chain referral tracking
    uint256 private tokenSupply_;
    uint256 private profitPerShare_;
    uint256 public totalDeposits;
    uint256 public totalWithdrawn;
    uint256 internal lastBalance_;
    uint private lockedBalance;

    uint public players;
    uint public totalTxs;
    uint public dividendBalance;

    uint public lastPayout;

    uint256 public balanceInterval = 2 seconds;
    uint256 public distributionInterval = 2 seconds;


    address constant public swapAddress =  address(0x41aaa7d283fa8ff534ca65a5a311e376b63411981a); //TRXYvAoYvCqmvZWpFCTLc4rdQ7KxbLsUSj
    address constant public collateralAddress = address(0x418caeea9c7ebb8840ee4b49d10542b99cec6ffbc6); //TNo59Khpq46FGf4sD7XSWYFNfYfbc8CqNK

    Token private swapToken;
    Token private cToken;
    Swap private swap;


    /*=======================================
    =            PUBLIC FUNCTIONS           =
    =======================================*/

    constructor() public {

        swapToken = Token(swapAddress);
        swap = Swap(swapAddress);


        cToken = Token(collateralAddress);

        lastPayout = now;

    }

    /// @dev converts TRX into liquidity and buys
    function buy() public payable returns (uint256){
        require(msg.value > 1e4, "Has to be greater than 0.01 TRX");

        totalDeposits += msg.value;

        //Refresh approvals
        approveSwap();

        //use dust from previous txs
        uint balance = address(this).balance;

        uint tokens = sellTrx(balance / 2);

        //the secret sauce for adding liquidity properly
        uint trxAmount = SafeMath.min(swap.getTokenToTrxInputPrice(tokens), address(this).balance);

        //If you don't get trxAmount from the contract you will have pain
        uint liquidAmount = swap.addLiquidity.value(trxAmount)(1, tokens);
        return buyFor(msg.sender, liquidAmount);
    }

    /// @dev Converts all incoming eth to tokens for the caller, and passes down the referral addy (if any)
    function buyFor(address _customerAddress, uint _buy_amount) internal returns (uint256)  {

        uint amount = purchaseTokens(_customerAddress, _buy_amount);

        emit onLeaderBoard(_customerAddress,
            stats[_customerAddress].invested,
            tokenBalanceLedger_[_customerAddress],
            stats[_customerAddress].withdrawn,
            now
        );

        return amount;
    }




    /**
     * @dev Fallback function to handle eth that was send straight to the contract
     *  Unfortunately we cannot use a referral address this way.
     */
    function() public payable  {
       //DO NOTHING!!! Swap will send TRX to us!!!
    }

    /// @dev Converts all of caller's dividends to tokens.
    function reinvest() public onlyStronghands returns (uint) {
        // fetch dividends
        uint256 _dividends = myDividends();
        // retrieve ref. bonus later in the code

        // pay out the dividends virtually
        address _customerAddress = msg.sender;
        payoutsTo_[_customerAddress] += (int256) (_dividends * magnitude);

        // dispatch a buy order with the virtualized "withdrawn dividends"
        uint256 _tokens = purchaseTokens(msg.sender, _dividends);

        uint trxAmount = calculateLiquidityToTrx(_dividends);

        // fire event
        emit onReinvestment(_customerAddress, trxAmount, _tokens, now);

        //Stats
        stats[_customerAddress].reinvested = SafeMath.add(stats[_customerAddress].reinvested, trxAmount);
        stats[_customerAddress].xReinvested += 1;

        emit onLeaderBoard(_customerAddress,
            stats[_customerAddress].invested,
            tokenBalanceLedger_[_customerAddress],
            stats[_customerAddress].withdrawn,
            now
        );

        //distribute
        distribute();

        return _tokens;
    }

    /// @dev Withdraws all of the callers earnings.
    function withdraw() public onlyStronghands returns (uint) {
        // setup data
        address _customerAddress = msg.sender;
        uint256 _dividends = myDividends();

        // update dividend tracker
        payoutsTo_[_customerAddress] += (int256) (_dividends * magnitude);

        //remove liquidity and sell the tokens for TRX
        (uint trxAmount, uint tokenAmount) = swap.removeLiquidity(_dividends,1,1);
        trxAmount = trxAmount.add(sellTokens(tokenAmount));

        // lambo delivery service
        _customerAddress.transfer(trxAmount);

        totalWithdrawn += trxAmount;

        //stats
        stats[_customerAddress].withdrawn = SafeMath.add(stats[_customerAddress].withdrawn, trxAmount);
        stats[_customerAddress].xWithdrawn += 1;
        totalTxs += 1;

        // fire event
        emit onWithdraw(_customerAddress, trxAmount, now);

        emit onLeaderBoard(_customerAddress,
            stats[_customerAddress].invested,
            tokenBalanceLedger_[_customerAddress],
            stats[_customerAddress].withdrawn,
            now
        );

        return trxAmount;
    }


    /// @dev Liquifies STCK to collateral tokens.
    function sell(uint256 _amountOfTokens) onlyBagholders public {
        // setup data
        address _customerAddress = msg.sender;

        require(_amountOfTokens <= tokenBalanceLedger_[_customerAddress], "Amount of tokens is greater than balance");


        // data setup
        uint256 _undividedDividends = SafeMath.mul(_amountOfTokens, exitFee_) / 100;
        uint256 _taxedeth = SafeMath.sub(_amountOfTokens, _undividedDividends);

        // burn the sold tokens
        tokenSupply_ = SafeMath.sub(tokenSupply_, _amountOfTokens);
        tokenBalanceLedger_[_customerAddress] = SafeMath.sub(tokenBalanceLedger_[_customerAddress], _amountOfTokens);

        // update dividends tracker
        int256 _updatedPayouts = (int256) (profitPerShare_ * _amountOfTokens + (_taxedeth * magnitude));
        payoutsTo_[_customerAddress] -= _updatedPayouts;

        //drip and buybacks applied after supply is updated
        allocateFees(_undividedDividends);

        totalTxs += 1;

        // fire event
        emit onTokenSell(_customerAddress, _amountOfTokens, _taxedeth, now);

        emit onLeaderBoard(_customerAddress,
            stats[_customerAddress].invested,
            tokenBalanceLedger_[_customerAddress],
            stats[_customerAddress].withdrawn,
            now
        );

        //distribute
        distribute();
    }

    /**
    * @dev Transfer tokens from the caller to a new holder.
    *  Zero fees
    */
    function transfer(address _toAddress, uint256 _amountOfTokens) external onlyBagholders  returns (bool) {
        // setup
        address _customerAddress = msg.sender;

        // make sure we have the requested tokens
        require(_amountOfTokens <= tokenBalanceLedger_[_customerAddress], "Amount of tokens is greater than balance");

        // withdraw all outstanding dividends first
        if (myDividends() > 0) {
            withdraw();
        }


        // exchange tokens
        tokenBalanceLedger_[_customerAddress] = SafeMath.sub(tokenBalanceLedger_[_customerAddress], _amountOfTokens);
        tokenBalanceLedger_[_toAddress] = SafeMath.add(tokenBalanceLedger_[_toAddress], _amountOfTokens);

        // update dividend trackers
        payoutsTo_[_customerAddress] -= (int256) (profitPerShare_ * _amountOfTokens);
        payoutsTo_[_toAddress] += (int256) (profitPerShare_ * _amountOfTokens);

        /* Members
            A player can be initialized by buying or receiving and we want to add the user ASAP
         */
        if (stats[_toAddress].invested == 0 && stats[_toAddress].receivedTokens == 0) {
            players += 1;
        }

        //Stats
        stats[_customerAddress].xTransferredTokens += 1;
        stats[_customerAddress].transferredTokens += _amountOfTokens;
        stats[_toAddress].receivedTokens += _amountOfTokens;
        stats[_toAddress].xReceivedTokens += 1;
        totalTxs += 1;

        // fire event
        emit onTransfer(_customerAddress, _toAddress, _amountOfTokens, now);

        emit onLeaderBoard(_customerAddress,
            stats[_customerAddress].invested,
            tokenBalanceLedger_[_customerAddress],
            stats[_customerAddress].withdrawn,
            now
        );

        emit onLeaderBoard(_toAddress,
            stats[_toAddress].invested,
            tokenBalanceLedger_[_toAddress],
            stats[_toAddress].withdrawn,
            now
        );

        // ERC20
        return true;
    }


    /*=====================================
    =      HELPERS AND CALCULATORS        =
    =====================================*/

    /**
     * @dev Method to view the current eth stored in the contract
     */
    function totalTokenBalance() public view returns (uint256) {
        return swapToken.balanceOf(address(this));
    }

    function lockedTokenBalance() public view returns (uint256) {
        return lockedBalance;
    }

    function collateralBalance() public view returns (uint256) {
        return cToken.balanceOf(address(this));
    }

    /// @dev Retrieve the total token supply.
    function totalSupply() public view returns (uint256) {
        return tokenSupply_;
    }

    /// @dev Retrieve the tokens owned by the caller.
    function myTokens() public view returns (uint256) {
        address _customerAddress = msg.sender;
        return balanceOf(_customerAddress);
    }

    /**
     * @dev Retrieve the dividends owned by the caller.
     */
    function myDividends() public view returns (uint256) {
        address _customerAddress = msg.sender;
        return dividendsOf(_customerAddress);
    }


    /// @dev Retrieve the token balance of any single address.
    function balanceOf(address _customerAddress) public view returns (uint256) {
        return tokenBalanceLedger_[_customerAddress];
    }

    /// @dev Retrieve the token balance of any single address.
    function trxBalance(address _customerAddress) public view returns (uint256) {
        return _customerAddress.balance;
    }

    /// @dev Retrieve the dividend balance of any single address.
    function dividendsOf(address _customerAddress) public view returns (uint256) {
        return (uint256) ((int256) (profitPerShare_ * tokenBalanceLedger_[_customerAddress]) - payoutsTo_[_customerAddress]) / magnitude;
    }

    function approveSwap() internal {
        require(cToken.approve(swapAddress, MAX_UINT), "Need to approve swap before selling tokens");
    }

    function sellTokens(uint256 amount) internal returns (uint256) {
        approveSwap();
        return swap.tokenToTrxSwapInput(amount,1);
    }

    function sellTrx(uint256 amount) internal returns (uint256){
        return swap.trxToTokenSwapInput.value(amount)(1);
    }


    function calculateLiquidityToTrx(uint256 _amount) public view returns (uint256){
        if (_amount > 0){
            (uint trxAmount, uint tokenAmount) = swap.getLiquidityToReserveInputPrice(_amount);
            return trxAmount.add(swap.getTokenToTrxInputPrice(tokenAmount));
        } else {
            return 0;
        }
    }

    function calculateTaxedTrxToTokenLiquidity(uint256 _amount) public view returns (uint256){
         if (_amount > 0){
            uint amount = swap.getTrxToLiquidityInputPrice(_amount.div(2));
            return amount.mul(SafeMath.sub(100,entryFee_)).div(100);
         } else {
             return 0;
         }
    }


    function calculateTaxedLiquidityToTrx(uint256 _amount) public view returns (uint256){
         if (_amount > 0){
             _amount = _amount.mul(SafeMath.sub(100,entryFee_)).div(100);
            (uint trxAmount, uint tokenAmount) = swap.getLiquidityToReserveInputPrice(_amount);
            return trxAmount.add(swap.getTokenToTrxInputPrice(tokenAmount));
         } else {
             return 0;
         }
    }

    function sweep() public returns (uint256){

        uint balanceOriginTokens = collateralBalance();


        if (balanceOriginTokens >= 10e6  && tokenSupply_ > 0){

            uint halfTokens = balanceOriginTokens.div(2);

            //We need to start with TRX so we can safely split and add liquidity; also collect TRX dust in the constract
            uint balanceTrx = sellTokens(halfTokens);

            uint balanceTokens = collateralBalance();

             //the secret sauce for adding liquidity properly
            uint trxAmount = SafeMath.min(swap.getTokenToTrxInputPrice(balanceTokens), balanceTrx);

            //If you don't get trxAmount from the contract you will have pain
            uint liquidAmount = swap.addLiquidity.value(trxAmount)(1, balanceTokens);

            //half goes to lock and the other half goes to Stronghold LPs
            uint halfLiq = liquidAmount.div(2);


            uint sweepBalance = liquidAmount.sub(halfLiq);

            //Apply sweep divs to LPs
            profitPerShare_ = SafeMath.add(profitPerShare_, (sweepBalance * magnitude) / tokenSupply_);

            //Add the new liquidity to locked; Stronghold should show up on the leaderboard
            lockedBalance += halfLiq;

            emit onLiquiditySweep(halfLiq);
            emit onLiquidityProviderReward(halfLiq);
            return liquidAmount;
        } else {
            return 0;
        }

    }




    /// @dev Stats of any single address
    function statsOf(address _customerAddress) public view returns (uint256[14] memory){
        Stats memory s = stats[_customerAddress];
        uint256[14] memory statArray = [s.invested, s.withdrawn, s.rewarded, s.contributed, s.transferredTokens, s.receivedTokens, s.xInvested, s.xRewarded, s.xContributed, s.xWithdrawn, s.xTransferredTokens, s.xReceivedTokens, s.reinvested, s.xReinvested];
        return statArray;
    }

    /// @dev Calculate daily estimate of swap tokens awarded in TRX
    function dailyEstimateTrx(address _customerAddress) public view returns (uint256){
        if (tokenSupply_ > 0){
            uint256 share = dividendBalance.mul(payoutRate_).div(100);
            uint256 estimate = share.mul(tokenBalanceLedger_[_customerAddress]).div(tokenSupply_);
            (uint trxAmount, uint tokenAmount) = swap.getLiquidityToReserveInputPrice(estimate);
            return trxAmount.add(swap.getTokenToTrxInputPrice(tokenAmount));
        } else {
            return 0;
        }
    }

     /// @dev Calculate daily estimate of swap tokens awarded
    function dailyEstimate(address _customerAddress) public view returns (uint256){
        uint256 share = dividendBalance.mul(payoutRate_).div(100);
        return (tokenSupply_ > 0) ? share.mul(tokenBalanceLedger_[_customerAddress]).div(tokenSupply_) : 0;
    }



    /*==========================================
    =            INTERNAL FUNCTIONS            =
    ==========================================*/

    /// @dev Distribute undividend in and out fees across drip pools and instant divs
    function allocateFees(uint fee) private {
        uint _share = fee.div(100);
        uint _drip = _share.mul(dripFee);
        uint _instant = _share.mul(instantFee);
        uint _lock = fee.safeSub(_drip + _instant);

        //Apply divs
        profitPerShare_ = SafeMath.add(profitPerShare_, (_instant * magnitude) / tokenSupply_);

        //Add to dividend drip pools
        dividendBalance += _drip;

        //Add locked tokens to global count; we don't actually every move them
        lockedBalance += _lock;

    }

    // @dev Distribute drip pools
    function distribute() private {

        if (now.safeSub(lastBalance_) > balanceInterval && totalTokenBalance() > 0) {
            (uint trxAmount, uint tokenAmount) = swap.getLiquidityToReserveInputPrice(totalTokenBalance());
            emit onBalance(trxAmount, tokenAmount, now);
            lastBalance_ = now;
        }


        if (SafeMath.safeSub(now, lastPayout) > distributionInterval && tokenSupply_ > 0) {

            //A portion of the dividend is paid out according to the rate
            uint256 share = dividendBalance.mul(payoutRate_).div(100).div(24 hours);
            //divide the profit by seconds in the day
            uint256 profit = share * now.safeSub(lastPayout);
            //share times the amount of time elapsed
            dividendBalance = dividendBalance.safeSub(profit);

            //Apply divs
            profitPerShare_ = SafeMath.add(profitPerShare_, (profit * magnitude) / tokenSupply_);

            sweep();

            lastPayout = now;
        }



    }

    /// @dev Internal function to actually purchase the tokens.
    function purchaseTokens(address _customerAddress, uint256 _incomingtokens) internal returns (uint256) {

        /* Members */
        if (stats[_customerAddress].invested == 0 && stats[_customerAddress].receivedTokens == 0) {
            players += 1;
        }

        totalTxs += 1;

        // data setup
        uint256 _undividedDividends = SafeMath.mul(_incomingtokens, entryFee_) / 100;
        uint256 _amountOfTokens = SafeMath.sub(_incomingtokens, _undividedDividends);

        uint256 trxAmount = calculateLiquidityToTrx(_incomingtokens);

        // fire event
        emit onTokenPurchase(_customerAddress, trxAmount, _amountOfTokens, now);

        // yes we know that the safemath function automatically rules out the "greater then" equation.
        require(_amountOfTokens > 0 && SafeMath.add(_amountOfTokens, tokenSupply_) > tokenSupply_, "Tokens need to be positive");


        // we can't give people infinite eth
        if (tokenSupply_ > 0) {
            // add tokens to the pool
            tokenSupply_ += _amountOfTokens;

        } else {
            // add tokens to the pool
            tokenSupply_ = _amountOfTokens;
        }

        // update circulating supply & the ledger address for the customer
        tokenBalanceLedger_[_customerAddress] = SafeMath.add(tokenBalanceLedger_[_customerAddress], _amountOfTokens);

        // Tells the contract that the buyer doesn't deserve dividends for the tokens before they owned them;
        // really i know you think you do but you don't
        int256 _updatedPayouts = (int256) (profitPerShare_ * _amountOfTokens);
        payoutsTo_[_customerAddress] += _updatedPayouts;

        //drip and buybacks; instant requires being called after supply is updated
        allocateFees(_undividedDividends);

        //Stats
        stats[_customerAddress].invested += trxAmount;
        stats[_customerAddress].xInvested += 1;

        return _amountOfTokens;
    }


}

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

    /**
    * @dev Multiplies two numbers, throws on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
            return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
    }

    /**
    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /* @dev Subtracts two numbers, else returns zero */
    function safeSub(uint a, uint b) internal pure returns (uint) {
        if (b > a) {
            return 0;
        } else {
            return a - b;
        }
    }

    /**
    * @dev Adds two numbers, throws on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}