zash-sdk

Fastest and easiest blockchain data SDK.

Delightful, ergonomic blockchain data SDK built for data scientist, ML engineers and data analysts. Wrangle and explore transactions under a minute.

Install

pip install zash-sdk

Quickstart

Authentication

Get your credentials from zash.sh

from zash_sdk.zash import Zash
zash = Zash('your_username', 'your_api_key')
Authenticated!

Accessing NFT collection trades

Grab all Bored Ape trades in x2y2 since yesterday (contract address here):

bayc = zash.nft('eth').collection('0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D')
trades_df = bayc.trades('yesterday')
trades_df.query("marketplace_name == 'x2y2'").head()
id hash buyer seller collection_address token_id marketplace_address marketplace_name price currency block_hash block_number mint bundle timestamp updated_at
19 e80e354c-e3d8-3538-9788-817693f55783 0x6a7d16abd0b13522a99c5879f2e62ae66c15d91e4be7... 0xbdBa56dac0C99FA9A020045D9ccc774Ed2489558 0xed2ab4948bA6A909a7751DEc4F34f303eB8c7236 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D 7369 0x74312363e45DCaBA76c59ec49a7Aa8A65a67EeD3 x2y2 69.000000 ETH 0x1407e979138ab4e4cff899a25c735b587279898edb59... 15490769 False False 1662560018 2022-09-07 14:16:27
68 3a018278-681f-31e9-815f-97694ea9e48f 0x14f6f7698fe763c61ebb146d047fdc70973bb8f2a1d9... 0xed2ab4948bA6A909a7751DEc4F34f303eB8c7236 0x70219c18604DebF89379d566a622BDe2c5bc7621 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D 4788 0x74312363e45DCaBA76c59ec49a7Aa8A65a67EeD3 x2y2 67.670000 WETH 0xd07c225d1ad934f6544114734392ebe9e767388ae80a... 15493679 False False 1662600397 2022-09-08 01:31:10
78 2b2da6c2-717d-3d7c-87d0-af205258adec 0xeb23a4aa54a9b26bb6c1e50c9a4f5608572a5029f4d3... 0xed2ab4948bA6A909a7751DEc4F34f303eB8c7236 0xDa6391FB338F155a5b1036b9f5F7D19F4076779E 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D 3277 0x74312363e45DCaBA76c59ec49a7Aa8A65a67EeD3 x2y2 67.273004 WETH 0x32f058cb9aca9f92629ee47414a70a8a865dc6fde22b... 15493761 False False 1662601462 2022-09-08 01:46:13

A closer look at a trade:

trade = trades_df.query("marketplace_name == 'x2y2'").head(1).squeeze()
trade
id                                  e80e354c-e3d8-3538-9788-817693f55783
hash                   0x6a7d16abd0b13522a99c5879f2e62ae66c15d91e4be7...
buyer                         0xbdBa56dac0C99FA9A020045D9ccc774Ed2489558
seller                        0xed2ab4948bA6A909a7751DEc4F34f303eB8c7236
collection_address            0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D
token_id                                                            7369
marketplace_address           0x74312363e45DCaBA76c59ec49a7Aa8A65a67EeD3
marketplace_name                                                    x2y2
price                                                               69.0
currency                                                             ETH
block_hash             0x1407e979138ab4e4cff899a25c735b587279898edb59...
block_number                                                    15490769
mint                                                               False
bundle                                                             False
timestamp                                                     1662560018
updated_at                                           2022-09-07 14:16:27
Name: 19, dtype: object
# You can check out the transaction on etherscan:
!echo https://etherscan.io/tx/{trade['hash']}
https://etherscan.io/tx/0x6a7d16abd0b13522a99c5879f2e62ae66c15d91e4be7caa745c5bf0b0b2c3031

Simple marketplace comparison

You can get near-real time view of a chain in a single line:

last_hour_trades = zash.nft('eth').trades('1 hour ago')

NFT.trades accepts time ranges or shortcuts such as “yesterday” or “today”.

# offmarket marketplaces are labelled as -
last_hour_trades\
    .query('marketplace_name != "-"')\
    .groupby('marketplace_name')\
    .agg({"price":'sum'})\
    .sort_values('price', ascending=False)\
    .plot(kind='bar', ylabel='price_in_eth', legend=False)
<AxesSubplot:xlabel='marketplace_name', ylabel='price_in_eth'>

Example: Deep dive on BNB

In this example, we’ll show you can go from a macro view to a micro one, from marketplaces all the way to the tokens.

Let’s look at BNB chain this time, across all marketplaces:

bnb = zash.nft('bnb')
trades = bnb.trades('1 hour ago')

Off-market trades are market with “-” in marketplace names, you can filter them out as such:

marketplace_trades = trades.query('marketplace_name != "-"')
marketplace_trades.groupby('marketplace_name').agg({"price":'sum'}).plot(kind='bar')
<AxesSubplot:xlabel='marketplace_name'>

From here we see Element has the highest volume, can do a drill on this to find out the top collections:

top = marketplace_trades.query("marketplace_name == 'element'")\
    .groupby('collection_address')\
    .sum('price')[['price']]\
    .sort_values('price', ascending=False)
top
price
collection_address
0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6 3.9900
0x9CEE09946A8113a503C1264e328c0e3aEe4c8bCf 0.3000
0x85F0e02cb992aa1F9F47112F815F519EF1A59E2D 0.2000
0xADc466855ebe8d1402C5F7e6706Fccc3AEdB44a0 0.0110
0xC2A19349D5f451071C3085B90f531D19F190FF21 0.0099
0x1e13BDCB500a9B24b8221B290aD5E535D34E4218 0.0000

We see that 0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6 has the highest volume as a collection. To find more about this collection we can grab it and check it’s metadata:

bnb.collection('0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6').metadata()
collection_id    0xe3b1d32e43ce8d658368e2cbff95d57ef39be8a6
name                                               SPACE ID
slug                                      space-id-bnb-name
marketplace                                            tofu
website_url                               https://space.id/
discord_url                   https://discord.gg/cXP5UtYjHY
twitter_url             https://twitter.com/SpaceIDProtocol
floor_price                                           28.93
updated_at                       2022-08-30 11:53:38.548041
created_at                              2022-08-07 12:49:06
Name: SPACE ID, dtype: object

We see it is Space ID! We even have Twitter, Discord and website references to find more about this dapp/collection. Let’s do more drilling on this, checking out what was the split on primary vs secondary and also top mints traded can be a good idea:

spaceid = bnb.collection('0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6')
spaceid_trades = spaceid.trades('last month')
# can look at some price summary stats:
spaceid_trades['price'].describe()
count    54230.000000
mean         0.220979
std          1.219418
min          0.000000
25%          0.008280
50%          0.009268
75%          0.037172
max        123.000000
Name: price, dtype: float64

Can check primary vs seconday split on volume:

spaceid_trades.groupby('mint').sum('price')[['price']].plot(kind='barh')
<AxesSubplot:ylabel='mint'>

We can also check for primary vs secondary trade counts…

spaceid_trades['mint'].value_counts(normalize=True).reset_index().style.format({'mint': "%{:.2f}"})
  index mint
0 False %0.57
1 True %0.43

So primary and secondary sale numbers are close but secondary sales volume is almost 5x.

Next, we can check out also highest value token trade as an example:

top_trade = spaceid_trades\
    .query('mint == False')\
    .sort_values('price', ascending=False).head(1).squeeze()
top_trade
id                                  56466d58-e366-3f96-8bd6-115f1054bf36
hash                   0x99eceaa0a93e960f162f94b3248aadba2d280af4c245...
buyer                         0x68CA671253729039c1596856A0492B5979FCF37b
seller                        0xC25751a1cE2eE2F62599F3Cc238a874C631aa4FC
collection_address            0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6
token_id               4563769053854199209000009877284788645708242223...
marketplace_address           0xb3e3DfCb2d9f3DdE16d78B9e6EB3538Eb32B5ae1
marketplace_name                                                 element
price                                                              123.0
currency                                                             BNB
block_hash             0xae31bce2d4f9e6442b83f41e47236ef56f970ba9c2c1...
block_number                                                    21088593
mint                                                               False
bundle                                                             False
timestamp                                                     1662447211
updated_at                                           2022-09-06 07:01:48
Name: 15223, dtype: object

If we are curious to get more info on this we can then grab this token as such:

token = spaceid.token(top_trade.token_id)
pprint(token.metadata())
{'attributes': BoxList([{'trait_type': 'Created Date', 'display_type': 'date', 'value': 1661401461}, {'trait_type': 'Registration Date', 'display_type': 'date', 'value': 1661401461}, {'trait_type': 'Expiration Date', 'display_type': 'date', 'value': 1692955724}, {'trait_type': 'Length', 'display_type': 'number', 'value': 3}, {'trait_type': 'Segment Length', 'display_type': 'number', 'value': 3}, {'trait_type': 'Character Set', 'display_type': 'string', 'value': 'digit'}]),
 'description': '123.bnb, a bnb name.',
 'image': 'https://meta.image.space.id/image/mainnet/45637690538541992090000098772847886457082422231295691457910964509567538102535.svg',
 'name': '123.bnb',
 'name_length': 3,
 'segment_length': 3,
 'uri': 'https://meta.space.id/45637690538541992090000098772847886457082422231295691457910964509567538102535'}

So this is 123.bnb id!

We also have traits (can be used to calculate rarities for PFP/Gamefi collections), and more info that can be accessed with the token model.

You can then also get the history of trades as such:

token_trades = token.trades('last month')
token_trades.sort_values('timestamp', ascending=True)
id hash buyer seller collection_address token_id marketplace_address marketplace_name price currency block_hash block_number mint bundle timestamp updated_at
0 f072e372-518d-31b5-bd91-803162bb1d73 0xe1e0ac10537fd5b2a723a3dedea6feb2223083bd83f1... 0xC25751a1cE2eE2F62599F3Cc238a874C631aa4FC 0x48af770f89F03C6cCea6919df6F89bC903cE2F9C 0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6 4563769053854199209000009877284788645708242223... 0x48af770f89F03C6cCea6919df6F89bC903cE2F9C - 0.0 BNB 0xf88eb7636afedda5a88dc8b4f6f53558052e5838941d... 20739907 False True 1661398772 2022-08-26 20:26:52
1 037e325f-8e64-355d-ad07-0c812d94ac39 0xe1e0ac10537fd5b2a723a3dedea6feb2223083bd83f1... 0x48af770f89F03C6cCea6919df6F89bC903cE2F9C 0x0000000000000000000000000000000000000000 0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6 4563769053854199209000009877284788645708242223... 0x48af770f89F03C6cCea6919df6F89bC903cE2F9C - 0.0 BNB 0xf88eb7636afedda5a88dc8b4f6f53558052e5838941d... 20739907 True True 1661398772 2022-08-26 20:26:52
2 56466d58-e366-3f96-8bd6-115f1054bf36 0x99eceaa0a93e960f162f94b3248aadba2d280af4c245... 0x68CA671253729039c1596856A0492B5979FCF37b 0xC25751a1cE2eE2F62599F3Cc238a874C631aa4FC 0xE3b1D32e43Ce8d658368e2CBFF95D57Ef39Be8a6 4563769053854199209000009877284788645708242223... 0xb3e3DfCb2d9f3DdE16d78B9e6EB3538Eb32B5ae1 element 123.0 BNB 0xae31bce2d4f9e6442b83f41e47236ef56f970ba9c2c1... 21088593 False False 1662447211 2022-09-06 07:01:48

Apparently, there was only a single mint (combined with a transfer to the owner) and then a secondary sale worth ~$34,194.

Wrapping up, this was just an example of how from gross analysis you can go to token level in just a few lines. Let us know how we can improve the docs if you have any ideas.

Advanced

Social metrics over time

Since Twitter and Discord metrics can be significant indicators for NFT collections we aggregate these metrics as well. Specifically, for Twitter we pull follower/following/tweet counts and for Discord active/passive members. Note: Currently this is only supported for eth chain.

Here is an example of discord members over time for BAYC for instance:

zash.nft('eth')\
    .collection('0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D')\
    .socials('boredapeyachtclub')\
    .discord\
    .set_index('ts')\
    .resample('D').mean()\
    .plot()
<AxesSubplot:xlabel='ts'>

Looks like active member activity started to fluctuate as we went deeper into the bear market 🐻

Network analysis on trades

We are building and enriching network analysis tools to be go deeper on a given trade network. Below is a flavor of what is to come.

from zash_sdk.graph import *
network = build_network(bayc.trades('yesterday'))
plot_trade_network(network)

You can filter for wash trades (triangular or bidirectional cycles for instance).

Stay tuned!

This is the beginning of what you can do with Zash SDK. We would be adding transparent NFT price prediction and wallet based analysis tools in the upcoming weeks. If you have any feature requests get in touch. We are also hiring!