Finding out who delegated to me with Python - Is there an easier way?

in #steem6 years ago (edited)

Hello Steemians! If you seen my previous post on a simple related link builder, you will know that I am trying to build some projects on top of STEEM. As part of the projects, I need to know who have delegated SP to my account and also the amount of SP delegated. There is a ready API, get_vesting_delegations, to list all delegations made by a particular account. By running it against my account, I can see that I have delegated SP to @teamsingapore.

image.png

However, it seems like there is no easy way to list all delegations made to a particular account (please let me know if is a direct API call to list all delegators for a particular account 😅). The only way I found is to run through the entire transaction history of the target account and identify who are the delegators. And in this post, I will be showing you how I did it with Python.


Getting account transaction history

The API to get the transaction history of an account is get_account_history, but there is a problem, the API only allow maximum of 10000 records to be extracted each time. Hence, I need to create a loop to get the full history. Also, each transaction record is stored in the following format:

image.png

As you can see, the operation to look for is delegate_vesting_shares, which will contain the delegatee, the delegator and the vesting_shares delegated. I created a while loop to append each delegate_vesting_shares operation to a list. Below is the code:

        delegation_records= []
        index = -1
        while index != 0: #continue to retrieve next 10000 records until reaches entry 0
            print("index: " + str(index))
            if index < 0 or index > 10000:
                limit = 10000
            else:
                limit = index
            data = s.get_account_history(account, index, limit)
            index = int(data[0][0])
            for x in range(len(data)):
                if (int(data[x][0]) != index or int(data[x][0]) == 0) and data[x][1]['op'][0] == 'delegate_vesting_shares': #handle possible duplicated records
                    delegation_records.append(data[x])  

Extracting delegation records

For easier explanation, I will be using the @teamsingapore account as the object of reference. In the previous section, I have extracted all delegation transactions related to @teamsingapore. With the data, the next thing I need to do is to identify current delgations made to @teamsingapore. Steem delegation works in such a way that each time you make a new delegation to an account, it overwrites your previous delegation with the new value. Hence, the order of delegation transactions is important to identify the current delegators for the target account.

        sorted_delegation_records = sorted(delegation_records, reverse=True) #sort records from latest to earliest
        is_delegatee = {}
        is_delegator = {}

        for x in range(len(sorted_delegation_records)):
            if sorted_delegation_records[x][1]['op'][1]['delegator'] != account and sorted_delegation_records[x][1]['op'][1]['delegator'] not in is_delegatee:
                is_delegatee[sorted_delegation_records[x][1]['op'][1]['delegator']] = c.vests_to_sp(Amount(sorted_delegation_records[x][1]['op'][1]['vesting_shares']).amount)
            if sorted_delegation_records[x][1]['op'][1]['delegator'] == account and sorted_delegation_records[x][1]['op'][1]['delegatee'] not in is_delegator:
                is_delegator[sorted_delegation_records[x][1]['op'][1]['delegatee']] = c.vests_to_sp(Amount(sorted_delegation_records[x][1]['op'][1]['vesting_shares']).amount)

        delegation_file = open("delegation.txt", "a+")
        delegation_file.write("Delegation from:\n" + json.dumps(is_delegatee, indent=4, sort_keys=True))
        delegation_file.write("Delegation to:\n" + json.dumps(is_delegator, indent=4, sort_keys=True))
        delegation_file.close()
        print("Delegation from:\n" + json.dumps(is_delegatee, indent=4, sort_keys=True))
        print("Delegation to:\n" + json.dumps(is_delegator, indent=4, sort_keys=True))

In the above code, I first sorted the records from the latest (highest entry number) to oldest. Next I use a "for-loop" to classify delegation transactions to the following cases:

  • The target account is the delegatee
  • The target account is the delegator

I only take the most recent entry as only that is needed. The relevant transactions are stored in Python dictionaries, with the delegator/delegatee account being the key and the SP delegated being the value. One thing to note here is that I am using the tools provided by Steem to convert vests to SP.

Putting it all together

With the functions ready, I put them all into one proper script. Code below:

from steem import Steem
from steem.converter import Converter
from steem.amount import Amount
import json, sys

if len(sys.argv) < 2:
    print('Insufficient arguments. Please run script with the following arguments without brackets: [account]')
    exit()
    
account = sys.argv[1]
s = Steem()
c = Converter()

def get_delegation_records_from_STEEM():
    try:
        delegation_records= []
        index = -1
        while index != 0: #continue to retrieve next 10000 records until reaches entry 0
            print("index: " + str(index))
            if index < 0 or index > 10000:
                limit = 10000
            else:
                limit = index
            data = s.get_account_history(account, index, limit)
            index = int(data[0][0])
            for x in range(len(data)):
                if (int(data[x][0]) != index or int(data[x][0]) == 0) and data[x][1]['op'][0] == 'delegate_vesting_shares': #handle possible duplicated records
                    delegation_records.append(data[x])  
        
    except Exception as e:
        print(str(e))
        
    finally:
        #return as many delegation_records as possible even if there are errors along the way
        return delegation_records

def process_delegation_records(delegation_records):
    try:
        sorted_delegation_records = sorted(delegation_records, reverse=True) #sort records from latest to earliest
        is_delegatee = {}
        is_delegator = {}

        for x in range(len(sorted_delegation_records)):
            if sorted_delegation_records[x][1]['op'][1]['delegator'] != account and sorted_delegation_records[x][1]['op'][1]['delegator'] not in is_delegatee:
                is_delegatee[sorted_delegation_records[x][1]['op'][1]['delegator']] = c.vests_to_sp(Amount(sorted_delegation_records[x][1]['op'][1]['vesting_shares']).amount)
            if sorted_delegation_records[x][1]['op'][1]['delegator'] == account and sorted_delegation_records[x][1]['op'][1]['delegatee'] not in is_delegator:
                is_delegator[sorted_delegation_records[x][1]['op'][1]['delegatee']] = c.vests_to_sp(Amount(sorted_delegation_records[x][1]['op'][1]['vesting_shares']).amount)

        delegation_file = open("delegation.txt", "a+")
        delegation_file.write("Delegation from:\n" + json.dumps(is_delegatee, indent=4, sort_keys=True))
        delegation_file.write("Delegation to:\n" + json.dumps(is_delegator, indent=4, sort_keys=True))
        delegation_file.close()
        print("Delegation from:\n" + json.dumps(is_delegatee, indent=4, sort_keys=True))
        print("Delegation to:\n" + json.dumps(is_delegator, indent=4, sort_keys=True))
        
    except Exception as e:
        print(str(e))   

def run():
    try:        
        data = get_delegation_records_from_STEEM()
        process_delegation_records(data)
        
    except Exception as e:
        print(str(e))

if __name__ == '__main__':
    run()

To run the script, simply save the codes as a Python script (I saved it as get_delegations.py in this case) and include the account you want to check as the argument. Example below:

image.png

The script will output the delegation information and also save a copy into a file.

image.png


Conclusion

It seems like I am taking a long route to get the information I need. By doing it this way, it will take huge amount of time to check delegation information for an account which has a lot of transactions (e.g. @smartsteem). If this the only way, then I think it will be good to cache the information into a database or a file and then refresh the information periodically so that you do not need to check through the entire history each time.

In my opinion, I think there should be a straightforward way to get delegation information programmatically. So I highly suspect I am missing something. Thanks for reading and do let me know your thoughts!

steem-divider1.png

Projects/Services I am working on:


You can find me in these communities:

Sort:  

Maybe @justyy could help you on this. He made this amazing tool to see who delegates SP to one's account :)

https://helloacm.com/tools/steemit/delegators/

Thanks! I found the site before my post. Currently his delegator API is not opened to public, but I will contact him to seek some help. :)

@culgin hi there, did you find out a one call function method to get in on shot the list of delegators ??? not the api one (https://helloacm.com/tools/steemit/delegators/)

Nope. I have contacted the creator of helloacm.com, and according to him, he keeps a database of delegation records to enable the quick search. So it's some kind of a layer 2 solution to this problem. I don't see an official function call to get the required info

well done my friend, very nice article.

YOU JUST GOT UPVOTED

Congratulations,
you just received a 18.22% upvote from @steemhq - Community Bot!

Wanna join and receive free upvotes yourself?
Vote for steemhq.witness on Steemit or directly on SteemConnect and join the Community Witness.

This service was brought to you by SteemHQ.com

Coin Marketplace

STEEM 0.16
TRX 0.13
JST 0.027
BTC 58115.81
ETH 2623.89
USDT 1.00
SBD 2.42