Help of a blockchain dev pro please

I have something fun planned for when we hit 5,000 humans.

I see PoH has about 3,500 registered humans. But need some help building a list. I played with The Graph API being used by the webapp but was having trouble. Rather than wasting time figuring out the idiosyncrasies, figured I would ask for help from other devs used to it.

What I would like:

  • An easy way to pull a list of registered humans. With at minimum:
    • Registration time
    • ETH address
    • “Display Name” (or if easier just the IPFS metadata URL)
    • Status (that they are registered and not removed)

An endpoint for JSON, CSV, Jupyter/Colab notebook, automated Google Sheet, anything would be fine.

Cheers

4 Likes

Heres a quick site: https://list.humanity.tools/

it queries the graph on page load, getting only registered users, and then orders by submissionTime. And its currently capped at 5000 entries.
You can export a csv of the data with the link at the top after the table loads.
Time is currently unix-stamp, also some display names get missing characters from the graph - this can be fixed by adding in a loop to get the name from the ipfs file instead. I’ll tidy it up over the weekend!

(also made this over lunch so might have some bugs, will have a look over again later to check i didnt get anything too wrong with the query, it seems to line up with the numbers on https://pohgraph.vercel.app)

8 Likes

See the below example to fetch everything you asked
You can run this in your browser

fetch('https://api.thegraph.com/subgraphs/name/kleros/proof-of-humanity-mainnet', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: `
        {
          submissions(where: { registered: true }, first: 3) {
            id
            registered
            submissionTime
            name
            requests( where: { type:Registration }, orderBy:resolutionTime, orderDirection:desc, first: 1) {
	    	evidence {
		URI
	      }  
	    }
          }
        }
      `,
  }),
}).then((a) => a.json()).then((a) => console.info(a))

Returns

{
  "submissions": [
    {
      "id": "0x0002801411400e2dcaa33800b881e1a486611d44",
      "name": "MARU",
      "registered": true,
      "requests": [
        {
          "evidence": [
            {
              "URI": "/ipfs/QmQgKNLdm3S9bQXU77RNvTJXWLm8jWe3DNY6bKSx5u1gAB/registration.json"
            }
          ]
        }
      ],
      "submissionTime": "1619575758"
    },
    {
      "id": "0x000b85652fc321561cdf2bcadb07b61d8ab9ab8d",
      "name": "Jony",
      "registered": true,
      "requests": [
        {
          "evidence": [
            {
              "URI": "/ipfs/QmWKofjK6GyRZVia3zsvyj9U7gXnvfVNP1AGKDHEMKHAAq/registration.json"
            }
          ]
        }
      ],
      "submissionTime": "1618759341"
    },
    {
      "id": "0x0013e34f237879f29c6785c3b50f9d9caef4953c",
      "name": "Luisito",
      "registered": true,
      "requests": [
        {
          "evidence": [
            {
              "URI": "/ipfs/Qmczzs8j2Vdn9izRu28rFSGMPoCMx2Vg8uAw9qD6yyaRo1/registration.json"
            }
          ]
        }
      ],
      "submissionTime": "1617516301"
    }
  ]
}

Details

  • Use the first field to determine how many profiles you want to return;
  • You might need paging/do multiple requests to fetch every profile. To do that you can use the skip option. For example to fetch the “second page” you would replace the first: 3 win the query with first: 3, skip: 3 (assuming you want to return in batches of 3 profiles`.

Additional information

  • The id field is the profile’s address;
  • While the display name is already included in the returned results, you may want to also display (for example) the profile’s picture. To do that use fetch the URI from an ipfs gateway. It will return a json object with a fileURI field. Fetch that and it will return the profile picture URI (along the first and last name, video URI and bio).

Example:
GET https://gateway.ipfs.io/ipfs/QmQgKNLdm3S9bQXU77RNvTJXWLm8jWe3DNY6bKSx5u1gAB/registration.json
returns

{
  "fileURI":"/ipfs/QmTP8rfJC8AQ5QPYtHkoG7cSQWHQTz6GHZHbKFynxup9oX/file.json",
  "name":"Registration"
}

Then GET https://gateway.ipfs.io/ipfs/QmTP8rfJC8AQ5QPYtHkoG7cSQWHQTz6GHZHbKFynxup9oX/file.json
returns

{
  "name": "MARU",
  "firstName": "Maria Eugenia",
  "lastName": "Piriz",
  "bio": "Amante de las criptomonedas",
  "photo": "/ipfs/QmXgDBrz27TCH3hv2mu234WPtCksaqXa5RiY5B89hVMAkE/win-20210420-14-28-58-pro-2-.jpg",
  "video": "/ipfs/QmVFmnvbXBptM3SYtxUSjnaThh6zddMUaPLfhmuhnbcnfz/win-20210420-14-16-58-pro-trim-2-.mp4"
}

Feel free to ask any more questions.

5 Likes

:star_struck:thanks, this is great! I appreciate the help.

Great breakdown, thanks for the JS and walking through it. This is going to help out a lot.

1 Like

Just for reference, something i have discovered is that you can only skip 5000 records in graph protocol, anything above that errors. So you have to take some other index and increment that value instead, eg. get the next 500 registered after time, and then increase the time and get the next 500…

Its broken my graph and faces pages :sweat_smile: will update the list site too when i have a fix worked out.

I also ran into this. I used something like this:

(first: 1000, orderBy: creationTime, orderDirection: desc, where: {creationTime_lte: ___CREATION_TIME_FROM_PREVIOUS_PAGE___})

But you could get duplicates (if a shared creation time spanned over the 1000).

Here is a quick TS function I put together for requests: Fetch all subgraph PoH requests using ghetto creation time pagination · GitHub

1 Like