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.
// Deployed at TQ4zMrXKmWDyG3EV26pMuToQXsntztDGAX
/*
SPDX-License-Identifier: MIT
A Bankteller Production
Bankroll Network
Copyright
*/
pragma solidity ^0.4.25;// File: openzeppelin-solidity/audits/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/audits/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 SourceHat.com) "
// Deployed at - TQ5ZVjbJwYk6a9n6RrpsYVuFaiVK2r1GAb
/*
SPDX-License-Identifier: MIT
A Bankteller Production
Bankroll Network
Copyright
*/
pragma solidity ^0.4.25;// File: openzeppelin-solidity/audits/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/audits/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 SourceHat.com) "
pragma solidity ^0.4.25;// File: openzeppelin-solidity/audits/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/audits/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/audits/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/audits/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/audits/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/audits/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/audits/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/audits/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 SourceHat.com) >>"
/*
SPDX-License-Identifier: MIT
A Bankteller Production
Bankroll Network
Copyright
*/
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;
}
}