Table of Contents

  1. Introduction
  2. Allocations
    1. Allocation Splitting
  3. GNO Holders
    1. Mainnet
      1. Raw Balances
      2. Liquidity Providers
    2. Gnosis Chain
      1. Raw Balances
      2. Liquidity Providers
      3. Staked GNO
  4. CowSwap Users
    1. Primary Trader Allocation
    2. Consolation Trader Allocation
    3. Community Allocation
  5. Dev Guide: Installation and Usage

Introduction

This repository contains a collection of scripts and tools used to fetch deterministic
dataset pertaining to CoW Token airdrop. According to the announcement in
this Gnosis Forum Post
the airdrop will be made to GNO holders on Mainnet and Gnosis Chain (formerly xDai)
including consideration of the following liquidity pools:

  • Balancer V2 (Mainnet)
  • Uniswap V3 (Mainnet)
  • HoneySwap (Gnosis Chain)
  • Symmetric (Gnosis Chain)
  • SushiSwap (Gnosis Chain)
  • Elk (Gnosis Chain)
  • Swapr (Gnosis Chain)

Note that all our holder queries use strict inequality on the block number, so the
snapshot block number is the first block occurring on Jan 10. These
are 13974427 on mainnet
and 20024195 on gnosis chain. Relevant
query here.

Note that we have excluded pools within these protocols containing a total of < 1 GNO
and user accounts having a GNO balance < 0.1 at the time of the snapshot.

To, briefly summarize the approach we;

  1. Fetch Mainnet & Gnosis Chain GNO Token Holders at specific block
  2. Fetch LP holders (specifically % of the total supply they own)
  3. Fetch UniswapV3 Holders (specifically how much GNO)
  4. Fetch Gnosis Chain Depositors
  5. Compute GNO holdings of LP providers based on share % in correspondence with the
    Pool’s holdings (from step 1)
  6. Combine all of these values together to generate combined (Mainnet and Gnosis Chain
    CSV) representing total GNO holdings across all eligible platforms.
  7. Fetch and merge trader data from both networks
  8. Filter the combined Trader data by the eligibility criteria
    outlined below
  9. Transform the holder and user data into allocations in their respective categories.
  10. Merge allocations into a combined, universal allocation list.
  11. The allocations are then split across both networks based loosely on the criteria
    that Allocations with an Airdrop claim less than 10K vCoW tokens will be eligible
    for claim on Gnosis Chain. Above 10K claims are on Mainnet. Note that we can only
    perform this splitting criteria to Externally owned accounts (since smart contracts
    such as Gnosis Safe are not “multi-network compatible”).
  12. As a final step, we append Advisor, Investor and Team allocations to the bottom of
    the mainnet allocation file.

Resulting allocation files have the following columns:

[ Account | Airdrop | GnoOption | UserOption | Investor | Team | Advisor ]

The allocation files are committed to this repo and can be viewed here:

Allocations

An Allocation (represented in the project as a MerkleLeaf), attributed to each
eligible account, consists of several categories briefly define here (some of which will
be elaborated upon in their own section):

  1. Airdrop: Consists of the combined sum of allocations for GNO holders and CoWSwap
    Users (outlined below)
  2. GNO Option: Constructed from GNO holder data. Represents amount of vCoW that can be
    purchased with GNO.
  3. User Option: Constructed from Primary Trader data (a sub-category of CoWSwap Users).
    Represents amount of vCoW that can be purchased with ETH/XDAI. Note that while 45M
    tokens we allocated for primary trader airdrop, 50M were allocated to the user option
    with different weight factors for each trading volume tier.
  4. Investor: Represents amount of vCoW that can be purchased with USDC
  5. Team: Represents a 4 year linearly vested entitlement of tokens for team members.
  6. Advisor: Allocation attributed to advisors.

Each of the last 3 categories were appended to the end of mainnet allocation file after
all the holder and user data was compiled.

Allocation Splitting

Allocations were split over two networks (Mainnet and Gnosis Chain) based on the
following criteria:

  1. Mainnet Allocation:
    allocation >= ALLOCATION_SPLIT
  2. Gnosis Chain:
    allocation < ALLOCATION_SPLIT

where ALLOCATION_SPLIT = 10K token units

Additionally, since externally owned accounts are cross-network compatible, but smart
contracts (such as Gnosis Safe) are not, we have to investigate this for each account.

Accounts which are contracts on only one of the two networks will receive their
allocation on the network they exist (regardless of allocation split).

Accounts which are contracts on both networks are treated as a “special case”
we collect this list and parse through all the accounts from the data files generated
throughout the program and partition them by network of eligibility.

If the account is exclusively eligible for allocation on one of the two networks the
allocation is given there.

There was only one case of a Gnosis Safe contract on both networks that was eligible for
allocation on both networks:

This is a Safe on both networks with an overlapping set of owner accounts (beyond the
signing threshold of 2)

The total allocations to each category are

======================
Allocation Counts
   Mainnet:       1465
   Gnosis Chain: 53750
----------------------
Category Totals
   Airdrop:     150.0M
   Gno Option:   50.0M
   User Option:  50.0M
   Investor:    100.0M
   Advisory:    106.1M
   Team:         99.3M
----------------------
Grand Total:    555.3M
----------------------
Unallocated Amount
        6900034565 WEI
======================

GNO Token Holders

Mainnet

Mainnet Holders

The goal of this snapshot is to deterministically and reproducibly fetch the GNO token
holders on both networks at a specific time. For this we use Dune
Analytics erc20.view_token_balances_daily table on Mainnet.

For reference, non-deterministic (i.e. current) token balances on each network can be
found
on Etherscan
.

Deterministically,

Mainnet Holders Query Jan 10, 2022

which returns csv with columns [ account | amount ].

Query here

Mainnet Liquidity Providers

  1. Balancer v2: https://app.balancer.fi/#/pool/<PoolId>

The query for balancer holders is also in this repo
at ./queries/generic_lp_holders.sql.

For an account of the GNO balances corresponding to each Balancer Pool at the time of
the snapshot, please visit here.

  1. Uniswap v3: https://info.uniswap.org/#/pools/<PoolAddress>

For current individual pool positions visit https://app.uniswap.org/#/pool/<TokenId>

Deterministically, GNO balances corresponding to holder positions were computed using
their SubGraph
along with code here adapted from their SDK.

  1. SushiSwap: https://analytics.sushi.com/pairs/<PoolAddress>

Gnosis Chain

Gnosis Chain Holders

The balances view does not exist in Dune on gnosischain, so we rely on event
accounting of the token contract available in the gnosis.GnosisToken table.

Gnosis Chain

The Gnosis Chain Holders can also be retrieved in JSON format via the
Blockscout API Request

Deterministically, this Gnosis Chain Holders Query
will become “static” as of the snapshot date. The query is also available within this
repo at /queries/gchain_holders.sql

Gnosis Chain Liquidity Providers

A complete query for all eligible liquidity sources on
Gnosis Chain. This is also available in Dune, but
only those with GNO balance > 1 at the time of snapshot are considered eligible.

  1. HoneySwap: https://info.honeyswap.org/#/pair/<PoolAddress>

  2. Symmetric: https://xdai-pools.symmetric.exchange/#/pool/<PoolAddress>

  3. SushiSwap: https://analytics-xdai.sushi.com/pairs/<PoolAddress>

  4. Elk: https://xdai-info.elk.finance/pair/<PoolAddress>

  5. Swapr: https://dxstats.eth.link/#/pair/<PoolAddress>

Staked GNO

The set of depositors and number of deposits (up until the snapshot deadline) are
fetched via Dune
Analytics https://dune.xyz/queries/330002 and in this
repo ./queries/staked_gno.sql. Note that the number of
deposits corresponds directly to the integer number of GNO staked.

CowSwap Users

The funds allocated to users make a combined total of 50M tokens (5% of the supply).
This allocation has been split up into three categories:

  1. Primary Trader: users (a.k.a. traders) satisfying all of the criteria outlined
    below
  2. Consolation Trader: users who were not eligible for primary allocation, but do
    satisfy the eligible volume criteria below
  3. Community: This category includes both of POAP holders and a special allocation to
    our alpha contract traders.

The 50M tokens has been partitioned as (44M, 3M, 3M) into each of the above three
categories respectively.

We elaborate on each of the three categories in their own sections below.

Users, aka those who have traded on the platform, are entitled to an airdrop based on
the following parameters:

  1. Eligible Trading Volume: A weighted sum of the total USD value of all non-stable
    and stable trades. Everyone who has a total of at least V is considered.
    Concretely, that
    is eligible_volume = non_stable_volume + StableFactor * stable_volume
    where stable_volume is the trading volume for trades between stable coins
    and non_stable_volume is the volume of all others.

  2. Stable Factor A factor S used to lower the weight of stable to stable trading
    volume

  3. Number of Trades: All users having made at least T trades.

  4. Days Between: All users having traded at least D apart.

Primary Trader Allocation

Users satisfying all of the above criteria have been included in this list.

The parameters used for primary allocation both networks are

V - 1000 USD
S - 0.1
T - 3 trades
D - 14 days between first and last trade

The primary trading allocation has been distributed to users with weight factors
according to the following eligible volume tiers

Tier Eligible Volume Weight Factor
5 >= 1M 28
4 >= 500K and < 1M 16
3 >= 100K and < 500K 8
2 >= 50K and < 100K 4
1 >= 10K and < 50K 3
0 >= 1K and < 10K 1

Please refer to
src/constants.py
where all of these parameters are defined in the code.

Consolation Trader Allocation

Users not meeting the Primary criteria, but satisfying either

  1. The eligible volume condition (i.e. at least 1000 USD in eligible trading volume) OR
  2. Having made at least 5 trades.

There are no weight factors assigned to this category, the 3M tokens has been
distributed equally to each of the eligible recipients.

Trader Data Queries

The Dune query used for both networks is available in this repo
at ./queries/generic_trader_data.sql. For
convenience, the permanent fixtures for each network are also available in the Dune
interface at

Community

  1. Retained Alpha Traders: Anyone who traded on both the alpha (unaudited) version
    of the contract, and the version 1 deployment. The weight factor attributed to this
    category (for each network) is outlined along with POAP holders in the table below
    Dune Query for this is here and a permanent
    version is available at
  1. POAP Holders: The following table outlines the considered POAPs for this allocation
    along with their weight factors

For a full list of POAP weight factors
see here.

Event Token ID(s) Weight Factor
Kaffeekränzchen low attendance 4437, 4813, 5182, 6457, 6887 4
Kaffeekränzchen medium attendance 7330, 8092 2
Kaffeekränzchen high attendance 8824 1
Kaffeekränzchen challenge winners 13346, 15296, 15739, 21839 20
UX Research Participants 11743 40
Squid 15311 20
CowStars 6739, 9533, 12654, 18465, 22201 100
SCdeploymentMainnet 6102 2
SCdeploymentGnoChain 6103 2
Picasso Winners 12420 100
AlphaUsersRetainedMainnet N/A 16
AlphaUsersRetainedGnoChain N/A 4

Unfortunately, due to an exploit in the POAP.xyz we were not able to automatically
recover the correct POAP token holders, so we have fallen back on our own, internal,
hard coded list of eligible token recipients.

For further details on the dates and names of specific event tokens please refer to our
token data files here

Dev Guide: Installation & Usage

python3 -m venv env
source ./env/bin/activate
pip install -r requirements.txt
cp .env.sample .env
source .env

Fill out your Dune credentials in the .env file. The Dune user and password are
straight-forward login credentials to Dune Analytics. The DUNE_QUERY_ID is an integer
id found in the URL of a query when saved in the Dune interface. This should be created
beforehand, but the same query id can be used everywhere throughout the program (as long
as it is owned by the account corresponding to the user credentials provided).

The other necessary environment variable is NODE_URL. This should be the entire URL
with API key. Something like

NODE_URL = https://mainnet.infura.io/v3/XXXYOURXXXXXXAPIXXXXXXKEYXXXXXXX

To generate the entire allocation from scratch run

python -m src.main

NOTE Entire allocation generation from scratch takes about 15 minutes.

DISCLAIMER Due to reliance on a non-deterministic price feed in the trader query we
are experiencing infinitesimal difference from one run to the next. While the results
will turn out marginally different the allocation files are not yet deterministic. We
are working toward fixing this, but will rely on the committed file here at the time of
deployment even if this non-determinism has not been resolved. In the meantime, we have
temporarily included the trader data that these results are based on to ensure identical
results.

Verifying results

If you generate the output files yourself, you can compare the output files with:

$ diff out/allocations-mainnet.csv allocations-mainnet.csv 
$ diff out/allocations-gchain.csv allocations-gchain.csv 

Note that every file in this repo runs as a standalone script for its intended purpose.
For example, to fetch GNO token holders run

python -m src.fetch.gno_holders

or to generate sub allocations (e.g. holder, poap, trader) run

python -m src.generate.{name}_allocation

This program writes files to CSV as it goes. By default, data is loaded from file when
available.

This will write two files into the data/ directory. Namely

mainnet-gno-holders.csv
gchain-gno-holders.csv

To fetch LP token holder results run

python -m src.fetch_lp_holders

which will result in files ./out/{network}-lp-holders.csv.

GitHub

View Github