Transaction Hash:
Block:
10462936 at Jul-15-2020 08:10:09 AM +UTC
Transaction Fee:
0.007310952 ETH
$15.68
Gas Used:
166,158 Gas / 44 Gwei
Emitted Events:
| 170 |
EtherHives.RewardCollected( user=[Sender] 0x5049a273ea497be23b97794b27b36876453f85ad, honeyReward=3932383888888888888888, waxReward=983095972222222222223 )
|
| 171 |
EtherHives.ReferrerPaid( user=[Sender] 0x5049a273ea497be23b97794b27b36876453f85ad, referrer=0xc05C9391...05d525A75, level=1, amount=316521362499999999999 )
|
| 172 |
EtherHives.ReferrerPaid( user=[Sender] 0x5049a273ea497be23b97794b27b36876453f85ad, referrer=0x2414E5c0...8F0A9956A, level=2, amount=158260681249999999999 )
|
| 173 |
EtherHives.ReferrerPaid( user=[Sender] 0x5049a273ea497be23b97794b27b36876453f85ad, referrer=0x0DC36111...F47bCE393, level=3, amount=94956408749999999999 )
|
| 174 |
EtherHives.BeesBought( user=[Sender] 0x5049a273ea497be23b97794b27b36876453f85ad, bee=1, count=3 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x5049A273...6453F85Ad |
0.040216512 Eth
Nonce: 12
|
0.03290556 Eth
Nonce: 13
| 0.007310952 | ||
|
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 35.133128859961417992 Eth | 35.140439811961417992 Eth | 0.007310952 | |
| 0x6dcb2F99...183340c8A | 6.936143172532666834 Eth | 6.937409257982666833 Eth | 0.001266085449999999 | ||
| 0x8963B689...aFD7B2cB6 | 587.788973040549539731 Eth | 587.787706955099539732 Eth | 0.001266085449999999 |
Execution Trace
EtherHives.buyBees( bee=1, count=3 )
- ETH 0.001266085449999999
0x6dcb2f99b50c71d18fd3ffa6fae1346183340c8a.CALL( )
buyBees[EtherHives (ln:456)]
deposit[EtherHives (ln:460)]referrerOf[EtherHives (ln:338)]_register[EtherHives (ln:344)]add[EtherHives (ln:568)]push[EtherHives (ln:573)]_addToBonusIfNeeded[EtherHives (ln:579)]_addUserToBonus[EtherHives (ln:614)]
Registered[EtherHives (ln:581)]
collect[EtherHives (ln:347)]userBonusEarned[EtherHives (ln:385)]retrieveBonus[EtherHives (ln:386)]add[EtherHives (ln:528)]userBonusEarned[EtherHives (ln:528)]retrieveBonus[EtherHives (ln:529)]
instantBalance[EtherHives (ln:389)]RewardCollected[EtherHives (ln:390)]sub[EtherHives (ln:392)]sub[EtherHives (ln:393)]
mul[EtherHives (ln:350)]add[EtherHives (ln:351)]add[EtherHives (ln:352)]add[EtherHives (ln:353)]add[EtherHives (ln:354)]Deposited[EtherHives (ln:355)]_distributeFees[EtherHives (ln:359)]transfer[EtherHives (ln:539)]owner[EtherHives (ln:539)]add[EtherHives (ln:544)]_addToBonusIfNeeded[EtherHives (ln:545)]_addUserToBonus[EtherHives (ln:614)]
div[EtherHives (ln:550)]mul[EtherHives (ln:550)]add[EtherHives (ln:551)]add[EtherHives (ln:552)]div[EtherHives (ln:552)]mul[EtherHives (ln:552)]ReferrerPaid[EtherHives (ln:553)]
_addToBonusIfNeeded[EtherHives (ln:361)]_addUserToBonus[EtherHives (ln:614)]
owner[EtherHives (ln:363)]max[EtherHives (ln:364)]add[EtherHives (ln:364)]
collect[EtherHives (ln:463)]userBonusEarned[EtherHives (ln:385)]retrieveBonus[EtherHives (ln:386)]add[EtherHives (ln:528)]userBonusEarned[EtherHives (ln:528)]retrieveBonus[EtherHives (ln:529)]
instantBalance[EtherHives (ln:389)]RewardCollected[EtherHives (ln:390)]sub[EtherHives (ln:392)]sub[EtherHives (ln:393)]
superBeeUnlocked[EtherHives (ln:467)]sub[EtherHives (ln:468)]add[EtherHives (ln:473)]add[EtherHives (ln:474)]add[EtherHives (ln:475)]_payWithWaxAndHoney[EtherHives (ln:476)]mul[EtherHives (ln:476)]_distributeFees[EtherHives (ln:478)]transfer[EtherHives (ln:539)]owner[EtherHives (ln:539)]add[EtherHives (ln:544)]_addToBonusIfNeeded[EtherHives (ln:545)]_addUserToBonus[EtherHives (ln:614)]
div[EtherHives (ln:550)]mul[EtherHives (ln:550)]add[EtherHives (ln:551)]add[EtherHives (ln:552)]div[EtherHives (ln:552)]mul[EtherHives (ln:552)]ReferrerPaid[EtherHives (ln:553)]
referrerOf[EtherHives (ln:478)]BeesBought[EtherHives (ln:480)]
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
library Math {
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;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
contract Context {
constructor () internal { }
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
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 UserBonus {
using SafeMath for uint256;
uint256 public constant BONUS_PERCENTS_PER_WEEK = 1;
uint256 public constant BONUS_TIME = 1 weeks;
struct UserBonusData {
uint256 threadPaid;
uint256 lastPaidTime;
uint256 numberOfUsers;
mapping(address => bool) userRegistered;
mapping(address => uint256) userPaid;
}
UserBonusData public bonus;
event BonusPaid(uint256 users, uint256 amount);
event UserAddedToBonus(address indexed user);
modifier payRepBonusIfNeeded {
payRepresentativeBonus();
_;
}
constructor() public {
bonus.lastPaidTime = block.timestamp;
}
function payRepresentativeBonus() public {
while (bonus.numberOfUsers > 0 && bonus.lastPaidTime.add(BONUS_TIME) <= block.timestamp) {
uint256 reward = address(this).balance.mul(BONUS_PERCENTS_PER_WEEK).div(100);
bonus.threadPaid = bonus.threadPaid.add(reward.div(bonus.numberOfUsers));
bonus.lastPaidTime = bonus.lastPaidTime.add(BONUS_TIME);
emit BonusPaid(bonus.numberOfUsers, reward);
}
}
function userRegisteredForBonus(address user) public view returns(bool) {
return bonus.userRegistered[user];
}
function userBonusPaid(address user) public view returns(uint256) {
return bonus.userPaid[user];
}
function userBonusEarned(address user) public view returns(uint256) {
return bonus.userRegistered[user] ? bonus.threadPaid.sub(bonus.userPaid[user]) : 0;
}
function retrieveBonus() public virtual payRepBonusIfNeeded {
require(bonus.userRegistered[msg.sender], "User not registered for bonus");
uint256 amount = Math.min(address(this).balance, userBonusEarned(msg.sender));
bonus.userPaid[msg.sender] = bonus.userPaid[msg.sender].add(amount);
msg.sender.transfer(amount);
}
function _addUserToBonus(address user) internal payRepBonusIfNeeded {
require(!bonus.userRegistered[user], "User already registered for bonus");
bonus.userRegistered[user] = true;
bonus.userPaid[user] = bonus.threadPaid;
bonus.numberOfUsers = bonus.numberOfUsers.add(1);
emit UserAddedToBonus(user);
}
}
contract Claimable is Ownable {
address public pendingOwner;
modifier onlyPendingOwner() {
require(msg.sender == pendingOwner);
_;
}
function renounceOwnership() public override(Ownable) onlyOwner {
revert();
}
function transferOwnership(address newOwner) public override(Ownable) onlyOwner {
pendingOwner = newOwner;
}
function claimOwnership() public virtual onlyPendingOwner {
transferOwnership(pendingOwner);
delete pendingOwner;
}
}
contract EtherHives is Claimable, UserBonus {
struct Player {
uint256 registeredDate;
bool airdropCollected;
address referrer;
uint256 balanceHoney;
uint256 balanceWax;
uint256 points;
uint256 medals;
uint256 qualityLevel;
uint256 lastTimeCollected;
uint256 unlockedBee;
uint256[BEES_COUNT] bees;
uint256 totalDeposited;
uint256 totalWithdrawed;
uint256 referralsTotalDeposited;
uint256 subreferralsCount;
address[] referrals;
}
uint256 public constant BEES_COUNT = 8;
uint256 public constant SUPER_BEE_INDEX = BEES_COUNT - 1;
uint256 public constant TRON_BEE_INDEX = BEES_COUNT - 2;
uint256 public constant MEDALS_COUNT = 10;
uint256 public constant QUALITIES_COUNT = 6;
uint256[BEES_COUNT] public BEES_PRICES = [0e18, 1500e18, 7500e18, 30000e18, 75000e18, 250000e18, 750000e18, 100000e18];
uint256[BEES_COUNT] public BEES_LEVELS_PRICES = [0e18, 0e18, 11250e18, 45000e18, 112500e18, 375000e18, 1125000e18, 0];
uint256[BEES_COUNT] public BEES_MONTHLY_PERCENTS = [0, 220, 223, 226, 229, 232, 235, 333];
uint256[MEDALS_COUNT] public MEDALS_POINTS = [0e18, 50000e18, 190000e18, 510000e18, 1350000e18, 3225000e18, 5725000e18, 8850000e18, 12725000e18, 23500000e18];
uint256[MEDALS_COUNT] public MEDALS_REWARDS = [0e18, 3500e18, 10500e18, 24000e18, 65000e18, 140000e18, 185000e18, 235000e18, 290000e18, 800000e18];
uint256[QUALITIES_COUNT] public QUALITY_HONEY_PERCENT = [80, 82, 84, 86, 88, 90];
uint256[QUALITIES_COUNT] public QUALITY_PRICE = [0e18, 15000e18, 50000e18, 120000e18, 250000e18, 400000e18];
uint256 public constant COINS_PER_ETH = 250000;
uint256 public constant MAX_BEES_PER_TARIFF = 32;
uint256 public constant FIRST_BEE_AIRDROP_AMOUNT = 500e18;
uint256 public constant ADMIN_PERCENT = 10;
uint256 public constant HONEY_DISCOUNT_PERCENT = 10;
uint256 public constant SUPERBEE_PERCENT_UNLOCK = 30;
uint256 public constant SUPER_BEE_BUYER_PERIOD = 7 days;
uint256[] public REFERRAL_PERCENT_PER_LEVEL = [10, 5, 3];
uint256[] public REFERRAL_POINT_PERCENT = [50, 25, 0];
uint256 public maxBalance;
uint256 public totalPlayers;
uint256 public totalDeposited;
uint256 public totalWithdrawed;
uint256 public totalBeesBought;
mapping(address => Player) public players;
event Registered(address indexed user, address indexed referrer);
event Deposited(address indexed user, uint256 amount);
event Withdrawed(address indexed user, uint256 amount);
event ReferrerPaid(address indexed user, address indexed referrer, uint256 indexed level, uint256 amount);
event MedalAwarded(address indexed user, uint256 indexed medal);
event QualityUpdated(address indexed user, uint256 indexed quality);
event RewardCollected(address indexed user, uint256 honeyReward, uint256 waxReward);
event BeeUnlocked(address indexed user, uint256 bee);
event BeesBought(address indexed user, uint256 bee, uint256 count);
constructor() public {
_register(owner(), address(0));
}
receive() external payable {
if (msg.value == 0) {
if (players[msg.sender].registeredDate > 0) {
collect();
}
} else {
deposit(address(0));
}
}
function playerBees(address who) public view returns(uint256[BEES_COUNT] memory) {
return players[who].bees;
}
function superBeeUnlocked() public view returns(bool) {
return address(this).balance <= maxBalance.mul(100 - SUPERBEE_PERCENT_UNLOCK).div(100);
}
function referrals(address user) public view returns(address[] memory) {
return players[user].referrals;
}
function referrerOf(address user, address ref) internal view returns(address) {
if (players[user].registeredDate == 0 && ref != user) {
return ref;
}
return players[user].referrer;
}
function transfer(address account, uint256 amount) public returns(bool) {
require(msg.sender == owner());
collect();
_payWithWaxAndHoney(msg.sender, amount);
players[account].balanceWax = players[account].balanceWax.add(amount);
return true;
}
function deposit(address ref) public payable payRepBonusIfNeeded {
Player storage player = players[msg.sender];
address refAddress = referrerOf(msg.sender, ref);
require((msg.value == 0) != player.registeredDate > 0, "Send 0 for registration");
if (player.registeredDate == 0) {
_register(msg.sender, refAddress);
}
collect();
uint256 wax = msg.value.mul(COINS_PER_ETH);
player.balanceWax = player.balanceWax.add(wax);
player.totalDeposited = player.totalDeposited.add(msg.value);
totalDeposited = totalDeposited.add(msg.value);
player.points = player.points.add(wax);
emit Deposited(msg.sender, msg.value);
_distributeFees(msg.sender, wax, msg.value, refAddress);
_addToBonusIfNeeded(msg.sender);
uint256 adminWithdrawed = players[owner()].totalWithdrawed;
maxBalance = Math.max(maxBalance, address(this).balance.add(adminWithdrawed));
}
function withdraw(uint256 amount) public {
Player storage player = players[msg.sender];
collect();
uint256 value = amount.div(COINS_PER_ETH);
require(value > 0, "Trying to withdraw too small");
player.balanceHoney = player.balanceHoney.sub(amount);
player.totalWithdrawed = player.totalWithdrawed.add(value);
totalWithdrawed = totalWithdrawed.add(value);
msg.sender.transfer(value);
emit Withdrawed(msg.sender, value);
}
function collect() public payRepBonusIfNeeded {
Player storage player = players[msg.sender];
require(player.registeredDate > 0, "Not registered yet");
if (userBonusEarned(msg.sender) > 0) {
retrieveBonus();
}
(uint256 balanceHoney, uint256 balanceWax) = instantBalance(msg.sender);
emit RewardCollected(
msg.sender,
balanceHoney.sub(player.balanceHoney),
balanceWax.sub(player.balanceWax)
);
if (!player.airdropCollected && player.registeredDate < now) {
player.airdropCollected = true;
}
player.balanceHoney = balanceHoney;
player.balanceWax = balanceWax;
player.lastTimeCollected = block.timestamp;
}
function instantBalance(address account)
public
view
returns(
uint256 balanceHoney,
uint256 balanceWax
)
{
Player storage player = players[account];
if (player.registeredDate == 0) {
return (0, 0);
}
balanceHoney = player.balanceHoney;
balanceWax = player.balanceWax;
uint256 collected = earned(account);
if (!player.airdropCollected && player.registeredDate < now) {
collected = collected.sub(FIRST_BEE_AIRDROP_AMOUNT);
balanceWax = balanceWax.add(FIRST_BEE_AIRDROP_AMOUNT);
}
uint256 honeyReward = collected.mul(QUALITY_HONEY_PERCENT[player.qualityLevel]).div(100);
uint256 waxReward = collected.sub(honeyReward);
balanceHoney = balanceHoney.add(honeyReward);
balanceWax = balanceWax.add(waxReward);
}
function unlock(uint256 bee) public payable payRepBonusIfNeeded {
Player storage player = players[msg.sender];
if (msg.value > 0) {
deposit(address(0));
}
collect();
require(bee < SUPER_BEE_INDEX, "No more levels to unlock");
require(player.bees[bee - 1] == MAX_BEES_PER_TARIFF, "Prev level must be filled");
require(bee == player.unlockedBee + 1, "Trying to unlock wrong bee type");
if (bee == TRON_BEE_INDEX) {
require(player.medals >= 9);
}
_payWithWaxAndHoney(msg.sender, BEES_LEVELS_PRICES[bee]);
player.unlockedBee = bee;
player.bees[bee] = 1;
emit BeeUnlocked(msg.sender, bee);
}
function buyBees(uint256 bee, uint256 count) public payable payRepBonusIfNeeded {
Player storage player = players[msg.sender];
if (msg.value > 0) {
deposit(address(0));
}
collect();
require(bee > 0 && bee < BEES_COUNT, "Don't try to buy bees of type 0");
if (bee == SUPER_BEE_INDEX) {
require(superBeeUnlocked(), "SuperBee is not unlocked yet");
require(block.timestamp.sub(player.registeredDate) < SUPER_BEE_BUYER_PERIOD, "You should be registered less than 7 days ago");
} else {
require(bee <= player.unlockedBee, "This bee type not unlocked yet");
}
require(player.bees[bee].add(count) <= MAX_BEES_PER_TARIFF);
player.bees[bee] = player.bees[bee].add(count);
totalBeesBought = totalBeesBought.add(count);
uint256 honeySpent = _payWithWaxAndHoney(msg.sender, BEES_PRICES[bee].mul(count));
_distributeFees(msg.sender, honeySpent, 0, referrerOf(msg.sender, address(0)));
emit BeesBought(msg.sender, bee, count);
}
function updateQualityLevel() public payRepBonusIfNeeded {
Player storage player = players[msg.sender];
collect();
require(player.qualityLevel < QUALITIES_COUNT - 1);
_payWithHoneyOnly(msg.sender, QUALITY_PRICE[player.qualityLevel + 1]);
player.qualityLevel++;
emit QualityUpdated(msg.sender, player.qualityLevel);
}
function earned(address user) public view returns(uint256) {
Player storage player = players[user];
if (player.registeredDate == 0) {
return 0;
}
uint256 total = 0;
for (uint i = 1; i < BEES_COUNT; i++) {
total = total.add(
player.bees[i].mul(BEES_PRICES[i]).mul(BEES_MONTHLY_PERCENTS[i]).div(100)
);
}
return total
.mul(block.timestamp.sub(player.lastTimeCollected))
.div(30 days)
.add(player.airdropCollected || player.registeredDate == now ? 0 : FIRST_BEE_AIRDROP_AMOUNT);
}
function collectMedals(address user) public payRepBonusIfNeeded {
Player storage player = players[user];
collect();
for (uint i = player.medals; i < MEDALS_COUNT; i++) {
if (player.points >= MEDALS_POINTS[i]) {
player.balanceWax = player.balanceWax.add(MEDALS_REWARDS[i]);
player.medals = i + 1;
emit MedalAwarded(user, i + 1);
}
}
}
function retrieveBonus() public override(UserBonus) {
totalWithdrawed = totalWithdrawed.add(userBonusEarned(msg.sender));
super.retrieveBonus();
}
function claimOwnership() public override(Claimable) {
super.claimOwnership();
_register(owner(), address(0));
}
function _distributeFees(address user, uint256 wax, uint256 deposited, address refAddress) internal {
address(uint160(owner())).transfer(wax * ADMIN_PERCENT / 100 / COINS_PER_ETH);
if (refAddress != address(0)) {
Player storage referrer = players[refAddress];
referrer.referralsTotalDeposited = referrer.referralsTotalDeposited.add(deposited);
_addToBonusIfNeeded(refAddress);
address to = refAddress;
for (uint i = 0; to != address(0) && i < REFERRAL_PERCENT_PER_LEVEL.length; i++) {
uint256 reward = wax.mul(REFERRAL_PERCENT_PER_LEVEL[i]).div(100);
players[to].balanceHoney = players[to].balanceHoney.add(reward);
players[to].points = players[to].points.add(wax.mul(REFERRAL_POINT_PERCENT[i]).div(100));
emit ReferrerPaid(user, to, i + 1, reward);
to = players[to].referrer;
}
}
}
function _register(address user, address refAddress) internal {
Player storage player = players[user];
player.registeredDate = block.timestamp;
player.bees[0] = MAX_BEES_PER_TARIFF;
player.unlockedBee = 1;
player.lastTimeCollected = block.timestamp;
totalBeesBought = totalBeesBought.add(MAX_BEES_PER_TARIFF);
totalPlayers++;
if (refAddress != address(0)) {
player.referrer = refAddress;
players[refAddress].referrals.push(user);
if (players[refAddress].referrer != address(0)) {
players[players[refAddress].referrer].subreferralsCount++;
}
_addToBonusIfNeeded(refAddress);
}
emit Registered(user, refAddress);
}
function _payWithHoneyOnly(address user, uint256 amount) internal {
Player storage player = players[user];
player.balanceHoney = player.balanceHoney.sub(amount);
}
function _payWithWaxOnly(address user, uint256 amount) internal {
Player storage player = players[user];
player.balanceWax = player.balanceWax.sub(amount);
}
function _payWithWaxAndHoney(address user, uint256 amount) internal returns(uint256) {
Player storage player = players[user];
uint256 wax = Math.min(amount, player.balanceWax);
uint256 honey = amount.sub(wax).mul(100 - HONEY_DISCOUNT_PERCENT).div(100);
player.balanceWax = player.balanceWax.sub(wax);
_payWithHoneyOnly(user, honey);
return honey;
}
function _addToBonusIfNeeded(address user) internal {
if (user != address(0) && !bonus.userRegistered[user]) {
Player storage player = players[user];
if (player.totalDeposited >= 5 ether &&
player.referrals.length >= 10 &&
player.referralsTotalDeposited >= 50 ether)
{
_addUserToBonus(user);
}
}
}
}