From 63fb0831db101a226a02ab022dd5c36ea7dd7c32 Mon Sep 17 00:00:00 2001
From: holgern <holgernahrstaedt@gmx.de>
Date: Wed, 1 Apr 2020 22:48:41 +0200
Subject: [PATCH] Fix curation and author reward calculation

---
 .circleci/config.yml | 40 +++++++---------------------------------
 CHANGELOG.rst        |  2 ++
 beem/account.py      |  4 +---
 beem/cli.py          | 38 +++++++++++++++++++++++++-------------
 beem/comment.py      | 15 +++++++++------
 beem/vote.py         |  7 ++++++-
 tox.ini              |  2 +-
 7 files changed, 51 insertions(+), 57 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 978aa795..55eca99e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -56,9 +56,9 @@ jobs:
       #        tox -e upload_coverage
       #      fi
 
-  build-python2.7:
+  build-python3.8:
     docker:
-      - image: circleci/python:2.7
+      - image: circleci/python:3.8
     working_directory: ~/repo
     steps:
       - checkout
@@ -77,30 +77,7 @@ jobs:
       - run:
           name: run tests
           command: |
-            tox -e py27
-
-  build-python3.4:
-    docker:
-      - image: circleci/python:3.4
-    working_directory: ~/repo
-    steps:
-      - checkout
-      # Download and cache dependencies
-      - restore_cache:
-          keys:
-          - v1-dependencies-{{ checksum "requirements-test.txt" }}
-          # fallback to using the latest cache if no exact match is found
-          - v1-dependencies-
-      - run:
-          name: install dependencies
-          command: |
-            sudo python -m pip install --upgrade -r requirements-test.txt
-            sudo python -m pip install --upgrade secp256k1
-
-      - run:
-          name: run tests
-          command: |
-            tox -e py34
+            tox -e py38
 
   build-python3.5:
     docker:
@@ -150,15 +127,12 @@ workflows:
   build:
     jobs:
       - build-python3.6
-      - build-python2.7:
-          requires:
-            - build-python3.6
-      - build-python3.4:
-          requires:
-            - build-python2.7
       - build-python3.5:
           requires:
-            - build-python3.4
+            - build-python3.6
       - build-python3.7:
           requires:
             - build-python3.5
+      - build-python3.8:
+          requires:
+            - build-python3.7
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 758b0d30..45e13142 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,6 +9,8 @@ Changelog
 * Discussions has been fixed
 * raw_data parameter added to all discussions
 * beempy curation, beempy votes and beempy pending has been fixed
+* Votes table improved
+* fix curation and author reward calculation
 
 0.22.11
 -------
diff --git a/beem/account.py b/beem/account.py
index c7de1357..b5197f55 100644
--- a/beem/account.py
+++ b/beem/account.py
@@ -1513,7 +1513,7 @@ class Account(BlockchainObject):
         else:
             return self.steem.rpc.get_expiring_vesting_delegations(account, formatTimeString(after), limit)
 
-    def get_account_votes(self, account=None):
+    def get_account_votes(self, account=None, start_author="", start_permlink=""):
         """ Returns all votes that the account has done
 
             :rtype: list
@@ -1543,8 +1543,6 @@ class Account(BlockchainObject):
         #    vote_list = self.steem.rpc.get_account_votes(account)
         # if isinstance(vote_list, dict) and "error" in vote_list:
         self.steem.rpc.set_next_node_on_empty_reply(True)
-        start_author = ""
-        start_permlink = ""
         vote_list = []
         finished = False
         while not finished:
diff --git a/beem/cli.py b/beem/cli.py
index bfe9f0c7..85d6217e 100644
--- a/beem/cli.py
+++ b/beem/cli.py
@@ -33,7 +33,7 @@ from beem.asset import Asset
 from beem.witness import Witness, WitnessesRankedByVote, WitnessesVotedByAccount
 from beem.blockchain import Blockchain
 from beem.utils import formatTimeString, construct_authorperm, derive_beneficiaries, derive_tags, seperate_yaml_dict_from_body
-from beem.vote import AccountVotes, ActiveVotes
+from beem.vote import AccountVotes, ActiveVotes, Vote
 from beem import exceptions
 from beem.version import version as __version__
 from beem.asciichart import AsciiChart
@@ -2516,7 +2516,9 @@ def votes(account, direction, outgoing, incoming, days, export):
         account = Account(account, steem_instance=stm)
         votes_list = []
         for v in account.history(start=limit_time, only_ops=["vote"]):
-            votes_list.append(v)
+            vote = Vote(v, steem_instance=stm)
+            vote.refresh()
+            votes_list.append(vote)
         votes = ActiveVotes(votes_list, steem_instance=stm)
         in_votes_str = votes.printAsTable(votee=account["name"], return_str=True)
     if export:
@@ -2567,13 +2569,13 @@ def curation(authorperm, account, limit, min_vote, max_vote, min_performance, ma
         if not account:
             account = stm.config["default_account"]
         utc = pytz.timezone('UTC')
-        limit_time = utc.localize(datetime.utcnow()) - timedelta(days=days)
+        limit_time = utc.localize(datetime.utcnow()) - timedelta(days=7)
         votes = AccountVotes(account, start=limit_time, steem_instance=stm)
-        authorperm_list = [Comment(vote.authorperm, steem_instance=stm) for vote in votes]
+        authorperm_list = [vote.authorperm for vote in votes]
         if authorperm.isdigit():
             if len(authorperm_list) < int(authorperm):
                 raise ValueError("Authorperm id must be lower than %d" % (len(authorperm_list) + 1))
-            authorperm_list = [authorperm_list[int(authorperm) - 1]["authorperm"]]
+            authorperm_list = [authorperm_list[int(authorperm) - 1]]
             all_posts = False
         else:
             all_posts = True
@@ -2937,8 +2939,9 @@ def rewards(accounts, only_sum, post, comment, curation, length, author, permlin
 @click.option('--author', '-a', help='Show the author for each entry', is_flag=True, default=False)
 @click.option('--permlink', '-e', help='Show the permlink for each entry', is_flag=True, default=False)
 @click.option('--title', '-t', help='Show the title for each entry', is_flag=True, default=False)
-@click.option('--days', '-d', default=1., help="Limit shown rewards by this amount of days (default: 1), max is 7 days.")
-def pending(accounts, only_sum, post, comment, curation, length, author, permlink, title, days):
+@click.option('--days', '-d', default=7., help="Limit shown rewards by this amount of days (default: 7), max is 7 days.")
+@click.option('--from', '-f', '_from', default=0., help="Start day from which on rewards are shown (default: 0), max is 7 days.")
+def pending(accounts, only_sum, post, comment, curation, length, author, permlink, title, days, _from):
     """ Lists pending rewards
     """
     stm = shared_steem_instance()
@@ -2953,12 +2956,20 @@ def pending(accounts, only_sum, post, comment, curation, length, author, permlin
         days = 1
     if days > 7:
         days = 7
+    if _from < 0:
+        _from = 0
+    if _from > 7:
+        _from = 7
+    if _from + days > 7:
+        days = 7 - _from
     sp_symbol = "SP"
     if stm.is_hive:
         sp_symbol = "HP"
 
     utc = pytz.timezone('UTC')
-    limit_time = utc.localize(datetime.utcnow()) - timedelta(days=days)
+    max_limit_time = utc.localize(datetime.utcnow()) - timedelta(days=7)
+    limit_time = utc.localize(datetime.utcnow()) - timedelta(days=_from + days)
+    start_time = utc.localize(datetime.utcnow()) - timedelta(days=_from)
     for account in accounts:
         sum_reward = [0, 0, 0, 0]
         account = Account(account, steem_instance=stm)
@@ -2981,10 +2992,11 @@ def pending(accounts, only_sum, post, comment, curation, length, author, permlin
         rows = []
         c_list = {}
         start_op = account.estimate_virtual_op_num(limit_time)
+        stop_op = account.estimate_virtual_op_num(start_time)
         if start_op > 0:
             start_op -= 1
-        progress_length = (account.virtual_op_count() - start_op) / 1000
-        with click.progressbar(map(Comment, account.history(start=start_op, use_block_num=False, only_ops=["comment"])), length=progress_length) as comment_hist:
+        progress_length = (stop_op - start_op) / 1000
+        with click.progressbar(map(Comment, account.history(start=start_op, stop=stop_op, use_block_num=False, only_ops=["comment"])), length=progress_length) as comment_hist:
             for v in comment_hist:
                 try:
                     v.refresh()
@@ -3021,20 +3033,20 @@ def pending(accounts, only_sum, post, comment, curation, length, author, permlin
                         permlink_row = v.permlink
                 rows.append([v["author"],
                              permlink_row,
-                             ((v["created"] - limit_time).total_seconds() / 60 / 60 / 24),
+                             ((v["created"] - max_limit_time).total_seconds() / 60 / 60 / 24),
                              (payout_SBD),
                              (payout_SP),
                              (liquid_USD),
                              (invested_USD)])
         if curation:
-            votes = AccountVotes(account, start=limit_time, steem_instance=stm)
+            votes = AccountVotes(account, start=limit_time, stop=start_time, steem_instance=stm)
             for vote in votes:
                 authorperm = construct_authorperm(vote["author"], vote["permlink"])
                 c = Comment(authorperm, steem_instance=stm)
                 rewards = c.get_curation_rewards()
                 if not rewards["pending_rewards"]:
                     continue
-                days_to_payout = ((c["created"] - limit_time).total_seconds() / 60 / 60 / 24)
+                days_to_payout = ((c["created"] - max_limit_time).total_seconds() / 60 / 60 / 24)
                 if days_to_payout < 0:
                     continue
                 payout_SP = rewards["active_votes"][account["name"]]
diff --git a/beem/comment.py b/beem/comment.py
index cd368545..0fb8c5fe 100644
--- a/beem/comment.py
+++ b/beem/comment.py
@@ -354,7 +354,7 @@ class Comment(BlockchainObject):
         return K * vote_value_SBD * t * math.sqrt(estimated_value_SBD)
 
     def get_curation_penalty(self, vote_time=None):
-        """ If post is less than 15 minutes old, it will incur a curation
+        """ If post is less than 5 minutes old, it will incur a curation
             reward penalty.
 
             :param datetime vote_time: A vote time can be given and the curation
@@ -453,6 +453,8 @@ class Comment(BlockchainObject):
     def get_author_rewards(self):
         """ Returns the author rewards.
 
+            
+            
             Example::
 
                 {
@@ -468,12 +470,12 @@ class Comment(BlockchainObject):
                     "payout_SP": Amount(0, self.steem.steem_symbol, steem_instance=self.steem),
                     "payout_SBD": Amount(0, self.steem.sbd_symbol, steem_instance=self.steem),
                     "total_payout_SBD": Amount(self["total_payout_value"], steem_instance=self.steem)}
-
+        author_reward_factor = 0.5
         median_hist = self.steem.get_current_median_history()
         if median_hist is not None:
             median_price = Price(median_hist, steem_instance=self.steem)
         beneficiaries_pct = self.get_beneficiaries_pct()
-        curation_tokens = self.reward * 0.25
+        curation_tokens = self.reward * author_reward_factor
         author_tokens = self.reward - curation_tokens
         curation_rewards = self.get_curation_rewards()
         if self.steem.hardfork >= 20 and median_hist is not None:
@@ -490,7 +492,7 @@ class Comment(BlockchainObject):
             return {'pending_rewards': True, "total_payout": author_tokens}
 
     def get_curation_rewards(self, pending_payout_SBD=False, pending_payout_value=None):
-        """ Returns the curation rewards.
+        """ Returns the curation rewards. The split between creator/curator is currently 50%/50%.
 
             :param bool pending_payout_SBD: If True, the rewards are returned in SBD and not in STEEM (default is False)
             :param pending_payout_value: When not None this value instead of the current
@@ -523,6 +525,7 @@ class Comment(BlockchainObject):
             median_price = Price(median_hist, steem_instance=self.steem)
         pending_rewards = False
         active_votes_list = self.get_votes()
+        curator_reward_factor = 0.5
         
         if "total_vote_weight" in self:
             total_vote_weight = self["total_vote_weight"]
@@ -551,9 +554,9 @@ class Comment(BlockchainObject):
             elif isinstance(pending_payout_value, str):
                 pending_payout_value = Amount(pending_payout_value, steem_instance=self.steem)
             if pending_payout_SBD or median_hist is None:
-                max_rewards = (pending_payout_value * 0.25)
+                max_rewards = (pending_payout_value * curator_reward_factor)
             else:
-                max_rewards = median_price.as_base(self.steem.steem_symbol) * (pending_payout_value * 0.25)
+                max_rewards = median_price.as_base(self.steem.steem_symbol) * (pending_payout_value * curator_reward_factor)
             unclaimed_rewards = max_rewards.copy()
             pending_rewards = True
 
diff --git a/beem/vote.py b/beem/vote.py
index 93491977..96927156 100644
--- a/beem/vote.py
+++ b/beem/vote.py
@@ -259,12 +259,15 @@ class VotesObject(list):
             if (start is None or d_time >= start) and (stop is None or d_time <= stop) and\
                 (start_percent is None or percent >= start_percent) and (stop_percent is None or percent <= stop_percent) and\
                 (voter is None or vote["voter"] == voter) and (votee is None or vote.votee == votee):
+                percent = vote.get('percent', '')
+                if percent == '':
+                    percent = vote.get('vote_percent', '')
                 t.add_row([vote['voter'],
                            vote.votee,
                            str(round(vote.sbd, 2)).ljust(5) + "$",
                            timestr,
                            vote.get("rshares", ""),
-                           str(vote.get('percent', '')),
+                           str(percent),
                            str(vote['weight'])])
 
         if return_str:
@@ -282,6 +285,8 @@ class VotesObject(list):
                 start = None
                 stop = None
             percent = vote.get('percent', '')
+            if percent == '':
+                percent = vote.get('vote_percent', '') 
             if percent == '':
                 start_percent = None
                 stop_percent = None
diff --git a/tox.ini b/tox.ini
index 5e8d759d..0a4350ae 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py{27,34,35,36,37}
+envlist = py{27,35,36,37,38}
 skip_missing_interpreters = true
 
 [testenv]
-- 
GitLab