SimpleSteem 1.1 ~ New Features!
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.
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.
- Can now vote and unvote for a witness.
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.
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()
.
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.
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.
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
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!