// SPDX-License-Identifier: MIT
pragma solidity =0.7.6;
contract Context {
/**
* @dev returns address executing the method
*/
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
/**
* @dev returns data passed into the method
*/
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
contract ERC20 is Context {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
string private _name;
string private _symbol;
uint8 private _decimals;
uint256 private _totalSupply = 0.404 ether;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor (string memory tokenName, string memory tokenSymbol) {
_name = tokenName;
_symbol = tokenSymbol;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the decimals of the token.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev Returns the total supply of the token.
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev Returns the token balance of specific address.
*/
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public returns (bool) {
_transfer(_msgSender(), recipient, amount );
return true;
}
/**
* @dev Returns approved balance to be spent by another address
* by using transferFrom method
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev Sets the token allowance to another spender
*/
function approve(address spender, uint256 amount) public returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev Allows to transfer tokens on senders behalf
* based on allowance approved for the executer
*/
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount));
_transfer(sender, recipient, amount);
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* Emits a {Transfer} event.
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0x0));
require(recipient != address(0x0));
_balances[sender] = _balances[sender].sub(amount);
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
* Requirements:
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0x0));
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0x0), account, amount);
}
/**
* @dev Allows to burn tokens if token sender
* wants to reduce totalSupply() of the token
*/
function burn(uint256 amount) external {
_burn(msg.sender, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0x0));
_balances[account] = _balances[account].sub(amount);
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0x0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0x0));
require(spender != address(0x0));
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
}
contract Events {
event StakeStart(
bytes16 indexed stakeID,
address indexed stakerAddress,
address indexed referralAddress,
uint256 stakedAmount,
uint256 stakesShares,
uint256 referralShares,
uint256 startDay,
uint256 lockDays,
uint256 daiEquivalent
);
event StakeEnd(
bytes16 indexed stakeID,
address indexed stakerAddress,
address indexed referralAddress,
uint256 stakedAmount,
uint256 stakesShares,
uint256 referralShares,
uint256 rewardAmount,
uint256 closeDay,
uint256 penaltyAmount
);
event InterestScraped(
bytes16 indexed stakeID,
address indexed stakerAddress,
uint256 scrapeAmount,
uint256 scrapeDay,
uint256 stakersPenalty,
uint256 referrerPenalty,
uint256 currentSwappDay
);
event ReferralCollected(
address indexed staker,
bytes16 indexed stakeID,
address indexed referrer,
bytes16 referrerID,
uint256 rewardAmount
);
event NewGlobals(
uint256 totalShares,
uint256 totalStaked,
uint256 shareRate,
uint256 referrerShares,
uint256 indexed currentSwappDay
);
event NewSharePrice(
uint256 newSharePrice,
uint256 oldSharePrice,
uint64 currentSwappDay
);
event LiquidityGuardStatus(
bool isActive
);
}
abstract contract Global is ERC20, Events {
using SafeMath for uint256;
struct Globals {
uint256 totalStaked;
uint256 totalShares;
uint256 sharePrice;
uint256 currentSwappDay;
uint256 referralShares;
uint256 liquidityShares;
}
Globals public globals;
constructor() {
globals.sharePrice = 100E15;
}
function _increaseGlobals(
uint256 _staked,
uint256 _shares,
uint256 _rshares
) internal {
globals.totalStaked = globals.totalStaked.add(_staked);
globals.totalShares = globals.totalShares.add(_shares);
if (_rshares > 0) {
globals.referralShares = globals.referralShares.add(_rshares);
}
_logGlobals();
}
function _decreaseGlobals(
uint256 _staked,
uint256 _shares,
uint256 _rshares
) internal {
globals.totalStaked = globals.totalStaked > _staked ? globals.totalStaked - _staked : 0;
globals.totalShares = globals.totalShares > _shares ? globals.totalShares - _shares : 0;
if (_rshares > 0) {
globals.referralShares = globals.referralShares > _rshares ? globals.referralShares - _rshares : 0;
}
_logGlobals();
}
function _logGlobals() private {
emit NewGlobals(
globals.totalShares,
globals.totalStaked,
globals.sharePrice,
globals.referralShares,
globals.currentSwappDay
);
}
}
interface IUniswapV2Factory {
function createPair(
address tokenA,
address tokenB
) external returns (
address pair
);
}
interface IUniswapRouterV2 {
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
}
interface IUniswapV2Pair {
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function token1() external view returns (address);
}
interface ILiquidityGuard {
function getInflation(uint32 _amount) external view returns (uint256);
}
interface TokenInterface {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
function approve(address _spender, uint256 _value) external returns (bool success);
}
abstract contract Declaration is Global {
uint256 constant _decimals = 18;
uint256 constant TESLAS_PER_SWAPP = 10 ** _decimals;
uint32 constant SECONDS_IN_DAY = 86400 seconds;
uint16 constant MIN_LOCK_DAYS = 1;
uint16 constant FORMULA_DAY = 65;
uint16 constant MAX_LOCK_DAYS = 15330;
uint16 constant MAX_BONUS_DAYS_A = 1825;
uint16 constant MAX_BONUS_DAYS_B = 13505;
uint16 constant MIN_REFERRAL_DAYS = 365;
uint32 constant MIN_STAKE_AMOUNT = 1000000; // TESLA
uint32 constant REFERRALS_RATE = 366816973; // 1.000% (direct value, can be used right away)
uint32 public INFLATION_RATE = 103000; // 3.000% (indirect -> checks throgh LiquidityGuard)
uint64 constant PRECISION_RATE = 1E18;
uint96 constant THRESHOLD_LIMIT = 10000E18; // $10,000 DAI
uint96 constant DAILY_BONUS_A = 13698630136986302; // 25%:1825 = 0.01369863013 per day;
uint96 constant DAILY_BONUS_B = 370233246945575; // 5%:13505 = 0.00037023324 per day;
uint256 public LAUNCH_TIME;
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
IUniswapRouterV2 public constant UNISWAP_ROUTER = IUniswapRouterV2(
0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
);
IUniswapV2Factory public constant UNISWAP_FACTORY = IUniswapV2Factory(
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
);
ILiquidityGuard public LIQUIDITY_GUARD = ILiquidityGuard(
0xECd13A6c13A97483deA1e31101e63718FcBd6b73
);
IUniswapV2Pair public UNISWAP_PAIR;
bool public isLiquidityGuardActive;
uint256 public latestDaiEquivalent;
address[] internal _path = [address(this), WETH, DAI];
constructor() {
LAUNCH_TIME = 1620518400; // 2021.05.09 GMT
}
function createPair() external {
UNISWAP_PAIR = IUniswapV2Pair(
UNISWAP_FACTORY.createPair(
WETH, address(this)
)
);
}
struct Stake {
uint256 stakesShares;
uint256 stakedAmount;
uint256 rewardAmount;
uint64 startDay;
uint64 lockDays;
uint64 finalDay;
uint64 closeDay;
uint256 scrapeDay;
uint256 daiEquivalent;
uint256 referrerShares;
address referrer;
bool isActive;
}
struct ReferrerLink {
address staker;
bytes16 stakeID;
uint256 rewardAmount;
uint256 processedDays;
bool isActive;
}
struct CriticalMass {
uint256 totalAmount;
uint256 activationDay;
}
mapping(address => uint256) public stakeCount;
mapping(address => uint256) public referralCount;
mapping(address => CriticalMass) public criticalMass;
mapping(address => mapping(bytes16 => uint256)) public scrapes;
mapping(address => mapping(bytes16 => Stake)) public stakes;
mapping(address => mapping(bytes16 => ReferrerLink)) public referrerLinks;
mapping(uint256 => uint256) public scheduledToEnd;
mapping(uint256 => uint256) public referralSharesToEnd;
mapping(uint256 => uint256) public totalPenalties;
mapping(address => uint256) public userStakedAmount;
}
abstract contract Helper is Declaration {
using SafeMath for uint256;
function currentSwappDay() public view returns (uint64) {
return getNow() >= LAUNCH_TIME ? _currentSwappDay() : 0;
}
function _currentSwappDay() internal view returns (uint64) {
return swappDayFromStamp(getNow());
}
function nextSwappDay() public view returns (uint64) {
return _currentSwappDay() + 1;
}
function previousSwappDay() public view returns (uint64) {
return _currentSwappDay() - 1;
}
function swappDayFromStamp(uint256 _timestamp) public view returns (uint64) {
return uint64((_timestamp - LAUNCH_TIME) / SECONDS_IN_DAY);
}
function getNow() public view returns (uint256) {
return block.timestamp;
}
function notContract(address _addr) internal view returns (bool) {
uint32 size;
assembly { size := extcodesize(_addr) }
return (size == 0);
}
function toBytes16(uint256 x) internal pure returns (bytes16 b) {
return bytes16(bytes32(x));
}
function generateID(address x, uint256 y, bytes1 z) public pure returns (bytes16 b) {
b = toBytes16(uint256(keccak256(abi.encodePacked(x, y, z))));
}
function generateStakeID(address _staker) internal view returns (bytes16 stakeID) {
return generateID(_staker, stakeCount[_staker], 0x01);
}
function generateReferralID(address _referrer) internal view returns (bytes16 referralID) {
return generateID(_referrer, referralCount[_referrer], 0x02);
}
function stakesPagination(
address _staker,
uint256 _offset,
uint256 _length
) external view returns (bytes16[] memory _stakes) {
uint256 start = _offset > 0 &&
stakeCount[_staker] > _offset ?
stakeCount[_staker] - _offset : stakeCount[_staker];
uint256 finish = _length > 0 &&
start > _length ?
start - _length : 0;
uint256 i;
_stakes = new bytes16[](start - finish);
for (uint256 _stakeIndex = start; _stakeIndex > finish; _stakeIndex--) {
bytes16 _stakeID = generateID(_staker, _stakeIndex - 1, 0x01);
if (stakes[_staker][_stakeID].stakedAmount > 0) {
_stakes[i] = _stakeID; i++;
}
}
}
function referralsPagination(
address _referrer,
uint256 _offset,
uint256 _length
) external view returns (bytes16[] memory _referrals) {
uint256 start = _offset > 0 &&
referralCount[_referrer] > _offset ?
referralCount[_referrer] - _offset : referralCount[_referrer];
uint256 finish = _length > 0 &&
start > _length ?
start - _length : 0;
uint256 i;
_referrals = new bytes16[](start - finish);
for (uint256 _rIndex = start; _rIndex > finish; _rIndex--) {
bytes16 _rID = generateID(_referrer, _rIndex - 1, 0x02);
if (_nonZeroAddress(referrerLinks[_referrer][_rID].staker)) {
_referrals[i] = _rID; i++;
}
}
}
function latestStakeID(address _staker) external view returns (bytes16) {
return stakeCount[_staker] == 0 ? bytes16(0) : generateID(_staker, stakeCount[_staker].sub(1), 0x01);
}
function latestReferralID(address _referrer) external view returns (bytes16) {
return referralCount[_referrer] == 0 ? bytes16(0) : generateID(_referrer, referralCount[_referrer].sub(1), 0x02);
}
function _increaseStakeCount(address _staker) internal {
stakeCount[_staker] = stakeCount[_staker] + 1;
}
function _increaseReferralCount(address _referrer) internal {
referralCount[_referrer] = referralCount[_referrer] + 1;
}
function _isMatureStake(Stake memory _stake) internal view returns (bool) {
return _stake.closeDay > 0
? _stake.finalDay <= _stake.closeDay
: _stake.finalDay <= _currentSwappDay();
}
function _notCriticalMassReferrer(address _referrer) internal view returns (bool) {
return criticalMass[_referrer].activationDay == 0;
}
function _stakeNotStarted(Stake memory _stake) internal view returns (bool) {
return _stake.closeDay > 0
? _stake.startDay > _stake.closeDay
: _stake.startDay > _currentSwappDay();
}
function _stakeEnded(Stake memory _stake) internal view returns (bool) {
return _stake.isActive == false || _isMatureStake(_stake);
}
function _daysLeft(Stake memory _stake) internal view returns (uint256) {
return _stake.isActive == false
? _daysDiff(_stake.closeDay, _stake.finalDay)
: _daysDiff(_currentSwappDay(), _stake.finalDay);
}
function _daysDiff(uint256 _startDate, uint256 _endDate) internal pure returns (uint256) {
return _startDate > _endDate ? 0 : _endDate.sub(_startDate);
}
function _calculationDay(Stake memory _stake) internal view returns (uint256) {
return _stake.finalDay > globals.currentSwappDay ? globals.currentSwappDay : _stake.finalDay;
}
function _startingDay(Stake memory _stake) internal pure returns (uint256) {
return _stake.scrapeDay == 0 ? _stake.startDay : _stake.scrapeDay;
}
function _notFuture(uint256 _day) internal view returns (bool) {
return _day <= _currentSwappDay();
}
function _notPast(uint256 _day) internal view returns (bool) {
return _day >= _currentSwappDay();
}
function _nonZeroAddress(address _address) internal pure returns (bool) {
return _address != address(0x0);
}
function _getLockDays(Stake memory _stake) internal pure returns (uint256) {
return
_stake.lockDays > 1 ?
_stake.lockDays - 1 : 1;
}
function _preparePath(
address _tokenAddress,
address _swappAddress
) internal pure returns (address[] memory _path) {
_path = new address[](3);
_path[0] = _tokenAddress;
_path[1] = WETH;
_path[2] = _swappAddress;
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))));
}
function safeTransferFrom(
address token,
address from,
address to,
uint value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
require(success && (data.length == 0 || abi.decode(data, (bool))));
}
}
abstract contract Snapshot is Helper {
using SafeMath for uint;
// regular shares
struct SnapShot {
uint256 totalShares;
uint256 inflationAmount;
uint256 scheduledToEnd;
}
// referral shares
struct rSnapShot {
uint256 totalShares;
uint256 inflationAmount;
uint256 scheduledToEnd;
}
mapping(uint256 => SnapShot) public snapshots;
mapping(uint256 => rSnapShot) public rsnapshots;
modifier snapshotTrigger() {
_dailySnapshotPoint(_currentSwappDay());
_;
}
/**
* @notice allows to activate/deactivate
* liquidity guard manually based on the
* liquidity in UNISWAP pair contract
*/
function liquidityGuardTrigger() public {
(
uint112 reserveA,
uint112 reserveB,
) = UNISWAP_PAIR.getReserves();
uint256 onUniswap = UNISWAP_PAIR.token1() == WETH
? reserveA
: reserveB;
uint256 ratio = totalSupply() == 0
? 0
: onUniswap
.mul(200)
.div(totalSupply());
if (ratio < 40 && isLiquidityGuardActive == false) enableLiquidityGuard();
if (ratio > 60 && isLiquidityGuardActive == true) disableLiquidityGuard();
emit LiquidityGuardStatus(isLiquidityGuardActive);
}
function enableLiquidityGuard() private {
isLiquidityGuardActive = true;
}
function disableLiquidityGuard() private {
isLiquidityGuardActive = false;
}
/**
* @notice allows volunteer to offload snapshots
* to save on gas during next start/end stake
*/
function manualDailySnapshot() external {
_dailySnapshotPoint(_currentSwappDay());
}
/**
* @notice allows volunteer to offload snapshots
* to save on gas during next start/end stake
* in case manualDailySnapshot reach block limit
*/
function manualDailySnapshotPoint(uint64 _updateDay) external {
require(_updateDay > 0 && _updateDay < _currentSwappDay());
require(_updateDay > globals.currentSwappDay);
_dailySnapshotPoint(_updateDay);
}
/**
* @notice internal function that offloads
* global values to daily snapshots
* updates globals.currentSwappDay
*/
function _dailySnapshotPoint(uint64 _updateDay) private {
liquidityGuardTrigger();
uint256 scheduledToEndToday;
uint256 totalStakedToday = globals.totalStaked;
for (uint256 _day = globals.currentSwappDay; _day < _updateDay; _day++) {
// ------------------------------------
// prepare snapshot for regular shares
// reusing scheduledToEndToday variable
scheduledToEndToday = scheduledToEnd[_day] + snapshots[_day - 1].scheduledToEnd;
SnapShot memory snapshot = snapshots[_day];
snapshot.scheduledToEnd = scheduledToEndToday;
snapshot.totalShares =
globals.totalShares > scheduledToEndToday ?
globals.totalShares - scheduledToEndToday : 0;
snapshot.inflationAmount = snapshot.totalShares
.mul(PRECISION_RATE)
.div(
_inflationAmount(
totalStakedToday,
totalSupply(),
totalPenalties[_day],
LIQUIDITY_GUARD.getInflation(
INFLATION_RATE
)
)
);
// store regular snapshot
snapshots[_day] = snapshot;
// ------------------------------------
// prepare snapshot for referrer shares
// reusing scheduledToEndToday variable
scheduledToEndToday = referralSharesToEnd[_day] + rsnapshots[_day - 1].scheduledToEnd;
rSnapShot memory rsnapshot = rsnapshots[_day];
rsnapshot.scheduledToEnd = scheduledToEndToday;
rsnapshot.totalShares =
globals.referralShares > scheduledToEndToday ?
globals.referralShares - scheduledToEndToday : 0;
rsnapshot.inflationAmount = rsnapshot.totalShares
.mul(PRECISION_RATE)
.div(
_referralInflation(
totalStakedToday,
totalSupply()
)
);
// store referral snapshot
rsnapshots[_day] = rsnapshot;
adjustLiquidityRates();
globals.currentSwappDay++;
}
}
/**
* @notice moves inflation up and down by 0.006%
* from regular shares to liquidity shares
* if the liquidityGuard is active (visa-versa)
*/
function adjustLiquidityRates() private {
if (isLiquidityGuardActive == true) {
INFLATION_RATE = INFLATION_RATE - 6;
return;
}
if (isLiquidityGuardActive == false) {
INFLATION_RATE = INFLATION_RATE + 6;
return;
}
}
function _inflationAmount(
uint256 _totalStaked,
uint256 _totalSupply,
uint256 _totalPenalties,
uint256 _INFLATION_RATE
) private pure returns (uint256) {
return (_totalStaked + _totalSupply) * 10000 / _INFLATION_RATE + _totalPenalties;
}
function _referralInflation(
uint256 _totalStaked,
uint256 _totalSupply
) private pure returns (uint256) {
return (_totalStaked + _totalSupply) * 10000 / REFERRALS_RATE;
}
}
abstract contract ReferralToken is Snapshot {
using SafeMath for uint256;
function _addReferrerSharesToEnd(uint256 _finalDay, uint256 _shares) internal {
referralSharesToEnd[_finalDay] =
referralSharesToEnd[_finalDay].add(_shares);
}
function _removeReferrerSharesToEnd(uint256 _finalDay, uint256 _shares) internal {
if (_notPast(_finalDay)) {
referralSharesToEnd[_finalDay] =
referralSharesToEnd[_finalDay] > _shares ?
referralSharesToEnd[_finalDay] - _shares : 0;
} else {
uint256 _day = previousSwappDay();
rsnapshots[_day].scheduledToEnd =
rsnapshots[_day].scheduledToEnd > _shares ?
rsnapshots[_day].scheduledToEnd - _shares : 0;
}
}
function _belowThresholdLevel(address _referrer) private view returns (bool) {
return criticalMass[_referrer].totalAmount < THRESHOLD_LIMIT;
}
function _addCriticalMass(address _referrer, uint256 _daiEquivalent) internal {
criticalMass[_referrer].totalAmount =
criticalMass[_referrer].totalAmount.add(_daiEquivalent);
criticalMass[_referrer].activationDay = _determineActivationDay(_referrer);
}
function _removeCriticalMass(
address _referrer,
uint256 _daiEquivalent,
uint256 _startDay
) internal {
if (
_notFuture(_startDay) == false &&
_nonZeroAddress(_referrer)
) {
criticalMass[_referrer].totalAmount =
criticalMass[_referrer].totalAmount > _daiEquivalent ?
criticalMass[_referrer].totalAmount - _daiEquivalent : 0;
criticalMass[_referrer].activationDay = _determineActivationDay(_referrer);
}
}
function _determineActivationDay(address _referrer) private view returns (uint256) {
return _belowThresholdLevel(_referrer) ? 0 : _activationDay(_referrer);
}
function _activationDay(address _referrer) private view returns (uint256) {
return
criticalMass[_referrer].activationDay > 0 ?
criticalMass[_referrer].activationDay : _currentSwappDay();
}
function _updateDaiEquivalent() internal returns (uint256) {
try UNISWAP_ROUTER.getAmountsOut(
TESLAS_PER_SWAPP, _path
) returns (uint256[] memory results) {
latestDaiEquivalent = results[2];
return latestDaiEquivalent;
} catch Error(string memory) {
return latestDaiEquivalent;
} catch (bytes memory) {
return latestDaiEquivalent;
}
}
function referrerInterest(
bytes16 _referralID,
uint256 _scrapeDays
) external snapshotTrigger {
_referrerInterest(
msg.sender,
_referralID,
_scrapeDays
);
}
function referrerInterestBulk(
bytes16[] memory _referralIDs,
uint256[] memory _scrapeDays
) external snapshotTrigger {
for(uint256 i = 0; i < _referralIDs.length; i++) {
_referrerInterest(
msg.sender,
_referralIDs[i],
_scrapeDays[i]
);
}
}
function _referrerInterest(
address _referrer,
bytes16 _referralID,
uint256 _processDays
) internal {
ReferrerLink memory link =
referrerLinks[_referrer][_referralID];
require(link.isActive == true);
address staker = link.staker;
bytes16 stakeID = link.stakeID;
Stake memory stake = stakes[staker][stakeID];
uint256 startDay = _determineStartDay(stake, link);
uint256 finalDay = _determineFinalDay(stake);
if (_stakeEnded(stake)) {
if (
_processDays > 0 &&
_processDays < _daysDiff(startDay, finalDay)
)
{
link.processedDays =
link.processedDays.add(_processDays);
finalDay =
startDay.add(_processDays);
} else {
link.isActive = false;
}
} else {
_processDays = _daysDiff(startDay, _currentSwappDay());
link.processedDays =
link.processedDays.add(_processDays);
finalDay =
startDay.add(_processDays);
}
uint256 referralInterest = _checkReferralInterest(
stake,
startDay,
finalDay
);
link.rewardAmount = link.rewardAmount.add(referralInterest);
referrerLinks[_referrer][_referralID] = link;
_mint(_referrer, referralInterest);
emit ReferralCollected(
staker,
stakeID,
_referrer,
_referralID,
referralInterest
);
}
function checkReferralsByID(
address _referrer,
bytes16 _referralID
) external view returns (
address staker,
bytes16 stakeID,
uint256 referrerShares,
uint256 referralInterest,
bool isActiveReferral,
bool isActiveStake,
bool isMatureStake,
bool isEndedStake
) {
ReferrerLink memory link = referrerLinks[_referrer][_referralID];
staker = link.staker;
stakeID = link.stakeID;
isActiveReferral = link.isActive;
Stake memory stake = stakes[staker][stakeID];
referrerShares = stake.referrerShares;
referralInterest = _checkReferralInterest(
stake,
_determineStartDay(stake, link),
_determineFinalDay(stake)
);
isActiveStake = stake.isActive;
isEndedStake = _stakeEnded(stake);
isMatureStake = _isMatureStake(stake);
}
function _checkReferralInterest(
Stake memory _stake,
uint256 _startDay,
uint256 _finalDay
) internal view returns (uint256 _referralInterest) {
return _notCriticalMassReferrer(_stake.referrer) ? 0 : _getReferralInterest(_stake, _startDay, _finalDay);
}
function _getReferralInterest(
Stake memory _stake,
uint256 _startDay,
uint256 _finalDay
) private view returns (uint256 _referralInterest) {
for (uint256 _day = _startDay; _day < _finalDay; _day++) {
_referralInterest += _stake.stakesShares * PRECISION_RATE / rsnapshots[_day].inflationAmount;
}
}
function _determineStartDay(
Stake memory _stake,
ReferrerLink memory _link
) internal view returns (uint256) {
return (
criticalMass[_stake.referrer].activationDay > _stake.startDay ?
criticalMass[_stake.referrer].activationDay : _stake.startDay
).add(_link.processedDays);
}
function _determineFinalDay(
Stake memory _stake
) internal view returns (uint256) {
return
_stake.closeDay > 0 ?
_stake.closeDay : _calculationDay(_stake);
}
}
abstract contract StakingToken is ReferralToken {
using SafeMath for uint256;
/**
* @notice A method for a staker to create multiple stakes
* @param _stakedAmount amount of SWAPP staked.
* @param _lockDays amount of days it is locked for.
* @param _referrer address of the referrer
*/
function createStakeBulk(
uint256[] memory _stakedAmount,
uint64[] memory _lockDays,
address[] memory _referrer
) external {
for(uint256 i = 0; i < _stakedAmount.length; i++) {
createStake(_stakedAmount[i], _lockDays[i], _referrer[i]);
}
}
/**
* @notice A method for a staker to create a stake
* @param _stakedAmount amount of SWAPP staked.
* @param _lockDays amount of days it is locked for.
* @param _referrer address of the referrer
*/
function createStake(
uint256 _stakedAmount,
uint64 _lockDays,
address _referrer
) public returns (bytes16, uint256, bytes16 referralID) {
require(msg.sender != _referrer && notContract(_referrer));
require(_lockDays >= MIN_LOCK_DAYS && _lockDays <= MAX_LOCK_DAYS);
require(_stakedAmount >= MIN_STAKE_AMOUNT);
(
Stake memory newStake,
bytes16 stakeID,
uint256 _startDay
) = _createStake(msg.sender, _stakedAmount, _lockDays, _referrer);
if (newStake.referrerShares > 0) {
ReferrerLink memory referrerLink;
referrerLink.staker = msg.sender;
referrerLink.stakeID = stakeID;
referrerLink.isActive = true;
referralID = generateReferralID(_referrer);
referrerLinks[_referrer][referralID] = referrerLink;
_increaseReferralCount(_referrer);
_addReferrerSharesToEnd(newStake.finalDay, newStake.referrerShares);
}
stakes[msg.sender][stakeID] = newStake;
_increaseStakeCount(msg.sender);
_increaseGlobals(
newStake.stakedAmount,
newStake.stakesShares,
newStake.referrerShares
);
_addScheduledShares(newStake.finalDay, newStake.stakesShares);
emit StakeStart(
stakeID,
msg.sender,
_referrer,
newStake.stakedAmount,
newStake.stakesShares,
newStake.referrerShares,
newStake.startDay,
newStake.lockDays,
newStake.daiEquivalent
);
return (stakeID, _startDay, referralID);
}
function getStakingShare(
uint256 _stakedAmount,
uint64 _lockDays,
address _referrer
) external view returns (uint256 stakingShare) {
return _stakesShares(
_stakedAmount,
_lockDays,
_referrer,
globals.sharePrice
);
}
/**
* @notice A method for a staker to start a stake
* @param _staker ...
* @param _stakedAmount ...
* @param _lockDays ...
*/
function _createStake(
address _staker,
uint256 _stakedAmount,
uint64 _lockDays,
address _referrer
) private returns (Stake memory _newStake, bytes16 _stakeID, uint64 _startDay) {
_burn(_staker, _stakedAmount);
userStakedAmount[_staker] = userStakedAmount[_staker].add(_stakedAmount);
_startDay = nextSwappDay();
_stakeID = generateStakeID(_staker);
_newStake.lockDays = _lockDays;
_newStake.startDay = _startDay;
_newStake.finalDay = _startDay + _lockDays;
_newStake.isActive = true;
_newStake.stakedAmount = _stakedAmount;
_newStake.stakesShares = _stakesShares(
_stakedAmount,
_lockDays,
_referrer,
globals.sharePrice
);
_updateDaiEquivalent();
_newStake.daiEquivalent = latestDaiEquivalent
.mul(_newStake.stakedAmount)
.div(TESLAS_PER_SWAPP);
if (_nonZeroAddress(_referrer)) {
_newStake.referrer = _referrer;
_addCriticalMass(_newStake.referrer, _newStake.daiEquivalent);
_newStake.referrerShares = _referrerShares(
_stakedAmount,
_lockDays,
_referrer
);
}
}
/**
* @notice A method for a staker to remove a stake
* belonging to his address by providing ID of a stake.
* @param _stakeID unique bytes sequence reference to the stake
*/
function endStake(bytes16 _stakeID) snapshotTrigger external returns (uint256) {
(
Stake memory endedStake,
uint256 penaltyAmount
) = _endStake(msg.sender, _stakeID);
_decreaseGlobals(
endedStake.stakedAmount,
endedStake.stakesShares,
endedStake.referrerShares
);
_removeScheduledShares(endedStake.finalDay, endedStake.stakesShares);
_removeReferrerSharesToEnd(endedStake.finalDay, endedStake.referrerShares);
_removeCriticalMass(
endedStake.referrer,
endedStake.daiEquivalent,
endedStake.startDay
);
_storePenalty(endedStake.closeDay, penaltyAmount);
_sharePriceUpdate(
endedStake.stakedAmount > penaltyAmount ?
endedStake.stakedAmount - penaltyAmount : 0,
endedStake.rewardAmount + scrapes[msg.sender][_stakeID],
endedStake.referrer,
endedStake.lockDays,
endedStake.stakesShares
);
emit StakeEnd(
_stakeID,
msg.sender,
endedStake.referrer,
endedStake.stakedAmount,
endedStake.stakesShares,
endedStake.referrerShares,
endedStake.rewardAmount,
endedStake.closeDay,
penaltyAmount
);
return endedStake.rewardAmount;
}
function _endStake(
address _staker,
bytes16 _stakeID
) private returns (Stake storage _stake, uint256 _penalty) {
require(stakes[_staker][_stakeID].isActive);
_stake = stakes[_staker][_stakeID];
_stake.closeDay = _currentSwappDay();
_stake.rewardAmount = _calculateRewardAmount(_stake);
_penalty = _calculatePenaltyAmount(_stake);
_stake.isActive = false;
userStakedAmount[_staker] = userStakedAmount[_staker].sub(_stake.stakedAmount);
_mint(
_staker,
_stake.stakedAmount > _penalty ?
_stake.stakedAmount - _penalty : 0
);
_mint(_staker, _stake.rewardAmount);
}
/**
* @notice alloes to scrape interest from active stake
* @param _stakeID unique bytes sequence reference to the stake
* @param _scrapeDays amount of days to proccess, 0 = all
*/
function scrapeInterest(
bytes16 _stakeID,
uint64 _scrapeDays
) external snapshotTrigger returns (
uint256 scrapeDay,
uint256 scrapeAmount,
uint256 remainingDays,
uint256 stakersPenalty,
uint256 referrerPenalty
) {
require(stakes[msg.sender][_stakeID].isActive);
Stake memory stake = stakes[msg.sender][_stakeID];
scrapeDay = _scrapeDays > 0
? _startingDay(stake).add(_scrapeDays)
: _calculationDay(stake);
scrapeDay = scrapeDay > stake.finalDay
? _calculationDay(stake)
: scrapeDay;
scrapeAmount = _loopRewardAmount(
stake.stakesShares,
_startingDay(stake),
scrapeDay
);
if (_isMatureStake(stake) == false) {
remainingDays = _daysLeft(stake);
stakersPenalty = _stakesShares(
scrapeAmount,
remainingDays,
msg.sender,
globals.sharePrice
);
stake.stakesShares = stake.stakesShares.sub(stakersPenalty);
_removeScheduledShares(stake.finalDay, stakersPenalty);
if (stake.referrerShares > 0) {
referrerPenalty = _stakesShares(
scrapeAmount,
remainingDays,
address(0x0),
globals.sharePrice
);
stake.referrerShares = stake.referrerShares.sub(referrerPenalty);
_removeReferrerSharesToEnd(stake.finalDay, referrerPenalty);
}
_decreaseGlobals(0, stakersPenalty, referrerPenalty);
_sharePriceUpdate(
stake.stakedAmount,
scrapeAmount,
stake.referrer,
stake.lockDays,
stake.stakesShares
);
}
else {
scrapes[msg.sender][_stakeID] = scrapes[msg.sender][_stakeID].add(scrapeAmount);
_sharePriceUpdate(
stake.stakedAmount,
scrapes[msg.sender][_stakeID],
stake.referrer,
stake.lockDays,
stake.stakesShares
);
}
stake.scrapeDay = scrapeDay;
stakes[msg.sender][_stakeID] = stake;
_mint(msg.sender, scrapeAmount);
emit InterestScraped(
_stakeID,
msg.sender,
scrapeAmount,
scrapeDay,
stakersPenalty,
referrerPenalty,
_currentSwappDay()
);
}
function _addScheduledShares(uint256 _finalDay, uint256 _shares) internal {
scheduledToEnd[_finalDay] = scheduledToEnd[_finalDay].add(_shares);
}
function _removeScheduledShares(uint256 _finalDay, uint256 _shares) internal {
if (_notPast(_finalDay)) {
scheduledToEnd[_finalDay] =
scheduledToEnd[_finalDay] > _shares ?
scheduledToEnd[_finalDay] - _shares : 0;
} else {
uint256 _day = previousSwappDay();
snapshots[_day].scheduledToEnd =
snapshots[_day].scheduledToEnd > _shares ?
snapshots[_day].scheduledToEnd - _shares : 0;
}
}
function _sharePriceUpdate(
uint256 _stakedAmount,
uint256 _rewardAmount,
address _referrer,
uint256 _lockDays,
uint256 _stakeShares
) private {
if (_stakeShares > 0 && _currentSwappDay() > FORMULA_DAY) {
uint256 newSharePrice = _getNewSharePrice(
_stakedAmount,
_rewardAmount,
_stakeShares,
_lockDays,
_referrer
);
if (newSharePrice > globals.sharePrice) {
newSharePrice = newSharePrice < globals.sharePrice.mul(110).div(100) ?
newSharePrice : globals.sharePrice.mul(110).div(100);
emit NewSharePrice(
newSharePrice,
globals.sharePrice,
_currentSwappDay()
);
globals.sharePrice = newSharePrice;
}
return;
}
if (_currentSwappDay() == FORMULA_DAY) {
globals.sharePrice = 110E15;
}
}
function _getNewSharePrice(
uint256 _stakedAmount,
uint256 _rewardAmount,
uint256 _stakeShares,
uint256 _lockDays,
address _referrer
) private pure returns (uint256) {
uint256 _bonusAmount = _getBonus(
_lockDays, _nonZeroAddress(_referrer) ? 11E9 : 10E9
);
return
_stakedAmount
.add(_rewardAmount)
.mul(_bonusAmount)
.mul(1E8)
.div(_stakeShares);
}
function checkMatureStake(
address _staker,
bytes16 _stakeID
) external view returns (bool isMature) {
Stake memory stake = stakes[_staker][_stakeID];
isMature = _isMatureStake(stake);
}
function checkStakeByID(address _staker, bytes16 _stakeID) external view
returns (
uint256 startDay,
uint256 lockDays,
uint256 finalDay,
uint256 closeDay,
uint256 scrapeDay,
uint256 stakedAmount,
uint256 stakesShares,
uint256 rewardAmount,
uint256 penaltyAmount,
bool isActive,
bool isMature
)
{
Stake memory stake = stakes[_staker][_stakeID];
startDay = stake.startDay;
lockDays = stake.lockDays;
finalDay = stake.finalDay;
closeDay = stake.closeDay;
scrapeDay = stake.scrapeDay;
stakedAmount = stake.stakedAmount;
stakesShares = stake.stakesShares;
rewardAmount = _checkRewardAmount(stake);
penaltyAmount = _calculatePenaltyAmount(stake);
isActive = stake.isActive;
isMature = _isMatureStake(stake);
}
function _stakesShares(
uint256 _stakedAmount,
uint256 _lockDays,
address _referrer,
uint256 _sharePrice
) private pure returns (uint256) {
return _nonZeroAddress(_referrer)
? _sharesAmount(_stakedAmount, _lockDays, _sharePrice, 11E9)
: _sharesAmount(_stakedAmount, _lockDays, _sharePrice, 10E9);
}
function _sharesAmount(
uint256 _stakedAmount,
uint256 _lockDays,
uint256 _sharePrice,
uint256 _extraBonus
) private pure returns (uint256) {
return _baseAmount(_stakedAmount, _sharePrice)
.mul(_getBonus(_lockDays, _extraBonus))
.div(10E9);
}
function _getBonus(
uint256 _lockDays,
uint256 _extraBonus
) private pure returns (uint256) {
return
_regularBonus(_lockDays, DAILY_BONUS_A, MAX_BONUS_DAYS_A) +
_regularBonus(
_lockDays > MAX_BONUS_DAYS_A ?
_lockDays - MAX_BONUS_DAYS_A : 0, DAILY_BONUS_B, MAX_BONUS_DAYS_B
) + _extraBonus;
}
function _regularBonus(
uint256 _lockDays,
uint256 _daily,
uint256 _maxDays
) private pure returns (uint256) {
return (
_lockDays > _maxDays
? _maxDays.mul(_daily)
: _lockDays.mul(_daily)
).div(10E9);
}
function _baseAmount(
uint256 _stakedAmount,
uint256 _sharePrice
) private pure returns (uint256) {
return _stakedAmount.mul(PRECISION_RATE).div(_sharePrice);
}
function _referrerShares(
uint256 _stakedAmount,
uint256 _lockDays,
address _referrer
) private view returns (uint256) {
return
_notCriticalMassReferrer(_referrer) ||
_lockDays < MIN_REFERRAL_DAYS
? 0
: _sharesAmount(
_stakedAmount,
_lockDays,
globals.sharePrice,
10E9
);
}
function _checkRewardAmount(Stake memory _stake) private view returns (uint256) {
return _stake.isActive ? _detectReward(_stake) : _stake.rewardAmount;
}
function _detectReward(Stake memory _stake) private view returns (uint256) {
return _stakeNotStarted(_stake) ? 0 : _calculateRewardAmount(_stake);
}
function _storePenalty(uint64 _storeDay, uint256 _penalty) private {
if (_penalty > 0) {
totalPenalties[_storeDay] =
totalPenalties[_storeDay].add(_penalty);
}
}
function _calculatePenaltyAmount(Stake memory _stake) private view returns (uint256) {
return _stakeNotStarted(_stake) || _isMatureStake(_stake) ? 0 : _getPenalties(_stake);
}
function _getPenalties(Stake memory _stake) private view returns (uint256) {
return _stake.stakedAmount * (100 + (800 * (_daysLeft(_stake) - 1) / (_getLockDays(_stake)))) / 1000;
}
function _calculateRewardAmount(Stake memory _stake) private view returns (uint256) {
return _loopRewardAmount(
_stake.stakesShares,
_startingDay(_stake),
_calculationDay(_stake)
);
}
function _loopRewardAmount(
uint256 _stakeShares,
uint256 _startDay,
uint256 _finalDay
) private view returns (uint256 _rewardAmount) {
for (uint256 _day = _startDay; _day < _finalDay; _day++) {
_rewardAmount += _stakeShares * PRECISION_RATE / snapshots[_day].inflationAmount;
}
}
}
contract SwappToken is StakingToken {
address public LIQUIDITY_TRANSFORMER;
address public YIELD_FARM_STABLE;
address public YIELD_FARM_LP;
address public tokenMinterDefiner;
modifier onlyMinter() {
require(
msg.sender == LIQUIDITY_TRANSFORMER ||
msg.sender == YIELD_FARM_STABLE ||
msg.sender == YIELD_FARM_LP,
'SWAPP: Invalid token minter'
);
_;
}
constructor() ERC20("Swapp Token", "SWAPP") {
tokenMinterDefiner = msg.sender;
_mint(0x0d970a04d46c73B6d20d9a0B2B07C35F2495ca9c, 162500000E18); // SWAPP FOUNDATION - Contract Owner Wallet
_mint(0x915D99375Ba8EDbbee46bE1AD045718a05A6655b, 3307862E18); // MM-PRESALE Investors Wallet
_mint(0x7Db4456a73a9C94a381d244E9dfC76E83C05913E, 58364082E18); // Employee Pool Including Founders MM Wallet
_mint(0x62F16a5bA06693B1E96a656d46e66A8CdaE17C69, 13328056E18); // Swapp Previous Investors MM Wallet
_mint(0x94dc2f1823AbfdC2fb9BB8Ae10162b65D2Cf1c65, 250000000E18); // Rewards Wallet
_mint(0x2a8eA8a4842DA268FA4180b1a99B7876f820ECC1, 35000000E18); // Future Development Wallet
_mint(0x000baFB91ED6436ad2888C2418197aFDB85785C5, 5000000E18); // Reserved Funding Wallet
_mint(0xd4041e1c24A54134Fb9657e8DA85e75001D7Ea44, 5000000E18); // Bounty, Advisors, Partnership Wallet
}
receive() external payable {
revert();
}
function setMinters(
address _transformer,
address _yieldFarmStable,
address _yieldFarmLP
) external {
require(tokenMinterDefiner == msg.sender);
LIQUIDITY_TRANSFORMER = _transformer;
YIELD_FARM_STABLE = _yieldFarmStable;
YIELD_FARM_LP = _yieldFarmLP;
}
function burnMinterDefiner() external {
require(tokenMinterDefiner == msg.sender);
tokenMinterDefiner = address(0x0);
}
/**
* @notice allows liquidityTransformer to mint supply
* @dev executed from liquidityTransformer upon UNISWAP transfer
* and during reservation payout to contributors and referrers
* @param _investorAddress address for minting SWAPP tokens
* @param _amount of tokens to mint for _investorAddress
*/
function mintSupply(address _investorAddress, uint256 _amount) external onlyMinter {
_mint(_investorAddress, _amount);
}
/**
* @notice allows to grant permission to CM referrer status
* @dev called from liquidityTransformer if user referred 50 ETH
* @param _referrer - address that becomes a CM reffer
*/
function giveStatus(address _referrer) external onlyMinter {
criticalMass[_referrer].totalAmount = THRESHOLD_LIMIT;
criticalMass[_referrer].activationDay = nextSwappDay();
}
/**
* @notice allows to create stake directly with ETH
* if you don't have SWAPP tokens method will convert
* and use amount returned from UNISWAP to open a stake
* @param _lockDays amount of days it is locked for.
* @param _referrer referrer address for +10% bonus
*/
function createStakeWithETH(
uint64 _lockDays,
address _referrer
) external payable returns (bytes16, uint256, bytes16 referralID) {
address[] memory path = new address[](2);
path[0] = WETH;
path[1] = address(this);
uint256[] memory amounts = UNISWAP_ROUTER.swapExactETHForTokens{value: msg.value}(
1,
path,
msg.sender,
block.timestamp
);
return createStake(amounts[1], _lockDays, _referrer);
}
/**
* @notice allows to create stake with another token
* if you don't have SWAPP tokens method will convert
* and use amount returned from UNISWAP to open a stake
* @dev the token must have WETH pair on UNISWAP
* @param _tokenAddress any ERC20 token address
* @param _tokenAmount amount to be converted to SWAPP
* @param _lockDays amount of days it is locked for.
* @param _referrer referrer address for +10% bonus
*/
function createStakeWithToken(
address _tokenAddress,
uint256 _tokenAmount,
uint64 _lockDays,
address _referrer
) external returns (bytes16, uint256, bytes16 referralID) {
TokenInterface token = TokenInterface(_tokenAddress);
token.transferFrom(msg.sender, address(this), _tokenAmount);
token.approve(address(UNISWAP_ROUTER), _tokenAmount);
address[] memory path = _preparePath(_tokenAddress, address(this));
uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(
_tokenAmount,
1,
path,
msg.sender,
block.timestamp
);
return createStake(amounts[2], _lockDays, _referrer);
}
}
{
"compilationTarget": {
"SwappToken.sol": "SwappToken"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"stakeID","type":"bytes16"},{"indexed":true,"internalType":"address","name":"stakerAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"scrapeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scrapeDay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakersPenalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referrerPenalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentSwappDay","type":"uint256"}],"name":"InterestScraped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"LiquidityGuardStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referrerShares","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currentSwappDay","type":"uint256"}],"name":"NewGlobals","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newSharePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldSharePrice","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"currentSwappDay","type":"uint64"}],"name":"NewSharePrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"bytes16","name":"stakeID","type":"bytes16"},{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"bytes16","name":"referrerID","type":"bytes16"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"name":"ReferralCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"stakeID","type":"bytes16"},{"indexed":true,"internalType":"address","name":"stakerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"referralAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakesShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referralShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"closeDay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penaltyAmount","type":"uint256"}],"name":"StakeEnd","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"stakeID","type":"bytes16"},{"indexed":true,"internalType":"address","name":"stakerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"referralAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakesShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referralShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startDay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockDays","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"daiEquivalent","type":"uint256"}],"name":"StakeStart","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"INFLATION_RATE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LAUNCH_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDITY_GUARD","outputs":[{"internalType":"contract ILiquidityGuard","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDITY_TRANSFORMER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_FACTORY","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_PAIR","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_ROUTER","outputs":[{"internalType":"contract IUniswapRouterV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YIELD_FARM_LP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YIELD_FARM_STABLE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnMinterDefiner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"bytes16","name":"_stakeID","type":"bytes16"}],"name":"checkMatureStake","outputs":[{"internalType":"bool","name":"isMature","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"bytes16","name":"_referralID","type":"bytes16"}],"name":"checkReferralsByID","outputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"bytes16","name":"stakeID","type":"bytes16"},{"internalType":"uint256","name":"referrerShares","type":"uint256"},{"internalType":"uint256","name":"referralInterest","type":"uint256"},{"internalType":"bool","name":"isActiveReferral","type":"bool"},{"internalType":"bool","name":"isActiveStake","type":"bool"},{"internalType":"bool","name":"isMatureStake","type":"bool"},{"internalType":"bool","name":"isEndedStake","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"bytes16","name":"_stakeID","type":"bytes16"}],"name":"checkStakeByID","outputs":[{"internalType":"uint256","name":"startDay","type":"uint256"},{"internalType":"uint256","name":"lockDays","type":"uint256"},{"internalType":"uint256","name":"finalDay","type":"uint256"},{"internalType":"uint256","name":"closeDay","type":"uint256"},{"internalType":"uint256","name":"scrapeDay","type":"uint256"},{"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"internalType":"uint256","name":"stakesShares","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"penaltyAmount","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isMature","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"createPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakedAmount","type":"uint256"},{"internalType":"uint64","name":"_lockDays","type":"uint64"},{"internalType":"address","name":"_referrer","type":"address"}],"name":"createStake","outputs":[{"internalType":"bytes16","name":"","type":"bytes16"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes16","name":"referralID","type":"bytes16"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakedAmount","type":"uint256[]"},{"internalType":"uint64[]","name":"_lockDays","type":"uint64[]"},{"internalType":"address[]","name":"_referrer","type":"address[]"}],"name":"createStakeBulk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_lockDays","type":"uint64"},{"internalType":"address","name":"_referrer","type":"address"}],"name":"createStakeWithETH","outputs":[{"internalType":"bytes16","name":"","type":"bytes16"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes16","name":"referralID","type":"bytes16"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint64","name":"_lockDays","type":"uint64"},{"internalType":"address","name":"_referrer","type":"address"}],"name":"createStakeWithToken","outputs":[{"internalType":"bytes16","name":"","type":"bytes16"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes16","name":"referralID","type":"bytes16"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"criticalMass","outputs":[{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"activationDay","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentSwappDay","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"_stakeID","type":"bytes16"}],"name":"endStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"x","type":"address"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"bytes1","name":"z","type":"bytes1"}],"name":"generateID","outputs":[{"internalType":"bytes16","name":"b","type":"bytes16"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getNow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakedAmount","type":"uint256"},{"internalType":"uint64","name":"_lockDays","type":"uint64"},{"internalType":"address","name":"_referrer","type":"address"}],"name":"getStakingShare","outputs":[{"internalType":"uint256","name":"stakingShare","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"}],"name":"giveStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"globals","outputs":[{"internalType":"uint256","name":"totalStaked","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"},{"internalType":"uint256","name":"sharePrice","type":"uint256"},{"internalType":"uint256","name":"currentSwappDay","type":"uint256"},{"internalType":"uint256","name":"referralShares","type":"uint256"},{"internalType":"uint256","name":"liquidityShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLiquidityGuardActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestDaiEquivalent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"}],"name":"latestReferralID","outputs":[{"internalType":"bytes16","name":"","type":"bytes16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"latestStakeID","outputs":[{"internalType":"bytes16","name":"","type":"bytes16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityGuardTrigger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manualDailySnapshot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_updateDay","type":"uint64"}],"name":"manualDailySnapshotPoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_investorAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextSwappDay","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previousSwappDay","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"referralSharesToEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_length","type":"uint256"}],"name":"referralsPagination","outputs":[{"internalType":"bytes16[]","name":"_referrals","type":"bytes16[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"_referralID","type":"bytes16"},{"internalType":"uint256","name":"_scrapeDays","type":"uint256"}],"name":"referrerInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"_referralIDs","type":"bytes16[]"},{"internalType":"uint256[]","name":"_scrapeDays","type":"uint256[]"}],"name":"referrerInterestBulk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes16","name":"","type":"bytes16"}],"name":"referrerLinks","outputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"bytes16","name":"stakeID","type":"bytes16"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"processedDays","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rsnapshots","outputs":[{"internalType":"uint256","name":"totalShares","type":"uint256"},{"internalType":"uint256","name":"inflationAmount","type":"uint256"},{"internalType":"uint256","name":"scheduledToEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"scheduledToEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"_stakeID","type":"bytes16"},{"internalType":"uint64","name":"_scrapeDays","type":"uint64"}],"name":"scrapeInterest","outputs":[{"internalType":"uint256","name":"scrapeDay","type":"uint256"},{"internalType":"uint256","name":"scrapeAmount","type":"uint256"},{"internalType":"uint256","name":"remainingDays","type":"uint256"},{"internalType":"uint256","name":"stakersPenalty","type":"uint256"},{"internalType":"uint256","name":"referrerPenalty","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes16","name":"","type":"bytes16"}],"name":"scrapes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_transformer","type":"address"},{"internalType":"address","name":"_yieldFarmStable","type":"address"},{"internalType":"address","name":"_yieldFarmLP","type":"address"}],"name":"setMinters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"snapshots","outputs":[{"internalType":"uint256","name":"totalShares","type":"uint256"},{"internalType":"uint256","name":"inflationAmount","type":"uint256"},{"internalType":"uint256","name":"scheduledToEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakeCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes16","name":"","type":"bytes16"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"stakesShares","type":"uint256"},{"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint64","name":"startDay","type":"uint64"},{"internalType":"uint64","name":"lockDays","type":"uint64"},{"internalType":"uint64","name":"finalDay","type":"uint64"},{"internalType":"uint64","name":"closeDay","type":"uint64"},{"internalType":"uint256","name":"scrapeDay","type":"uint256"},{"internalType":"uint256","name":"daiEquivalent","type":"uint256"},{"internalType":"uint256","name":"referrerShares","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_length","type":"uint256"}],"name":"stakesPagination","outputs":[{"internalType":"bytes16[]","name":"_stakes","type":"bytes16[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"swappDayFromStamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenMinterDefiner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalPenalties","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]