History of tgbn_token
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] New entry: tgbn_token e3403ad
diff --git a/entries/tgbn_token/__init__.py b/entries/tgbn_token/__init__.py
new file mode 100644
index 0000000..66ae0b6
--- /dev/null
+++ b/entries/tgbn_token/__init__.py
@@ -0,0 +1,92 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 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/>.
+
+
+
+import pandas
+
+from .. import *
+
+
+title = "Ethereum users and the tokens they transfer (tgbn-token, TGB, 2016-2018)"
+description = """A temporal bipartite network of Ethereum addresses ("users") and the ERC20 tokens they sent or received, from April 2016 to June 2018, from the `tgbn-token` dataset of the Temporal Graph Benchmark (TGB), extracted from the token transaction data of Shamsi et al. (Chartalist). For a selection of users, each transfer of a token from or to one of them gives a timestamped edge from the user to the token, with the amount transferred, and whether the user sent or received it (a transfer between two selected users gives two edges). Transfers of a zero amount were removed by TGB. The tokens are identified by the addresses of their contracts.
+
+The network has the following properties:
+
+- `is_token`: whether the node is a token (otherwise a user).
+- `address`: the Ethereum address of the user, or of the contract of the token.
+- Edge `time`: the time of the transfer, in Unix time.
+- Edge `value`: the amount of the token transferred, as given by the data (in the smallest units of the token).
+- Edge `sender`: whether the user sent the amount (otherwise received it)."""
+tags = ['Economic', 'Cryptocurrency', 'Weighted', 'Multigraph', 'Timestamps', 'Metadata']
+url = ['https://tgb.complexdatalab.com/docs/nodeprop/',
+ 'https://github.com/shenyangHuang/TGB',
+ 'https://www.chartalist.org/']
+citation = [('S. Huang, F. Poursafaei, J. Danovitch, M. Fey, W. Hu, E. Rossi, J. Leskovec, M. Bronstein, G. Rabusseau, R. Rabbany, "Temporal Graph Benchmark for Machine Learning on Temporal Graphs." Advances in Neural Information Processing Systems 36 (Datasets and Benchmarks Track) (2023)', 'https://doi.org/10.48550/arXiv.2307.01026'),
+ ('K. Shamsi, F. Victor, M. Kantarcioglu, Y. R. Gel, C. G. Akcora, "Chartalist: Labeled Graph Datasets for UTXO and Account-based Blockchains." Advances in Neural Information Processing Systems 35 (Datasets and Benchmarks Track) (2022)', 'https://proceedings.neurips.cc/paper_files/paper/2022/hash/e245189a86310b6667ac633dbb922d50-Abstract-Datasets_and_Benchmarks.html')]
+icon_hash = None
+upstream_license = ('CC BY-NC', 'https://creativecommons.org/licenses/by-nc/4.0/')
+upstream_prefix = 'https://object-arbutus.alliancecan.ca/swift/v1/14c95234f6cd4a21a47deafe20cce2a7/tgb'
+files = [('tgbn-token.zip:tgbn-token_edgelist.csv', None, None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+@cache_network()
+@coerce_props(vforce={"address": "string"})
+@annotate()
+def parse(alts=None):
+ global files
+ name = __name__.split(".")[-1]
+ for fname, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ users, tokens = {}, {}
+ cols = {k: [] for k in ["user", "token", "time", "value", "sender"]}
+ # "timestamp,user_address,token_address,value,IsSender", read in
+ # chunks (the file has 8 GB)
+ with open_upstream_file(name, fname, "rb") as f:
+ for df in pandas.read_csv(f, chunksize=5 * 10**6,
+ dtype={"timestamp": "int64",
+ "user_address": "category",
+ "token_address": "category",
+ "value": "float64",
+ "IsSender": "int8"}):
+ for c, d, k in [("user_address", users, "user"),
+ ("token_address", tokens, "token")]:
+ cats = df[c].cat.categories
+ ids = numpy.array([d.setdefault(x, len(d)) for x in cats],
+ dtype="int32")
+ cols[k].append(ids[df[c].cat.codes.values])
+ cols["time"].append(df["timestamp"].values)
+ cols["value"].append(df["value"].values)
+ cols["sender"].append(df["IsSender"].values)
+ cols = {k: numpy.concatenate(v) for k, v in cols.items()}
+ N = len(users)
+ g = Graph(directed=True)
+ g.add_vertex(N + len(tokens))
+ g.vp.is_token = g.new_vp("bool")
+ g.vp.is_token.a[N:] = True
+ g.vp.address = g.new_vp("string", vals=list(users) + list(tokens))
+ g.add_edge_list(numpy.column_stack([cols.pop("user"),
+ N + cols.pop("token")]))
+ g.ep.time = g.new_ep("int64_t", vals=cols.pop("time"))
+ g.ep.value = g.new_ep("double", vals=cols.pop("value"))
+ g.ep.sender = g.new_ep("bool", vals=cols.pop("sender"))
+ yield alt, g