Tutorial: Viewing Steemit Account History
utopian-io·@r351574nc3·
0.000 HBDTutorial: Viewing Steemit Account History
Recently, I and another Steemit user were discussing (I don't remember exactly why) what user accounts were created on '2017-10-11' by `anonsteem`. Those of you who don't know, `anonsteem` is an account that will instantly create Steemit accounts for you at the expense of 5 STEEM. This tutorial is not about that though. As we were asking this, we realized that the API for account history is just a stream of information. It is not easy to filter or query. As we hacked away at it, I realized that this would be a valuable tutorial to give including some lessons learned. ## What will you learn * Fetching Steemit Account history with `nodejs` api * Steemit api with promises * Typescript usage of nodejs API * Generator functions and iterating results from asynchronous calls using a `for` loop * Knowledge of what the account history object looks like * Manipulating the account history object ## Requirements This tutorial is written for Typescript. To use typescript you really just need `nodejs`. ## Setup In my [Github Repository](https://www.github.com/r351574nc3/steem-bot-examples), there is a module I created for this tutorial for this called `steemit-account-history`. Please clone this project and open the following file in your IDE: `steemit-account-history/src/manage.ts`(https://github.com/r351574nc3/steem-bot-examples/blob/topic/steemit-account-history/steemit-account-history/src/manage.ts) ## Account History Account history are transactions that happen to your account like when you change your profile picture or permissions on your keys. Here's an example of what the JSON looks like: ```javascript {"trx_id":"092fb94e7ba1b3a66fda64d3fbf4262d5d1c686d","block":16255559,"trx_in_block":0,"op_in_trx":0,"virtual_op":0,"timestamp":"2017-10-12T04:27:03","op":["account_create_with_delegation",{"fee":"6.000 STEEM","delegation":"0.000000 VESTS","creator":"anonsteem","new_account_name":"tapcrypto","owner":{"weight_threshold":1,"account_auths":[],"key_auths":[["STM5ukwG1g39NvtCuG9EfpLWMULFDVCcWUrpsCzufBSebHDmq9RAh",1]]},"active":{"weight_threshold":1,"account_auths":[],"key_auths":[["STM8DFbKF5U2pXScbfm6V6Ro4V52e87Das5RuZtL47JXYcR1cD75d",1]]},"posting":{"weight_threshold":1,"account_auths":[],"key_auths":[["STM7QcUVhUyae3Ec8UFAiqyqFBDb69MX91wn8xmBwk636yxHRCRY9",1]]},"memo_key":"STM5VrJZ4LJ4YZEdkXDk32DqeM7SAV5SFRhfXreUYaL8oYDbHxbBM","json_metadata":"","extensions":[]}]} ``` ## getAccountHistory ```javascript steem.api.getAccountHistoryAsync(account, from, limit) ``` My first mistake here was thinking `from` is a date. It's actually the start index or record number. The reason is the amount of account history can be really HUGE! `limit` is given to reduce the amount of data which then forces the need to page through data. What you would normally do is start at record `0` and page through the data until you find what you're looking for. ```javascript steem.api.getAccountHistoryAsync(account, 0, 100) steem.api.getAccountHistoryAsync(account, 100, 100) steem.api.getAccountHistoryAsync(account, 200, 100) ``` > The above shows how multiple calls can be made to page 3 times through 100 account history records (300 in total). That is pretty much what you would have to do. You can't just retrieve all account history records. Retrieving so much information isn't reliable. In many cases, you will run into a `Gateway Timeout`. It's best to avoid those; therefore, paging is our only option. ### Iterating through every record Suppose there is some information and you don't know what record you're looking for. How do you query it? First, what I like to do is find out what the absolute last record is. This is actually not a difficult task. I created a function for this: ```javascript async function find_last_record(user: string): Promise<number> { let retval = 0; await steem.api.getAccountHistoryAsync(user, Number.MAX_SAFE_INTEGER, 1) .then((history: any[]) => { const record = history[0]; retval = record[0]; }); return retval; } ``` You can see I used a really huge number (Number.MAX_SAFE_INTEGER) . Now, I can safely page through the data knowing just how far I need to go. ```javascript for (let start = step; start < end; start = start + step) { await steem.api.getAccountHistoryAsync(user, start, step) ``` `end` represents that upper bound I discovered by grabbing the last record. Now, what I need are all the records after `2017-10-11`. To get these, I'm going go iterate through all the records and skip them until I arrive at the first record I care about. Here's my full loop. ```javascript for (let start = step; start < end; start = start + step) { await steem.api.getAccountHistoryAsync(user, start, step) .each((history: any[]) => { if (!history || history.length < 1) { return; } const record = history[1]; const on_date = moment(date); const ts = moment(record.timestamp); if (ts.startOf("day").isAfter(on_date.startOf("day"))) { retval.push(record); } }); } ``` You can see that I check for `ts.startOf("day").isAfter(on_date.startOf("day")` to determine if the record is important or not. If it is, I push it onto a buffer. I then stuff all this goodness into a generator function ```javascript async function* seek(user: string, date: string): any { const step = 1000; const retval: any[] = []; let end = 0; await find_last_record(user).then((result: number) => { end = result; }); for (let start = step; start < end; start = start + step) { await steem.api.getAccountHistoryAsync(user, start, step) .each((history: any[]) => { if (!history || history.length < 1) { return; } const record = history[1]; const on_date = moment(date); const ts = moment(record.timestamp); if (ts.startOf("day").isAfter(on_date.startOf("day"))) { retval.push(record); } }); } yield* retval; } ``` The reason I did this is because I want to be able to loop through my account history records with a `for` loop. ```javascript async function main() { const result = seek("anonsteem", "2017-10-11"); for await (const item of result) { console.log("Record %s", JSON.stringify({ operation: item.op[0], timestamp: item.timestamp })); } } ``` I slimmed down the records with `{ operation: item.op[0], timestamp: item.timestamp }` because I just wanted to know what the operation was. I could always add more details if I want later. My results end up looking like this: ```javascript Record {"operation":"transfer","timestamp":"2017-10-12T04:02:54"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T04:03:09"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T04:20:21"} Record {"operation":"transfer","timestamp":"2017-10-12T04:25:42"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T04:27:03"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T05:03:03"} Record {"operation":"transfer","timestamp":"2017-10-12T06:43:45"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T06:44:09"} Record {"operation":"transfer","timestamp":"2017-10-12T07:17:03"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T07:17:57"} Record {"operation":"transfer","timestamp":"2017-10-12T10:15:00"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T10:16:15"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T10:29:27"} Record {"operation":"account_create_with_delegation","timestamp":"2017-10-12T14:47:42"} ``` # Thank you ---- I hope you enjoyed this and that it was helpful to you. # Other Tutorials in this Series * [Tutorial: Getting Started with git-steem-bot](https://utopian.io/utopian-io/@r351574nc3/tutorial-git-steem-bot) * [Tutorial: Weekly Digest Steembot in a Docker Container](https://utopian.io/utopian-io/@r351574nc3/tutorial-weekly-digest-steembot-in-a-docker-container) <br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@r351574nc3/tutorial-viewing-steemit-account-history">Utopian.io - Rewarding Open Source Contributors</a></em><hr/>