Tutorial - Getting started with DSteem - Auto Vote Bot

in #dsteem6 years ago (edited)

Repository

https://github.com/jnordberg/dsteem/

tutorial-banner.jpg

Outline

In this tutorial we’re going to be looking into the DSteem javascript library. DSteem, created by @almost-digital is significantly more performant than steem-js. We’ll use DSteem to create a script that watches for transactions on the blockchain and automatically votes posts from a specific user.

👨🏼‍💻 The full code for the script can be found on Github & CodePen 🚀

Requirements

  • A plain text editor (I use VS Code)
  • A browser (I use Brave)

Difficulty

Beginner

Learning Goals

  • Connect to the api.steemit.com using DSteem
  • listen for blockchain transactions
  • Check transactions against rules
  • Send votes using DSteem

Preface

There are a bunch of tutorials, plenty in fact. There’s 34 tutorials in the official repo to be precise. So then why do I get the sentiment from the community that dSteem is unapproachable and steem-js is easier to use?! Has anyone else thought or felt this?

While the documentation is great the code example might be lost on beginners. Why? Well, as a developer with some experience you can clone a repo, install the dependencies and kickstart a dev server all whist sipping coffee with your other hand. The new dev is thinking WTF am I doing, why do I have 9 files already and why do I have to enter the matrix just to run one line of code from this library!

No you don’t need Node.js or a development server to make use of Dsteem. Yes you can create simple scripts in the browser to interact with the Steem blockchain.

Let’s do this.

We’ll stream blocks from the blockchain. Check for specific users. Vote as a response when a specific user post comes through. kaboom!

Step 1 - Setup

We can run this script in the browser. Create a .html file. We’ll include a specific version of dsteem and create a script tag for out own javascript code.

<html>
    <head>
    <script src="https://unpkg.com/[email protected]/dist/dsteem.js"></script>
        <script>
                        // Tutorial Code here
                </script>
    </head>
    <body></body>
</html>

Alternatively you can work in codepen.io - Fork this Pen.

Step 2 - Listen for transactions on the Blockchain

Now we’re setup we can start to interact with the blockchain using DSteem. First up we need to setup a connection to one of the Steem API servers. We’ll use Steemit.com’s API server. This client is what we’ll use to make calls against the API.

const client = new dsteem.Client('https://api.steemit.com');

DSteem has a number of helper functions separated into categories blockchain, broadcast and database. As part of the blockchain helpers we can stream blocks as they’re processed by the network.

First save a reference to the stream

const stream = client.blockchain.getBlockStream();

If you’ve never used Streams before and are confused dig into this article to learn more. Streams emit events we can hook into (‘data’, ‘end’, ‘error’, ‘close’, ‘readable’). We’ll listen for the data event and for each chunk of data we receive from the stream we’ll run a function. For now lets log the result.

const stream = client.blockchain.getBlockStream();
stream.on('data', (block) => console.log(block))

You should start seeing blocks in your console
console-001.png

Nice. lets abstract this out to keep our code friendly

const stream = client.blockchain.getBlockStream();
stream.on('data', (block) => processBlock(block))

// Helper function to separate logic into smaller pieces
function processBlock(block) {
    console.log(block)
}

[cosole.log screenshot - operations]
Digging into the console results you’ll notice the blocks contain and array of transactions. Of those transactions each has an operation type which we’re used to understanding ‘vote’, ‘comment’, ‘custom_json’ etc. Dsteem also has a helper for streaming operations directly but I think it’s useful to look at inspecting the blocks ourselves. Operations are stored in an array of each transaction, it doesn’t look the friendliest to access.

// check individual operation type
block.transactions[0].operations[0][0] 

Now we can filter the array to check for a specific type of operation. In this project we’re going to be looking for comments (also includes top level posts) by a specific author. Filter for ‘comment’.

function processBlock(block) {
  // Each block contains multiple transactions
  const txs = block.transactions.filter( tx => tx.operations[0][0] === ‘comment’ )
// you’ll see arrays of varying lengths populating the console
console.log(txs)
}

lets extract our filter function into something more generalised. This way we can reuse this function through our app for different purposes.

function processBlock(block) {
  // filter by operation type
  block.transactions.filter( tx => filterTransactions(tx, ’comment’) )
}

function filterTransaction(tx, operationType){
  return tx.operations[0][0] === operationType
} 

Step 3 - Check for specific data within a transaction

We’ve split the transactions in the blocks to only show those we’re interested in. Next we’ll check the specific data of each of the transactions. First lets see each transaction in the console. Similar to the operationType the operationData is also nested in an array.

// check individual operation Data
block.transactions[0].operations[0][1] 
function processBlock(block) {
  // Each block contains multiple transactions
  block.transactions
      // create a new list of transactions that only include a specific type of operation
     .filter( tx => filterTransaction(tx, 'comment') )
      // Check the data of each operation 
     .forEach( tx => console.log(tx.operations[0][1] ))
}

Again we can abstract the operationsData into a friendly function. This makes working with our app less cognitively intensive. We can use words that describe whats happening instead of looking at nested objects and arrays.

// Helper for nested transaction Data
function transactionData(tx){
  return tx.operations[0][1]
}

Now we can abstract the processing of the data into a separate function also.

function processBlock(block) {
  block.transactions
     .filter( tx => filterTransaction(tx, 'comment') )
     .forEach( tx => processTransaction( transactionData(tx) ))
}

processTransaction( txData) {
    console.log(txData)
}

We now have a functions that has access to individual transaction data. We can choose how to process the data and how to respond. For this project we’re interested in the author of the comment. If the author matches that of a predetermined list we’ll send a vote.

Make a list of usernames.

// perhaps you want your list to look like this and to support my content ;)
const AUTO_VOTE_LIST = ['sambillingham', 'codewithsam', 'finallynetwork']

create a helper function for checking this list of usernames. If a username exists in our list it should return true.

// Helper for checking vote list
function isAutoVote(name){
  return (AUTO_VOTE_LIST.indexOf(name) > -1);
}

Edit the processTransaction function to make use of our new helper.

processTransaction( txData) {
    if ( isAutoVote(txData.author) ) console.log( `${txData.author} just posted a comment` ) 
}

Let's move on to broadacting a transaction instead of just viewing data.

Step 4 - Broadcast Votes

Different from Steem-js library DSteem creates a decoded instance of the posting key rather than using the raw string.

setup our username and private posting key (wif). Grab this from the steemit.com permissions tab.

const USERNAME = ''
const POSTING_KEY = dsteem.PrivateKey.fromString('')

We’ll use the broadcast helper and call vote client.broadcast.vote, passing an object with the relevant data. let’s wrap the DSteem library call into our own function.

// Broadcast vote using DSteem
function sendVote(author, permlink) {
  client.broadcast.vote({
      voter: USERNAME,
      author: author,
      permlink: permlink,
      weight: 10000
  }, POSTING_KEY)
  .then( (result) => {
     console.log(`VOTE FOR ${author}:${permlink}`)
     console.log(result)
  })  
}

We can now send votes with a small helper function sendVote(author, permlink) passing in an author and permlink to vote on. Moving back to the processTransaction() function we can broadcast a vote instead of logging the data.

// Process Post against any rules and send response
function processTransaction(txData){
  if ( isAutoVote(txData.author) ) sendVote(txData.author, txData.permlink)
}

Just like that we’ve created a simple auto voting bot. Go ahead and test it, make a post from your testing account or add username you know are posting regularly.

👨🏼‍💻 The full code for the script can be found on Github & CodePen 🚀

I hope you have found this tutorial useful. If you have questions or I can help with a project please comment below.

Sort:  

I thank you for your contribution. Here are my thoughts. Note that, my thoughts are my personal ideas on your post and they are not directly related to the review and scoring unlike the answers I gave in the questionnaire;

  • Structure

    • I appreciate the structure of your post. It is well done; organizes the post and makes it easier to read.
  • Language

    • I personally think the usage of the first person reduces the efficiency of the post. I advise you to consider using less first person. Still, this is a personal thought, don't get me wrong! :)
  • Content

    • I quite liked the content of your post. Keep up the good work!

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]

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

Congratulations @codewithsam! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You made more than 10 upvotes. Your next target is to reach 50 upvotes.

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @codewithsam! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You got your First payout
You received more than 50 as payout for your posts. Your next target is to reach a total payout of 100

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

Support SteemitBoard's project! Vote for its witness and get one more award!

Hi @codewithsam!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @codewithsam!

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

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

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

Vote for Utopian Witness!

Thank you for posting! Probably helped me out a lot.