History of erc20_ethereum
The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.
[entries] Add the date when each entry was added, and remove icon_hash beff7c9
The dates are those of the commits that first added the entries' files (2020-08-11 for the entries of the initial commit); renamed entries keep the date of their first name. Changed: none
diff --git a/entries/erc20_ethereum/__init__.py b/entries/erc20_ethereum/__init__.py
index 492759a..116c30c 100644
--- a/entries/erc20_ethereum/__init__.py
+++ b/entries/erc20_ethereum/__init__.py
@@ -50,7 +50,7 @@ url = ['https://snap.stanford.edu/data/ERC20-stablecoins.html',
'https://snap.stanford.edu/data/ethereum-exchanges.html']
citation = [('K. Shamsi, F. Victor, M. Kantarcioglu, Y. R. Gel, and C. G. Akcora, "Chartalist: Labeled Graph Datasets for UTXO and Account-based Blockchains." Advances in Neural Information Processing Systems 35 (NeurIPS 2022), Datasets and Benchmarks Track (2022).', 'https://openreview.net/forum?id=10iA3OowAV3'),
('F. Victor, C. G. Akcora, Y. R. Gel, and M. Kantarcioglu, "Alphacore: Data Depth based Core Decomposition." Proceedings of the 27th ACM SIGKDD Conference on Knowledge Discovery & Data Mining, 1625-1633 (2021).', 'https://doi.org/10.1145/3447548.3467322')]
-icon_hash = None
+date_added = '2026-10-27'
upstream_license = None
upstream_prefix = 'https://snap.stanford.edu/data'
_labels = 'ethereum-exchanges.zip:alphacore_labels_stablecoin.csv'
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) bc3dbbd
The lists of properties at the end of the descriptions marked edge properties with "Edge" but left node properties unmarked, or grouped them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property was often unclear. Every item now starts with (Node), (Edge) or (Graph), followed by the property names, a colon and the explanation, one item per property or group of properties; qualifications (kinds of nodes, networks) follow the names in parentheses. Properties that were only named got a short explanation, and a few items that named the wrong kind of property were corrected.
diff --git a/entries/erc20_ethereum/__init__.py b/entries/erc20_ethereum/__init__.py
index 1706369..492759a 100644
--- a/entries/erc20_ethereum/__init__.py
+++ b/entries/erc20_ethereum/__init__.py
@@ -31,10 +31,20 @@ The price series of the stablecoins and the list of events of the crash, which a
The networks have the following properties:
-- `address`: the Ethereum address.
-- `stablecoins`: `label`, `label_name` and `label_asset`: the label of the address in the Alphacore of the stablecoin network (e.g. "uniswap"), the name of the labeled entity (e.g. "Uniswap V3") and the asset (e.g. "DAI-FRAX"), if any. Edges: `time`, the time of the block of the transfer, in Unix time; `block`, the block number; `tx_index`, the index of the transaction in the block; `token`, the token transferred, as an index into the graph property `tokens` (0: USDT, 1: USDC, 2: DAI, 3: UST, 4: PAX, 5: WLUNA, by their contract addresses, see below); `value`, the quantity transferred, in units of the token.
-- `exchanges`: `exchange_type` ("cex" for centralized and "dex" for decentralized exchanges, if labeled) and `exchange_name`, the name of the exchange. Edges: `block`, the block number; `log_index`, the index of the transfer event in the block; `token`, the token transferred, as an index into the graph property `tokens`; `value`, the quantity transferred, in the smallest units of the token (as a floating-point number, which may round large integer values).
-- Graph `tokens`: the contract addresses of the tokens."""
+- (Node) `address`: the Ethereum address.
+- (Node) `label`, `label_name` and `label_asset` (`stablecoins`): the label of the address in the Alphacore of the stablecoin network (e.g. "uniswap"), the name of the labeled entity (e.g. "Uniswap V3") and the asset (e.g. "DAI-FRAX"), if any.
+- (Edge) `time` (`stablecoins`): the time of the block of the transfer, in Unix time.
+- (Edge) `block` (`stablecoins`): the block number.
+- (Edge) `tx_index` (`stablecoins`): the index of the transaction in the block.
+- (Edge) `token` (`stablecoins`): the token transferred, as an index into the graph property `tokens` (0: USDT, 1: USDC, 2: DAI, 3: UST, 4: PAX, 5: WLUNA, by their contract addresses, see below).
+- (Edge) `value` (`stablecoins`): the quantity transferred, in units of the token.
+- (Node) `exchange_type` (`exchanges`): "cex" for centralized and "dex" for decentralized exchanges, if labeled.
+- (Node) `exchange_name` (`exchanges`): the name of the exchange.
+- (Edge) `block` (`exchanges`): the block number.
+- (Edge) `log_index` (`exchanges`): the index of the transfer event in the block.
+- (Edge) `token` (`exchanges`): the token transferred, as an index into the graph property `tokens`.
+- (Edge) `value` (`exchanges`): the quantity transferred, in the smallest units of the token (as a floating-point number, which may round large integer values).
+- (Graph) `tokens`: the contract addresses of the tokens."""
tags = ['Economic', 'Cryptocurrency', 'Multigraph', 'Timestamps', 'Weighted', 'Metadata']
url = ['https://snap.stanford.edu/data/ERC20-stablecoins.html',
'https://snap.stanford.edu/data/ethereum-exchanges.html']
[entries] New entry: erc20_ethereum 44714fb
diff --git a/entries/erc20_ethereum/__init__.py b/entries/erc20_ethereum/__init__.py
new file mode 100644
index 0000000..1706369
--- /dev/null
+++ b/entries/erc20_ethereum/__init__.py
@@ -0,0 +1,187 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2020-2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from .. import *
+
+import csv
+
+title = "Ethereum token transfers: stablecoins (2022) and exchange tokens (2018-2020)"
+description = r"""Networks of transfers of ERC20 tokens between addresses of the Ethereum blockchain, extracted from the blockchain and distributed by SNAP as part of the Chartalist collection of blockchain data sets (C. G. Akcora, M. Kantarcioglu, Y. R. Gel, F. Victor and collaborators). Nodes are Ethereum addresses (externally owned accounts, controlled by people or organizations, or smart contracts), and an edge $u \to v$ is a transfer of a quantity of a token from address $u$ to address $v$. Each transfer is a separate edge (a multigraph). The addresses are not anonymized, and can be looked up in block explorers. There are two data sets:
+
+- `stablecoins`: the transfers of the five largest stablecoins by market capitalization, tokens meant to keep a fixed price of 1 USD (USDT, USDC, DAI, UST and PAX), and of Wrapped LUNA (WLUNA), around the crash of the Terra (LUNA) ecosystem in May 2022, when UST lost its peg. The network spans the blocks 14,500,001 to 15,872,937 (1 April to 1 November 2022), with 36.7 million transfers. The data come in three versions, each spanning a longer period than the previous one; since the two shorter versions are contiguous parts of the longest one (from 28 April 2022), only the longest is included. The addresses of the Alphacore of the network (a core decomposition) are labeled by their kind (e.g. decentralized exchanges such as Uniswap).
+- Exchange tokens (`exchanges`): the transfers of 28 of the largest ERC20 tokens (TUSD, BAT, MANA, MGC, BNT, HEX, AMB, LINK, DAI, HT, AZ, LAMB, SAI, EGT, MXM, USDP, MKR, USDC, NPXS, STORJ, BNB, EBK, WETH, KICK, OMG, KNC, ZRX and ENJ) between 16 October 2018 and 4 May 2020, for the study of the classification of exchange addresses with the Alphacore decomposition. The addresses of 149 centralized and decentralized exchanges (296 addresses), from the labels of the block explorer Etherscan.io in May 2020, are labeled. The token of each transfer is given by its contract address; the data do not give which of the token names corresponds to which address.
+
+The price series of the stablecoins and the list of events of the crash, which are provided with the stablecoin data, are not included. The transaction hashes of the transfers of the exchange tokens are also left out (the transfers are identified by their block and log index).
+
+The networks have the following properties:
+
+- `address`: the Ethereum address.
+- `stablecoins`: `label`, `label_name` and `label_asset`: the label of the address in the Alphacore of the stablecoin network (e.g. "uniswap"), the name of the labeled entity (e.g. "Uniswap V3") and the asset (e.g. "DAI-FRAX"), if any. Edges: `time`, the time of the block of the transfer, in Unix time; `block`, the block number; `tx_index`, the index of the transaction in the block; `token`, the token transferred, as an index into the graph property `tokens` (0: USDT, 1: USDC, 2: DAI, 3: UST, 4: PAX, 5: WLUNA, by their contract addresses, see below); `value`, the quantity transferred, in units of the token.
+- `exchanges`: `exchange_type` ("cex" for centralized and "dex" for decentralized exchanges, if labeled) and `exchange_name`, the name of the exchange. Edges: `block`, the block number; `log_index`, the index of the transfer event in the block; `token`, the token transferred, as an index into the graph property `tokens`; `value`, the quantity transferred, in the smallest units of the token (as a floating-point number, which may round large integer values).
+- Graph `tokens`: the contract addresses of the tokens."""
+tags = ['Economic', 'Cryptocurrency', 'Multigraph', 'Timestamps', 'Weighted', 'Metadata']
+url = ['https://snap.stanford.edu/data/ERC20-stablecoins.html',
+ 'https://snap.stanford.edu/data/ethereum-exchanges.html']
+citation = [('K. Shamsi, F. Victor, M. Kantarcioglu, Y. R. Gel, and C. G. Akcora, "Chartalist: Labeled Graph Datasets for UTXO and Account-based Blockchains." Advances in Neural Information Processing Systems 35 (NeurIPS 2022), Datasets and Benchmarks Track (2022).', 'https://openreview.net/forum?id=10iA3OowAV3'),
+ ('F. Victor, C. G. Akcora, Y. R. Gel, and M. Kantarcioglu, "Alphacore: Data Depth based Core Decomposition." Proceedings of the 27th ACM SIGKDD Conference on Knowledge Discovery & Data Mining, 1625-1633 (2021).', 'https://doi.org/10.1145/3447548.3467322')]
+icon_hash = None
+upstream_license = None
+upstream_prefix = 'https://snap.stanford.edu/data'
+_labels = 'ethereum-exchanges.zip:alphacore_labels_stablecoin.csv'
+# The stablecoin data come in three versions (token_transfers.csv,
+# token_transfers_V2.0.0.csv, token_transfers_V3.0.0.csv), each of which is a
+# contiguous part of the next one; only the longest is used.
+files = [(('ERC20-stablecoins.zip:token_transfers_V3.0.0.csv', _labels), 'stablecoins', None),
+ (('ethereum-exchanges.zip:token_transfers_full.csv',
+ 'ethereum-exchanges.zip:exchangeLabels.csv'), 'exchanges', None)]
+
+# contract addresses of the stablecoins and WLUNA
+stablecoins = [('USDT', '0xdac17f958d2ee523a2206206994597c13d831ec7'),
+ ('USDC', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'),
+ ('DAI', '0x6b175474e89094c44da98b954eedeac495271d0f'),
+ ('UST', '0xa47c8bf37f92abed4a126bda807a7b7498661acd'),
+ ('PAX', '0x8e870d67f660d95d5be530380d0ec0bd388289e1'),
+ ('WLUNA', '0xd2877702675e6ceb975b4a1dff9fb7baf4c91ea9')]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+class _Index(dict):
+ "Map of addresses to consecutive indices."
+ def get_indices(self, xs):
+ out = numpy.empty(len(xs), dtype="int64")
+ for i, x in enumerate(xs):
+ j = self.get(x)
+ if j is None:
+ j = self[x] = len(self)
+ out[i] = j
+ return out
+
+def _read_transfers(name, fname, cols, ints, token_col, tokens):
+ """Read the transfers of the CSV file `fname` in chunks, returning the
+ edge list, the token indices and the columns `ints` (as int64 arrays)
+ and "value" (as float64), and the address index."""
+ import pandas
+ idx = _Index()
+ E, tok, vals = [], [], []
+ other = {c: [] for c in ints}
+ tidx = {t: i for i, t in enumerate(tokens)}
+ with open_upstream_file(name, fname, "r") as f:
+ for df in pandas.read_csv(f, usecols=cols, chunksize=1 << 20,
+ dtype={c: str for c in cols}):
+ u = idx.get_indices(df["from_address"].str.lower().to_numpy())
+ v = idx.get_indices(df["to_address"].str.lower().to_numpy())
+ E.append(numpy.column_stack([u, v]).astype("int32"))
+ t = numpy.empty(len(df), dtype="int16")
+ for i, x in enumerate(df[token_col].str.lower().to_numpy()):
+ j = tidx.get(x)
+ if j is None:
+ j = tidx[x] = len(tokens)
+ tokens.append(x)
+ t[i] = j
+ tok.append(t)
+ vals.append(df["value"].astype("float64").to_numpy())
+ for c in ints:
+ other[c].append(df[c].astype("int64").to_numpy())
+ E = numpy.concatenate(E)
+ return (E, numpy.concatenate(tok), numpy.concatenate(vals),
+ {c: numpy.concatenate(x) for c, x in other.items()}, idx)
+
+@cache_network()
+@coerce_props(vforce={"address": "string"})
+@annotate()
+def parse(alts=None):
+ name = __name__.split(".")[-1]
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ if alt.startswith("stablecoins"):
+ tokens = [a for n, a in stablecoins]
+ E, tok, vals, other, idx = \
+ _read_transfers(name, fnames[0],
+ ["block_number", "transaction_index",
+ "from_address", "to_address", "time_stamp",
+ "contract_address", "value"],
+ ["block_number", "transaction_index", "time_stamp"],
+ "contract_address", tokens)
+ assert len(tokens) == len(stablecoins)
+ else:
+ tokens = []
+ E, tok, vals, other, idx = \
+ _read_transfers(name, fnames[0],
+ ["token_address", "from_address", "to_address",
+ "value", "log_index", "block_number"],
+ ["block_number", "log_index"],
+ "token_address", tokens)
+ g = Graph(directed=True)
+ g.add_vertex(len(idx))
+ g.add_edge_list(E)
+ del E
+ # edge indices follow the order in which the edges were added
+ if alt.startswith("stablecoins"):
+ g.ep.time = g.new_ep("int64_t")
+ g.ep.time.a = other["time_stamp"]
+ g.ep.block = g.new_ep("int64_t")
+ g.ep.block.a = other["block_number"]
+ g.ep.tx_index = g.new_ep("int32_t")
+ g.ep.tx_index.a = other["transaction_index"]
+ else:
+ g.ep.block = g.new_ep("int64_t")
+ g.ep.block.a = other["block_number"]
+ g.ep.log_index = g.new_ep("int32_t")
+ g.ep.log_index.a = other["log_index"]
+ del other
+ g.ep.token = g.new_ep("int16_t")
+ g.ep.token.a = tok
+ g.ep.value = g.new_ep("double")
+ g.ep.value.a = vals
+ del tok, vals
+ g.gp.tokens = g.new_gp("vector<string>", val=tokens)
+ addrs = [None] * len(idx)
+ for a, i in idx.items():
+ addrs[i] = a
+ g.vp.address = g.new_vp("string", vals=addrs)
+ del addrs
+ vs = idx
+ # the Alphacore labels are encoded in Windows-1252
+ enc = "cp1252" if alt.startswith("stablecoins") else "utf8"
+ with open_upstream_file(name, fnames[1], "r", encoding=enc) as f:
+ rows = [{k: x.strip() for k, x in r.items()} for r in csv.DictReader(f)]
+ if alt.startswith("stablecoins"):
+ for p in ["label", "label_name", "label_asset"]:
+ g.vp[p] = g.new_vp("string")
+ for r in rows:
+ v = vs.get(r["address"].lower())
+ if v is None:
+ continue
+ g.vp.label[v] = r["label"]
+ g.vp.label_name[v] = r["name"]
+ g.vp.label_asset[v] = r["asset"]
+ else:
+ g.vp.exchange_type = g.new_vp("string")
+ g.vp.exchange_name = g.new_vp("string")
+ for r in rows:
+ v = vs.get(r["address"].lower())
+ if v is None:
+ continue
+ g.vp.exchange_type[v] = r["type"]
+ g.vp.exchange_name[v] = r["name"]
+ del vs, idx
+ yield alt, g