SteemAX is an auto upvote exchange program that lets Steemians swap votes with each other for an agreed upon length of time.
SteemAX 1.1 Released
First I'd like to give much thanks to @outwork who has once again stepped up and delivered excellent quality work in response to my task request for a new homepage for SteemAX. This is the first of many task requests I plan on creating in the upcoming weeks as SteemAX needs help with the creation, revamping and redesigning of certain pages and functions. I'm just a meek back-end programmer with an idea and I could use help from visionary designers and graphics experts like @outwork. Thank you!
In this new release from SteemAX, version 1.1 provides an optimized vote exchange algorithm aimed at a faster run-time and that's less consuming of resources. This will be a continual endeavor throughout all future releases. New functionality has been added as well. A page that shows the history of all exchanges was created to show details about the time, post identifiers, and vote values traded in each exchange. This can be displayed as a list of all exchanges on SteemAX, or a list of all exchanges for a particular account.
Some Of The Benefits Of Using SteemAX
- Better relations with your fellow Steemians.
- A mechanism for supporting minnows long-term.
- A better way for whales to distribute upvotes.
- An avenue for minnows to seek support without feeling like they have their hand out.
- A way of socializing the current platform away from pure capitalism...
- But also a true "open market" where upvotes can be traded and bartered upon.
- Since Steemians can trade their vote at disproportional ratios, they can seek profits above and beyond what self voting could achieve, thus eliminating the temptation to over self vote.
- Whales that exchange at ratios favorable to minnows stand a better chance of receiving curation rewards, plus a substantial return on the value of their vote.
- To use SteemAX is free since no fees are taken and all SBD used to start and accept invites goes directly to the other party.
SteemAX Benefits The Whole System
Because whales are unable to manually distribute their upvote consistently, bid bots were created. SteemAX is a much better solution for distributing upvotes automatically than a bid bot:
Because the number of blocks processed by witnesses is perhaps as equally important as the "distribution of wealth" on the Steemit platform, bid bots were created to provide both. SteemAX solves this problem by still maintaining a high number of transactions, but via an exchange, from voter to voter, rather than centrally distributed by a bid bot.
Because each exchange must be manually agreed upon, the likely-hood of upvotes going to human created content rather than spam is greatly increased, as people are much more likely to agree to things they support.
Exchanges Have Been Running Smoothly
The first users of SteemAX have already created a number of exchanges which have commenced since my last post. Each exchange has occurred automatically without any problems, and it appears that transactions are at least scalable beyond what they are currently running at by several factors. Of course, I anticipate the need for optimization will arrive quickly. As a step towards a faster algorithm, I've reduced the need for SteemAX to renew access tokens to only when they expire. I accomplished this by refactoring the methods
renew_token and by creating a new method which, for lack of imagination, I named
sc_vote, which actually initializes SteemConnect and makes the vote.
vote_on_it checks if
sc_vote fails and if so uses
renew_token to use the refresh token to gain a new access token and save it to the database, then tries
sc_vote to make a vote again.
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 refreshtoken = db.dbresults 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 access 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
The commit for these changes also includes some PEP 8 inspired adjustments of whitespace and triple double quotes for the doc strings.
New Feature: Exchange History
SteemAX now has a public page that displays a history of all exchanges that have taken place between its users. The history details the two parties involved in the exchange (inviter vs. invitee), the amount exchanged ($0.10 vs. $0.10), the date and time the exchange took place, and the respective blog posts that were upvoted, which can be seen by placing the cursor over the account names.
This page has been placed at the address:
Or see an individual account history by visiting
Please do not judge the web page design because layout and design are not my primary skills. It's my intention to create a task request to hand over the actual design of this page (plus a few others) to someone with more skill than myself. My goal was to create the back-end functionality and have a front-end that demonstrates that functionality.
These new features were accomplished by creating a new table in the database that records all the archived exchanges and their pertinent information. A method was also created for inserting an exchange into the database.
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)
I also created a method for retrieving archived exchanges for all of steemax or just an individual account.
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
The commit for this code also contains a change to the
archive_exchange method and a slight change to the size of the table columns.
Next, the code in
steemax.py was created that is necessary for displaying the list of archived exchanges on the command line, both for easy access as well as testing prior to going live on the website.
def do_exchanges(self, args): """ Lists all the archived exchanges for an account """ account = input("Account (press enter for none): ") # If no account is entered return the whole list if not account or account == "" or account == 0: account = None else: print ("Looking up " + account) axlist = db.get_exchange_archive(account) for trade in axlist: print(str(trade)) print("@" + str(trade) + "/" + str(trade) + "\nvs.\n" + "@" + str(trade) + "/" + str(trade)) print(str(trade) + " vs. " + str(trade) + "\n\n")
Obviously the command line list is for administrator use so a method was created for displaying the list as a web page. It simply gets the list of archived exchanges from the database, then using the
make_page methods generates and returns an HTML page of the list.
def archive_page(self, account=None): """ Provides a list of all the exchanges that have occurred for a particular account. if no account is provided then a list of all exchanges for all accounts is returned. """ infobox = "" if account is not None: account = sec.filter_account(account) # If the token is invalid return user to the login page if not self.db.get_user_token(account): return self.auth_url() axlist = self.db.get_exchange_archive(account) boxtemplate = self.load_template("templates/archivebox.html") for trade in axlist: date = (str(trade.hour) + ":" + str(trade.minute) + " " + str(trade.strftime("%B")) + " " + str(trade.day) + ", " + str(trade.year) + " ") box = self.make_page(boxtemplate, TIMESTAMP=date, ACCOUNT1=trade, ACCOUNT2=trade, IDENT1=trade, IDENT2=trade, VOTEVALUE1=trade, VOTEVALUE2=trade) infobox = infobox + box pagetemplate = self.load_template("templates/archive.html") # If the account was provide we display it with the @ # however if it's not we convert it to an empty string # so that it is not displayed in HTML if account is None: account = "" else: account = "@" + account return ("\r\n" + self.make_page(pagetemplate, ACCOUNT=account, INFOBOX=infobox))
This commit also contains some minor refactoring to better conform to PEP 8 standards.
Finally, the HTML and CSS were created for the history page as well as the Python script that executes the 'archive_page` on the server.
#!/usr/bin/python3 from cgi import FieldStorage from steemax.web import Web account = FieldStorage().getvalue('account') print ("Content-type: text/html") print (Web().archive_page(account))
Commit #1 for HTML
Commit #2 for HTML
Commit #3 for HTML
Commit #4 for CSS
Commit #5 for Python
In the future more contributors will be brought into the fold
via Task Requests to help improve the functionality of the site and most especially the look and feel. After all, projects always benefit from the synergistic action of teamwork.
Please contact Mike (Mike-A) on Discord