The Claimdrop Contract V1 distributes tokens to recipients using a Merkle tree (proof-based claims). The Merkle root is stored on the campaign and used to verify proofs submitted by recipients.
Features
- Merkle-tree based distribution
- Lump sum and/or linear vesting distribution (two distribution types can be used simultaneously)
- Linear vesting may include an optional cliff
- One campaign per contract
- Campaign can be closed to retrieve unclaimed funds and restart with a new contract/campaign
Generating airdrop data
You can generate the merkle root and proofs using the JS scripts in the contract repository.
- Prepare a CSV file (header required) with columns:
contract_addr,address,amount.
contract_addr,address,amount
mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra1x5nk33zpglp4ge6q9a8xx3zceqf4g8nvaggjmc,100
mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra1rj2n3hge32n5u6zzw0u7clrys76srapulsvv39,200
mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra18mv5sz7nj2arpsqjc2aeslhh3v475np8ng6tt5,300
mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra16qtk5fnm4se6362yaah0scdmatx0qvp70fhej2,400
- Generate:
node merkle_root.js → generates the merkle root
node merkle_proof.js → generates the proofs
Only a single claim entry per address should exist in the CSV. If an address has multiple entries, consolidate them first.
How it works
- Contract owner can create a campaign (optionally appointing a different campaign owner).
- Campaign owner can top up a campaign before it ends.
- Users claim by submitting a valid Merkle proof.
- Contract owner or campaign owner can close a campaign, returning unclaimed funds to the campaign owner.
Instantiate
{
"owner": "mantra1..."
}
| Key | Type | Description |
|---|
owner | Option<String> | Contract owner. If omitted, the instantiating address becomes owner. |
ExecuteMsg
ManageCampaign
Actions:
- CreateCampaign: create a new campaign (contract owner only)
- TopUpCampaign: add funds (campaign owner only)
- CloseCampaign: close and refund remaining funds (contract owner or campaign owner)
CreateCampaign
{
"manage_campaign": {
"action": {
"create_campaign": {
"params": {
"owner": "mantra1...",
"name": "Airdrop",
"description": "This is an airdrop description.",
"reward_asset": { "denom": "uom", "amount": "888888888888" },
"distribution_type": [
{ "lump_sum": { "percentage": "0.25", "start_time": 1571797419 } },
{
"linear_vesting": {
"percentage": "0.75",
"start_time": 1572402219,
"end_time": 1573007019,
"cliff_duration": 86400
}
}
],
"start_time": 1571797419,
"end_time": 1573007019,
"merkle_root": "b32b978b07b56e8f10de1f098390407017daa61c90da6a6875ca0f2d655b6107"
}
}
}
}
}
The reward_asset must be sent with this transaction.
TopUpCampaign
{
"manage_campaign": {
"action": { "top_up_campaign": {} }
}
}
Send the same denom as reward_asset. You can’t top up a closed campaign.
CloseCampaign
{
"manage_campaign": {
"action": { "close_campaign": {} }
}
}
Claim
{
"claim": {
"total_claimable_amount": "88888",
"receiver": "mantra1...",
"proof": [
"1b20d6e1fa2e464d3a94fabdf28add25b6152663aa19efe1b6da2f28f50412cd",
"27c16d1dd47dedab5c9d394d02b507e3abd01ef11f753ffc3148b04bd1aa0487"
]
}
}
QueryMsg
Campaign
Rewards
{
"rewards": {
"total_claimable_amount": "8888",
"receiver": "mantra1...",
"proof": [
"1b20d6e1fa2e464d3a94fabdf28add25b6152663aa19efe1b6da2f28f50412cd",
"27c16d1dd47dedab5c9d394d02b507e3abd01ef11f753ffc3148b04bd1aa0487"
]
}
}
Claimed
{
"claimed": {
"address": "mantra1...",
"start_from": "mantra1...",
"limit": 50
}
}