SimpleSteem 1.1 ~ New Features!

in #utopian-io6 years ago (edited)

Repository

https://github.com/artolabs/simplesteem

SimpleSteem

SimpleSteem is a robust and reliable wrapper that dramatically simplifies the steem-python interface, expands functionality, and enables code that is gentle on public servers.

simplesteem1.1.png

New Features

SimpleSteem:

  • Can now fetch the market ticker and get the highest bid and lowest ask.

  • Can now do simple market transactions moving STEEM to SBD or SBD to STEEM. If given no arguments the conversion methods will fetch the highest bid or lowest ask to make the conversion.

steemtosbd_faster.gif

  • Can now vote and unvote for a witness.

votewitness_faster.gif

  • Can fetch all the names that an account is following and check to see if they have voted for that account as witness.

  • Can fetch all the names that an account is following to see if any of them have recently muted that account.

  • Can now delegate Steem Power to another account.

delegate_faster.gif

Steps I took

First, I added the methods for obtaining the market ticker and for converting STEEM to SBD. I ran into problems using the Converter class in Steem-Python due to the fact that this class makes a second call with a separate steem instance in order to obtain the steemd global properties. So I brought over the methods used to make the convertions and I added a method for obtaining the global properties using SimpleSteem's steem_instance().

Proof of work #1

Proof of work #2

Proof of work #3

    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
        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))
            return False
        else:
            self.msg.message("TRANSFERED " 
                                + str(steemamt) 
                                + " STEEM TO SBD AT THE PRICE OF: $"
                                + str(price))
            return True


    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
        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))
            return False
        else:
            self.msg.message("TRANSFERED " 
                                + str(sbd) 
                                + " SBD TO STEEM AT THE PRICE OF: $"
                                + str(price))
            return True

Global properties method


    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.
        '''
        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



Then I added the methods for voting and unvoting a witness. These are pretty straight forward.

Like all other methods in SimpleSteem the steem_instance is used to call a Steem-Python method. This is advantageous because the steem_instance method uses the goodnode method which gives SimpleSteem it's ability to be robust yet gentle on public servers.

While creating these new methods I realized too many calls were being made to fetch account information so I also created a new method for storing account info in a class variable.

Proof of work #1


    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 " + account), 
                    e, num_of_retries, default.wait_time)
            else:
                return self.accountinfo


    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)
            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)
            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



Finally I added the methods for finding those who've muted an account as well as delegating Steem Power. To find those who've muted was tricky as I had to traverse a custom JSON object inside a tuple.

In this final commit I make the STEEM to SBD and SBD to STEEm methods more robust with better error checking as well as account balance checking.

Proof of work

 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 not account:
            account = self.mainaccount
        following = self.following(account, limit)
        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))
            return False
        else:
            self.msg.message("DELEGATED " + str(steempower) + " STEEM POWER TO " + str(to))
            return True


Technology Stack

SimpleSteem is written using Python 3.5

Dependencies

SimpleSteem uses the Steem-Python library, the SteemConnect python library by emre, and ScreenLogger, a very simple class for logging what's printed to screen. All of these are automatically installed if using pip3.

Instructions

The project README was recently updated with a complete set of instructions that include all new features.

Roadmap

SimpleSteem is finished in it's current state but I do plan on flushing out the SteemConnect methods a bit more. Of course I plan to continue error checking and hardening as I continue to use SimpleSteem in my various projects.

Contact

Please contact Mike (Mike-A) on Discord
https://discord.gg/97GKVFC

Github

https://github.com/artolabs

Sort:  

Thank you for your contribution. Giving meaningful variable name would have been better.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @learnelectronics
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63342.09
ETH 2658.68
USDT 1.00
SBD 2.81