User Guide

Synapse-Chainalysis User Guide

Synapse-Chainalysis adds Storm commands to query the Chainalysis Data Solutions analytical SQL API using your existing API credentials.

Getting Started

Check with your Admin to enable permissions and find out if you need a personal API key. Each Chainalysis product is configured independently; configurations for the Data Solutions product live under the ds product namespace.

Examples

Setting your personal API key

To set up a personal Data Solutions configuration:

chainalysis.config.add ds ds_local myapikey --scope self

Executing a SQL query

Pass an arbitrary SQL query as a positional argument; results stream back as rows in API order:

> chainalysis.ds.sql.execute --pprint "SELECT * FROM bitcoin.clusters WHERE address = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'"
Chainalysis DS query_id=01ef2d0a-8a49-1127-8f56-f68535c4211d
Columns:
({'name': 'chain_id', 'type': 'string'},
 {'name': 'chain_name', 'type': 'string'},
 {'name': 'address', 'type': 'string'},
 {'name': 'cluster_id', 'type': 'string'},
 {'name': 'entity_name', 'type': 'string'},
 {'name': 'entity_category', 'type': 'string'},
 {'name': 'entity_category_changed_at', 'type': 'timestamp'},
 {'name': 'prior_entity_category', 'type': 'string'},
 {'name': 'is_contract_address', 'type': 'boolean'},
 {'name': '__entity_uuid', 'type': 'string'})
{'__entity_uuid': None,
 'address': '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
 'chain_id': 'bip122:000000000019d6689c085ae165831e93',
 'chain_name': 'bitcoin',
 'cluster_id': '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
 'entity_category': None,
 'entity_category_changed_at': None,
 'entity_name': None,
 'is_contract_address': False,
 'prior_entity_category': None}

Ingesting query results as Synapse nodes

The chainalysis.ds Storm module exposes a sqlExecute generator that emits a stream of (type, data, info) tuples. Each data row arrives as a dict keyed by the column names returned by Chainalysis, which makes it straightforward to drive Storm ingest directly from a SQL query.

The example below issues the same Bitcoin cluster lookup as the previous example and ingests the result into Synapse: it anchors the Bitcoin crypto:currency:chain, links the crypto:currency:address to it, and – when Chainalysis has attributed the row to an entity – anchors a meta:cluster node and applies its tag to the address along with a tag derived from the entity category.

$mod = $lib.import(chainalysis.ds)

$opts = $mod.resolveOpts()
$tag_prefix = $opts.vault.configs.tag_prefix
$source = $mod.getMetaSource()

$query = "SELECT * FROM bitcoin.clusters WHERE address = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'"

for ($mtyp, $data, $info) in $mod.sqlExecute($query, opts=$opts) {
    switch $mtyp {

        "init": {
            $lib.print(`Chainalysis DS query_id={$data}`)
        }

        "data": {

            $cat_tag = (null)
            $cat_type = (null)
            $cluster_tag = (null)

            if $data.entity_category {
                $cat_tag = `{$tag_prefix}.{$data.entity_category}`
                $cat_type = `chainalysis.{$data.entity_category}`
            }

            $chain = {[
                crypto:currency:chain=({
                    "id": $data.chain_id,
                    "$try": true,
                    "$props": {
                        "name": $data.chain_name,
                        "symbol": "btc",
                    }
                })
                <(seen)+ $source
            ]}

            if $data."__entity_uuid" {
                // Derive a stable tag from the entity uuid for
                // annotating nodes associated with this cluster.
                $cluster_tag = `{$tag_prefix}.cluster.{$data."__entity_uuid".replace("-", "")}`
                $cluster = {[
                    meta:cluster=({
                        "id": $data."__entity_uuid",
                        "reporter:name": "chainalysis",
                        "$try": true,
                        "$props": {
                            "name": $data.entity_name,
                            "type": $cat_type,
                            "tag": $cluster_tag,
                        }
                    })
                    <(seen)+ $source
                ]}
            }

            [ crypto:currency:address=(btc, $data.address)
                :chain=$chain
                +?#$cluster_tag
                +?#$cat_tag
                <(seen)+ $source
            ]
        }

        "print": {
            $lib.print($data)
        }

        "warn": {
            $lib.warn($data)
        }
    }
}