diff --git a/contracts/GlobalsAndUtility.sol b/contracts/GlobalsAndUtility.sol index 67a75af..bfbde4d 100644 --- a/contracts/GlobalsAndUtility.sol +++ b/contracts/GlobalsAndUtility.sol @@ -90,6 +90,7 @@ contract GlobalsAndUtility is ERC20 { uint256 private constant HEX_PER_BTC = 1e4; uint256 private constant SATOSHIS_PER_BTC = 1e8; uint256 internal constant HEARTS_PER_SATOSHI = HEARTS_PER_HEX / SATOSHIS_PER_BTC * HEX_PER_BTC; + uint256 internal constant INITIAL_SHARES_PER_HEART = 1e18; /* Time of contract launch (2019-03-04T00:00:00Z) */ uint256 internal constant LAUNCH_TIME = 1551657600; @@ -157,6 +158,7 @@ contract GlobalsAndUtility is ERC20 { uint256 _daysStored; uint256 _stakeSharesTotal; uint256 _nextStakeSharesTotal; + uint256 _sharesPerHeart; uint48 _latestStakeId; // 2 uint256 _stakePenaltyPool; @@ -170,8 +172,9 @@ contract GlobalsAndUtility is ERC20 { struct GlobalsStore { // 1 uint16 daysStored; - uint80 stakeSharesTotal; - uint80 nextStakeSharesTotal; + uint256 stakeSharesTotal; + uint256 nextStakeSharesTotal; + uint256 sharesPerHeart; uint48 latestStakeId; // 2 uint80 stakePenaltyPool; @@ -188,7 +191,7 @@ contract GlobalsAndUtility is ERC20 { /* Period data */ struct DailyDataStore { uint80 dayPayoutTotal; - uint80 dayStakeSharesTotal; + uint256 dayStakeSharesTotal; } mapping(uint256 => DailyDataStore) public dailyData; @@ -206,7 +209,7 @@ contract GlobalsAndUtility is ERC20 { struct StakeStore { uint48 stakeId; uint80 stakedHearts; - uint80 stakeShares; + uint256 stakeShares; uint16 pooledDay; uint16 stakedDays; uint16 unpooledDay; @@ -347,6 +350,7 @@ contract GlobalsAndUtility is ERC20 { g._daysStored = globals.daysStored; g._stakeSharesTotal = globals.stakeSharesTotal; g._nextStakeSharesTotal = globals.nextStakeSharesTotal; + g._sharesPerHeart = globals.sharesPerHeart; g._latestStakeId = globals.latestStakeId; // 2 g._stakePenaltyPool = globals.stakePenaltyPool; @@ -365,6 +369,7 @@ contract GlobalsAndUtility is ERC20 { gSnapshot._daysStored = g._daysStored; gSnapshot._stakeSharesTotal = g._stakeSharesTotal; gSnapshot._nextStakeSharesTotal = g._nextStakeSharesTotal; + gSnapshot._sharesPerHeart = g._sharesPerHeart; gSnapshot._latestStakeId = g._latestStakeId; // 2 gSnapshot._stakePenaltyPool = g._stakePenaltyPool; @@ -377,8 +382,9 @@ contract GlobalsAndUtility is ERC20 { internal { globals.daysStored = uint16(g._daysStored); - globals.stakeSharesTotal = uint80(g._stakeSharesTotal); - globals.nextStakeSharesTotal = uint80(g._nextStakeSharesTotal); + globals.stakeSharesTotal = g._stakeSharesTotal; + globals.nextStakeSharesTotal = g._nextStakeSharesTotal; + globals.sharesPerHeart = g._sharesPerHeart; globals.latestStakeId = g._latestStakeId; } @@ -388,6 +394,7 @@ contract GlobalsAndUtility is ERC20 { if (g._daysStored == gSnapshot._daysStored && g._stakeSharesTotal == gSnapshot._stakeSharesTotal && g._nextStakeSharesTotal == gSnapshot._nextStakeSharesTotal + && g._sharesPerHeart == gSnapshot._sharesPerHeart && g._latestStakeId == gSnapshot._latestStakeId) { return; } @@ -435,7 +442,7 @@ contract GlobalsAndUtility is ERC20 { { stRef.stakeId = st._stakeId; stRef.stakedHearts = uint80(st._stakedHearts); - stRef.stakeShares = uint80(st._stakeShares); + stRef.stakeShares = st._stakeShares; stRef.pooledDay = uint16(st._pooledDay); stRef.stakedDays = uint16(st._stakedDays); stRef.unpooledDay = uint16(st._unpooledDay); @@ -455,7 +462,7 @@ contract GlobalsAndUtility is ERC20 { StakeStore( newStakeId, uint80(newStakedHearts), - uint80(newStakeShares), + newStakeShares, uint16(newPooledDay), uint16(newStakedDays), uint16(0) // unpooledDay @@ -522,7 +529,7 @@ contract GlobalsAndUtility is ERC20 { if (g._stakeSharesTotal != 0) { _calcDailyRound(g, rs, day); dailyData[day].dayPayoutTotal = uint80(rs._payoutTotal); - dailyData[day].dayStakeSharesTotal = uint80(g._stakeSharesTotal); + dailyData[day].dayStakeSharesTotal = g._stakeSharesTotal; } else { if (day == CLAIM_REWARD_DAYS && g._unclaimedSatoshisTotal != 0) { /* diff --git a/contracts/HEX.sol b/contracts/HEX.sol index 7cb42fd..e0e25fc 100644 --- a/contracts/HEX.sol +++ b/contracts/HEX.sol @@ -9,6 +9,7 @@ contract HEX is StakeableToken { { /* Add all Satoshis from UTXO snapshot to contract */ globals.unclaimedSatoshisTotal = uint64(FULL_SATOSHIS_TOTAL); + globals.sharesPerHeart = INITIAL_SHARES_PER_HEART; _mint(address(this), FULL_SATOSHIS_TOTAL * HEARTS_PER_SATOSHI); } diff --git a/contracts/StakeableToken.sol b/contracts/StakeableToken.sol index ae95a5c..580eb90 100644 --- a/contracts/StakeableToken.sol +++ b/contracts/StakeableToken.sol @@ -29,7 +29,7 @@ contract StakeableToken is UTXORedeemableToken { /* Check if log data needs to be updated */ _storeDailyDataBefore(g, g._currentDay); - uint256 newStakeShares = calcStakeShares(newStakedHearts, newStakedDays); + uint256 newStakeShares = calcStakeShares(newStakedHearts, newStakedDays, g._sharesPerHeart); /* The startStake timestamp will always be part-way through the current @@ -220,6 +220,17 @@ contract StakeableToken is UTXORedeemableToken { _removeStakeFromList(stakeListRef, stakeIndex); + /* + Apply worst-price logic + Worst price is the current shares / return, adjusted for potential Larger Pays + Better on a restake OR the current shares/heart, whichever is lower + */ + uint256 effectiveReturn = stakeReturn > LPB_H_CAP_HEARTS ? LPB_H_CAP_HEARTS : stakeReturn; + uint256 proposedPrice = st._stakeShares/(stakeReturn + stakeReturn * effectiveReturn / LPB_H); + if(proposedPrice < g._sharesPerHeart){ + g._sharesPerHeart = proposedPrice; + } + _saveGlobals1(g); _syncGlobals2(g, gSnapshot); } @@ -259,7 +270,7 @@ contract StakeableToken is UTXORedeemableToken { * @param newStakedHearts Number of Hearts to stake * @param newStakedDays Number of days to stake */ - function calcStakeShares(uint256 newStakedHearts, uint256 newStakedDays) + function calcStakeShares(uint256 newStakedHearts, uint256 newStakedDays, uint256 sharesPerHeart) private pure returns (uint256) @@ -335,7 +346,7 @@ contract StakeableToken is UTXORedeemableToken { uint256 combinedAmount = cappedExtraDays * LPB_H + cappedStakedHearts * LPB_D; combinedAmount = newStakedHearts * combinedAmount / (LPB_D * LPB_H); - return newStakedHearts + combinedAmount; + return sharesPerHeart * (newStakedHearts + combinedAmount); } function _unpoolStake(GlobalsCache memory g, StakeCache memory st)