SteemAX 1.5 ~ Send All, Accept All and Cancel All Auto Exchange Invitations



SteemAX helps minnow content-creators

and whale curators by automating an exchange of upvotes between their quality blog posts, allowing both 1 to 1 as well as disproportional exchanges that grant bigger curations, better support than a bid bot, and the long-term support they both deserve.

Batch Processing

Although a user must still complete a Captcha in order to create each new invite, they can now accept, send and cancel all their exchanges with one button. This greatly aides the user in speeding up the process, but still ensures that spammers are deterred.

Batch processing uses Steem Connect in the same manner as for sending, accepting or canceling a single invite, and simply modifies the memo field to include a delineated list of all the commands to be processed. The user simply clicks the Send All, Accept All or Cancel All button, and when they are redirected to Steem Connect they can see the total SBD needed to be sent in order to process all the transactions ($0.001 per transaction).

SteemAX never takes a fee and the amount sent is used to forward messages to the other party via the memo field in an SBD send. This is a much more polite way to send an invitation than posting a comment.


To accomplish this:

Batch processing of actions can be done manually or on the website. Separate actions can be bundled into a batch by simply connecting them together with an underscore ( _ ).


The parse_memo function now parses the memo by splitting it on the underscore delineator, then splitting again on the semicolon delineator, into a list of dictionaries, each dictionary stores the memoid, action to be commenced, along with the ratio, percentage and duration if it is a barter.

    def parse_memo(self, memo=None):
        """ Parses the memo message in a transaction
        for the appropriate action.
        memodict = {}
        memos = []
        self.memolist = []
        if'_', memo): 
                memos = memo.split("_")
            # A broad exception is used because any exception
            # should return false.
                self.msg.error_message("Unable to parse memo. Error code 1.")
                return False
        for i in range(0, len(memos)):
            if i == len(memos):
                memo_parts = memos[i].split(":")
            # A broad exception is used because any exception
            # should return false.
                self.msg.error_message("Unable to parse memo. Error code 2.")
                return False
            # Everything from the outside world is 
            # filtered for security and added to a dictionary
            memodict['memoid'] = sec.filter_token(memo_parts[0])
            if len(memo_parts) == 2:
                memodict['action'] = sec.filter_account(memo_parts[1])
            elif len(memo_parts) == 5:
                memodict['action'] = sec.filter_account(memo_parts[1])
                memodict['percentage'] = sec.filter_number(memo_parts[2])
                memodict['ratio'] = sec.filter_number(memo_parts[3], 1000)
                memodict['duration'] = sec.filter_number(memo_parts[4], 365)
                self.msg.error_message("Unable to parse memo. Error code 3.")
                return False
            # The dictionary is added to a list
        return True

After the memo has been parsed, transactions are sent to receiving parties based on the content of the list of dictionaries.

elif self.memolist[i]['action'] == "start":
        elif self.memolist[i]['action'] == "cancel":
            self.react.cancel(self.memofrom, self.memolist[i]['memoid'], rstatus, acct2)
        elif self.memolist[i]['action'] == "accept":
            self.react.accept(acct1, acct2, self.memofrom, rstatus, self.memolist[i]['memoid'])
        elif self.memolist[i]['action'] == "barter":
            self.react.barter(acct1, acct2, self.memolist[i]['memoid'], self.memofrom, rstatus,
                              self.memolist[i]['percentage'], self.memolist[i]['ratio'], self.memolist[i]['duration'])

On the website javascript code was created to concatenate the command strings into one memo, and to calculate the cost of sending each each action to each receiving party. Along with this is code that determines if the buttons should be seen: no need to display a send-all button if there's nothing to send!

function sendAll(command) {
    regex = new RegExp('[^A-Za-z0-9\\:\\.]', 'g');
    var ids;
    if (command === "accept") {
        ids = document.getElementById("allacceptids").value.split(",");
    else if (command === "start") {
        ids = document.getElementById("allsendids").value.split(",");
    else if (command === "cancel") {
        ids = document.getElementById("allcancelids").value.split(",");
    var memoid = document.getElementById("memoid"+ids[0]).value.replace(regex, '');
    memo = memoid+":"+command;
    for(i=1;i<ids.length;i++) {
        memoid = document.getElementById("memoid"+ids[i]).value.replace(regex, '');
        memo += "_"+memoid+":"+command;
    sendamount = ids.length / 1000;
    var url = ""+myaccountname+"&to=steem-ax&amount="+sendamount+"%20SBD&memo="+memo+"&redirect_uri="+myaccountname;
    window.location = (url);
function showAllButtons() {
    var acceptids = document.getElementById("allacceptids").value.split(",");
    var sendids = document.getElementById("allsendids").value.split(",");
    var cancelids = document.getElementById("allcancelids").value.split(",");
    if (sendids.length > 1) {
        document.getElementById("sendall-button").style.display = 'block';
    if (acceptids.length > 1) {
        document.getElementById("acceptall-button").style.display = 'block';
    if (cancelids.length > 1) {
        document.getElementById("cancelall-button").style.display = 'block';

Commit #5dd6723

Technology Stack

SteemAX is written to use Python 3.5 and MySQL. The web interface for and has been written in HTML, CSS and Javascript.


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

GitHub Account


Thank you for your contribution. It is nice to see continuous development on the project. You said version is 1.5 but in your source code, you change it to 1.4.2 - which seems a bit odd to me. It is also worth separating your changes in a few commits and create a PR and merge which will keep your master branch history a bit clean.

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
Chat with us on Discord.

Yeah, I just forgot to update the version number on github, which has been done now. As for the commit: I did half the work for half the reward. I think it's fair. If either the price of Steem increases or Utopian modifies its upvote strategy to accommodate the price of steem then they might see a match between the actual output of quality and that which seems expected.

Thank you for your review, @justyy! Keep up the good work!

Thank you learnelectronics! You've just received an upvote of 80% by @ArtTurtle!

Learn how I will upvote each and every one of your art and music posts

Please come visit me as I've updated my daily report with more information about my upvote value and how to get the best upvote from me.

Hey, @learnelectronics!

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

Get higher incentives and support!
Simply set as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.26
TRX 0.10
JST 0.032
BTC 41890.69
ETH 2250.66
USDT 1.00
SBD 5.18