Exemple #1
0
class SteemConnect:
    def __init__(self,
                 client_id="",
                 client_secret="",
                 callback_url="",
                 permissions="login,offline,vote"):
        self.client_id = client_id
        self.client_secret = client_secret
        self.callback_url = callback_url
        self.permissions = permissions
        self.sc = None
        self.accesstoken = None
        self.msg = Msg("simplesteem.log", "~", "quiet")

    def steemconnect(self, accesstoken=None):
        ''' Initializes the SteemConnect Client
        class
        '''
        if self.sc is not None:
            return self.sc
        if accesstoken is not None:
            self.accesstoken = accesstoken
        if self.accesstoken is None:
            self.sc = Client(client_id=self.client_id,
                             client_secret=self.client_secret)
        else:
            self.sc = Client(access_token=self.accesstoken,
                             client_id=self.client_id,
                             client_secret=self.client_secret)
        return self.sc

    def get_token(self, code=None):
        ''' Uses a SteemConnect refresh token
        to retreive an access token
        '''
        tokenobj = self.steemconnect().get_access_token(code)
        for t in tokenobj:
            if t == 'error':
                self.msg.error_message(str(tokenobj[t]))
                return False
            elif t == 'access_token':
                self.username = tokenobj['username']
                self.refresh_token = tokenobj['refresh_token']
                return tokenobj[t]

    def auth_url(self):
        ''' Returns the SteemConnect url
        used for authentication
        '''
        return self.steemconnect().get_login_url(self.callback_url,
                                                 self.permissions,
                                                 "get_refresh_token=True")

    def vote(self, voter, author, permlink, voteweight):
        ''' Uses a SteemConnect accses token
        to vote.
        '''
        vote = Vote(voter, author, permlink, voteweight)
        result = self.steemconnect().broadcast([vote.to_operation_structure()])
        return result
Exemple #2
0
 def __init__(self, filename, path, screenmode):
     self.msg = Msg(filename, path, screenmode)
     self.total_vesting_fund_steem = None
     self.total_vesting_shares = None
     self.vote_power_reserve_rate = None
     self.info = None
     self.currentnode = 0
Exemple #3
0
 def __init__ (self, dbuser, dbpass, dbname):
     self.dbuser = dbuser
     self.dbpass = dbpass
     self.dbname = dbname
     self.msg = Msg(default.logfilename, 
                     default.logpath, 
                     default.msgmode)
Exemple #4
0
class DB:
    def __init__(self, dbuser, dbpass, dbname):
        self.dbuser = dbuser
        self.dbpass = dbpass
        self.dbname = dbname
        self.msg = Msg(default.logfilename, default.logpath, default.msgmode)
        self.db = None
        self.cursor = None
        self.dbresults = none

    def open_db(self):
        """ opens a database connection
        """
        self.db = pymysql.connect("localhost", self.dbuser, self.dbpass,
                                  self.dbname)
        self.cursor = self.db.cursor()

    def get_results(self, sql, *args):
        """ Gets the results of an SQL statement
        """
        self.open_db()
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.dbresults = self.cursor.fetchall()
        except Exception as e:
            self.msg.error_message(e)
            self.dbresults = False
            self.db.rollback()
            return False
        else:
            return len(self.dbresults)
        finally:
            # Every call to this method from the other
            # classes in this package only takes place once
            # so we can safely close the DB every time
            # This can be moved to the deconstructor
            # if functionality demands multiple calls to
            # this method
            self.db.close()

    def commit(self, sql, *args):
        """ Commits the actions of an SQL
        statement to the database
        """
        self.open_db()
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.db.commit()
        except Exception as e:
            self.msg.error_message(e)
            self.db.rollback()
            return False
        else:
            return True
        finally:
            self.db.close()


# EOF
Exemple #5
0
class DB():


    def __init__(self, dbuser, dbpass, dbname):
        self.dbuser = dbuser
        self.dbpass = dbpass
        self.dbname = dbname
        self.msg = Msg(default.logfilename, 
                        default.logpath, 
                        default.msgmode)



    def open_db(self):
        ''' opens a database connection
        '''
        self.db = pymysql.connect("localhost",
                                    self.dbuser,
                                    self.dbpass,
                                    self.dbname)
        self.cursor = self.db.cursor()



    def get_results(self, sql, *args):
        ''' Gets the results of an SQL statement
        '''
        self.open_db()
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.dbresults = self.cursor.fetchall()
        except Exception as e:
            self.msg.error_message(e)
            self.dbresults = False
            self.db.rollback()
            return False
        else:
            return len(self.dbresults)
        finally:
            self.db.close()



    def commit(self, sql, *args):
        ''' Commits the actions of an SQL 
        statement to the database
        '''
        self.open_db()
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.db.commit()
        except Exception as e:
            self.msg.error_message(e)
            self.db.rollback()
            return False
        else:
            return True
        finally:
            self.db.close()
Exemple #6
0
 def __init__(self, dbuser, dbpass, dbname):
     self.dbuser = dbuser
     self.dbpass = dbpass
     self.dbname = dbname
     self.msg = Msg(default.logfilename, default.logpath, default.msgmode)
     self.db = None
     self.cursor = None
     self.dbresults = none
Exemple #7
0
 def __init__(self, dbuser, dbpass, dbname):
     self.dbuser = dbuser
     self.dbpass = dbpass
     self.dbname = dbname
     self.msg = Msg(default.logfilename, default.logpath, default.msgmode)
     self.sendto = None
     self.inviter = None
     self.invitee = None
     self.errmsg = None
Exemple #8
0
 def __init__(self):
     self.msg = Msg(default.logfilename,
                    default.logpath,
                    default.msgmode)
     self.db = axdb.AXdb(default.dbuser,
                         default.dbpass,
                         default.dbname)
     self.steem = SimpleSteem()
     self.react = Reaction()
Exemple #9
0
 def __init__(self, **kwargs):
     for key, value in kwargs.items():
         setattr(self, key, value)
     try:
         imp.find_module('config',
                         [os.path.dirname(os.path.realpath(__file__))])
     except ImportError:
         makeconfig.MakeConfig().setup()
     from simplesteem import config
     try:
         self.mainaccount
     except:
         self.mainaccount = config.mainaccount
     try:
         self.keys
     except:
         self.keys = config.keys
     try:
         self.nodes
     except:
         self.nodes = config.nodes
     try:
         self.client_id
     except:
         self.client_id = config.client_id
     try:
         self.client_secret
     except:
         self.client_secret = config.client_secret
     try:
         self.callback_url
     except:
         self.callback_url = config.callback_url
     try:
         self.permissions
     except:
         self.permissions = config.permissions
     try:
         self.logpath
     except:
         self.logpath = config.logpath
     try:
         self.screenmode
     except:
         self.screenmode = config.screenmode
     self.s = None
     self.c = None
     self.msg = Msg("simplesteem.log", self.logpath, self.screenmode)
     self.util = util.Util()
     self.connect = steemconnectutil.SteemConnect(self.client_id,
                                                  self.client_secret,
                                                  self.callback_url,
                                                  self.permissions)
     self.checkedaccount = None
Exemple #10
0
 def __init__(self,
              client_id="",
              client_secret="",
              callback_url="",
              permissions="login,offline,vote"):
     self.client_id = client_id
     self.client_secret = client_secret
     self.callback_url = callback_url
     self.permissions = permissions
     self.sc = None
     self.accesstoken = None
     self.msg = Msg("simplesteem.log", "~", "quiet")
Exemple #11
0
 def __init__(self):
     self.steem = SimpleSteem(client_id=default.client_id,
                              client_secret=default.client_secret,
                              callback_url=default.callback_url,
                              screenmode=default.msgmode)
     self.msg = Msg(default.logfilename,
                    default.logpath,
                    default.msgmode)
     self.response = None
     self.post_one = ""
     self.post_two = ""
     self.vote_cut = 0
Exemple #12
0
class DB():
    def __init__(self, dbuser, dbpass, dbname):
        self.dbuser = dbuser
        self.dbpass = dbpass
        self.dbname = dbname
        self.msg = Msg(default.logfilename, default.logpath, default.msgmode)

    def open_db(self):
        ''' opens a database connection
        '''
        self.db = pymysql.connect("localhost", self.dbuser, self.dbpass,
                                  self.dbname)
        self.cursor = self.db.cursor()

    def get_results(self, sql, *args):
        ''' Gets the results of an SQL statement
        '''
        self.open_db()
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.dbresults = self.cursor.fetchall()
        except Exception as e:
            self.msg.error_message(e)
            self.dbresults = False
            self.db.rollback()
            return False
        else:
            return len(self.dbresults)
        finally:
            self.db.close()

    def commit(self, sql, *args):
        ''' Commits the actions of an SQL 
        statement to the database
        '''
        self.open_db()
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.db.commit()
        except Exception as e:
            self.msg.error_message(e)
            self.db.rollback()
            return False
        else:
            return True
        finally:
            self.db.close()
 def __init__(self, debug=False, mode="verbose", botname="settings"):
     ''' Uses simplesteem and screenlogger from
         https://github.com/ArtoLabs/SimpleSteem
         https://github.com/ArtoLabs/ScreenLogger
     '''
     bot = importlib.import_module("." + botname, "delegatorbot")
     self.debug = debug
     self.cfg = bot.Config()
     self.msg = Msg(self.cfg.logfilename, self.cfg.logpath, mode)
     self.db = BotDB(self.cfg.dbusername, self.cfg.dbpass, self.cfg.dbname,
                     self.cfg.dbtable, self.cfg.dbposttable,
                     self.cfg.delegatortable)
     self.steem = SimpleSteem(mainaccount=self.cfg.mainaccount,
                              keys=self.cfg.keys,
                              screenmode=mode)
     self.voteweight = 0
     self.bidbot = None
Exemple #14
0
 def __init__(self):
     self.msg = Msg(default.logfilename, 
                     default.logpath, 
                     default.msgmode)
     self.db = axdb.AXdb(default.dbuser, 
                         default.dbpass, 
                         default.dbname)
     self.steem = SimpleSteem()
     self.react = Reaction()
Exemple #15
0
class DB:
    def __init__(self, dbuser, dbpass, dbname, logfilename, logpath, msgmode):
        self.msg = Msg(logfilename, logpath, msgmode)
        self.db = pymysql.connect("localhost", dbuser, dbpass, dbname)
        self.cursor = self.db.cursor()
        self.dbresults = None

    def __del__(self):
        """ opens a database connection
        """
        self.db.close()

    def get_results(self, sql, *args):
        """ Gets the results of an SQL statement
        """
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.dbresults = self.cursor.fetchall()
        except Exception as e:
            self.msg.error_message(e)
            self.dbresults = False
            self.db.rollback()
            return False
        else:
            return len(self.dbresults)

    def commit(self, sql, *args):
        """ Commits the actions of an SQL
        statement to the database
        """
        try:
            self.cursor.execute(pymysql.escape_string(sql), args)
            self.db.commit()
        except Exception as e:
            self.msg.error_message(e)
            self.db.rollback()
            return False
        else:
            return True
Exemple #16
0
class AXverify:
    def __init__(self):
        self.steem = SimpleSteem(client_id=default.client_id,
                                 client_secret=default.client_secret,
                                 callback_url=default.callback_url,
                                 screenmode=default.msgmode)
        self.msg = Msg(default.logfilename,
                       default.logpath,
                       default.msgmode)
        self.response = None
        self.post_one = ""
        self.post_two = ""
        self.vote_cut = 0

    def vote_on_it(self, voter, author, post, weight):
        """ Use the tokens in the database to vote on
        a post. If the vote fails, renews the token
        and tries again.
        """
        db = axdb.AXdb(default.dbuser,
                       default.dbpass,
                       default.dbname)
        if db.get_user_token(voter) is not False:
            accesstoken = db.dbresults[0][1]
            refreshtoken = db.dbresults[0][2]
        else:
            return False
        # If the vote fails then we renew the token
        if not self.sc_vote(voter, author, post, weight, accesstoken):
            print("Renewing token for " + voter)
            newtoken = self.renew_token(voter, refreshtoken)
            if newtoken is not False:
                return self.sc_vote(voter, author, post, weight, newtoken)
            else:
                self.msg.error_message("A NEW TOKEN COULD NOT BE CREATED")
                return False

    def sc_vote(self, voter, author, post, weight, token):
        """ Takes the given token and initializes SteemConnect
        to make a vote. Analyzes the result and prints the
        outcome to screen as well as returns a boolean result.
        """
        self.steem.connect.sc = None
        self.steem.connect.steemconnect(
            token)
        result = self.steem.connect.vote(
            voter,
            author,
            post,
            int(weight))
        try:
            result['error']
        # We use a broad exception clause to "catch" everything
        # that is not an error
        except:
            # The vote was successful
            print(str(voter) + " has voted on "
                  + str(post) + " "
                  + str(weight) + "%")
            return True
        else:
            self.msg.error_message(str(result))
            return False

    def renew_token(self, accountname, refreshtoken):
        """ If the access token has expired
        use the refresh token to get a new accss token.
        """
        if self.steem.verify_key(
                acctname="", tokenkey=refreshtoken):
            db.update_token(self.steem.username,
                            self.steem.accesstoken,
                            self.steem.refreshtoken)
            return self.steem.accesstoken
        else:
            return False

    def get_vote_value(self, acctname, voteweight=100,
                       votepower=0):
        """ Voteweight and votepower are entered 
        as a percentage value (1 to 100)
        If the default is used for votepower (0) 
        it is set by the system at the time
        the account last voted.
        """
        self.steem.check_balances(acctname)
        if votepower == 0:
            votepower = self.steem.votepower
        self.votevalue = self.steem.current_vote_value(
            lastvotetime=self.steem.lastvotetime,
            steempower=self.steem.steempower,
            voteweight=int(voteweight),
            votepower=int(votepower))
        self.voteweight = voteweight
        self.votepower = votepower
        return self.steem.rshares

    def verify_post(self, account1, account2):
        """ Gets only the most recent post, gets the 
        timestamp and finds the age of the post in days.
        Is the post too old? Did account2 
        vote on the post already?
        """
        identifier = self.steem.recent_post(account1)
        if identifier is False or identifier is None:
            self.msg.error_message("No post for " + account1)
            return False
        else:
            permlink = self.steem.util.permlink(identifier)
            votes = self.steem.vote_history(permlink[1], account1)
            for v in votes:
                if v['voter'] == account2:
                    self.msg.error_message(account2 +
                                           " has aready voted on " + permlink[1])
                    return False
        return permlink[1]

    def eligible_posts(self, account1, account2):
        """ Verify the posts of both accounts
        """
        post = self.verify_post(account1, account2)
        if post is False or post is None:
            self.msg.message(account1
                             + " does not have an eligible post.")
            return False
        else:
            self.post_one = post
        post = self.verify_post(account2, account1)
        if post is False or post is None:
            self.msg.message(account2
                             + " does not have an eligible post.")
            return False
        else:
            self.post_two = post
        return True

    def eligible_votes(self, account1, account2,
                       percentage, ratio, flag):
        """ If the flag is raised use the full voting 
        power to make the comparison rather
        than the current voting power. 
        If ratio was not acheived return false 
        Otherwise display approximate 
        upvote matches
        """
        if flag == 1:
            vpow = 100
        else:
            vpow = 0
        v1 = self.get_vote_value(account1, percentage, vpow)
        v2 = self.get_vote_value(account2, 100, vpow)
        v3 = ((v1 / v2) * 100) / float(ratio)
        v3a = round(v3, 2)
        exceeds = False
        if v3a < 1:
            v3 = 1
            exceeds = True
        if v3a > 100:
            v3 = 100
            exceeds = True
        self.msg.message(account2 + " needs to vote "
                         + str(v3a) + "% in order to meet " + account1)
        self.vote_cut = v3
        v4 = self.get_vote_value(account2, v3, vpow)
        v1s = self.steem.rshares_to_steem(v1)
        v4s = self.steem.rshares_to_steem(v4)
        if exceeds and flag != 2:
            if v3 == 1:
                v5 = v4 - v1
                v5s = self.steem.rshares_to_steem(v5)
                self.response = (account2 + "'s vote of " + str(v4s)
                                 + " will be larger than " + account1
                                 + "'s vote by: " + str(v5s))
                self.msg.message(self.response)
            if v3 == 100:
                v5 = v1 - v4
                v5s = self.steem.rshares_to_steem(v5)
                self.response = (account1 + "'s vote of " + str(v1s)
                                 + " will be larger than " + account2
                                 + "'s vote by: " + str(v5s))
                self.msg.message(self.response)
            return False
        else:
            self.msg.message(account1 + " will upvote $" + str(v1s)
                             + " and " + account2 + " will upvote $" + str(v4s))
            return True
Exemple #17
0
class AXverify:



    def __init__(self):
        self.msg = Msg(default.logfilename, 
                        default.logpath, 
                        default.msgmode)
        self.steem = SimpleSteem()
        self.response = None



    def get_vote_value (self, acctname, voteweight=100, 
                        votepower=0):
        ''' Voteweight and votepower are entered 
        as a percentage value (1 to 100)
        If the default is used for votepower (0) 
        it is set by the system at the time
        the account last voted.
        '''
        self.steem.check_balances(acctname)
        if votepower == 0:
            votepower = self.steem.votepower
        self.votevalue = self.steem.current_vote_value(
                    self.steem.lastvotetime, 
                    self.steem.steempower, 
                    voteweight, 
                    votepower)
        self.voteweight = voteweight
        self.votepower = votepower
        return self.steem.rshares



    def verify_post (self, account1, account2, mode):
        ''' Gets only the most recent post, gets the 
        timestamp and finds the age of the post in days.
        Is the post too old? Did account2 
        vote on the post already?
        '''
        permlink = self.steem.get_post_info(account1)
        if not permlink:
            self.msg.error_message("No post for " + account1)
            return False
        else:
            votes = self.steem.vote_history(account1, permlink)
            for v in votes:
                if v['voter'] == account2:
                    self.msg.message(account2 + 
                        " has aready voted on " + permlink)
                    return False
        return True



    def eligible_posts (self, account1, account2, mode):
        ''' Verify the posts of both accounts
        '''
        if not self.verify_post(account1, account2, mode):
            return False
        if not self.verify_post(account2, account1, mode):
            return False
        return True



    def eligible_votes (self, account1, account2, 
                        percentage, ratio, mode, flag):
        ''' If the flag is raised use the full voting 
        power to make the comparison rather
        than the current voting power. 
        If ratio was not acheived return false 
        Otherwise display approximate 
        upvote matches
        '''
        if flag == 1:
            vpow = 100
        else:
            vpow = 0
        v1 = self.get_vote_value(account1, percentage, vpow, mode)
        v2 = self.get_vote_value(account2, 100, vpow, mode)
        v3 = ((v1 / v2) * 100) / float(ratio)
        v3a = round(v3, 2)
        exceeds = False
        if v3a < 1:
            v3 = 1
            exceeds = True
        if v3a > 100:
            v3 = 100
            exceeds = True
        self.msg.message(account2 + " needs to vote " 
                + str(v3a) + "% in order to meet " + account1)
        v4 = self.get_vote_value(account2, v3, vpow, mode)
        v1s = self.steem.rshares_to_steem(v1)
        v4s = self.steem.rshares_to_steem(v4)
        if exceeds:
            if v3 == 1:
                v5 = v4 - v1
                v5s = self.steem.rshares_to_steem(v5)
                self.response = (account2 + "'s vote of " + str(v4s) 
                                + " will be larger than " + account1 
                                + "'s vote by: " + str(v5s))
                self.msg.message(self.response)
            if v3 == 100:
                v5 = v1 - v4
                v5s = self.steem.rshares_to_steem(v5)
                self.response = (account1 + "'s vote of " + str(v1s) 
                                + " will be larger than " + account2 
                                + "'s vote by: " + str(v5s))
                self.msg.message(self.response)
            return False
        else:
            self.msg.message(account1 + " will upvote $" + str(v1s) 
                    + " and " + account2 + " will upvote $" + str(v4s))
            return True
Exemple #18
0
 def __init__(self):
     self.msg = Msg(default.logfilename, 
                     default.logpath, 
                     default.msgmode)
     self.steem = SimpleSteem()
     self.response = None
Exemple #19
0
 def __init__(self):
     self.msg = Msg()
Exemple #20
0
 def __init__(self, dbuser, dbpass, dbname, logfilename, logpath, msgmode):
     self.msg = Msg(logfilename, logpath, msgmode)
     self.db = pymysql.connect("localhost", dbuser, dbpass, dbname)
     self.cursor = self.db.cursor()
     self.dbresults = None
Exemple #21
0
class AXdb(DB):
    def __init__(self, dbuser, dbpass, dbname):
        self.dbuser = dbuser
        self.dbpass = dbpass
        self.dbname = dbname
        self.msg = Msg(default.logfilename, default.logpath, default.msgmode)
        self.sendto = None
        self.inviter = None
        self.invitee = None
        self.errmsg = None

    def first_time_setup(self):
        """ Sets up all three needed tables if they do not
        already exist
        """
        if not self.get_results("SELECT * FROM users WHERE 1;"):
            self.commit('CREATE TABLE IF NOT EXISTS users ' +
                        '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, ' +
                        'Account varchar(50), PrivateKey varchar(100), ' +
                        'RefreshToken varchar(400), Token varchar(400), ' +
                        'Time TIMESTAMP DEFAULT CURRENT_TIMESTAMP);')
        if not self.get_results("SELECT * FROM axlist WHERE 1;"):
            self.commit('CREATE TABLE IF NOT EXISTS axlist ' +
                        '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, ' +
                        'Account1 varchar(50), Account2 varchar(50), ' +
                        'Percentage varchar(5), Ratio varchar(5), ' +
                        'Duration varchar(5), MemoID varchar(100), ' +
                        'Status varchar(10), ' +
                        'Time TIMESTAMP DEFAULT CURRENT_TIMESTAMP);')
        if not self.get_results("SELECT * FROM axtrans WHERE 1;"):
            self.commit('CREATE TABLE IF NOT EXISTS axtrans ' +
                        '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, ' +
                        'TXID varchar(50), MemoFrom varchar(20), ' +
                        'Amount varchar(20), MemoID varchar(100), ' +
                        'Action varchar(20), TxTime TIMESTAMP NULL, ' +
                        'DiscoveryTime TIMESTAMP NOT NULL ' +
                        'DEFAULT CURRENT_TIMESTAMP ' +
                        'ON UPDATE CURRENT_TIMESTAMP);')
        if not self.get_results("SELECT * FROM axhistory WHERE 1;"):
            self.commit(
                'CREATE TABLE IF NOT EXISTS axhistory ' +
                '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, ' +
                'MemoID varchar(100), ' +
                'Account1 varchar(200), Account2 varchar(200), ' +
                'VoteValue1 varchar(100), VoteValue2 varchar(100), ' +
                'Identifier1 varchar(400), Identifier2 varchar(400), ' +
                'Time TIMESTAMP NOT NULL ' + 'DEFAULT CURRENT_TIMESTAMP ' +
                'ON UPDATE CURRENT_TIMESTAMP);')

    def archive_exchange(self, memoid, account1, account2, ident1, ident2,
                         vote1, vote2):
        """ If posts and votes are eligible and
        an exchange occurs it is recorded in the
        database. 
        """
        return self.commit(
            'INSERT INTO axhistory (MemoID, Account1, ' +
            'Account2, VoteValue1, VoteValue2, Identifier1, Identifier2) ' +
            'VALUES (%s, %s, %s, %s, %s, %s, %s);', memoid, account1, account2,
            vote1, vote2, ident1, ident2)

    def get_exchange_archive(self, account=None):
        """ Returns a list of all the recent exchanges
        that have occured on steemax
        """
        if account is None:
            if self.get_results('SELECT Account1, Account2, VoteValue1, ' +
                                'VoteValue2, Identifier1, Identifier2, Time ' +
                                'FROM axhistory WHERE 1 ORDER BY Time DESC;'):
                return self.dbresults
        else:
            if self.get_results(
                    'SELECT Account1, Account2, VoteValue1, ' +
                    'VoteValue2, Identifier1, Identifier2, Time ' +
                    'FROM axhistory WHERE %s IN (Account1, Account2) ' +
                    'ORDER BY Time DESC;', str(account)):
                return self.dbresults

    def get_most_recent_trans(self):
        """ Returns the timestamp from 
        the most recent memo id message. 
        """
        if not self.get_results('SELECT TxTime FROM axtrans ' +
                                'WHERE 1 ORDER BY TxTime DESC LIMIT 1;'):
            return datetime.utcnow() - timedelta(days=5)
        else:
            return self.dbresults[0][0]

    def add_trans(self, txid, memofrom, amt, memoid, action, txtime):
        """ Adds a processed transaction 
        to the axtrans database 
        """
        return self.commit(
            'INSERT INTO axtrans (TXID, MemoFrom, ' +
            'Amount, MemoID, Action, TxTime) ' +
            'VALUES (%s, %s, %s, %s, %s, %s);', txid, memofrom, amt, memoid,
            action, txtime)

    def verify_memoid(self, acct0, memoid):
        """Verify that the Memo ID entered 
        matches the account name entered. 
        """
        if not self.get_results(
                'SELECT Account1, Account2, ' +
                'Status FROM axlist WHERE MemoID = %s;', memoid):
            self.msg.error_message("The Memo ID " + memoid +
                                   " is not in database.")
            return False
        if acct0 == self.dbresults[0][0]:
            self.sendto = self.dbresults[0][1]
            self.inviter = self.dbresults[0][0]
            self.invitee = self.dbresults[0][1]
        elif acct0 == self.dbresults[0][1]:
            self.sendto = self.dbresults[0][0]
            self.inviter = self.dbresults[0][1]
            self.invitee = self.dbresults[0][0]
        else:
            self.msg.error_message("Account does not match Memo ID.")
            return False
        return True

    def cancel(self, acct, memoid):
        """ Either account can cancel
        """
        return self.commit(
            'DELETE FROM axlist WHERE %s IN ' +
            '(Account1, Account2) AND (MemoID = %s);', acct, memoid)

    def get_invite(self, memoid):
        """ Gets an invite from the database
        and returns it as a list
        """
        if self.get_results(
                "SELECT Percentage, Ratio, Duration, " +
                "Status FROM axlist WHERE MemoID = %s;", memoid):
            return [
                self.dbresults[0][0], self.dbresults[0][1],
                self.dbresults[0][2], self.dbresults[0][3]
            ]
        else:
            self.msg.error_message("No invite found for " + memoid)
            return [0, 0, 0, 0]

    def update_invite(self, percent, ratio, duration, memoid, status):
        """ Updates and invite during
        the barter process
        """
        return self.commit(
            'UPDATE axlist SET Percentage = %s, ' +
            'Ratio = %s, Duration = %s, Status = %s WHERE MemoID = %s;',
            percent, ratio, duration, status, memoid)

    def update_status(self, status, memoid):
        """
        -1 = waiting for inviter to authorize
         0 = invite sent. waiting for invitee
         1 = exchange authorized by both parties
         2 = inviter (account1) has offered to barter
         3 = invitee (account2) has offered to barter
         4 = exchange has been cancelled
        """
        return self.commit("UPDATE axlist SET Status = %s WHERE MemoID = %s;",
                           status, memoid)

    def check_status(self, memoid):
        """ Checks the status of an invite
        so that steemax knows how to react to
        a command
        """
        if self.get_results("SELECT Status FROM axlist WHERE MemoID = %s;",
                            memoid):
            return self.dbresults[0][0]
        else:
            return False

    def get_user_token(self, acct):
        """ Gets a user's SteemConnect tokens 
        and Private Posting Key
        """
        if self.get_results(
                'SELECT PrivateKey, Token, RefreshToken ' +
                'FROM users WHERE Account = %s;', acct):
            return self.dbresults[0][1]
        else:
            return False

    def update_token(self, acct, accesstoken, refreshtoken):
        """ Updates a user's SteemConnect tokens
        """
        return self.commit(
            "UPDATE users SET Token = %s, " +
            "RefreshToken = %s WHERE Account = %s;", accesstoken, refreshtoken,
            acct)

    def add_invite(self, acct1, acct2, percent, ratio, duration):
        """Adds the initial invite to the database 
        and provides the unique Memo ID.
        """
        memoid = self.generate_memoid()
        if acct1 == acct2:
            self.errmsg = ('The same account name was ' +
                           'entered for both accounts.')
            self.msg.error_message(self.errmsg)
            return False
        if self.get_results(
                'SELECT * FROM axlist ' + 'WHERE %s IN (Account1, Account2) ' +
                'AND (%s IN (Account1, Account2)) ' + 'AND (Status != 4);',
                acct1, acct2):
            self.errmsg = ('An exchange has already been ' +
                           'made between these accounts.')
            self.msg.error_message(self.errmsg)
            return False
        if self.commit(
                'INSERT INTO axlist (Account1, Account2, ' +
                'Percentage, Ratio, ' + 'Duration, MemoID, Status) ' +
                'VALUES (%s, %s, %s, %s, %s, %s, %s);', acct1, acct2, percent,
                ratio, duration, memoid, -1):
            return memoid
        else:
            return False

    def add_user(self, acct, key, refreshtoken, accesstoken):
        """ Adds a user and their tokens/key to the database
        """
        return self.commit(
            'INSERT INTO users (Account, PrivateKey, ' +
            'RefreshToken, Token) ' + 'VALUES (%s, %s, %s, %s);', acct, key,
            refreshtoken, accesstoken)

    def get_axlist(self, account=None, run=False):
        """ Gets the entire list of transactions
        to be processed
        """
        if run:
            self.get_results('SELECT * FROM axlist WHERE Status = 1;')
        elif account is None:
            self.get_results(
                'SELECT * FROM axlist WHERE Status != 4 ORDER BY Status;')
        else:
            self.get_results(
                'SELECT * FROM axlist ' +
                'WHERE %s IN (Account1, Account2) AND (Status != 4) ORDER BY Status;',
                account)
        return self.dbresults

    def generate_memoid(self, length=32):
        return ''.join([str(random.randint(0, 9)) for i in range(length)])

    def expiration_date(self, timestamp, duration):
        end_date = (datetime.strptime(str(timestamp), '%Y-%m-%d %H:%M:%S') +
                    timedelta(days=int(duration)))
        return (str(end_date.strftime("%B")) + " " + str(end_date.day) + ", " +
                str(end_date.year))

    def expire(self):
        self.get_results(
            "SELECT ID, Duration, Time, Account1, Account2 FROM axlist WHERE 1;"
        )
        for row in self.dbresults:
            if (datetime.strptime(str(row[2]), '%Y-%m-%d %H:%M:%S') +
                    timedelta(days=int(row[1])) < datetime.now()):
                self.commit("UPDATE axlist SET Status = 4 WHERE ID = %s;",
                            row[0])
                self.msg.message(row[3] + " vs. " + row[4] + " has expired.")
Exemple #22
0
class SimpleSteem:  


    def __init__(self, **kwargs):
        ''' Looks for config.py if not found runs
        setup which prompts user for the config values
        one time only.
        '''
        for key, value in kwargs.items():
            setattr(self, key, value)
        try:
            imp.find_module('config', 
                [os.path.dirname(os.path.realpath(__file__))])
        except ImportError:
            makeconfig.MakeConfig().setup()
        from simplesteem import config
        try:
            self.mainaccount
        except:
            self.mainaccount = config.mainaccount
        try:
            self.keys
        except:
            self.keys = config.keys
        try:
            self.nodes
        except:
            self.nodes = config.nodes
        try:
            self.client_id
        except:
            self.client_id = config.client_id
        try:
            self.client_secret
        except:
            self.client_secret = config.client_secret
        try:
            self.callback_url
        except:
            self.callback_url = config.callback_url
        try:
            self.permissions
        except:
            self.permissions = config.permissions
        try:
            self.logpath
        except:
            self.logpath = config.logpath
        try:
            self.screenmode
        except:
            self.screenmode = config.screenmode
        self.s = None
        self.c = None
        self.e = None
        self.dex = None
        self.msg = Msg("simplesteem.log",
                        self.logpath, 
                        self.screenmode)
        self.util = util.Util("simplesteem.log", 
                        self.logpath, 
                        self.screenmode)
        self.connect = steemconnectutil.SteemConnect(
                        self.client_id, 
                        self.client_secret, 
                        self.callback_url, 
                        self.permissions)
        self.checkedaccount = None
        self.accountinfo = None
        self.blognumber = 0
        self.reward_balance = 0
        self.price_of_steem = 0


    def account(self, account=None):
        ''' Fetches account information and stores the
        result in a class variable. Returns that variable
        if the account has not changed.
        '''
        for num_of_retries in range(default.max_retry):
            if account is None:
                account = self.mainaccount
            if account == self.checkedaccount:
                return self.accountinfo
            self.checkedaccount = account
            try:
                self.accountinfo = self.steem_instance().get_account(account)
            except Exception as e:
                self.util.retry(("COULD NOT GET ACCOUNT INFO FOR " + str(account)), 
                    e, num_of_retries, default.wait_time)
                self.s = None
                self.e = e
            else:
                if self.accountinfo is None:
                    self.msg.error_message("COULD NOT FIND ACCOUNT: " + str(account))
                    return False
                else:
                    return self.accountinfo


    def steem_instance(self):
        ''' Returns the steem instance if it already exists
        otherwise uses the goodnode method to fetch a node
        and instantiate the Steem class.
        '''
        if self.s:
            return self.s
        for num_of_retries in range(default.max_retry):
            node = self.util.goodnode(self.nodes)
            try:
                self.s = Steem(keys=self.keys, 
                    nodes=[node])
            except Exception as e:
                self.util.retry("COULD NOT GET STEEM INSTANCE", 
                    e, num_of_retries, default.wait_time)
                self.s = None
                self.e = e
            else:
                return self.s
        return False


    def claim_rewards(self):
        if self.steem_instance().claim_reward_balance(
                account=self.mainaccount):
            time.sleep(5)
            return True
        else:
            return False


    def verify_key (self, acctname=None, tokenkey=None):
        ''' This can be used to verify either a private
        posting key or to verify a steemconnect refresh
        token and retreive the access token.
        '''
        if (re.match( r'^[A-Za-z0-9]+$', tokenkey)
                        and tokenkey is not None
                        and len(tokenkey) <= 64
                        and len(tokenkey) >= 16):
            pubkey = PrivateKey(tokenkey).pubkey or 0
            pubkey2 = self.account(acctname)
            if (str(pubkey) 
                    == str(pubkey2['posting']['key_auths'][0][0])):
                self.privatekey = tokenkey
                self.refreshtoken = None
                self.accesstoken = None
                return True
            else:
                return False
        elif (re.match( r'^[A-Za-z0-9\-\_\.]+$', tokenkey)
                        and tokenkey is not None
                        and len(tokenkey) > 64):
            self.privatekey = None
            self.accesstoken = self.connect.get_token(tokenkey)
            if self.accesstoken:
                self.username = self.connect.username
                self.refreshtoken = self.connect.refresh_token
                return True
            else:
                return False
        else:
            return False


    def reward_pool_balances(self):
        ''' Fetches and returns the 3 values
        needed to calculate the reward pool
        and other associated values such as rshares.
        Returns the reward balance, all recent claims
        and the current price of steem.
        '''
        if self.reward_balance > 0:
            return self.reward_balance
        else:
            reward_fund = self.steem_instance().get_reward_fund()
            self.reward_balance = Amount(
                reward_fund["reward_balance"]).amount
            self.recent_claims = float(reward_fund["recent_claims"])
            self.base = Amount(
                self.steem_instance(
                ).get_current_median_history_price()["base"]
                ).amount
            self.quote = Amount(
                self.steem_instance(
                ).get_current_median_history_price()["quote"]
                ).amount
            self.price_of_steem = self.base / self.quote
        return [self.reward_balance, self.recent_claims, self.price_of_steem]


    def rshares_to_steem (self, rshares):
        ''' Gets the reward pool balances
        then calculates rshares to steem
        '''
        self.reward_pool_balances()
        return round(
            rshares 
            * self.reward_balance 
            / self.recent_claims 
            * self.price_of_steem, 4)


    def global_props(self):
        ''' Retrieves the global properties
        used to determine rates used for calculations
        in converting steempower to vests etc.
        Stores these in the Utilities class as that
        is where the conversions take place, however
        SimpleSteem is the class that contains
        steem_instance, so to to preserve heirarchy 
        and to avoid "spaghetti code", this method
        exists in this class.
        '''
        if self.util.info is None:
            self.util.info = self.steem_instance().get_dynamic_global_properties()
            self.util.total_vesting_fund_steem = Amount(self.util.info["total_vesting_fund_steem"]).amount
            self.util.total_vesting_shares = Amount(self.util.info["total_vesting_shares"]).amount
            self.util.vote_power_reserve_rate = self.util.info["vote_power_reserve_rate"]
        return self.util.info


    def current_vote_value(self, **kwargs):
        ''' Ensures the needed variables are
        created and set to defaults although
        a variable number of variables are given.
        '''
        try:
            kwargs.items()
        except:
            pass
        else:
            for key, value in kwargs.items():
                setattr(self, key, value)
        try:
            self.lastvotetime
        except:
            self.lastvotetime=None
        try:
            self.steempower
        except:
            self.steempower=0
        try:
            self.voteweight
        except:
            self.voteweight=100
        try:
            self.votepoweroverride
        except:
            self.votepoweroverride=0
        try:
            self.accountname
        except:
            self.accountname=None              
        if self.accountname is None:
            self.accountname = self.mainaccount   
        if self.check_balances(self.accountname) is not False:
            if self.voteweight > 0 and self.voteweight < 101:
                self.voteweight = self.util.scale_vote(self.voteweight)
            if self.votepoweroverride > 0 and self.votepoweroverride < 101:
                self.votepoweroverride = self.util.scale_vote(self.votepoweroverride) 
            else:
                self.votepoweroverride = (self.votepower 
                                + self.util.calc_regenerated(
                                self.lastvotetime))
            self.vpow = round(self.votepoweroverride / 100, 2)
            self.global_props()
            self.rshares = self.util.sp_to_rshares(self.steempower, 
                                            self.votepoweroverride, 
                                            self.voteweight)
            self.votevalue = self.rshares_to_steem(self.rshares)
            return self.votevalue
        return None


    def check_balances(self, account=None):
        ''' Fetches an account balance and makes
        necessary conversions
        '''
        a = self.account(account)
        if a is not False and a is not None:
            self.sbdbal = Amount(a['sbd_balance']).amount
            self.steembal = Amount(a['balance']).amount
            self.votepower = a['voting_power']
            self.lastvotetime = a['last_vote_time']
            vs = Amount(a['vesting_shares']).amount
            dvests = Amount(a['delegated_vesting_shares']).amount
            rvests = Amount(a['received_vesting_shares']).amount
            vests = (float(vs) - float(dvests)) + float(rvests)
            try:
                self.global_props()
                self.steempower_delegated = self.util.vests_to_sp(dvests)
                self.steempower_raw = self.util.vests_to_sp(vs)
                self.steempower = self.util.vests_to_sp(vests)
            except Exception as e:
                self.msg.error_message(e)
                self.e = e
            else:
                return [self.sbdbal, self.steembal, self.steempower, 
                        self.votepower, self.lastvotetime]
        return False


    def transfer_funds(self, to, amount, denom, msg):
        ''' Transfer SBD or STEEM to the given account
        '''
        try:
            self.steem_instance().commit.transfer(to, 
                float(amount), denom, msg, self.mainaccount)
        except Exception as e:
            self.msg.error_message(e)
            self.e = e
            return False
        else:
            return True


    def get_my_history(self, account=None, limit=10000):
        ''' Fetches the account history from
        most recent back
        '''
        if not account:
            account = self.mainaccount
        try:
            h = self.steem_instance().get_account_history(
                account, -1, limit)
        except Exception as e:
            self.msg.error_message(e)
            self.e = e
            return False
        else:
            return h


    def post(self, title, body, permlink, tags):
        ''' Used for creating a main post
        to an account's blog. Waits 20 seconds
        after posting as that is the required 
        amount of time between posting.
        '''
        for num_of_retries in range(default.max_retry):
            try:
                self.msg.message("Attempting to post " + permlink)
                self.steem_instance().post(title, 
                                            body, 
                                            self.mainaccount, 
                                            permlink, 
                                            None, None, None, None, 
                                            tags, None, False)   
            except Exception as e:
                self.util.retry("COULD NOT POST '" + title + "'", 
                    e, num_of_retries, 10)
                self.s = None
                self.e = e
            else:
                self.msg.message("Post seems successful. Wating 60 seconds before verifying...")
                self.s = None
                time.sleep(60)
                checkident = self.recent_post()
                ident = self.util.identifier(self.mainaccount, permlink)
                if checkident == ident:
                    return True
                else:
                    self.util.retry('A POST JUST CREATED WAS NOT FOUND IN THE '
                                    + 'BLOCKCHAIN {}'''.format(title), 
                                    "Identifiers do not match", 
                                    num_of_retries, default.wait_time)
                    self.s = None


    def reply(self, permlink, msgbody):
        ''' Used for creating a reply to a 
        post. Waits 20 seconds
        after posting as that is the required 
        amount of time between posting.
        '''
        for num_of_retries in range(default.max_retry): 
            try:
                self.steem_instance().post("message", 
                                            msgbody, 
                                            self.mainaccount, 
                                            None, 
                                            permlink, 
                                            None, None, "", 
                                            None, None, False)
            except Exception as e:
                self.util.retry("COULD NOT REPLY TO " + permlink, 
                    e, num_of_retries, default.wait_time)
                self.s = None
                self.e = e
            else:
                self.msg.message("Replied to " + permlink)
                time.sleep(20)
                return True


    def follow(self, author):
        ''' Follows the given account
        '''
        try:
            self.steem_instance().commit.follow(author, 
                ['blog'], self.mainaccount)
        except Exception as e:
            self.msg.error_message(e)
            self.e = e
            return False
        else:
            return True


    def unfollow(self, author):
        ''' Unfollows the given account
        '''
        try:
            self.steem_instance().commit.unfollow(author, 
                ['blog'], self.mainaccount)
        except Exception as e:
            self.msg.error_message(e)
            self.e = e
            return False
        else:
            return True


    def following(self, account=None, limit=100):
        ''' Gets a list of all the followers
        of a given account. If no account is given
        the followers of the mainaccount are
        returned.
        '''
        if not account:
            account = self.mainaccount
        followingnames = []
        try:
            self.followed = self.steem_instance().get_following(account, 
                '', 'blog', limit)
        except Exception as e:
            self.msg.error_message(e)
            self.e = e
            return False
        else:
            for a in self.followed:
                followingnames.append(a['following'])
            return followingnames


    def recent_post(self, author=None, daysback=0, flag=0):
        ''' Returns the most recent post from the account
        given. If the days back is greater than zero
        then the most recent post is returned for that
        day. For instance if daysback is set to 2
        then it will be the most recent post from 2 days
        ago (48 hours).
        '''
        if not author:
            author = self.mainaccount
        for num_of_retries in range(default.max_retry):
            try:
                self.blog = self.steem_instance().get_blog(author, 0, 30)
            except Exception as e:
                self.util.retry('COULD NOT GET THE '
                                + 'MOST RECENT POST FOR '
                                + '{}'.format(author), 
                                e, num_of_retries, default.wait_time)
                self.s = None
                self.e = e
            else:
                i = 0
                for p in self.blog:
                    if p != "error":
                        if p['comment']['author'] == author:
                            self.blognumber = i
                            ageinminutes = self.util.minutes_back(p['comment']['created'])
                            ageindays = (ageinminutes / 60) / 24
                            if (int(ageindays) == daysback):
                                if flag == 1 and ageinminutes < 15:
                                    return None
                                else:
                                    return self.util.identifier(
                                        p['comment']['author'],
                                        p['comment']['permlink'])
                            else:
                                return None
                    i += 1


    def vote_history(self, permlink, author=None):
        ''' Returns the raw vote history of a
        given post from a given account
        '''
        if author is None:
            author = self.mainaccount
        return self.steem_instance().get_active_votes(author, permlink)


    def vote(self, identifier, weight=100.0):
        ''' Waits 5 seconds as that is the required amount 
        of time between votes.
        '''
        for num_of_retries in range(default.max_retry):
            try:
                self.steem_instance().vote(identifier, 
                    weight, self.mainaccount)
                self.msg.message("voted for " + identifier)
                time.sleep(5)
            except Exception as e:
                if re.search(r'You have already voted in a similar way', str(e)):
                    self.msg.error_message('''Already voted on 
                                        {}'''.format(identifier))
                    return "already voted"
                else:
                    self.util.retry('''COULD NOT VOTE ON 
                                    {}'''.format(identifier), 
                                    e, num_of_retries, default.wait_time)
                    self.s = None
                self.e = e
            else:
                return True


    def resteem(self, identifier):
        ''' Waits 20 seconds as that is the required 
        amount of time between resteems
        '''
        for num_of_retries in range(default.max_retry):
            try:
                self.steem_instance().resteem(
                    identifier, self.mainaccount)
                self.msg.message("resteemed " + identifier)
                time.sleep(10)
            except Exception as e:
                self.util.retry('''COULD NOT RESTEEM 
                                {}'''.format(identifier), 
                                e, num_of_retries, default.wait_time)
                self.s = None
                self.e = e
            else:
                return True


    def dex_ticker(self):
        ''' Simply grabs the ticker using the 
        steem_instance method and adds it
        to a class variable.
        '''
        self.dex = Dex(self.steem_instance())
        self.ticker = self.dex.get_ticker();
        return self.ticker


    def steem_to_sbd(self, steemamt=0, price=0, account=None):
        ''' Uses the ticker to get the highest bid
        and moves the steem at that price.
        '''
        if not account:
            account = self.mainaccount
        if self.check_balances(account):
            if steemamt == 0:
                steemamt = self.steembal
            elif steemamt > self.steembal:
                self.msg.error_message("INSUFFICIENT FUNDS. CURRENT STEEM BAL: " 
                                        + str(self.steembal))
                return False
            if price == 0:
                price = self.dex_ticker()['highest_bid']
            try:
                self.dex.sell(steemamt, "STEEM", price, account=account)
            except Exception as e:
                self.msg.error_message("COULD NOT SELL STEEM FOR SBD: " + str(e))
                self.e = e
                return False
            else:
                self.msg.message("TRANSFERED " 
                                    + str(steemamt) 
                                    + " STEEM TO SBD AT THE PRICE OF: $"
                                    + str(price))
                return True
        else:
            return False


    def sbd_to_steem(self, sbd=0, price=0, account=None):
        ''' Uses the ticker to get the lowest ask
        and moves the sbd at that price.
        '''
        if not account:
            account = self.mainaccount
        if self.check_balances(account):
            if sbd == 0:
                sbd = self.sbdbal
            elif sbd > self.sbdbal:
                self.msg.error_message("INSUFFICIENT FUNDS. CURRENT SBD BAL: " 
                                        + str(self.sbdbal))
                return False
            if price == 0:
                price = 1 / self.dex_ticker()['lowest_ask']
            try:
                self.dex.sell(sbd, "SBD", price, account=account)
            except Exception as e:
                self.msg.error_message("COULD NOT SELL SBD FOR STEEM: " + str(e))
                self.e = e
                return False
            else:
                self.msg.message("TRANSFERED " 
                                    + str(sbd) 
                                    + " SBD TO STEEM AT THE PRICE OF: $"
                                    + str(price))
                return True
        else:
            return False


    def vote_witness(self, witness, account=None):
        ''' Uses the steem_instance method to
        vote on a witness.
        '''
        if not account:
            account = self.mainaccount
        try:
            self.steem_instance().approve_witness(witness, account=account)
        except Exception as e:
            self.msg.error_message("COULD NOT VOTE " 
                                    + witness + " AS WITNESS: " + e)
            self.e = e
            return False
        else:
            return True


    def unvote_witness(self, witness, account=None):
        ''' Uses the steem_instance method to
        unvote a witness.
        '''
        if not account:
            account = self.mainaccount
        try:
            self.steem_instance().disapprove_witness(witness, account=account)
        except Exception as e:
            self.msg.error_message("COULD NOT UNVOTE " 
                                    + witness + " AS WITNESS: " + e)
            self.e = e
            return False
        else:
            return True


    def voted_me_witness(self, account=None, limit=100):
        ''' Fetches all those a given account is
        following and sees if they have voted that
        account as witness.
        '''
        if not account:
            account = self.mainaccount
        self.has_voted = []
        self.has_not_voted = []
        following = self.following(account, limit)
        for f in following:
            wv = self.account(f)['witness_votes']
            voted = False
            for w in wv:
                if w == account:
                    self.has_voted.append(f)
                    voted = True
            if not voted:
                self.has_not_voted.append(f)
        return self.has_voted


    def muted_me(self, account=None, limit=100):
        ''' Fetches all those a given account is
        following and sees if they have muted that
        account.
        '''
        self.has_muted = []
        if account is None:
            account = self.mainaccount
        following = self.following(account, limit)
        if following is False:
            self.msg.error_message("COULD NOT GET FOLLOWING FOR MUTED")
            return False
        for f in following:
            h = self.get_my_history(f)
            for a in h:
                if a[1]['op'][0] == "custom_json":
                    j = a[1]['op'][1]['json']
                    d = json.loads(j)
                    try:
                        d[1]
                    except:
                        pass
                    else:
                        for i in d[1]:
                            if i == "what":
                                if len(d[1]['what']) > 0:
                                    if d[1]['what'][0] == "ignore":
                                        if d[1]['follower'] == account:
                                            self.msg.message("MUTED BY " + f)
                                            self.has_muted.append(f)
        return self.has_muted


    def delegate(self, to, steempower):
        ''' Delegates based on Steem Power rather
        than by vests.
        '''
        self.global_props()
        vests = self.util.sp_to_vests(steempower)
        strvests = str(vests)
        strvests = strvests + " VESTS"
        try:
            self.steem_instance().commit.delegate_vesting_shares(to, 
                                                                strvests, 
                                                                account=self.mainaccount)
        except Exception as e:
            self.msg.error_message("COULD NOT DELEGATE " 
                                    + str(steempower) + " SP TO " 
                                    + to + ": " + str(e))
            self.e = e
            return False
        else:
            self.msg.message("DELEGATED " + str(steempower) + " STEEM POWER TO " + str(to))
            return True


    def create_account(new_account, new_account_master_key, creator):
        self.steem_instance().create_account(
            new_account,
            delegation_fee_steem="3 STEEM",
            password=new_account_master_key,
            creator=creator,
        )
        keys = {}
        for key_type in ['posting','active','owner','memo']:
            private_key = PasswordKey(
                new_account, new_account_master_key, key_type).get_private_key()

            keys[key_type] = {
                "public": str(private_key.pubkey),
                "private": str(private_key),
            }
        return keys
Exemple #23
0
class AXdb(DB):



    def __init__ (self, dbuser, dbpass, dbname):
        self.dbuser = dbuser
        self.dbpass = dbpass
        self.dbname = dbname
        self.msg = Msg(default.logfilename, 
                        default.logpath, 
                        default.msgmode)



    def first_time_setup (self):
        if not self.get_results("SELECT * FROM users WHERE 1;"):
            self.commit('CREATE TABLE IF NOT EXISTS users '
                + '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, '
                + 'Account varchar(50), PrivateKey varchar(100), '
                + 'RefreshToken varchar(400), Token varchar(400), '
                + 'Time TIMESTAMP DEFAULT CURRENT_TIMESTAMP);')
        if not self.get_results("SELECT * FROM axlist WHERE 1;"):
            self.commit('CREATE TABLE IF NOT EXISTS axlist '
                + '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, '
                + 'Account1 varchar(50), Account2 varchar(50), '
                + 'Percentage varchar(5), Ratio varchar(5), '
                + 'Duration varchar(5), MemoID varchar(100), '
                + 'Status varchar(10), '
                + 'Time TIMESTAMP DEFAULT CURRENT_TIMESTAMP);')
        if not self.get_results("SELECT * FROM axtrans WHERE 1;"):
            self.commit('CREATE TABLE IF NOT EXISTS axtrans '
                + '(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, '
                + 'TXID varchar(50), MemoFrom varchar(20), '
                + 'Amount varchar(20), MemoID varchar(100), '
                + 'Action varchar(20), TxTime TIMESTAMP NULL, '
                + 'DiscoveryTime TIMESTAMP NOT NULL '
                + 'DEFAULT CURRENT_TIMESTAMP '
                + 'ON UPDATE CURRENT_TIMESTAMP);')



    def get_most_recent_trans (self):
        ''' Returns the timestamp from 
        the most recent memo id message. 
        '''
        if not self.get_results('SELECT TxTime FROM axtrans '
                            + 'WHERE 1 ORDER BY TxTime DESC LIMIT 1;'):
            return datetime.utcnow() - timedelta(days=5)
        else:
            return self.dbresults[0][0]



    def add_trans (self, txid, memofrom, amt, 
                    memoid, action, txtime):
        ''' Adds a processed transaction 
        to the axtrans database 
        '''
        return self.commit('INSERT INTO axtrans (TXID, MemoFrom, '
            + 'Amount, MemoID, Action, TxTime) '
            + 'VALUES (%s, %s, %s, %s, %s, %s);',
            txid, memofrom, amt,  memoid, action, txtime)
        


    def verify_memoid (self, acct0, memoid):
        '''Verify that the Memo ID entered 
        matches the account name entered. 
        '''
        if not self.get_results('SELECT Account1, Account2, '
                                + 'Status FROM axlist WHERE MemoID = %s;',
                                memoid):
            self.msg.error_message("Memo ID not in database.")
            return False
        if acct0 == self.dbresults[0][0]:
            self.sendto = self.dbresults[0][1]
            self.inviter = self.dbresults[0][0]
            self.invitee = self.dbresults[0][1]
        elif acct0 == self.dbresults[0][1]:
            self.sendto = self.dbresults[0][0]
            self.inviter = self.dbresults[0][1]
            self.invitee = self.dbresults[0][0]
        else:
            self.msg.error_message("Account does not match Memo ID.")
            return False
        return True



    def cancel (self, acct, memoid):
        ''' Either account can cancel
        '''
        return self.commit('DELETE FROM axlist WHERE %s IN '
            + '(Account1, Account2) AND (MemoID = %s);',
            acct, memoid)



    def get_invite (self, memoid):
        if self.get_results("SELECT Percentage, Ratio, Duration, "
                        + "Status FROM axlist WHERE MemoID = %s;", 
                        memoid):
            return [self.dbresults[0][0], 
                    self.dbresults[0][1], 
                    self.dbresults[0][2], 
                    self.dbresults[0][3]]
        else:
            self.msg.error_message("No invite found for " + memoid)
            return [0, 0, 0, 0]


    def update_invite (self, percent, ratio, duration, memoid, status):
        return self.commit('UPDATE axlist SET Percentage = %s, '
            + 'Ratio = %s, Duration = %s, Status = %s WHERE MemoID = %s;',
            percent, ratio, duration, status, memoid)



    def update_status (self, status, memoid):
        '''
        -1 = waiting for inviter to authorize
         0 = invite sent. waiting for invitee
         1 = exchange authorized by both parties
         2 = inviter (account1) has offered to barter
         3 = invitee (account2) has offered to barter
         4 = exchange has been cancelled
        '''
        return self.commit("UPDATE axlist SET Status = %s WHERE MemoID = %s;", 
            status, memoid)



    def check_status (self, memoid):
        if self.get_results("SELECT Status FROM axlist WHERE MemoID = %s;", 
                memoid):
            return self.dbresults[0][0]
        else:
            return False



    def get_user_token (self, acct):
        if self.get_results("SELECT PrivateKey, Token, RefreshToken "
                            + "FROM users WHERE Account = %s;",
                            acct):
            return self.dbresults[0][1]
        else:
            return False



    def update_token (self, acct, accesstoken, refreshtoken):
        return self.commit("UPDATE users SET Token = %s, "
                            + "RefreshToken = %s WHERE Account = %s;",
                            accesstoken, refreshtoken, acct)



    def add_invite (self, acct1, acct2, percent, ratio, duration):
        '''Adds the initial invite to the database 
        and provides the unique Memo ID.
        '''
        memoid = self.generate_memoid()
        if acct1 == acct2:
            self.msg.message('The same account name was '
                        + 'entered for both accounts.')
            return False
        if self.get_results('SELECT * FROM axlist '
                        + 'WHERE %s IN (Account1, Account2) '
                        + 'AND (%s IN (Account1, Account2));',
                        acct1, acct2):
            self.msg.message('An exchange has already been '
                        + 'made between these accounts.')
            return False
        if self.commit('INSERT INTO axlist (Account1, Account2, '
                        + 'Percentage, Ratio, '
                        + 'Duration, MemoID, Status) '
                        + 'VALUES (%s, %s, %s, %s, %s, %s, %s);',
                        acct1, acct2, 
                        percent, ratio, duration, memoid, -1):
            return memoid
        else:
            return False



    def add_user (self, acct, key, refreshtoken, accesstoken):
        return self.commit('INSERT INTO users (Account, PrivateKey, '
                        + 'RefreshToken, Token) '
                        + 'VALUES (%s, %s, %s, %s);',
                        acct, key, refreshtoken, accesstoken)
            


    def get_axlist (self):
        self.get_results("SELECT * FROM axlist WHERE 1;")
        return self.dbresults



    def generate_memoid (self, length=32):
        return ''.join([str(random.randint(0, 9)) for i in range(length)])
Exemple #24
0
class AXtrans:
    def __init__(self):
        self.msg = Msg(default.logfilename, default.logpath, default.msgmode)
        self.db = axdb.AXdb(default.dbuser, default.dbpass, default.dbname)
        self.steem = SimpleSteem()
        self.react = Reaction()

    def parse_memo(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        # Ew this is dirty and came from
        # strangers! Must be sanitized!
        try:
            memo = self.memo.split(":")
        except:
            return False
        self.memoid = memo[0] or None
        if re.match(r'^[A-Za-z0-9\:]$', self.memoid):
            return False
        if len(memo) == 2:
            self.action = memo[1] or None
            return True
        elif len(memo) == 5:
            self.action = memo[1] or None
            self.percentage = memo[2] or None
            self.ratio = memo[3] or None
            self.duration = memo[4] or None
            return True
        else:
            return False

    def send(self, to="artopium", amt="0.001 SBD", msg="test"):
        r = amt.split(" ")
        if self.steem.transfer_funds(to, float(r[0]), r[1], msg):
            self.msg.message(("Transaction committed. Sent {} "
                              "{} to {} with the memo: "
                              "{}").format(r[0], r[1], to, msg))

    def act(self, acct1, acct2, rstatus, sendto):
        if not self.db.get_user_token(self.memofrom):
            self.react.ignore(("{} is not a current member of " +
                               " https://steemax.trade! Join now " +
                               "using SteemConnect.").format(self.memofrom))
        elif (self.action == "start"):
            self.react.start(acct1, acct2, self.memofrom, rstatus, self.memoid)
        elif (self.action == "cancel"):
            self.react.cancel(self.memofrom, self.memoid)
        elif (self.action == "accept"):
            self.react.accept(acct1, acct2, self.memofrom, rstatus,
                              self.memoid)
        elif (self.action == "barter"):
            self.react.barter(acct1, acct2, self.memoid, self.memofrom,
                              rstatus, self.percentage, self.ratio,
                              self.duration)
        else:
            self.react.ignore("Invalid action.")
        if self.react.reaction == "refund":
            self.sendto = self.memofrom
        else:
            self.sendto = sendto

    def parse_history_record(self, record, lasttrans):
        if (record[1]['op'][0] == 'transfer' and datetime.strptime(
                record[1]['timestamp'], '%Y-%m-%dT%H:%M:%S') > lasttrans
                and re.match(r'^[0-9]{32}', record[1]['op'][1]['memo'])
                and record[1]['op'][1]['to'] == self.steem.mainaccount):
            return True
        else:
            return False

    def fetch_history(self):
        ''' Processes the transaction history. 
        The memo message is parsed for a valid 
        command and performs the 
        directed action.
        '''
        rt = self.db.get_most_recent_trans()
        for a in self.steem.get_my_history():
            if self.parse_history_record(a, rt):
                if self.parse_memo(memofrom=a[1]['op'][1]['from'],
                                   memo=a[1]['op'][1]['memo'],
                                   amount=a[1]['op'][1]['amount'],
                                   trxid=a[1]['trx_id'],
                                   txtime=a[1]['timestamp']):
                    if self.db.verify_memoid(self.memofrom, self.memoid):
                        self.act(self.db.dbresults[0][0],
                                 self.db.dbresults[0][1],
                                 int(self.db.dbresults[0][2]), self.db.sendto)
                    else:
                        self.react.ignore("Invalid Memo ID.")
                        self.sendto = self.memofrom
                else:
                    self.react.ignore("Invalid Memo.")
                    self.sendto = self.memofrom

                self.send(self.sendto, self.amount, self.react.returnmsg)
                self.db.add_trans(self.trxid, self.memofrom, self.amount,
                                  self.memoid, self.react.reaction,
                                  self.txtime)
Exemple #25
0
class Util:


    def __init__(self, filename, path, screenmode):
        self.msg = Msg(filename, path, screenmode)
        self.total_vesting_fund_steem = None
        self.total_vesting_shares = None
        self.vote_power_reserve_rate = None
        self.info = None
        self.currentnode = 0


    def current_node(self, listlength):
        newnodenumber = 0
        path = os.path.dirname(os.path.abspath(__file__)) + "/node.dat"
        try:
            with open(path, 'r') as fh:
                try:
                    self.currentnode = fh.read()
                except Exception as e:
                    self.msg.error_message(e)
                finally:
                    fh.close()
        except Exception as e:
            self.msg.error_message(e)
        if int(self.currentnode) >= int(listlength):
            self.currentnode = 0
        else:
            newnodenumber = int(self.currentnode) + 1
        with open(path, 'w+') as fh:
            try:
                fh.write(str(newnodenumber))
            except Exception as e:
                self.msg.error_message(e)
            finally:
                fh.close()
        return int(self.currentnode)


    def goodnode(self, nodelist):
        ''' Goes through the provided list
        and returns the first server node
        that does not return an error.
        '''
        l = len(nodelist)
        for n in range(self.current_node(l), l):
            self.msg.message("Trying node " + str(n) + ": " + nodelist[n])
            try:
                req = urllib.request.Request(url=nodelist[n])
                urllib.request.urlopen(req)
            except HTTPError as e:
                self.msg.error_message(e)
                self.currentnode = int(self.currentnode) + 1
            else:
                self.msg.message("Using " + nodelist[n])
                return nodelist[n]


    def identifier(self, author, permlink):
        ''' Converts an author's name and permlink 
        into an identifier
        '''
        strlink = ("@" + author + "/" + permlink)
        return strlink


    def permlink(self, identifier):
        ''' Deconstructs an identifier into
        an account name and permlink
        '''
        temp = identifier.split("@")
        temp2 = temp[1].split("/")
        return [temp2[0], temp2[1]]


    def minutes_back(self, date):
        ''' Gives a number (integer) of days
        since a given date
        '''
        elapsed = (datetime.utcnow() - datetime.strptime(date,'%Y-%m-%dT%H:%M:%S'))
        if elapsed.days > 0:
            secondsback = (elapsed.days * 24 * 60 * 60) + elapsed.seconds
        else:
            secondsback = elapsed.seconds
        minutesback = secondsback / 60
        return int(minutesback)


    def scale_vote(self, value):
        ''' Scales a vote value between 1 and 100
        to 150 to 10000 as required by Steem-Python
        for certain method calls
        '''
        value = int(value) * 100
        if value < 100:
            value = 100
        if value > 10000:
            value = 10000
        return value


    def calc_regenerated(self, lastvotetime):
        ''' Uses math formula to calculate the amount
        of steem power that would have been regenerated
        given a certain datetime object
        '''
        delta = datetime.utcnow() - datetime.strptime(lastvotetime,'%Y-%m-%dT%H:%M:%S')
        td = delta.days
        ts = delta.seconds
        tt = (td * 86400) + ts
        return tt * 10000 / 86400 / 5


    def retry(self, msg, e, retry_num, waittime):
        ''' Creates the retry message and waits the 
        given default time when a method call fails
        or a server does not respond appropriately.
        '''
        self.msg.error_message(msg)
        self.msg.error_message(e)
        self.msg.error_message("Attempt number " + str(retry_num) + ". Retrying in " + str(waittime) + " seconds.")
        time.sleep(waittime)


    def steem_per_mvests(self):
        """ Obtain STEEM/MVESTS ratio
        """
        return (self.total_vesting_fund_steem /
                (self.total_vesting_shares / 1e6))


    def sp_to_vests(self, sp):
        """ Obtain VESTS (not MVESTS!) from SP
            :param number sp: SP to convert
        """
        return sp * 1e6 / self.steem_per_mvests()


    def vests_to_sp(self, vests):
        """ Obtain SP from VESTS (not MVESTS!)
            :param number vests: Vests to convert to SP
        """
        return vests / 1e6 * self.steem_per_mvests()


    def sp_to_rshares(self, sp, voting_power=10000, vote_pct=10000):
        """ Obtain the r-shares
            :param number sp: Steem Power
            :param int voting_power: voting power (100% = 10000)
            :param int vote_pct: voting participation (100% = 10000)
        """
        vesting_shares = int(self.sp_to_vests(sp) * 1e6)
        used_power = int((voting_power * vote_pct) / 10000);
        max_vote_denom = self.vote_power_reserve_rate * (5 * 60 * 60 * 24) / (60 * 60 * 24);
        used_power = int((used_power + max_vote_denom - 1) / max_vote_denom)
        rshares = ((vesting_shares * used_power) / 10000)
        return rshares
Exemple #26
0
class AXtrans:
    def __init__(self):
        self.msg = Msg(default.logfilename,
                       default.logpath,
                       default.msgmode)
        self.db = axdb.AXdb(default.dbuser,
                            default.dbpass,
                            default.dbname)
        self.steem = SimpleSteem()
        self.react = Reaction()

    def parse_memo(self, **kwargs):
        """ Parses the memo message in a transaction
        for the appropriate action.
        """
        for key, value in kwargs.items():
            setattr(self, key, value)
        try:
            memo = self.memo.split(":")
        # A broad exception is used because any exception
        # should return false.
        except:
            return False
        self.memoid = sec.filter_token(memo[0])
        if len(memo) == 2:
            self.action = sec.filter_account(memo[1])
            return True
        elif len(memo) == 5:
            self.action = sec.filter_account(memo[1])
            self.percentage = sec.filter_number(memo[2])
            self.ratio = sec.filter_number(memo[3], 1000)
            self.duration = sec.filter_number(memo[4], 365)
            return True
        else:
            return False

    def send(self, to="artopium",
             amt="0.001 SBD",
             msg="test"):
        """ Sends the forwarded amount of SBD along
        with the reaction message
        """
        r = amt.split(" ")
        if self.steem.transfer_funds(to, float(r[0]),
                                     r[1], msg):
            self.msg.message(("Transaction committed. Sent {} "
                              "{} to {} with the memo: "
                              "{}").format(r[0], r[1], to, msg))

    def act(self, acct1, acct2, rstatus, sendto):
        """ Decides how to react baed on the action
        present in the memo message
        """
        if not self.db.get_user_token(self.memofrom):
            self.react.ignore(
                ("@{} is not a current member of "
                 + " https://steemax.trade !!Join now!! "
                 + "using SteemConnect.").format(self.memofrom))
        elif self.action == "start":
            self.react.start(acct1,
                             acct2,
                             self.memofrom,
                             rstatus,
                             self.memoid)
        elif self.action == "cancel":
            self.react.cancel(self.memofrom,
                              self.memoid)
        elif self.action == "accept":
            self.react.accept(acct1,
                              acct2,
                              self.memofrom,
                              rstatus,
                              self.memoid)
        elif self.action == "barter":
            self.react.barter(acct1,
                              acct2,
                              self.memoid,
                              self.memofrom,
                              rstatus,
                              self.percentage,
                              self.ratio,
                              self.duration)
        else:
            self.react.ignore("Invalid action.")
        if self.react.reaction == "refund":
            self.sendto = self.memofrom
        else:
            self.sendto = sendto

    def parse_history_record(self, record, lasttrans):
        """ Parses the blockchain record for transdactions
        sent to @steem-ax 
        """
        if (record[1]['op'][0] == 'transfer'
            and datetime.strptime(
                record[1]['timestamp'],
                '%Y-%m-%dT%H:%M:%S')
                > lasttrans
            and re.match(r'^[0-9]{32}',
                         record[1]['op'][1]['memo'])
            and record[1]['op'][1]['to']
                == self.steem.mainaccount):
            return True
        else:
            return False

    def fetch_history(self):
        """ Processes the transaction history. 
        The memo message is parsed for a valid 
        command and performs the 
        directed action.
        """
        rt = self.db.get_most_recent_trans()
        for a in self.steem.get_my_history():
            if self.parse_history_record(a, rt):
                if self.parse_memo(memofrom=a[1]['op'][1]['from'],
                                   memo=a[1]['op'][1]['memo'],
                                   amount=a[1]['op'][1]['amount'],
                                   trxid=a[1]['trx_id'],
                                   txtime=a[1]['timestamp']):
                    if self.db.verify_memoid(self.memofrom, self.memoid):
                        self.act(self.db.dbresults[0][0],
                                 self.db.dbresults[0][1],
                                 int(self.db.dbresults[0][2]),
                                 self.db.sendto)
                    else:
                        self.react.ignore("Invalid Memo ID.")
                        self.sendto = self.memofrom
                else:
                    self.react.ignore("Invalid Memo.")
                    self.sendto = self.memofrom
                self.send(self.sendto,
                          self.amount,
                          self.react.returnmsg)
                self.db.add_trans(self.trxid,
                                  self.memofrom,
                                  self.amount,
                                  self.memoid,
                                  self.react.reaction,
                                  self.txtime)
Exemple #27
0
 def __init__(self, **kwargs):
     ''' Looks for config.py if not found runs
     setup which prompts user for the config values
     one time only.
     '''
     for key, value in kwargs.items():
         setattr(self, key, value)
     try:
         imp.find_module('config', 
             [os.path.dirname(os.path.realpath(__file__))])
     except ImportError:
         makeconfig.MakeConfig().setup()
     from simplesteem import config
     try:
         self.mainaccount
     except:
         self.mainaccount = config.mainaccount
     try:
         self.keys
     except:
         self.keys = config.keys
     try:
         self.nodes
     except:
         self.nodes = config.nodes
     try:
         self.client_id
     except:
         self.client_id = config.client_id
     try:
         self.client_secret
     except:
         self.client_secret = config.client_secret
     try:
         self.callback_url
     except:
         self.callback_url = config.callback_url
     try:
         self.permissions
     except:
         self.permissions = config.permissions
     try:
         self.logpath
     except:
         self.logpath = config.logpath
     try:
         self.screenmode
     except:
         self.screenmode = config.screenmode
     self.s = None
     self.c = None
     self.e = None
     self.dex = None
     self.msg = Msg("simplesteem.log",
                     self.logpath, 
                     self.screenmode)
     self.util = util.Util("simplesteem.log", 
                     self.logpath, 
                     self.screenmode)
     self.connect = steemconnectutil.SteemConnect(
                     self.client_id, 
                     self.client_secret, 
                     self.callback_url, 
                     self.permissions)
     self.checkedaccount = None
     self.accountinfo = None
     self.blognumber = 0
     self.reward_balance = 0
     self.price_of_steem = 0
Exemple #28
0
class SimpleSteem:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        try:
            imp.find_module('config',
                            [os.path.dirname(os.path.realpath(__file__))])
        except ImportError:
            makeconfig.MakeConfig().setup()
        from simplesteem import config
        try:
            self.mainaccount
        except:
            self.mainaccount = config.mainaccount
        try:
            self.keys
        except:
            self.keys = config.keys
        try:
            self.nodes
        except:
            self.nodes = config.nodes
        try:
            self.client_id
        except:
            self.client_id = config.client_id
        try:
            self.client_secret
        except:
            self.client_secret = config.client_secret
        try:
            self.callback_url
        except:
            self.callback_url = config.callback_url
        try:
            self.permissions
        except:
            self.permissions = config.permissions
        try:
            self.logpath
        except:
            self.logpath = config.logpath
        try:
            self.screenmode
        except:
            self.screenmode = config.screenmode
        self.s = None
        self.c = None
        self.msg = Msg("simplesteem.log", self.logpath, self.screenmode)
        self.util = util.Util()
        self.connect = steemconnectutil.SteemConnect(self.client_id,
                                                     self.client_secret,
                                                     self.callback_url,
                                                     self.permissions)
        self.checkedaccount = None

    def steem_instance(self):
        if self.s:
            return self.s
        for num_of_retries in range(default.max_retry):
            try:
                self.s = Steem(keys=self.keys,
                               nodes=[self.util.goodnode(self.nodes)])
            except Exception as e:
                self.util.retry("COULD NOT GET STEEM INSTANCE", e,
                                num_of_retries, default.wait_time)
            else:
                return self.s
        return False

    def claim_rewards(self):
        if self.steem_instance().claim_reward_balance(
                account=self.mainaccount):
            time.sleep(5)
            return True
        else:
            return False

    def verify_key(self, acctname=None, tokenkey=None):
        if (re.match(r'^[A-Za-z0-9]+$', tokenkey) and tokenkey is not None
                and len(tokenkey) <= 64 and len(tokenkey) >= 16):
            pubkey = PrivateKey(tokenkey).pubkey or 0
            pubkey2 = self.steem_instance().get_account(acctname)
            if (str(pubkey) == str(pubkey2['posting']['key_auths'][0][0])):
                self.privatekey = tokenkey
                self.refreshtoken = None
                self.accesstoken = None
                return True
            else:
                return False
        elif (re.match(r'^[A-Za-z0-9\-\_\.]+$', tokenkey)
              and tokenkey is not None and len(tokenkey) > 64):
            self.privatekey = None
            self.accesstoken = self.connect.get_token(tokenkey)
            if self.accesstoken:
                self.username = self.connect.username
                self.refreshtoken = self.connect.refresh_token
                return True
            else:
                return False
        else:
            return False

    def reward_pool_balances(self):
        try:
            self.reward_balance
        except:
            reward_fund = self.steem_instance().get_reward_fund()
            self.reward_balance = Amount(reward_fund["reward_balance"]).amount
            self.recent_claims = float(reward_fund["recent_claims"])
            self.base = Amount(
                self.steem_instance().get_current_median_history_price()
                ["base"]).amount
        return [self.reward_balance, self.recent_claims, self.base]

    def rshares_to_steem(self, rshares):
        self.reward_pool_balances()
        return round(
            rshares * self.reward_balance / self.recent_claims * self.base, 4)

    def current_vote_value(self, *kwargs):
        try:
            kwargs.items()
        except:
            pass
        else:
            for key, value in kwargs.items():
                setattr(self, key, value)
        try:
            self.lastvotetime
        except:
            self.lastvotetime = None
        try:
            self.steempower
        except:
            self.steempower = 0
        try:
            self.voteweight
        except:
            self.voteweight = 100
        try:
            self.votepower
        except:
            self.votepower = 0
        try:
            self.account
        except:
            self.account = None
        if self.account is None:
            self.account = self.mainaccount
        if (self.lastvotetime is None or self.steempower == 0
                or self.votepower == 0):
            self.check_balances(self.account)
        c = Converter()
        self.voteweight = self.util.scale_vote(self.voteweight)
        if self.votepower > 0 and self.votepower < 101:
            self.votepower = self.util.scale_vote(self.votepower)
        else:
            self.votepower = (self.votepower +
                              self.util.calc_regenerated(self.lastvotetime))
        self.vpow = round(self.votepower / 100, 2)
        self.rshares = c.sp_to_rshares(self.steempower, self.votepower,
                                       self.voteweight)
        self.votevalue = self.rshares_to_steem(self.rshares)
        return self.votevalue

    def check_balances(self, account=None):
        if account is None:
            account = self.mainaccount
        try:
            self.votepower
        except:
            pass
        else:
            if account == self.checkedaccount:
                return [
                    self.sbdbal, self.steembal, self.steempower,
                    self.votepower, self.lastvotetime
                ]
        self.checkedaccount = account
        try:
            acct = self.steem_instance().get_account(account)
        except Exception as e:
            self.msg.error_message(e)
            return False
        else:
            c = Converter()
            self.sbdbal = Amount(acct['sbd_balance']).amount or 0
            self.steembal = Amount(acct['balance']).amount or 0
            self.votepower = acct['voting_power']
            self.lastvotetime = acct['last_vote_time']
            vs = Amount(acct['vesting_shares']).amount
            dvests = Amount(acct['delegated_vesting_shares']).amount
            rvests = Amount(acct['received_vesting_shares']).amount
            vests = (float(vs) - float(dvests)) + float(rvests)
            self.steempower = c.vests_to_sp(vests) or 0
            time.sleep(5)
            return [
                self.sbdbal, self.steembal, self.steempower, self.votepower,
                self.lastvotetime
            ]

    def transfer_funds(self, to, amount, denom, msg):
        try:
            self.steem_instance().commit.transfer(to, float(amount), denom,
                                                  msg, self.mainaccount)
        except Exception as e:
            self.msg.error_message(e)
            return False
        else:
            return True

    def get_my_history(self, account=None, limit=100):
        if not account:
            account = self.mainaccount
        try:
            h = self.steem_instance().get_account_history(account, -1, limit)
        except Exception as e:
            self.msg.error_message(e)
            return False
        else:
            return h

    def post(self, title, body, permlink, tags):
        for num_of_retries in range(default.max_retry):
            try:
                self.steem_instance().post(title, body, self.mainaccount,
                                           permlink, None, None, None, None,
                                           tags, None, True)
            except Exception as e:
                self.util.retry("COULD NOT POST '" + title + "'", e,
                                num_of_retries, 10)
            else:
                time.sleep(20)
                checkident = self.recent_post()
                ident = self.util.identifier(self.mainaccount, permlink)
                if checkident == ident:
                    return True
                else:
                    self.util.retry(
                        '''A POST JUST CREATED 
                                    WAS NOT FOUND IN THE 
                                    BLOCKCHAIN {}'''.format(title), e,
                        num_of_retries, default.wait_time)

    def reply(self, permlink, msgbody):
        for num_of_retries in range(default.max_retry):
            try:
                self.steem_instance().post("message", msgbody,
                                           self.mainaccount, None, permlink,
                                           None, None, "", None, None, False)
            except Exception as e:
                self.util.retry("COULD NOT REPLY TO " + permlink, e,
                                num_of_retries, default.wait_time)
            else:
                self.msg.message("Replied to " + permlink)
                time.sleep(20)
                return True

    def follow(self, author):
        try:
            self.steem_instance().commit.follow(author, ['blog'],
                                                self.mainaccount)
        except Exception as e:
            self.msg.error_message(e)
            return False
        else:
            return True

    def unfollow(self, author):
        try:
            self.steem_instance().commit.unfollow(author, ['blog'],
                                                  self.mainaccount)
        except Exception as e:
            self.msg.error_message(e)
            return False
        else:
            return True

    def following(self, account=None, limit=100):
        if not account:
            account = self.mainaccount
        followingnames = []
        try:
            self.followed = self.steem_instance().get_following(
                account, '', 'blog', limit)
        except Exception as e:
            self.msg.error_message(e)
            return False
        else:
            for a in self.followed:
                followingnames.append(a['following'])
            return followingnames

    def recent_post(self, author=None, daysback=0):
        if not author:
            author = self.mainaccount
        for num_of_retries in range(default.max_retry):
            try:
                self.blog = self.steem_instance().get_blog(author, 0, 30)
            except Exception as e:
                self.util.retry(
                    '''COULD NOT GET THE 
                                MOST RECENT POST FOR 
                                {}'''.format(author), e, num_of_retries,
                    default.wait_time)
            else:
                for p in self.blog:
                    age = self.util.days_back(p['comment']['created'])
                    if age < 0:
                        age = 0
                    if (p['comment']['author'] == author and age == daysback):
                        return self.util.identifier(p['comment']['author'],
                                                    p['comment']['permlink'])

    def vote_history(self, permlink, author=None):
        if not author:
            author = self.mainaccount
        return self.steem_instance().get_active_votes(author, permlink)

    def vote(self, identifier, weight=100.0):
        for num_of_retries in range(default.max_retry):
            try:
                self.steem_instance().vote(identifier, weight,
                                           self.mainaccount)
                self.msg.message("voted for " + identifier)
                time.sleep(5)
            except Exception as e:
                if re.search(r'You have already voted in a similar way',
                             str(e)):
                    self.msg.error_message('''Already voted on 
                                        {}'''.format(identifier))
                    return "already voted"
                else:
                    self.util.retry(
                        '''COULD NOT VOTE ON 
                                    {}'''.format(identifier), e,
                        num_of_retries, default.wait_time)
            else:
                return True

    def resteem(self, identifier):
        for num_of_retries in range(default.max_retry):
            try:
                self.steem_instance().resteem(identifier, self.mainaccount)
                self.msg.message("resteemed " + identifier)
                time.sleep(20)
            except Exception as e:
                self.util.retry(
                    '''COULD NOT RESTEEM 
                                {}'''.format(identifier), e, num_of_retries,
                    default.wait_time)
            else:
                return True
Exemple #29
0
#!/usr/bin/python3

import re
import sys
from cmd import Cmd
from steemax import axe
from steemax import axdb
from steemax import axverify
from steemax import axtrans
from steemax import default
from screenlogger.screenlogger import Msg

msg = Msg(default.logfilename, default.logpath, "")
db = axdb.AXdb(default.dbuser, default.dbpass, default.dbname)
xverify = axverify.AXverify()


# Entry point
def run(args=None):
    db.first_time_setup()
    prompt = MyPrompt()
    prompt.prompt = '[steemax]# '
    prompt.cmdloop('\n   ** Welcome to SteemAX ** \n')


class Enter:
    def new_account(self, acct):
        '''Prompts user to create an account
        when an account is not found
        '''
        answer = input(
class DelegatorBot():
    '''
    Main class holds functions for running the bot
    '''
    def __init__(self, debug=False, mode="verbose", botname="settings"):
        ''' Uses simplesteem and screenlogger from
            https://github.com/ArtoLabs/SimpleSteem
            https://github.com/ArtoLabs/ScreenLogger
        '''
        bot = importlib.import_module("." + botname, "delegatorbot")
        self.debug = debug
        self.cfg = bot.Config()
        self.msg = Msg(self.cfg.logfilename, self.cfg.logpath, mode)
        self.db = BotDB(self.cfg.dbusername, self.cfg.dbpass, self.cfg.dbname,
                        self.cfg.dbtable, self.cfg.dbposttable,
                        self.cfg.delegatortable)
        self.steem = SimpleSteem(mainaccount=self.cfg.mainaccount,
                                 keys=self.cfg.keys,
                                 screenmode=mode)
        self.voteweight = 0
        self.bidbot = None

    def get_replies_to_stop(self):
        ''' To have the delegation bot stop following
        someone and thus stop upvoting their posts
        they simply have to type STOP (in all caps)
        in a reply to the delegation bots own reply.
        '''
        c = 0
        # Get the bots history from the blockchain
        h = self.steem.get_my_history(limit=1000)
        if h is False or h is None:
            return False
        # iterate through the history
        for a in h:
            # Is it a comment (reply)?
            if a[1]['op'][0] == "comment":
                # Is it -not- from the bot?
                if not (a[1]['op'][1]['author'] == self.cfg.mainaccount):
                    # Does it contain the word STOP?
                    if re.match(r'STOP', a[1]['op'][1]['body']):
                        self.msg.error_message(a[1]['op'][1]['author'] +
                                               " said STOP in this post: \n" +
                                               a[1]['op'][1]['permlink'])
                        # Get the reply's identifier
                        ident = self.steem.util.identifier(
                            a[1]['op'][1]['author'], a[1]['op'][1]['permlink'])
                        # Unfollow
                        if not self.debug and self.steem.unfollow(
                                a[1]['op'][1]['author']):
                            # Reply to user with confirmation
                            self.steem.reply(
                                ident, "@" + self.cfg.mainaccount +
                                " has stopped " + "following you.")
                            c += 1
        self.msg.message(str(c) + " stop messages received")
        return True

    def process_delegators(self):
        ''' The delegation bot will follow and upvote
        those who have delegated. Delegating less than
        the minimum amount will cause the bot to unfollow
        '''
        # Create the table if it doesn't already exist
        self.db.initialize_delegators()
        # set variables
        followed = 0
        unfollowed = 0
        delegators = {}
        # Get blockchain global variables
        self.steem.global_props()
        # Get bot's history from the blockchain
        h = self.steem.get_my_history(limit=1000)
        if h is False or h is None:
            return False
        for i in h:
            # if the field is the delegate_vesting_shares
            # field than get the name
            # of the delegator and the sp delegated and
            # store it in the 'delegators' dictionary
            if i[1]['op'][0] == "delegate_vesting_shares":
                d = i[1]['op'][1]['delegator']
                vests = float(i[1]['op'][1]['vesting_shares'].replace(
                    " VESTS", ""))
                if d != self.cfg.mainaccount:
                    delegators[d] = vests
        # get all known delegators from the database
        self.db.get_delegators()
        # iterate through new delegators
        for d, vests in delegators.items():
            sp = self.steem.util.vests_to_sp(vests)
            found = False
            follow = False
            unfollow = False
            # iterate through known delegators
            if self.db.dbresults is not None and self.db.dbresults is not False:
                for row in self.db.dbresults:
                    if d == row[1]:
                        # new delegator is already known indicating a possible change
                        found = True
                        # has it been changed?
                        if float(vests) != float(row[2]):
                            self.db.update_delegator(d, vests)
                            self.msg.message(d + " changed delegation to " +
                                             str(vests) + " VESTS (" +
                                             str(sp) + " SP)")
                            # is it above or lower than minimum needed ?
                            if sp >= self.cfg.minimum_delegation:
                                follow = True
                            else:
                                unfollow = True
            # This is really a new delegator
            if found is False:
                # Add them to the database
                self.db.add_delegator(d, vests)
                self.msg.message("New delegation from " + d + " of " +
                                 str(vests) + " VESTS (" + str(sp) + " SP)")
                # Did they send more then the minimum?
                if sp >= self.cfg.minimum_delegation:
                    follow = True
            # Follow
            if follow:
                followed += 1
                if self.debug is False:
                    self.steem.follow(d)
            # Unfollow
            elif unfollow:
                unfollowed += 1
                if self.debug is False:
                    self.steem.unfollow(d)
        self.msg.message(
            str(followed) + " followed, " + str(unfollowed) + " unfollowed")
        return True

    def daily_report(self):
        ''' A report that is generated daily showing a list of current
        delegators, a list of the posts that were upvoted the day before,
        and instructions on how to get upvotes from the bot by delegating.
        '''
        # Create the table if it doesn't already exist
        self.db.initialize_bot_posts()
        # Get the date
        now = datetime.now()
        # Create the title for the report
        title = ("The @" + self.cfg.mainaccount + " Daily Report for " +
                 str(now.strftime("%B")) + " " + str(now.day) + ", " +
                 str(now.year))
        self.msg.message("Creating " + title)
        # Start the body of the report
        body = ("# @" + self.cfg.mainaccount +
                " wants to upvote *YOUR* posts! \n" + "@" +
                self.cfg.mainaccount + ", is an upvote bot run by @" +
                self.cfg.owner + ". Read more " + "below about what @" +
                self.cfg.mainaccount + " does and how you can use it.")
        # Fetch the bot's current upvote value at 100% voting power
        my_vote_value = self.steem.current_vote_value(
            accountname=self.cfg.mainaccount,
            voteweight=100,
            votepoweroverride=100)
        # Add the vote value to the report
        body += ("\n\n___\n### My current upvote value at 100% is: $" +
                 str(my_vote_value) + "\n___\n\n")
        # Add The list of delegators
        del_list = self.daily_report_delegators()
        if del_list is not False and del_list is not None:
            body += del_list
        # The link to delegate to the bot
        body += ('[Delegate now](' + self.cfg.delegationlink +
                 ') to get an upvote like these people.')
        body += (
            '\n\nBy delegating ' + str(self.cfg.minimum_delegation) +
            ' SP or more @' + self.cfg.mainaccount +
            ' will start following you within 45 minutes and upvoting all of your posts too!'
        )
        # Create the permlink from the title
        permlink = re.sub(r' ', '-', title)
        permlink = re.sub(r'[^A-Za-z0-9\-]', '', permlink)
        permlink = permlink.lower()
        # Add a list of all posts that received an upvote
        up_list = self.daily_report_upvote_list()
        if up_list is not False and up_list is not None:
            body += up_list
        # Add the template footer to the report
        footer = self.daily_report_footer()
        if footer is not False and footer is not None:
            body += footer
        # Check debug status
        if self.debug is False:
            self.msg.message("Posting, please wait... ")
            # post the daily report to the blockchain
            if self.steem.post(title, body, permlink, self.cfg.post_tags):
                identifier = self.steem.util.identifier(
                    self.cfg.mainaccount, permlink)
                # Add it to the database
                self.db.add_bot_post(self.cfg.post_tags[0], identifier)
                self.msg.message("Created report " + identifier)
                return identifier
            else:
                return False
        else:
            # If debug is on just print it out to the screen
            print(body)
        return True

    def daily_report_upvote_list(self):
        ''' Creates a list of everyone that has received an upvote
        from the bot in the last 24 hours
        '''
        # get the number of upvotes in the last 24 hours
        numofposts = self.db.upvote_stats(1)
        if (self.db.dbresults is not None and self.db.dbresults is not False
                and numofposts > 0):
            # Create the list header
            upvote_list = ("\n### @" + self.cfg.mainaccount + " upvoted " +
                           str(numofposts) +
                           " posts yesterday. They were:<br>\n")
            # display each post upvoted and the percentage they got
            for post in self.db.dbresults:
                upvote_list = (upvote_list + "https://steemit.com/" + post[1] +
                               "\nThis post was voted at " + str(post[3]) +
                               "%\n\n")
            return str(upvote_list)
        else:
            self.msg.error_message("\nThe database of posts is empty\n")
            return False

    def daily_report_delegators(self):
        ''' Creates a list of the bot's delegators
        '''
        # Get the number of delegators from the database
        numofdelegators = self.db.get_delegators()
        # Are there delegators?
        if (self.db.dbresults is not None and self.db.dbresults is not False
                and numofdelegators > 0):
            # Add the delegator count to the report
            delegator_list = ("\n\n## @" + self.cfg.mainaccount + " has " +
                              str(numofdelegators) +
                              " delegators. They are:\n\n")
            # Get the blockchain global variables
            self.steem.global_props()
            # Iterate through all the delegators and display how much they've delegated
            for d in self.db.dbresults:
                sp = int(self.steem.util.vests_to_sp(float(d[2])))
                # Those who delegate more will have their names made bigger
                if sp > 1000:
                    title_size = "##"
                elif sp > 500:
                    title_size = "###"
                elif sp > self.cfg.minimum_delegation + 5:
                    title_size = "####"
                else:
                    title_size = ""
                delegator_list = (delegator_list + title_size + " @" + d[1] +
                                  " has delegated " + str(sp) + " SP\n")
            # Thank you!
            delegator_list += "## Thank You Delegators! "
            return delegator_list
        else:
            self.msg.error_message("\nThe database of delegators is empty\n")
            return False

    def daily_report_footer(self):
        ''' opens the post_template.txt file and returns it populated with 
        values from settings.py
        '''
        # The directory we're in
        dir_path = os.path.dirname(os.path.realpath(__file__))
        # Does the file exist?
        if os.path.exists(dir_path + "/post_template.txt"):
            # Can we open it?
            with open(dir_path + "/post_template.txt", 'rb') as f:
                try:
                    # split the file up into a list of lines (byte list)
                    footer = f.read().splitlines()
                except:
                    f.close()
                    self.msg.error_message(
                        "\nCould not open post_template.txt!\n")
                    return False
                else:
                    f.close()
                    # Convert, format and return
                    return ((self.make_newlines(footer)).format(
                        self.cfg.footer_top_pic_url, self.cfg.mainaccount,
                        self.cfg.footer_info_url, self.cfg.reply_image,
                        self.cfg.footer_info_url, self.cfg.minimum_delegation,
                        self.cfg.delegationlink,
                        self.cfg.footer_delegate_button_url,
                        self.cfg.allowed_tags, self.cfg.mainaccount,
                        self.cfg.owner, self.cfg.footer_bottom_pic_url,
                        self.cfg.discord_invite_url, self.cfg.website_url,
                        self.cfg.website_name))
        else:
            self.msg.error_message(
                "\nCould not find post_template.txt directory.\n")
            return False

    def make_newlines(self, byte_text_list=None):
        ''' Converts a list of bytes into
        one string and adds the newline character
        '''
        newtext = ''
        # decode the byte list into a string list
        try:
            ls = [i.decode() for i in byte_text_list]
        except Exception as e:
            self.msg.error_message("Byte list error: " + str(e))
            return ""
        # concatenate that list adding newlines
        if len(ls) > 0:
            for line in ls:
                newtext += str(line) + '\n'
        return newtext

    def run_bot(self):
        ''' Runs through the list of those it is following and upvotes
        the most recent post. Vote weight is determined by an algorithm (see below)
        Note that someone does not need to be a delegator to receive
        upvotes, they simply need to be followed by the bot. Of course
        delegating causes the bot to follow someone, but you can also have
        the bot follow someone manually, thus granting them upvotes without delegating.
        '''
        # If the table does not exist create it
        self.db.initialize_bot_mem()
        # Get all the account names of all those the bot is following
        if self.debug:
            following = ["artopium"]
        else:
            following = self.steem.following(self.cfg.mainaccount)
        # Are we following anyone?
        if (following is not None and following is not False
                and len(following) > 0):
            self.msg.message("Following: " + str(len(following)))
            # Iterate through that list
            for f in following:
                self.msg.message('\n' + f)
                # Did we successfully vote?
                if self.debug is False:
                    identifier = self.run_bot_upvote(f)
                else:
                    identifier = "debug"
                if identifier is not False:
                    # Resteem the post
                    if self.debug is False:
                        self.steem.resteem(identifier)
                        # Reply to the post
                        self.run_bot_reply(identifier, f)
                else:
                    self.msg.message("No post found for " + f)
        else:
            self.msg.message("The bot is not following anyone.")
            return False
        return True

    def run_bot_upvote(self, followed):
        ''' upvotes the post if it's eligible
        '''
        # If the table does not exist create it
        self.db.initialize_bot_mem()
        if followed is False or followed is None:
            return False
        identifier = self.steem.recent_post(followed,
                                            self.cfg.post_max_days_old, 1)
        # Is there a post?
        if identifier is False or identifier is None:
            self.msg.message("Identifier is None")
            return False
        # Are they already in the database?
        if self.db.find_bot_mem(identifier) is not False:
            self.msg.message("Already voted for " + identifier)
            return False
        # Do they have the right tags? blognumber is assigned
        # During call to get recent_post
        if self.verify_tags(self.steem.blognumber):
            # Use the algorithm to adjust vote weight, assign it to
            # class variable so it can be accessed by run_bot_reply
            self.voteweight = self.adjust_vote_weight(followed)
            if self.debug:
                print("would've voted: " + identifier)
                v = True
            else:
                # Vote
                v = self.steem.vote(identifier, self.voteweight)
            # Does the blockchain say we already voted?
            if v == "already voted":
                self.msg.message("Already voted for " + identifier)
                # Add it to the database
                self.db.add_bot_mem(identifier, self.voteweight)
                return False
            elif v:
                self.msg.message(followed + " got a vote at " +
                                 str(self.voteweight) + "%")
                # Add it to the database
                self.db.add_bot_mem(identifier, self.voteweight)
                return identifier
            else:
                return False
        else:
            self.msg.message(followed + " does not have the right tag.")
            return False

    def run_bot_reply(self, identifier, followed):
        ''' Resteems a post after the bot has voted on it
        '''
        if identifier is None or followed is None:
            return False

        # The directory we're in
        dir_path = os.path.dirname(os.path.realpath(__file__))
        # Does the file exist?
        if os.path.exists(dir_path + "/reply_template.txt"):
            # Can we open it?
            with open(dir_path + "/reply_template.txt", 'rb') as bfile:
                try:
                    # split the file up into a list of lines (byte list)
                    reply = bfile.read().splitlines()
                except:
                    bfile.close()
                    self.msg.error_message(
                        "\nCould not open reply_template.txt!\n")
                    return False
                else:
                    dailyreport = self.db.get_recent_post()
                    bfile.close()
                    v = int(self.voteweight)
                    # format the tempalate
                    newtext = self.make_newlines(reply)
                    msg = newtext.format(followed, v, self.cfg.mainaccount,
                                         self.cfg.footer_info_url,
                                         self.cfg.reply_image,
                                         self.cfg.footer_info_url, dailyreport,
                                         self.cfg.alert_message)
                    if self.debug:
                        print(identifier)
                        print(msg)
                        return True
                    else:
                        self.steem.reply(identifier, msg)
                        return True
        else:
            self.msg.error_message(
                "\nCould not find reply_template.txt directory.\n")
            return False

    def adjust_vote_weight(self, account):
        ''' This algorithm takes an average of all the votes made in
        the last 3 days, then subtracts that from 3-days-worth of voting power;
        The remaining vote power determines the vote weight.
        '''
        if account is None or account is False:
            return 0
        if account == self.cfg.owner:
            return 100

        bal = self.steem.check_balances()
        votepower = round(
            (self.steem.votepower +
             self.steem.util.calc_regenerated(self.steem.lastvotetime)) / 100,
            2)
        total_vote_weight_used = 1
        # make sure vote power isn't too low
        if votepower > self.cfg.vote_power_threshold:
            numofposts = self.db.upvote_stats(3)
            for i in range(0, numofposts - 1):
                # for each post made we total the weight used, not the actual num of posts
                total_vote_weight_used += self.db.dbresults[i][3]
            # then we adjust based on the total weight used in the last 3 days
            # 800 is 80% of 1000, which is 10 votes at 100% per day (10 x 100)
            print(
                str(numofposts) + " previous posts in the last 3 days with " +
                str(total_vote_weight_used) + " total vote weight.")
            # 3 days of vote power would is 3000
            # to account for new users and surges in use the 3000 is
            # is multiplied by a user defined number
            adj = ((3000 * self.cfg.algorithm_scale) / total_vote_weight_used *
                   100)
            sec_since_last_vote = self.db.already_voted_today(account)
            minutes_since_last_vote = sec_since_last_vote / 60
            print("Base percentage: " + str(adj) + "%")
            # Caps the vote weight
            if adj > self.cfg.vote_weight_max:
                adj = self.cfg.vote_weight_max
                print("Adjusted to " + str(self.cfg.vote_weight_max))
            print("Minutes since last upvote: " + str(minutes_since_last_vote))
            # Check to see if the account is NVIP. If so let's give them the VIP amount
            if len(self.cfg.nvip_accounts) > 0:
                for nvip in self.cfg.nvip_accounts:
                    if account == nvip:
                        adj = self.cfg.nvip_vote_weight
                        print("NVIP account. Adjusted weight to: " + str(adj) +
                              "%")
            # Check to see if the account is VIP. If so let's give them the VIP amount
            if len(self.cfg.vip_accounts) > 0:
                for vip in self.cfg.vip_accounts:
                    if account == vip:
                        adj = self.cfg.vip_vote_weight
                        print("VIP account. Adjusted weight to: " + str(adj) +
                              "%")
            if sec_since_last_vote is not False and int(
                    sec_since_last_vote) < 86400:
                # if we voted them in the last 24 hours we scale the vote
                # based on how long ago the last vote was.
                # If it was less that 3 hours ago the weight is 3%
                if int(sec_since_last_vote
                       ) < self.cfg.reduced_vote_wait_time * 60 * 60:
                    adj = self.cfg.reduced_vote_weight
                else:
                    adj *= sec_since_last_vote / 86400
                print(
                    account +
                    " already got a vote in the last 24 hours. Adjusting vote further: "
                    + str(adj) + "%")
            else:
                if adj < self.cfg.vote_weight_min:
                    adj = self.cfg.vote_weight_min

            return adj
        else:
            return 10

    def verify_tags(self, blognumber):
        ''' Makes sure the post to be voted on has used the
        tags set in settings
        '''
        if blognumber is None:
            return False
        if self.steem.blog[blognumber]['comment']['json_metadata'] is not None:
            tags = json.loads(
                self.steem.blog[blognumber]['comment']['json_metadata'])
            if tags['tags'] is not None:
                for t in tags['tags']:
                    for a in self.cfg.allowed_tags:
                        if t == a:
                            return True
        else:
            self.msg.error_message("Blog comment was 'none'")
        return False

    def boost_post(self, daysback=0, denom="STEEM", amount=0.02):
        ''' boosts the payout of the daily report using bid bots
        '''
        if daysback < 0:
            self.msg.error_message("Invalid date to boost post")
            return False
        if denom != "STEEM" and denom != "SBD":
            self.msg.error_message("Invalid denomination to boost post")
            return False
        if amount < 0.01:
            self.msg.error_message("Invalid amount to boost post")
            return False
        # If the table doesn't exist create it
        self.db.initialize_bot_posts()
        # Get a daiy report from the past
        identifier = self.db.get_recent_post(daysback)
        if identifier is None or identifier is False:
            self.msg.message("No posts found")
            return False
        idkey = self.db.id
        ftag = self.db.firsttag
        # Make the whole url
        boostlink = ("https://steemit.com/" + ftag + "/" + identifier)
        # make sure we have enough in the coffers
        if self.ensure_balance(denom) is not False:
            self.msg.message("Boosting " + boostlink)
            # boost
            if self.debug is False:
                self.steem.transfer_funds(self.bidbot, amount, denom,
                                          boostlink)
            self.msg.message("Sent " + str(amount) + " " + denom + " to " +
                             self.bidbot)
            return True
        else:
            return False

    def ensure_balance(self, denom):
        ''' Does what it says. Ensures that the steem or sbd balance
        of the bot account has not reached below the minimums set in settings.
        Used when "boosting"
        '''
        # If the table doesn't exist create it
        self.db.initialize_bot_posts()
        # Check the bot's balances
        bal = self.steem.check_balances(self.cfg.mainaccount)
        # Check the reward pool
        #self.steem.reward_pool_balances()
        if (denom == "SBD"):
            print("Current SBD balance: " + str(bal[0]))
            self.bidbot = self.cfg.sbd_bidbot
            if float(bal[0]) > float(self.cfg.minimum_balance):
                return True
            else:
                self.msg.message(
                    ("Cannot boost posts because the current " +
                     "SBD balance is {}. The balance must " +
                     "be more than {} SBD").format(bal[0],
                                                   self.cfg.minimum_balance))
                return False
        elif (denom == "STEEM"):
            print("Current STEEM balance: " + str(bal[0]))
            self.bidbot = self.cfg.steem_bidbot
            if bal[1] > self.cfg.minimum_balance:
                return True
            else:
                self.msg.message(
                    ("Cannot boost posts because the current " +
                     "STEEM balance is {}. The balance must " +
                     "be more than {} STEEM").format(bal[1],
                                                     self.cfg.minimum_balance))
                return False
        else:
            return False

    def claim(self):
        ''' Claims the rewards of the bot's account
        '''
        return self.steem.claim_rewards()

    def balance(self):
        ''' Prints the current balance
        '''
        bal = self.steem.check_balances(self.cfg.mainaccount)
        self.msg.message('''
    __{}__
    {} SBD
    {} STEEM
    {} STEEM POWER'''.format(self.steem.mainaccount, bal[0], bal[1], bal[2]))
        return True
Exemple #31
0
class AXtrans:



    def __init__(self):
        self.msg = Msg(default.logfilename, 
                        default.logpath, 
                        default.msgmode)
        self.db = axdb.AXdb(default.dbuser, 
                            default.dbpass, 
                            default.dbname)
        self.steem = SimpleSteem()
        self.react = Reaction()



    def parse_memo(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        # Ew this is dirty and came from 
        # strangers! Must be sanitized!
        try:
            memo = self.memo.split(":")
        except:
            return False
        self.memoid = memo[0] or None
        if re.match(r'^[A-Za-z0-9\:]$', self.memoid):
            return False
        if len(memo) == 2:
            self.action = memo[1] or None
            return True
        elif len(memo) == 5:
            self.action = memo[1] or None
            self.percentage = memo[2] or None
            self.ratio = memo[3] or None
            self.duration = memo[4] or None
            return True
        else:
            return False



    def send(self, to="artopium", 
                    amt="0.001 SBD", 
                    msg="test"):
        r = amt.split(" ")
        if self.steem.transfer_funds(to, float(r[0]), 
                                    r[1], msg):
            self.msg.message(("Transaction committed. Sent {} "
                            "{} to {} with the memo: "
                            "{}").format(r[0], r[1], to, msg))



    def act(self, acct1, acct2, rstatus, sendto):
        if not self.db.get_user_token(self.memofrom):
            self.react.ignore(
                ("{} is not a current member of "
                + " https://steemax.trade! Join now "
                + "using SteemConnect.").format(self.memofrom))
        elif (self.action == "start"):
            self.react.start(acct1, 
                            acct2, 
                            self.memofrom, 
                            rstatus,
                            self.memoid)
        elif (self.action == "cancel"):
            self.react.cancel(self.memofrom, 
                            self.memoid)
        elif (self.action == "accept"):
            self.react.accept(acct1, 
                            acct2, 
                            self.memofrom, 
                            rstatus,
                            self.memoid)
        elif (self.action == "barter"):
            self.react.barter(acct1, 
                            acct2, 
                            self.memoid, 
                            self.memofrom, 
                            rstatus, 
                            self.percentage, 
                            self.ratio, 
                            self.duration)
        else:
            self.react.ignore("Invalid action.")
        if self.react.reaction == "refund":
            self.sendto = self.memofrom
        else:
            self.sendto = sendto



    def parse_history_record(self, record, lasttrans):
        if (record[1]['op'][0] == 'transfer'
                and datetime.strptime(
                    record[1]['timestamp'], 
                    '%Y-%m-%dT%H:%M:%S')  
                > lasttrans
                and re.match(r'^[0-9]{32}', 
                    record[1]['op'][1]['memo'])
                and record[1]['op'][1]['to'] 
                == self.steem.mainaccount):
            return True
        else:
            return False



    def fetch_history(self):
        ''' Processes the transaction history. 
        The memo message is parsed for a valid 
        command and performs the 
        directed action.
        '''
        rt = self.db.get_most_recent_trans()
        for a in self.steem.get_my_history():
            if self.parse_history_record(a, rt):
                if self.parse_memo(memofrom=a[1]['op'][1]['from'], 
                                memo=a[1]['op'][1]['memo'], 
                                amount=a[1]['op'][1]['amount'], 
                                trxid=a[1]['trx_id'], 
                                txtime=a[1]['timestamp']):
                    if self.db.verify_memoid(self.memofrom, self.memoid):
                        self.act(self.db.dbresults[0][0],
                                self.db.dbresults[0][1],
                                int(self.db.dbresults[0][2]),
                                self.db.sendto)
                    else:
                        self.react.ignore("Invalid Memo ID.")
                        self.sendto = self.memofrom
                else:
                    self.react.ignore("Invalid Memo.")
                    self.sendto = self.memofrom

                self.send(self.sendto, 
                                self.amount, 
                                self.react.returnmsg)
                self.db.add_trans(self.trxid, 
                                self.memofrom, 
                                self.amount, 
                                self.memoid, 
                                self.react.reaction, 
                                self.txtime)
Exemple #32
0
class Util:



    def __init__(self):
        self.msg = Msg()



    def goodnode(self, nodelist):
        for n in nodelist:
            req = urllib.request.Request(url=n)
            try:
                self.msg.message("Trying " + n)
                urllib.request.urlopen(req)
            except HTTPError as e:
                self.msg.error_message(e)
            else:
                self.msg.message("Using " + n)
                return n



    def identifier(self, author, permlink):
        return ("@" + author + "/" + permlink)



    def permlink(self, identifier):
        temp = identifier.split("@")
        temp2 = temp[1].split("/")
        return [temp2[0], temp2[1]]



    def days_back(self, date):
        daysback = (datetime.now() - datetime.strptime(date,'%Y-%m-%dT%H:%M:%S')).days
        if daysback < 0:
            daysback = 0
        return daysback



    def scale_vote(self, value):
        value = int(value) * 100
        if value < 150:
            value = 150
        if value > 10000:
            value = 10000
        return value



    def calc_regenerated(self, lastvotetime):
        delta = datetime.utcnow() - datetime.strptime(lastvotetime,'%Y-%m-%dT%H:%M:%S')
        td = delta.days
        ts = delta.seconds
        tt = (td * 86400) + ts
        return tt * 10000 / 86400 / 5



    def retry(self, msg, e, retry_num, waittime):
        self.msg.error_message(msg)
        self.msg.error_message(e)
        self.msg.error_message("Attempt number " + str(retry_num) + ". Retrying in " + str(waittime) + " seconds.")
        time.sleep(waittime)