ATTENTION: this README is OUTDATED
GnosisDAO received 15% of the total SAFE Token supply, vesting over 4 years. These tokens continuously vest to GnosisDAO, and this tool is responsible for distributing these tokens to GNO holders. The distributions for each address are calculated daily, and vested tokens are made available to claim monthly. GIP and discussion can be read here.
This repo contains the codebases for the distribution contracts, the scripts for claiming and calculating distributions, and the web app used by GNO holders to claim tokens.
Note: Token distributions will not be available until the SAFE Token is made transferable, and the Distribution contracts are deployed. Once SAFE is unpaused, and MerkleDistros deployed, distribution the first distribution will be handled manually.
This is a React app that allows you to connect a wallet, view claimed and unclaimed tokens, and submit transactions to claim any available tokens. This app is live here -> http://claim-safe.gnosis.io/
This directory contains the distribution contract code as well as the scripts that run periodically to calculate distributions and disburse tokens to the contracts.
The distribution contracts contain the tokens available for claiming, and the authorization logic (via MerkleTree/MerkleRoot) that grants whitelisted addresses a certain amount of tokens.
When a distribution runs, it funds these contracts (one on mainnet, one on gnosis), and updates their internal MerkleRoot storage variable.
Contract audit available here.
A json file containing a list of pairs (blockNumberMainnet
, blockNumberGnosis
). This file determines how allocation snapshots are taken. It has an entry for each day passed since VestingInception. The current schedule file can be found here.
For each past VestingSlice (~1 day) we select a block at random, and insert it into schedule.json. This random block becomes the upper boundary of the slice.
The task that progressively expands schedule is called schedule:expand
:
- Get all past daily intervals since VestingInception
VestingInception
is the block whereVestingId
was created
- For every interval not yet represented in the schedule:
- Generate a random mainnet blockNumber that falls within the interval
- Get the closest matching blockNumber on gnosis
- Insert pair into schedule
Allocations were calculated using, and published in, the safe-token-distribution-scripts repo.
A checkpoint file is an accumulation of allocations (simple sum). It's a map of addresses to balances, and it represents the absolute amount of SAFE tokens allocated to an address, up to a certain point. We can generate checkpoints at any arbitrary block by summing all prior allocations:
For a given blockNumber (or latest):
- Filter the schedule for entries older than blockNumber:
- Load corresponding allocation file
- Sum/Accumulate allocations
- Result is a map of addresses to balances
- Transform the map into list of pairs [address, balance]
- Build a MerkleTree with the pairs as leaves
The distribution is triggered by manually triggering the Distribute
workflow, it is defined here.
Posts two transactions - mainnet and gnosis - that take care of the following steps:
- TreasurySafe Mainnet:
multisendEncode
of:- Tx that claims the tokens from the
VestingPool
- Tx that funds
MerkleDistroMainnet
with SAFE - Tx that funds
MerkleDistroGnosis
with SAFE, via OmniBridge - Tx that updates the merkleRoot in
MerkleDistroMainnet
- Tx that claims the tokens from the
- TreasurySafe Gnosis:
- Tx that updates the merkleRoot in
MerkleDistroGnosis
- Tx that updates the merkleRoot in
To deploy the MerkleDistro.sol contract:
- copy
.env.template
to.env
and fill with valid keys and a mnemonic that resolves to a funded account - run
yarn run deploy-distros yarn run verify-distros
Note: The deploy will fail if SafeToken not yet deloyed and bridged to Gnosis Chain
- run
yarn hardhat checkpoint
- run
yarn hardhat audit