Sending Multiple Payments in a Single Transaction
At SteemSports, we do hundreds of payouts weekly. Currently, each payout is done as a standalone transaction.
I was wondering if its possible to be more efficient, and send multiple payouts at once. It turns out, its not only possible, but very easy to do.
I've borrowed some code from piston to hack together these two helper functions:
def broadcast_multi(steem, wifs, ops, write_mode=False):
tx = sign_multi_tx(steem, ops, wifs)
if not write_mode:
return tx
return steem.broadcast(tx)
def sign_multi_tx(steem, ops, wifs):
"""Construct a transaction that contains multiple operations."""
if not isinstance(wifs, list):
wifs = [wifs]
if not any(wifs) and not steem.unsigned:
raise MissingKeyError
ops = [transactions.Operation(x) for x in ops]
expiration = transactions.formatTimeFromNow(steem.expiration)
ref_block_num, ref_block_prefix = transactions.getBlockParams(steem.rpc)
tx = transactions.Signed_Transaction(
ref_block_num=ref_block_num,
ref_block_prefix=ref_block_prefix,
expiration=expiration,
operations=ops
)
if not steem.unsigned:
tx = tx.sign(wifs)
return tx.json()
To send multiple payments at once, we need to create a list of operations. I am going to do this manually here for sake of simplicity and ease of understanding:
ops = [
transactions.Transfer(
**{"from": "fnait",
"to": "furion",
"amount": '{:.{prec}f} {asset}'.format(
float(0.1),
prec=3,
asset="SBD"
),
"memo": "TEST MULTI"
}
),
transactions.Transfer(
**{"from": "fnait",
"to": "furion",
"amount": '{:.{prec}f} {asset}'.format(
float(0.1),
prec=3,
asset="SBD"
),
"memo": "TEST MULTI 2"
}
)
]
Now we can construct, sign and broadcast the transfers with a single line of code:
tx = broadcast_multi(steem, wifs, ops, write_mode=True)
Where do steem
and wifs
come from?
steem
is just a piston Steem instance: steem = Steem()
and wifs
is a list of private keys (in this case, we just need the active private key).
If we set write_mode
to False, it will run in simulation mode, without actually broadcasting the transaction to the network.
tx
Steemit
Note
Beware that the transaction has a hardcoded limit of 64k, so don't cram too many operations in one.
Don't miss out on the next post - follow me.
SteemSports | steemtools | steem.li | witness
When compiling a list of "wifs" you might use a bin packing algorithm before executing "broadcast_multi". That way you stay under 64k
Awesome, thanks for sharing @furion. I have thought about it but too lazy to try. Now I could steal your code to use it for my multivotes routine. :P Hope you don't mind ;)
Fairly confident it isn't stealing friend, when it has been shared openly.
Rock on, @furion! 🙌
Thank you for posting @furion. Steemsports is a winner blog....thank you for the Espirit de Corp you bring to Steemit and your professionalism. It is appreciated by many.
Needed something like this a month ago :(
Great job as always & Thank you for sharing.
Shared on twitter too.
Thank you :)
Steemland.com tweeted @ 16 Nov 2016 - 16:59 UTC
Disclaimer: I am just a bot trying to be helpful.
Upvoted.
This post has been ranked within the top 25 most undervalued posts in the second half of Nov 16. We estimate that this post is undervalued by $14.00 as compared to a scenario in which every voter had an equal say.
See the full rankings and details in The Daily Tribune: Nov 16 - Part II. You can also read about some of our methodology, data analysis and technical details in our initial post.
If you are the author and would prefer not to receive these comments, simply reply "Stop" to this comment.
Awesome work @furion. I think this will be very useful for many people in the future. I can think of many use already. I wish I would have voted before the first payout!
Is there anyway to add a list of usernames for "to", then the transfers would go down the list?
Thank you for sharing.
Here is a quick and dirty way: You could use dict comprehension to set a 'to' field from a list. I assume the other fields are the same for all payouts, then you can do something like:
Awesome I'll give it a try, thank you.
Gave you a witness vote :)