diff --git a/beem/account.py b/beem/account.py index aefe3b655a01bcf0398dad55fae8814489eceabc..a894a7efbefbe5cbf2b03caa3e39ad085c546140 100644 --- a/beem/account.py +++ b/beem/account.py @@ -301,13 +301,13 @@ class Account(BlockchainObject): def sp(self): """ Returns the accounts Steem Power """ - return self.get_steem_power() + return self.get_token_power() @property - def hp(self): - """ Returns the accounts Hive Power + def tp(self): + """ Returns the accounts Hive/Steem Power """ - return self.get_steem_power() + return self.get_token_power() @property def vp(self): @@ -350,7 +350,7 @@ class Account(BlockchainObject): t.add_row(["Vote Value", "%.2f $" % (self.get_voting_value_SBD())]) t.add_row(["Last vote", "%s ago" % last_vote_time_str]) t.add_row(["Full in ", "%s" % (self.get_recharge_time_str())]) - t.add_row(["Steem Power", "%.2f %s" % (self.get_steem_power(), self.blockchain.token_symbol)]) + t.add_row(["Token Power", "%.2f %s" % (self.get_token_power(), self.blockchain.token_symbol)]) t.add_row(["Balance", "%s, %s" % (str(self.balances["available"][0]), str(self.balances["available"][1]))]) if False and bandwidth is not None and bandwidth["allocated"] is not None and bandwidth["allocated"] > 0: t.add_row(["Remaining Bandwidth", "%.2f %%" % (remaining)]) @@ -383,7 +383,7 @@ class Account(BlockchainObject): ret += "--- Downvoting Power ---\n" ret += "%.2f %% \n" % (self.get_downvoting_power()) ret += "--- Balance ---\n" - ret += "%.2f SP, " % (self.get_steem_power()) + ret += "%.2f SP, " % (self.get_token_power()) ret += "%s, %s\n" % (str(self.balances["available"][0]), str(self.balances["available"][1])) if False and bandwidth["allocated"] > 0: ret += "--- Bandwidth ---\n" @@ -542,50 +542,43 @@ class Account(BlockchainObject): vesting_shares -= min(int(self["vesting_withdraw_rate"]), int(self["to_withdraw"]) - int(self["withdrawn"])) return vesting_shares - def get_steem_power(self, onlyOwnSP=False): - """ Returns the account steem power + def get_token_power(self, only_own_vests=False): + """ Returns the account Hive/Steem power (amount of staked token + delegations) """ from beem import Steem if isinstance(self.blockchain, Steem): - return self.blockchain.vests_to_sp(self.get_vests(only_own_vests=onlyOwnSP)) + return self.blockchain.vests_to_sp(self.get_vests(only_own_vests=only_own_vests)) else: - return self.get_hive_power(onlyOwnSP=onlyOwnSP) + return self.blockchain.vests_to_hp(self.get_vests(only_own_vests=only_own_vests)) - def get_hive_power(self, onlyOwnSP=False): + def get_steem_power(self, onlyOwnSP=False): """ Returns the account steem power """ - return self.blockchain.vests_to_hp(self.get_vests(only_own_vests=onlyOwnSP)) + return self.get_token_power(only_own_vests=onlyOwnSP) - - def get_voting_value_SBD(self, post_rshares=0, voting_weight=100, voting_power=None, steem_power=None, not_broadcasted_vote=True): - """ Returns the account voting value in SBD + def get_voting_value(self, post_rshares=0, voting_weight=100, voting_power=None, token_power=None, not_broadcasted_vote=True): + """ Returns the account voting value in Hive/Steem token units """ if voting_power is None: voting_power = self.get_voting_power() - if steem_power is None: - sp = self.get_steem_power() + if token_power is None: + tp = self.get_token_power() else: - sp = steem_power + tp = token_power from beem import Steem if isinstance(self.blockchain, Steem): - voteValue = self.blockchain.sp_to_sbd(sp, post_rshares=post_rshares, voting_power=voting_power * 100, vote_pct=voting_weight * 100, not_broadcasted_vote=not_broadcasted_vote) + voteValue = self.blockchain.sp_to_sbd(tp, post_rshares=post_rshares, voting_power=voting_power * 100, vote_pct=voting_weight * 100, not_broadcasted_vote=not_broadcasted_vote) else: - voteValue = self.blockchain.hp_to_hbd(sp, post_rshares=post_rshares, voting_power=voting_power * 100, vote_pct=voting_weight * 100, not_broadcasted_vote=not_broadcasted_vote) + voteValue = self.blockchain.hp_to_hbd(tp, post_rshares=post_rshares, voting_power=voting_power * 100, vote_pct=voting_weight * 100, not_broadcasted_vote=not_broadcasted_vote) return voteValue - def get_voting_value_HBD(self, post_rshares=0, voting_weight=100, voting_power=None, hive_power=None, not_broadcasted_vote=True): - """ Returns the account voting value in HBD + def get_voting_value_SBD(self, post_rshares=0, voting_weight=100, voting_power=None, steem_power=None, not_broadcasted_vote=True): + """ Returns the account voting value in SBD """ - if voting_power is None: - voting_power = self.get_voting_power() - if hive_power is None: - hp = self.get_hive_power() - else: - hp = hive_power - voteValue = self.blockchain.hp_to_hbd(hp, post_rshares=post_rshares, voting_power=voting_power * 100, vote_pct=voting_weight * 100, not_broadcasted_vote=not_broadcasted_vote) - return voteValue + return self.get_voting_value(post_rshares=post_rshares, voting_weight=voting_weight, voting_power=voting_power, + token_power=steem_power, not_broadcasted_vote=not_broadcasted_vote) - def get_vote_pct_for_SBD(self, sbd, voting_power=None, steem_power=None, not_broadcasted_vote=True): + def get_vote_pct_for_SBD(self, sbd, post_rshares=0, voting_power=None, steem_power=None, not_broadcasted_vote=True): """ Returns the voting percentage needed to have a vote worth a given number of SBD. If the returned number is bigger than 10000 or smaller than -10000, @@ -594,25 +587,37 @@ class Account(BlockchainObject): :param sbd: The amount of SBD in vote value :type sbd: str, int, amount.Amount + """ + return self.get_vote_pct_for_vote_value(sbd, post_rshares=post_rshares, voting_power=voting_power, token_power=steem_power, not_broadcasted_vote=not_broadcasted_vote) + + def get_vote_pct_for_vote_value(self, token_units, post_rshares=0, voting_power=None, token_power=None, not_broadcasted_vote=True): + """ Returns the voting percentage needed to have a vote worth a given number of Hive/Steem token units + + If the returned number is bigger than 10000 or smaller than -10000, + the given SBD value is too high for that account + + :param token_units: The amount of HBD/SBD in vote value + :type token_units: str, int, amount.Amount + """ if voting_power is None: voting_power = self.get_voting_power() - if steem_power is None: - steem_power = self.get_steem_power() + if token_power is None: + token_power = self.get_token_power() - if isinstance(sbd, Amount): - sbd = Amount(sbd, blockchain_instance=self.blockchain) - elif isinstance(sbd, string_types): - sbd = Amount(sbd, blockchain_instance=self.blockchain) + if isinstance(token_units, Amount): + token_units = Amount(token_units, blockchain_instance=self.blockchain) + elif isinstance(token_units, string_types): + token_units = Amount(token_units, blockchain_instance=self.blockchain) else: - sbd = Amount(sbd, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain) - if sbd['symbol'] != self.blockchain.backed_token_symbol: - raise AssertionError('Should input SBD, not any other asset!') + token_units = Amount(token_units, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain) + if token_units['symbol'] != self.blockchain.backed_token_symbol: + raise AssertionError('Should input %s, not any other asset!' % self.blockchain.backed_token_symbol) from beem import Steem if isinstance(self.blockchain, Steem): - vote_pct = self.blockchain.rshares_to_vote_pct(self.blockchain.sbd_to_rshares(sbd, not_broadcasted_vote=not_broadcasted_vote), voting_power=voting_power * 100, steem_power=steem_power) + vote_pct = self.blockchain.rshares_to_vote_pct(self.blockchain.sbd_to_rshares(token_units, not_broadcasted_vote=not_broadcasted_vote), post_rshares=post_rshares, voting_power=voting_power * 100, steem_power=token_power) else: - vote_pct = self.blockchain.rshares_to_vote_pct(self.blockchain.hbd_to_rshares(sbd, not_broadcasted_vote=not_broadcasted_vote), voting_power=voting_power * 100, hive_power=steem_power) + vote_pct = self.blockchain.rshares_to_vote_pct(self.blockchain.hbd_to_rshares(token_units, not_broadcasted_vote=not_broadcasted_vote), post_rshares=post_rshares, voting_power=voting_power * 100, hive_power=token_power) return vote_pct def get_creator(self): @@ -3453,7 +3458,7 @@ class AccountsObject(list): for f in self: rep.append(f.rep) own_mvest.append(float(f.balances["available"][2]) / 1e6) - eff_sp.append(f.get_steem_power()) + eff_sp.append(f.get_token_power()) last_vote = addTzInfo(datetime.utcnow()) - (f["last_vote_time"]) if last_vote.days >= 365: no_vote += 1 diff --git a/beem/blockchaininstance.py b/beem/blockchaininstance.py index c8fcbc48276195bd5b5a249d2ebbbb8c528093f7..0754188c84093cf81658d1ee918bbab82f088b16 100644 --- a/beem/blockchaininstance.py +++ b/beem/blockchaininstance.py @@ -608,6 +608,23 @@ class BlockChainInstance(object): vote_claim = post_rshares_curve_after_vote - post_rshares_curve return vote_claim + def _calc_revert_vote_claim(self, vote_claim, post_rshares): + post_rshares_normalized = post_rshares + CURVE_CONSTANT + post_rshares_curve = (post_rshares_normalized * post_rshares_normalized - SQUARED_CURVE_CONSTANT) / (post_rshares + CURVE_CONSTANT_X4) + post_rshares_curve_after_vote = vote_claim + post_rshares_curve + + a = 1 + b = (-post_rshares_curve_after_vote + 2 * post_rshares_normalized) + c = (post_rshares_normalized * post_rshares_normalized - SQUARED_CURVE_CONSTANT) - post_rshares_curve_after_vote * (post_rshares + CURVE_CONSTANT_X4) + # (effective_vote_rshares * effective_vote_rshares) + effective_vote_rshares * (-post_rshares_curve_after_vote + 2 * post_rshares_normalized) + ((post_rshares_normalized * post_rshares_normalized - SQUARED_CURVE_CONSTANT) - post_rshares_curve_after_vote * (post_rshares + CURVE_CONSTANT_X4)) = 0 + + x1 = (-b + math.sqrt(b*b-4*a*c)) / (2*a) + x2 = (-b - math.sqrt(b*b-4*a*c)) / (2*a) + if x1 > 0: + return x1 + else: + return x2 + def vests_to_rshares(self, vests, voting_power=STEEM_100_PERCENT, vote_pct=STEEM_100_PERCENT, subtract_dust_threshold=True, use_stored_data=True): """ Obtain the r-shares from vests diff --git a/beem/hive.py b/beem/hive.py index 672e02b754a2e6b32c0ea7bc63cda0ddd8995f9e..6726e4e52f9b7ff1b7efefb7f79e56d7d11f8e6b 100644 --- a/beem/hive.py +++ b/beem/hive.py @@ -332,7 +332,7 @@ class Hive(BlockChainInstance): rshares = recent_claims * float(hbd) / ((float(reward_balance) * float(median_price)) - float(hbd)) return int(rshares) - def rshares_to_vote_pct(self, rshares, hive_power=None, vests=None, voting_power=STEEM_100_PERCENT, use_stored_data=True): + def rshares_to_vote_pct(self, rshares, post_rshares=0, hive_power=None, vests=None, voting_power=STEEM_100_PERCENT, use_stored_data=True): """ Obtain the voting percentage for a desired rshares value for a given Hive Power or vesting shares and voting_power Give either hive_power or vests, not both. @@ -357,6 +357,8 @@ class Hive(BlockChainInstance): if self.hardfork >= 20: rshares += math.copysign(self.get_dust_threshold(use_stored_data=use_stored_data), rshares) + rshares = math.copysign(self._calc_revert_vote_claim(abs(rshares), post_rshares), rshares) + max_vote_denom = self._max_vote_denom(use_stored_data=use_stored_data) used_power = int(math.ceil(abs(rshares) * STEEM_100_PERCENT / vests)) @@ -365,7 +367,7 @@ class Hive(BlockChainInstance): vote_pct = used_power * STEEM_100_PERCENT / (60 * 60 * 24) / voting_power return int(math.copysign(vote_pct, rshares)) - def hbd_to_vote_pct(self, hbd, hive_power=None, vests=None, voting_power=STEEM_100_PERCENT, not_broadcasted_vote=True, use_stored_data=True): + def hbd_to_vote_pct(self, hbd, post_rshares=0, hive_power=None, vests=None, voting_power=STEEM_100_PERCENT, not_broadcasted_vote=True, use_stored_data=True): """ Obtain the voting percentage for a desired HBD value for a given Hive Power or vesting shares and voting power Give either Hive Power or vests, not both. @@ -392,7 +394,7 @@ class Hive(BlockChainInstance): if hbd['symbol'] != self.hbd_symbol: raise AssertionError() rshares = self.hbd_to_rshares(hbd, not_broadcasted_vote=not_broadcasted_vote, use_stored_data=use_stored_data) - return self.rshares_to_vote_pct(rshares, hive_power=hive_power, vests=vests, voting_power=voting_power, use_stored_data=use_stored_data) + return self.rshares_to_vote_pct(rshares, post_rshares=post_rshares, hive_power=hive_power, vests=vests, voting_power=voting_power, use_stored_data=use_stored_data) @property def chain_params(self): diff --git a/beem/steem.py b/beem/steem.py index ea58d5511a24ce81cf39edc13d8e1af4cf6b919c..21c7ace172d9872e090f541d86188bd011680766 100644 --- a/beem/steem.py +++ b/beem/steem.py @@ -343,7 +343,7 @@ class Steem(BlockChainInstance): rshares = recent_claims * float(sbd) / ((float(reward_balance) * float(median_price)) - float(sbd)) return int(rshares) - def rshares_to_vote_pct(self, rshares, steem_power=None, vests=None, voting_power=STEEM_100_PERCENT, use_stored_data=True): + def rshares_to_vote_pct(self, rshares, post_rshares=0, steem_power=None, vests=None, voting_power=STEEM_100_PERCENT, use_stored_data=True): """ Obtain the voting percentage for a desired rshares value for a given Steem Power or vesting shares and voting_power Give either steem_power or vests, not both. @@ -368,6 +368,8 @@ class Steem(BlockChainInstance): if self.hardfork >= 20: rshares += math.copysign(self.get_dust_threshold(use_stored_data=use_stored_data), rshares) + rshares = math.copysign(self._calc_revert_vote_claim(abs(rshares), post_rshares), rshares) + max_vote_denom = self._max_vote_denom(use_stored_data=use_stored_data) used_power = int(math.ceil(abs(rshares) * STEEM_100_PERCENT / vests)) @@ -376,7 +378,7 @@ class Steem(BlockChainInstance): vote_pct = used_power * STEEM_100_PERCENT / (60 * 60 * 24) / voting_power return int(math.copysign(vote_pct, rshares)) - def sbd_to_vote_pct(self, sbd, steem_power=None, vests=None, voting_power=STEEM_100_PERCENT, not_broadcasted_vote=True, use_stored_data=True): + def sbd_to_vote_pct(self, sbd, post_rshares=0, steem_power=None, vests=None, voting_power=STEEM_100_PERCENT, not_broadcasted_vote=True, use_stored_data=True): """ Obtain the voting percentage for a desired SBD value for a given Steem Power or vesting shares and voting power Give either Steem Power or vests, not both. @@ -403,7 +405,7 @@ class Steem(BlockChainInstance): if sbd['symbol'] != self.sbd_symbol: raise AssertionError() rshares = self.sbd_to_rshares(sbd, not_broadcasted_vote=not_broadcasted_vote, use_stored_data=use_stored_data) - return self.rshares_to_vote_pct(rshares, steem_power=steem_power, vests=vests, voting_power=voting_power, use_stored_data=use_stored_data) + return self.rshares_to_vote_pct(rshares, post_rshares=post_rshares, steem_power=steem_power, vests=vests, voting_power=voting_power, use_stored_data=use_stored_data) @property def chain_params(self): diff --git a/tests/beem/test_account.py b/tests/beem/test_account.py index c606659d8d19031aa237461480d7a0caccb9c7f0..65d29a58f12d9d2519b60d2709bb35b83ae542ea 100644 --- a/tests/beem/test_account.py +++ b/tests/beem/test_account.py @@ -269,7 +269,7 @@ class Testcases(unittest.TestCase): vp = account.get_voting_power() self.assertTrue(vp >= 0) self.assertTrue(vp <= 100) - sp = account.get_steem_power() + sp = account.get_token_power() self.assertTrue(sp >= 0) vv = account.get_voting_value_SBD() self.assertTrue(vv >= 0) @@ -498,10 +498,10 @@ class Testcases(unittest.TestCase): self.assertTrue(replies[0].is_comment()) self.assertTrue(replies[0].depth > 0) - def test_get_vote_pct_for_SBD(self): + def test_get_vote_pct_for_vote_value(self): account = self.account for vote_pwr in range(5, 100, 5): - self.assertTrue(9900 <= account.get_vote_pct_for_SBD(account.get_voting_value_SBD(voting_power=vote_pwr), voting_power=vote_pwr) <= 11000) + self.assertTrue(9900 <= account.get_vote_pct_for_vote_value(account.get_voting_value(voting_power=vote_pwr), voting_power=vote_pwr) <= 11000) def test_list_subscriptions(self): stm = self.bts diff --git a/tests/beem/test_hive.py b/tests/beem/test_hive.py index 21e742f1c81aa7c6b39b01c969ca2ca148919a3d..b758c8107320a36701f3bae1e84e92011e7a0880 100644 --- a/tests/beem/test_hive.py +++ b/tests/beem/test_hive.py @@ -410,7 +410,7 @@ class Testcases(unittest.TestCase): def test_hp_to_rshares(self): stm = self.bts - rshares = stm.hp_to_rshares(stm.vests_to_hp(1e6)) + rshares = stm.hp_to_rshares(stm.vests_to_hp(1e6), post_rshares=1e19) self.assertTrue(abs(rshares - 20000000000.0) < 2) def test_rshares_to_vests(self): diff --git a/tests/beem/test_steem.py b/tests/beem/test_steem.py index adf90fcff62bbcfa79a7a131810c78a00c9e2fe5..f56fb5b256329b5ad3264a480710fe1cd20b9b85 100644 --- a/tests/beem/test_steem.py +++ b/tests/beem/test_steem.py @@ -409,7 +409,7 @@ class Testcases(unittest.TestCase): def test_sp_to_rshares(self): stm = self.bts - rshares = stm.sp_to_rshares(stm.vests_to_sp(1e6)) + rshares = stm.sp_to_rshares(stm.vests_to_sp(1e6), post_rshares=1e19) self.assertTrue(abs(rshares - 20000000000.0) < 2) def test_rshares_to_vests(self):