Transaction Hash:
Block:
7242052 at Feb-19-2019 10:13:16 PM +UTC
Transaction Fee:
0.000148776 ETH
$0.29
Gas Used:
49,592 Gas / 3 Gwei
Emitted Events:
| 79 |
SnailTree.ClaimedShare( player=[Sender] 0xe84fd91cbba2fcddc22d96965158ae676dd61d28, eth=1376397469907407, pecan=56157016 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x1199e1C2...A6B587655 | |||||
|
0xb2930B35...e543a0347
Miner
| (MiningPoolHub: Old Address) | 5,968.679313222454331364 Eth | 5,968.679461998454331364 Eth | 0.000148776 | |
| 0xe84Fd91C...76Dd61D28 |
17.60722345324164671 Eth
Nonce: 4823
|
17.60707467724164671 Eth
Nonce: 4824
| 0.000148776 |
Execution Trace
SnailTree.CALL( )
pragma solidity ^0.4.24;
/* SNAILTREE
// SnailTree is a mock HYIP, coupled with a jackpot.
// To start, players spend ETH to plant a root.
// They get a "tree size" proportional to their investment.
// They also get Pecans the moment they invest.
// Pecan number starts proportional to ETH, and then multiplied.
// This buy multiplier is global.
// The longer nobody plants a root, the bigger multiplier.
// Each player gets to claim ETH equivalent to their treeSize.
// This claim starts equivalent to 4% of their initial, daily.
// This claim also gets them Pecans.
// The amount of Pecans given raises with time.
// This claim multiplier builds up the longer the player doesn't claim.
// Instead of claiming ETH, players can grow their tree.
// Growing the tree reinvests the ETH they would have claimed.
// Their treeSize raises proportionally.
// If their lastClaim was at least one hour ago, they receive a boost.
// Boosts are straight multipliers to Pecan rewards.
// A player can give Pecans to Wonkers the Squirrel,
// And receive ETH in return, from the wonkPot.
// Once Wonkers receives enough Pecans, the round is over.
// Whoever gave him Pecans last wins the roundPot (20% of the jackPot).
// A new round starts immediately.
// Players from the previous round see their treeSize decrease by 20%.
// Their growth boost also resets to 1.
// This occurs automatically on their next action.
*/
contract SnailTree {
using SafeMath for uint;
/* Event */
event PlantedRoot(address indexed player, uint eth, uint pecan, uint treesize);
event GavePecan(address indexed player, uint eth, uint pecan);
event ClaimedShare(address indexed player, uint eth, uint pecan);
event GrewTree(address indexed player, uint eth, uint pecan, uint boost);
event WonRound (address indexed player, uint indexed round, uint eth);
event WithdrewBalance (address indexed player, uint eth);
event PaidThrone (address indexed player, uint eth);
event BoostedPot (address indexed player, uint eth);
/* Constants */
uint256 constant SECONDS_IN_HOUR = 3600;
uint256 constant SECONDS_IN_DAY = 86400;
uint256 constant PECAN_WIN_FACTOR = 0.0000000001 ether; //add 1B pecans per 0.1 ETH in pot
uint256 constant TREE_SIZE_COST = 0.0000005 ether; //= 1 treeSize
uint256 constant REWARD_SIZE_ETH = 0.00000002 ether; //4% per day per treeSize
address constant SNAILTHRONE = 0x261d650a521103428C6827a11fc0CBCe96D74DBc;
/* Variables */
//Current round
uint256 public gameRound = 0;
//Fund for %claims
uint256 public treePot = 0;
//Direct rewards
uint256 public wonkPot = 0;
//Round winner reward
uint256 public jackPot = 0;
//Divs for SnailThrone holders
uint256 public thronePot = 0;
//Pecans required to win this round
uint256 public pecanToWin = 0;
//Pecans given this round
uint256 public pecanGiven = 0;
//Last ETH investment
uint256 public lastRootPlant = 0;
/* Mappings */
mapping (address => uint256) playerRound;
mapping (address => uint256) playerBalance;
mapping (address => uint256) treeSize;
mapping (address => uint256) pecan;
mapping (address => uint256) lastClaim;
mapping (address => uint256) boost;
/* Functions */
// Constructor
// Sets round to 1 and lastRootPlant to now
constructor() public {
gameRound = 1;
pecanToWin = 1;
lastRootPlant = now;
}
//-- PRIVATE --
// CheckRound
// Ensures player is on correct round
// If not, reduce his treeSize by 20% per round missed
// Increase his round until he's on the correct one
function CheckRound() private {
while(playerRound[msg.sender] != gameRound){
treeSize[msg.sender] = treeSize[msg.sender].mul(4).div(5);
playerRound[msg.sender] = playerRound[msg.sender].add(1);
boost[msg.sender] = 1;
}
}
// WinRound
// Called when a player gives enough Pecans to Wonkers
// Gives his earnings to winner
function WinRound(address _msgSender) private {
//Increment round
uint256 _round = gameRound;
gameRound = gameRound.add(1);
//Compute reward and adjust pot
uint256 _reward = jackPot.div(5);
jackPot = jackPot.sub(_reward);
//Reset pecan given to 0
pecanGiven = 0;
//Set new pecan requirement
pecanToWin = ComputePecanToWin();
//Send reward
playerBalance[_msgSender] = playerBalance[_msgSender].add(_reward);
emit WonRound(_msgSender, _round, _reward);
}
// PotSplit
// Allocates the ETH of every transaction
// 40% treePot, 30% wonkPot, 20% jackPot, 10% thronePot
function PotSplit(uint256 _msgValue) private {
treePot = treePot.add(_msgValue.mul(4).div(10));
wonkPot = wonkPot.add(_msgValue.mul(3).div(10));
jackPot = jackPot.add(_msgValue.div(5));
thronePot = thronePot.add(_msgValue.div(10));
}
//-- GAME ACTIONS --
// PlantRoot
// Gives player treeSize and pecan
// Sets lastRootPlant and lastClaim to now
function PlantRoot() public payable {
require(tx.origin == msg.sender, "no contracts allowed");
require(msg.value >= 0.001 ether, "at least 1 finney to plant a root");
//Check if player is in correct round
CheckRound();
//Split ETH to pot
PotSplit(msg.value);
//Set new pecan requirement
pecanToWin = ComputePecanToWin();
//Get pecans to give
uint256 _newPecan = ComputePlantPecan(msg.value);
//Set claims to now
lastRootPlant = now;
lastClaim[msg.sender] = now;
//Get treeSize to give
uint256 _treePlant = msg.value.div(TREE_SIZE_COST);
//Add player treeSize
treeSize[msg.sender] = treeSize[msg.sender].add(_treePlant);
//Add player pecans
pecan[msg.sender] = pecan[msg.sender].add(_newPecan);
emit PlantedRoot(msg.sender, msg.value, _newPecan, treeSize[msg.sender]);
}
// GivePecan
// Exchanges player Pecans for ETH
// Wins the round if enough Pecans are given
function GivePecan(uint256 _pecanGift) public {
require(pecan[msg.sender] >= _pecanGift, "not enough pecans");
//Check if player is in correct round
CheckRound();
//Get reward
uint256 _ethReward = ComputeWonkTrade(_pecanGift);
//Lower player pecan
pecan[msg.sender] = pecan[msg.sender].sub(_pecanGift);
//Adjust pecan given
pecanGiven = pecanGiven.add(_pecanGift);
//Lower wonkPot
wonkPot = wonkPot.sub(_ethReward);
//Give reward
playerBalance[msg.sender] = playerBalance[msg.sender].add(_ethReward);
//Check if player Wins
if(pecanGiven >= pecanToWin){
WinRound(msg.sender);
} else {
emit GavePecan(msg.sender, _ethReward, _pecanGift);
}
}
// ClaimShare
// Gives player his share of ETH, and Pecans
// Sets his lastClaim to now
function ClaimShare() public {
require(treeSize[msg.sender] > 0, "plant a root first");
//Check if player is in correct round
CheckRound();
//Get ETH reward
uint256 _ethReward = ComputeEtherShare(msg.sender);
//Get Pecan reward
uint256 _pecanReward = ComputePecanShare(msg.sender);
//Set lastClaim
lastClaim[msg.sender] = now;
//Lower treePot
treePot = treePot.sub(_ethReward);
//Give rewards
pecan[msg.sender] = pecan[msg.sender].add(_pecanReward);
playerBalance[msg.sender] = playerBalance[msg.sender].add(_ethReward);
emit ClaimedShare(msg.sender, _ethReward, _pecanReward);
}
// GrowTree
// Uses player share to grow his treeSize
// Gives share pecans multiplied by boost
// Increases boost if last claim was at least one hour ago
function GrowTree() public {
require(treeSize[msg.sender] > 0, "plant a root first");
//Check if player is in correct round
CheckRound();
//Get ETH used
uint256 _ethUsed = ComputeEtherShare(msg.sender);
//Get Pecan reward
uint256 _pecanReward = ComputePecanShare(msg.sender);
//Check if player gets a boost increase
uint256 _timeSpent = now.sub(lastClaim[msg.sender]);
//Set lastClaim
lastClaim[msg.sender] = now;
//Get treeSize to give
uint256 _treeGrowth = _ethUsed.div(TREE_SIZE_COST);
//Add player treeSize
treeSize[msg.sender] = treeSize[msg.sender].add(_treeGrowth);
//Give boost if eligible (maximum +10 at once)
if(_timeSpent >= SECONDS_IN_HOUR){
uint256 _boostPlus = _timeSpent.div(SECONDS_IN_HOUR);
if(_boostPlus > 10){
_boostPlus = 10;
}
boost[msg.sender] = boost[msg.sender].add(_boostPlus);
}
//Give Pecan reward
pecan[msg.sender] = pecan[msg.sender].add(_pecanReward);
emit GrewTree(msg.sender, _ethUsed, _pecanReward, boost[msg.sender]);
}
//-- MISC ACTIONS --
// WithdrawBalance
// Withdraws the ETH balance of a player to his wallet
function WithdrawBalance() public {
require(playerBalance[msg.sender] > 0, "no ETH in player balance");
uint _amount = playerBalance[msg.sender];
playerBalance[msg.sender] = 0;
msg.sender.transfer(_amount);
emit WithdrewBalance(msg.sender, _amount);
}
// PayThrone
// Sends thronePot to SnailThrone
function PayThrone() public {
uint256 _payThrone = thronePot;
thronePot = 0;
if (!SNAILTHRONE.call.value(_payThrone)()){
revert();
}
emit PaidThrone(msg.sender, _payThrone);
}
// fallback function
// Feeds the jackPot
function() public payable {
jackPot = jackPot.add(msg.value);
emit BoostedPot(msg.sender, msg.value);
}
//-- CALCULATIONS --
// ComputeEtherShare
// Returns ETH reward for a claim
// Reward = 0.00000002 ETH per treeSize per day
function ComputeEtherShare(address adr) public view returns(uint256) {
//Get time since last claim
uint256 _timeLapsed = now.sub(lastClaim[adr]);
//Compute reward
uint256 _reward = _timeLapsed.mul(REWARD_SIZE_ETH).mul(treeSize[adr]).div(SECONDS_IN_DAY);
//Check reward isn't above remaining treePot
if(_reward >= treePot){
_reward = treePot;
}
return _reward;
}
// ComputeShareBoostFactor
// Returns current personal Pecan multiplier
// Starts at 4, adds 1 per hour
function ComputeShareBoostFactor(address adr) public view returns(uint256) {
//Get time since last claim
uint256 _timeLapsed = now.sub(lastClaim[adr]);
//Compute boostFactor (starts at 4, +1 per hour)
uint256 _boostFactor = (_timeLapsed.div(SECONDS_IN_HOUR)).add(4);
return _boostFactor;
}
// ComputePecanShare
// Returns Pecan reward for a claim
// Reward = 1 Pecan per treeSize per day, multiplied by personal boost
function ComputePecanShare(address adr) public view returns(uint256) {
//Get time since last claim
uint256 _timeLapsed = now.sub(lastClaim[adr]);
//Get boostFactor
uint256 _shareBoostFactor = ComputeShareBoostFactor(adr);
//Compute reward
uint256 _reward = _timeLapsed.mul(treeSize[adr]).mul(_shareBoostFactor).mul(boost[msg.sender]).div(SECONDS_IN_DAY);
return _reward;
}
// ComputePecanToWin
// Returns amount of Pecans that must be given to win the round
// Pecans to win = 1B + (1B per 0.2 ETH in jackpot)
function ComputePecanToWin() public view returns(uint256) {
uint256 _pecanToWin = jackPot.div(PECAN_WIN_FACTOR);
return _pecanToWin;
}
// ComputeWonkTrade
// Returns ETH reward for a given amount of Pecans
// % of wonkPot rewarded = (Pecans gifted / Pecans to win) / 2, maximum 50%
function ComputeWonkTrade(uint256 _pecanGift) public view returns(uint256) {
//Make sure gift isn't above requirement to win
if(_pecanGift > pecanToWin) {
_pecanGift = pecanToWin;
}
uint256 _reward = _pecanGift.mul(wonkPot).div(pecanToWin).div(2);
return _reward;
}
// ComputePlantBoostFactor
// Returns global boost multiplier
// +1% per second
function ComputePlantBoostFactor() public view returns(uint256) {
//Get time since last global plant
uint256 _timeLapsed = now.sub(lastRootPlant);
//Compute boostFactor (starts at 100, +1 per second)
uint256 _boostFactor = (_timeLapsed.mul(1)).add(100);
return _boostFactor;
}
// ComputePlantPecan
// Returns Pecan reward for a given buy
// 1 Pecan per the cost of 1 Tree Size, multiplied by global boost
function ComputePlantPecan(uint256 _msgValue) public view returns(uint256) {
//Get boostFactor
uint256 _treeBoostFactor = ComputePlantBoostFactor();
//Compute reward
uint256 _reward = _msgValue.mul(_treeBoostFactor).div(TREE_SIZE_COST).div(100);
return _reward;
}
//-- GETTERS --
function GetTree(address adr) public view returns(uint256) {
return treeSize[adr];
}
function GetPecan(address adr) public view returns(uint256) {
return pecan[adr];
}
function GetMyBoost() public view returns(uint256) {
return boost[msg.sender];
}
function GetMyBalance() public view returns(uint256) {
return playerBalance[msg.sender];
}
function GetMyRound() public view returns(uint256) {
return playerRound[msg.sender];
}
function GetMyLastClaim() public view returns(uint256) {
return lastClaim[msg.sender];
}
}
/* SafeMath library */
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 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 c;
}
/**
* @dev Substracts 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) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}