From 8baa95f6c6a5d0dfbf503590ac9617f8e89cd8a4 Mon Sep 17 00:00:00 2001
From: Julian Arce <52429267+JuArce@users.noreply.github.com>
Date: Fri, 19 Jun 2026 16:42:45 -0300
Subject: [PATCH] feat: update claim_contract README and Makefile
---
claim_contracts/Makefile | 99 +++++---
claim_contracts/README.md | 219 ++++++++++--------
.../config.base-sepolia.example.json | 5 +
.../script-config/config.sepolia.example.json | 5 +
4 files changed, 205 insertions(+), 123 deletions(-)
create mode 100644 claim_contracts/script-config/config.base-sepolia.example.json
create mode 100644 claim_contracts/script-config/config.sepolia.example.json
diff --git a/claim_contracts/Makefile b/claim_contracts/Makefile
index c1ae58d0bc..1be3597241 100644
--- a/claim_contracts/Makefile
+++ b/claim_contracts/Makefile
@@ -1,5 +1,41 @@
-.PHONY: help deploy-aligned-token-implementation deploy-aligned-token-proxy deploy-claimable-airdrop-implementation deploy-claimable-airdrop-proxy upgrade-aligned-token-implementation aligned-token-proxy-deploy-data aligned-token-init-data aligned-token-upgrade-data aligned-token-create2 aligned-token-proxy-create2
-
+.PHONY: help \
+ calldata-update-merkle-root calldata-update-limit-timestamp calldata-approve-spending calldata-unpause calldata-pause \
+ deploy-token deploy-token-sepolia deploy-token-mainnet \
+ deploy-claimable-local deploy-claimable-sepolia deploy-claimable-base-sepolia deploy-claimable-mainnet \
+ update_token_proxy upgrade-token enable-claimability \
+ approve-claimable claimable-update-root claimable-get-root claimable-update-timestamp claimable-get-timestamp claimable-pause claimable-unpause \
+ upgrade-aligned-token-implementation \
+ test-token test-claim test-claimed test-airdrop \
+ deploy-example
+
+
+# ============================================================================
+# Configuration — override any of these on the command line, e.g.
+# make deploy-claimable-sepolia DEPLOYER_PRIVATE_KEY=0x... ETHERSCAN_API_KEY=...
+# (ETHERSCAN_API_KEY, KEYSTORE_PATH, MERKLE_ROOT, TIMESTAMP, CLAIM_PROXY_ADDRESS,
+# LIMIT_TIMESTAMP, etc. have no default and are passed in per invocation.)
+# ============================================================================
+
+# RPC endpoints (per network)
+RPC_URL ?= http://localhost:8545
+SEPOLIA_RPC_URL ?= https://ethereum-sepolia-rpc.publicnode.com
+BASE_SEPOLIA_RPC_URL ?= https://sepolia.base.org
+MAINNET_RPC_URL ?= https://ethereum-rpc.publicnode.com
+
+# Signing keys (anvil defaults, for local use)
+DEPLOYER_PRIVATE_KEY ?= 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
+DISTRIBUTOR_PRIVATE_KEY ?= 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
+OWNER_PRIVATE_KEY ?= 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
+
+# Deploy config + contract addresses (anvil defaults)
+CONFIG ?= example
+AIRDROP ?= 0xBC9129Dc0487fc2E169941C75aABC539f208fb01
+TOKEN ?= 0x2E983A1Ba5e8b38AAAeC4B440B9dDcFBf72E15d1
+APPROVE_AMOUNT ?= 2600000000000000000000000000
+
+# Test inputs — require the proof API running on localhost:4000
+AMOUNT_TO_CLAIM = $(shell curl -S -H "Content-Type: application/json" http://localhost:4000/api/proof/\$(CLAIMER) | jq -r .amount)
+MERKLE_PROOF_TO_CLAIM = $(shell curl -S -H "Content-Type: application/json" http://localhost:4000/api/proof/\$(CLAIMER) | jq .proof | tr -d '"\n ')
help: ## 📚 Show help for each of the Makefile recipes
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
@@ -23,9 +59,6 @@ calldata-pause: ## 💾 Calldata for the method `pause` to use in a transaction
# Deployments
-RPC_URL?=http://localhost:8545
-DEPLOYER_PRIVATE_KEY?=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
-CONFIG?=example
deploy-token: ## 🚀 Deploy the token contract
cd script && \
forge script DeployAlignedToken.s.sol \
@@ -33,26 +66,25 @@ deploy-token: ## 🚀 Deploy the token contract
$(CONFIG) \
--private-key $(DEPLOYER_PRIVATE_KEY) \
--rpc-url $(RPC_URL) \
- --broadcast \
- --verbosity 3
+ --broadcast
-deploy-token-testnet: ## 🚀 Deploy the token contract
+deploy-token-sepolia: ## 🚀 Deploy the token contract in Sepolia
cd script && \
forge script DeployAlignedToken.s.sol \
--sig "run(string)" sepolia \
--private-key $(DEPLOYER_PRIVATE_KEY) \
- --rpc-url $(RPC_URL) \
+ --rpc-url $(SEPOLIA_RPC_URL) \
--broadcast \
--verify \
--etherscan-api-key $(ETHERSCAN_API_KEY)
-deploy-token-prod: ## 🚀 Deploy the token contract
+deploy-token-mainnet: ## 🚀 Deploy the token contract in Mainnet
cd script && \
forge script DeployAlignedToken.s.sol \
--sig "run(string)" \
- $(PROD_CONFIG) \
+ mainnet \
--keystore $(KEYSTORE_PATH) \
- --rpc-url $(PROD_RPC_URL) \
+ --rpc-url $(MAINNET_RPC_URL) \
--broadcast \
--verbosity 3
@@ -64,12 +96,22 @@ deploy-claimable-local: ## 🚀 Deploy the airdrop contract in localnet
--rpc-url http://localhost:8545 \
--broadcast
-deploy-claimable-testnet: ## 🚀 Deploy the airdrop contract in Sepolia
+deploy-claimable-sepolia: ## 🚀 Deploy the airdrop contract in Sepolia
cd script && \
forge script DeployClaimableAirdrop.s.sol \
--sig "run(string)" sepolia \
--private-key $(DEPLOYER_PRIVATE_KEY) \
- --rpc-url $(RPC_URL) \
+ --rpc-url $(SEPOLIA_RPC_URL) \
+ --broadcast \
+ --verify \
+ --etherscan-api-key $(ETHERSCAN_API_KEY)
+
+deploy-claimable-base-sepolia: ## 🚀 Deploy the airdrop contract in Base Sepolia
+ cd script && \
+ forge script DeployClaimableAirdrop.s.sol \
+ --sig "run(string)" base-sepolia \
+ --private-key $(DEPLOYER_PRIVATE_KEY) \
+ --rpc-url $(BASE_SEPOLIA_RPC_URL) \
--broadcast \
--verify \
--etherscan-api-key $(ETHERSCAN_API_KEY)
@@ -79,40 +121,41 @@ deploy-claimable-mainnet: ## 🚀 Deploy the airdrop contract in Mainnet
forge script DeployClaimableAirdrop.s.sol \
--sig "run(string)" mainnet \
--keystore $(KEYSTORE_PATH) \
- --rpc-url https://eth.llamarpc.com \
+ --rpc-url $(MAINNET_RPC_URL) \
--broadcast \
--verify \
--etherscan-api-key $(ETHERSCAN_API_KEY)
+# TODO: broken — reads script-out/deployed_token_addresses.json (never generated by the deploy
+# scripts) and treats $(CONFIG) as a file path. Fix or remove.
update_token_proxy:
@NEW_TOKEN_PROXY=$$(jq -r '.tokenProxy' "script-out/deployed_token_addresses.json") && \
jq --arg new_proxy "$$NEW_TOKEN_PROXY" '.tokenProxy = $$new_proxy' $(CONFIG) > $(CONFIG).tmp \
&& mv $(CONFIG).tmp $(CONFIG)
+# TODO: broken — runs UpgradeToken.s.sol, which does not exist in script/. Fix or remove
+# (see the README "Upgrades" section, which expects the upgrade script to be written ad-hoc).
upgrade-token: ## 🚀 Upgrade the token contract
cd script && \
forge script UpgradeToken.s.sol \
--sig "run(string)" \
$(CONFIG) \
- --private-key $(PRIVATE_KEY) \
+ --private-key $(DEPLOYER_PRIVATE_KEY) \
--rpc-url $(RPC_URL) \
--broadcast \
--verbosity 3
# Miscellaneous
-DISTRIBUTOR_PRIVATE_KEY?=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
-OWNER_PRIVATE_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
-AIRDROP=0xBC9129Dc0487fc2E169941C75aABC539f208fb01
-TOKEN=0x2E983A1Ba5e8b38AAAeC4B440B9dDcFBf72E15d1
+enable-claimability: claimable-update-root claimable-update-timestamp approve-claimable claimable-unpause ## 🚀 Run every tx needed to start claiming (set root, set deadline, approve, unpause)
approve-claimable: ## 🚀 Approve the ClaimableAirdrop contract to spend the token
cast send \
--rpc-url $(RPC_URL) \
--private-key $(DISTRIBUTOR_PRIVATE_KEY) \
$(TOKEN) \
- 'approve(address,uint256)' $(AIRDROP) 2600000000000000000000000000
+ 'approve(address,uint256)' $(AIRDROP) $(APPROVE_AMOUNT)
claimable-update-root: ## 🚀 Update the merkle root of the ClaimableAirdrop contract
cast send \
@@ -154,13 +197,15 @@ claimable-unpause:
# Upgrades
+# TODO: broken — script/aligned_token/UpgradeAlignedTokenImplementation.s.sol doesn't exist and
+# --sig has a stray leading "function". Fix or remove.
upgrade-aligned-token-implementation: ## 🚀 Upgrade the AlignedToken implementation contract
cd script/aligned_token && \
forge script UpgradeAlignedTokenImplementation.s.sol \
--sig "function run(address,address,uint256,address,address,address,address,uint256)" \
$(PROXY) $(IMPLEMENTATION) $(VERSION) $(OWNER) $(BENEFICIARY1) $(BENEFICIARY2) $(BENEFICIARY3) $(MINT)\
--rpc-url $(RPC_URL) \
- --private-key $(PRIVATE_KEY) \
+ --private-key $(DEPLOYER_PRIVATE_KEY) \
--broadcast
# Test targets
@@ -170,21 +215,19 @@ test-token:
cast call $(ADDRESS) "symbol()(string)" --rpc-url $(RPC_URL)
cast call $(ADDRESS) "totalSupply()(uint256)" --rpc-url $(RPC_URL)
-# The following target needs the proof API running on localhost:4000
-AMOUNT_TO_CLAIM=$(shell curl -S -H "Content-Type: application/json" http://localhost:4000/api/proof/\$(CLAIMER) | jq -r .amount)
-MERKLE_PROOF_TO_CLAIM=$(shell curl -S -H "Content-Type: application/json" http://localhost:4000/api/proof/\$(CLAIMER) | jq .proof | tr -d '"\n ')
+# TODO: outdated — claim is now claim(uint256 amount,uint256 validFrom,bytes32[] proof) and the
+# proof comes from the web app's /api/wallets/
, not /api/proof/. Fix.
test-claim:
cast send $(AIRDROP) --private-key $(CLAIMER_PRIVATE_KEY) "claim(uint256,bytes32[])" $(AMOUNT_TO_CLAIM) "$(MERKLE_PROOF_TO_CLAIM)" --rpc-url $(RPC_URL)
+# TODO: outdated — hasClaimed is now hasClaimed(bytes32 leaf), not hasClaimed(address). Fix.
test-claimed:
cast call $(AIRDROP) "hasClaimed(address)(bool)" $(CLAIMER) --rpc-url $(RPC_URL)
cast balance --erc20 $(TOKEN) $(CLAIMER) --rpc-url $(RPC_URL)
-OWNER_PRIVATE_KEY?=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
-
test-airdrop:
cast call $(AIRDROP) "paused()(bool)" --rpc-url $(RPC_URL)
cast call $(AIRDROP) "owner()(address)" --rpc-url $(RPC_URL)
# Requires MERKLE_ROOT, TIMESTAMP
-deploy-example: deploy-token deploy-claimable-local claimable-update-root claimable-update-timestamp approve-claimable claimable-unpause
+deploy-example: deploy-token deploy-claimable-local enable-claimability
diff --git a/claim_contracts/README.md b/claim_contracts/README.md
index 65c2ba6a13..52dfc736ce 100644
--- a/claim_contracts/README.md
+++ b/claim_contracts/README.md
@@ -1,112 +1,141 @@
-#
+# ALIGN Claim Contracts
-## Local
+This repo deploys the **AlignedToken** (ALIGN) and the **ClaimableAirdrop** contract (both behind
+Transparent proxies). The airdrop is split across **Ethereum and Base** — each network has its own
+claim contract and its own merkle root (the `ethereum` root and the `base` root produced by the
+merkle generator in `aligned_airdrop_web`).
-### Requisites
+Each environment below is a single flow: **deploy → enable claiming**.
-- Foundry
+## Prerequisites
-### Run
+- [Foundry](https://book.getfoundry.sh/getting-started/installation).
+- A funded deployer account private key (a keystore for mainnet).
+- An Etherscan API key to verify the deployed contract (the same key works for Base via the
+ Etherscan v2 API).
-1. Run anvil in one terminal:
- ```
- anvil
- ```
-2. Deploy the token
- ```
- make deploy-token
- ```
-3. Write down the token proxy address that is printed in the console output. Do this in the `config.example.json` file, under the `tokenProxy` key.
-4. Deploy the claimable contract
- ```
- make deploy-claimable-local
- ```
-5. Write down the claimable contract proxy address that is printed in the console output.
+## Local (anvil)
-## Testnet (Sepolia)
+A single anvil chain that deploys the token + claim contract and turns claiming on.
-### Requisites
+One-shot (deploy everything and enable claiming):
-- Foundry
-- Etherscan API key
+```
+make deploy-example MERKLE_ROOT= TIMESTAMP=
+```
+
+This runs `deploy-token` → `deploy-claimable-local` → set root → set deadline → approve → unpause.
+
+Or step by step, if you need the deployed addresses along the way:
+
+1. Start anvil in another terminal: `anvil`
+2. Deploy the token: `make deploy-token`
+3. Copy the printed token proxy address into `script-config/config.example.json`, under `tokenProxy`.
+4. Deploy the claim contract: `make deploy-claimable-local`
+5. Enable claiming: `make enable-claimability MERKLE_ROOT= TIMESTAMP=`
+
+## Sepolia (testnet)
+
+> [!NOTE]
+> The ALIGN token is already deployed on both testnets (Ethereum Sepolia
+> `0xd2Fd114f098b355321cB3424400f3CC6a0d75C9A`, Base Sepolia
+> `0x4AAcFbc2C31598a560b285dB20966E00B73F9F81`) and the configs already point `tokenProxy` at it,
+> so you only deploy and enable `ClaimableAirdrop` — on **both** chains.
+>
+> Need to (re)deploy the token? On Ethereum Sepolia run
+> `make deploy-token-sepolia DEPLOYER_PRIVATE_KEY= ETHERSCAN_API_KEY=`; on Base Sepolia the
+> L2 token is created through the OP bridge factory, not forge (see [`base/`](base/README.md)). Then
+> put the new address under `tokenProxy` in the config.
+
+### 1. Deploy
-### Run
+**Ethereum Sepolia** — fill `foundation` (contract owner) and `tokenDistributor` (the account
+holding ALIGN to distribute) in `script-config/config.sepolia.json`, then:
-1. Create a file `script-config/config.sepolia.json` following the example in `script-config/config.sepolia.example.json`.
-2. Deploy the token
- ```
- make deploy-token-testnet RPC_URL= PRIVATE_KEY=
- ```
-3. Write down the `token-proxy-address` that is printed in the console output. Do this in the `config.sepolia.json` file, under the `tokenProxy` key.
-4. Deploy the claimable contract
- ```
- make deploy-claimable-testnet RPC_URL= DEPLOYER_PRIVATE_KEY= ETHERSCAN_API_KEY=
- ```
-5. Write down the `claimable-proxy-address` that is printed in the console output.
+```
+make deploy-claimable-sepolia DEPLOYER_PRIVATE_KEY= ETHERSCAN_API_KEY=
+```
+
+**Base Sepolia** — bridge ALIGN to your `tokenDistributor` first (see [`base/`](base/README.md)),
+fill `foundation` and `tokenDistributor` in `script-config/config.base-sepolia.json`, then:
+
+```
+make deploy-claimable-base-sepolia DEPLOYER_PRIVATE_KEY= ETHERSCAN_API_KEY=
+```
+
+Note the claimable proxy address printed for each.
+
+### 2. Enable claiming
-## Enabling Claimability
+Run once per network (the owner/distributor are plain accounts on testnet):
-### By Calldata
+```
+make enable-claimability \
+ AIRDROP= TOKEN= \
+ MERKLE_ROOT= TIMESTAMP= \
+ OWNER_PRIVATE_KEY= DISTRIBUTOR_PRIVATE_KEY= \
+ RPC_URL=
+```
+
+> [!IMPORTANT]
+> Use the **ethereum** root on the Sepolia contract and the **base** root on the Base Sepolia
+> contract.
+
+This runs, in order: `updateMerkleRoot` → `extendClaimPeriod` → `approve` (2.6B by default,
+override with `APPROVE_AMOUNT=`) → `unpause`. The contract must be paused for the first two steps,
+which it is right after deployment. Each step is also available as its own target
+(`claimable-update-root`, `claimable-update-timestamp`, `approve-claimable`, `claimable-unpause`).
+
+## Mainnet
+
+Covers Ethereum mainnet today. **Base mainnet: to be added later** (no claim target yet).
+
+### 1. Deploy (Ethereum mainnet)
+
+Fill `script-config/config.mainnet.json` with `foundation`, `tokenDistributor`, and `tokenProxy`
+(the mainnet ALIGN token), then:
+
+```
+make deploy-claimable-mainnet KEYSTORE_PATH= ETHERSCAN_API_KEY=
+```
+
+Note the claimable proxy address printed in the output.
+
+> [!NOTE]
+> The mainnet ALIGN token already exists — use its address as `tokenProxy`. To deploy the token
+> from scratch on Ethereum: `make deploy-token-mainnet KEYSTORE_PATH=`.
+
+### 2. Enable claiming (foundation multisig)
+
+On mainnet the owner is the foundation safe, so you generate the calldata for each step and execute
+it from the multisig rather than sending the transactions directly.
> [!IMPORTANT]
>
-> - This step-by-step **assumes** that the claimable proxy contract **is already deployed** and that **is already paused**. If it is not paused, the first transaction should be to pause it using this calldata `cast calldata "pause()"`.
-> - This method **only** generates the necessary calldata to call the methods through transactions. It does **not** actually call the methods. This method is useful for copy-pasting the calldata into a multisig wallet.
-> - Steps 1, 2, and 4 can be batched into a single transaction in a multisig wallet. This multisig must be the `ClaimableAirdrop` contract owner.
-> - Step 3 must be done by the token distributor multisig as it is the one that has the tokens to be claimed.
+> - This assumes the claim proxy is **already deployed** and **paused** (it is right after deploy).
+> If it is not paused, pause it first with `make calldata-pause`.
+> - These targets only **generate calldata** to copy into a multisig transaction; they do not send
+> anything.
+> - Steps 1, 2 and 4 are owner actions and can be batched in one multisig transaction. Step 3 must
+> be done by the token-distributor safe (it holds the tokens).
> [!WARNING]
-> - Double-check the data you passing into the commands, any mistake can lead to undesired behavior.
-
-1. Update the merkle root
- ```
- // Example merkle_root = 0x97619aea42a289b94acc9fb98f5030576fa7449f1dd6701275815a6e99441927
- cast calldata "updateMerkleRoot(bytes32)"
- ```
-2. Update the claim time limit
- ```
- // Example timestamp = 2733427549
- cast calldata "extendClaimPeriod(uint256)"
- ```
-3. Approve the claimable proxy contract to spend the token from the distributor (_2.6B, taking into account the 18 decimals_)
- ```
- // Example claim_proxy_address = 0x0234947ce63d1a5E731e5700b911FB32ec54C3c6
- cast calldata "approve(address,uint256)" 2600000000000000000000000000
- ```
-4. Unpause the claimable contract (it is paused by default)
- ```
- cast calldata "unpause()"
- ```
-
-### Local
-
-1. Deploy the claimable contract as explained above.
-2. Set the correct merkle root
- ```
- make claimable-update-root MERKLE_ROOT=
- ```
-3. Set the correct claim time limit
- ```
- make claimable-update-timestamp TIMESTAMP=2733427549
- ```
-4. Approve the claimable contract to spend the token from the distributor
- ```
- make approve-claimable
- ```
-5. Unpause the claimable contract
- ```
- make claimable-unpause
- ```
-
-or
-
-```
-make deploy-example MERKLE_ROOT= TIMESTAMP=2733427549
-```
-
-# Contract upgrade instructions
-
-To upgrade a contract, first make sure you pause the contract if it's not paused already (NOTE: the erc20 cannot be paused, the claim contract can though). Once that's done, clone the `aligned_layer` repo and go into the `claim_contracts` directory:
+> Double-check the data you pass into these commands — any mistake can lead to undesired behavior.
+
+1. Merkle root (use the **ethereum** root for the mainnet contract):
+ `make calldata-update-merkle-root MERKLE_ROOT=`
+2. Claim deadline: `make calldata-update-limit-timestamp LIMIT_TIMESTAMP=`
+3. Approve spending, run by the token-distributor safe:
+ `make calldata-approve-spending CLAIM_PROXY_ADDRESS=`
+4. Unpause: `make calldata-unpause`
+
+Submit each piece of calldata as a transaction from the appropriate safe. The same per-network root
+mapping (ethereum root on the Ethereum contract, base root on the Base contract) applies once Base
+mainnet is added.
+
+## Upgrades
+
+To upgrade a contract, first make sure you pause the contract if it's not paused already. Once that's done, clone the `aligned_layer` repo and go into the `claim_contracts` directory:
> [!NOTE]
> The ERC20 cannot be paused. Only the claimable airdrop proxy can be paused.
@@ -115,7 +144,7 @@ To upgrade a contract, first make sure you pause the contract if it's not paused
git clone git@github.com:yetanotherco/aligned_layer.git && cd aligned_layer/claim_contracts
```
-## Write the new contract implementation
+### Write the new contract implementation
This implementation will most likely be a copy paste of the old implementation, only with one or few changes. In addition to that, there is one thing that MUST be done on this new contract:
@@ -134,7 +163,7 @@ function reinitialize() public reinitializer(2) {
Put the new implementation in a file inside the `src` directory with an appropriate name.
-## Write the deployment script
+### Write the deployment script
Under the `script` directory, create a new forge script (with the `.s.sol` extension) with a name like `UpgradeContract.s.sol`, with this code in it:
@@ -216,7 +245,7 @@ Go into the `config.mainnet.json` file inside the `script-config` directory and
- `foundation` is the address of the foundation safe.
- `contractProxy` is the address of the contract proxy to upgrade.
-## Run the deployment script
+### Run the deployment script
Run the script with
diff --git a/claim_contracts/script-config/config.base-sepolia.example.json b/claim_contracts/script-config/config.base-sepolia.example.json
new file mode 100644
index 0000000000..dfbb1985c1
--- /dev/null
+++ b/claim_contracts/script-config/config.base-sepolia.example.json
@@ -0,0 +1,5 @@
+{
+ "foundation": "",
+ "tokenDistributor": "",
+ "tokenProxy": "0x4AAcFbc2C31598a560b285dB20966E00B73F9F81"
+}
diff --git a/claim_contracts/script-config/config.sepolia.example.json b/claim_contracts/script-config/config.sepolia.example.json
new file mode 100644
index 0000000000..50ac064946
--- /dev/null
+++ b/claim_contracts/script-config/config.sepolia.example.json
@@ -0,0 +1,5 @@
+{
+ "foundation": "",
+ "tokenDistributor": "",
+ "tokenProxy": "0xd2Fd114f098b355321cB3424400f3CC6a0d75C9A"
+}