Encompassing Campaigns

Get your campaign on the Merkl app while keeping control of computational load.

Merkl's All Encompassing Campaigns enable protocols to distribute rewards without requiring Merkl's Engine to calculate reward allocation. In this model, partners provide some API endpoints containing opportunity data and rewards, which are distributed based on the provided output.

The Merkl Engine aggregates the computed reward data provided by the partner into a Merkle root and pushes it onchain, enabling users to claim their rewards.

Once a reward update has been processed, it becomes immutable and cannot be reverted. Nevertheless, campaign data can be dynamically updated throughout the campaign duration by modifying the reward endpoint output, with the final update required before the campaign's end date.

🛠️ Campaign configuration

Campaigns creators must provide the following information upon creation:

  • 📅 Start Date – The date on which the campaign starts.

  • 📅 End Date – The date on which the campaign ends.

  • 🎁 Reward url - A public endpoint returning a reward JSON file.

  • 📊 Data url - A public endpoint returning a data JSON file.

1. 🎁 Reward JSON

The expected format for the JSON reward is the following

type EncompassingJSON = {
    // Token being distributed
    rewardToken: string;
    // User rewards
    rewards: {
        // recipient: user address
        [recipient: string]: {
            // Reason: how the user got the rewards
            [reason: string]: {
              // amount: amount with all decimals as a string
              amount: string;
              // timestamp: unix timestamp in seconds, date at which the reward is sent to the recipient (must not exceed the end date of the campaign)
              timestamp: string; 
            }
        };
    };
};

Example:

  • rewardToken: The token being distributed.

  • rewards: User rewards with recipient addresses, reasons, amount and timestamp for the rewards.

Good to know:

  • timestamp is the unix timestamp in seconds, date at which the reward is sent to the recipient. This timestamp must not exceed the end date of the campaign (it will not be processed if it's after the end date), and if it's before the start date of the campaign, the reward will be sent to the recipient at the start date.

  • Once the engine has processed some rewards, even if the reward endpoint is updated, the rewards already distributed can't be reverted. If a campaign creator needs to send additional rewards to the same user, he can do it by adding another reason for the same recipient.

Example:

2. 📊 Data JSON

The expected format for the JSON data is the following

Example:

This data will be used to display the campaign in the Merkl frontend.

Validating your endpoints

You can use this python script to validate that your endpoints are in the correct format

⚠️ Important Note

Merkl applies a 0.5% fee to this type of campaigns. This fee is added on top of the total airdropped amount, ensuring recipients receive the full intended distribution.

  • 💡 If you want exactly 100,000 tokens to be distributed to users, you need to provide 100,502.51 tokens (calculated as 100,000 / (1 - 0.5%)).

  • 💡 If you prefer to send exactly 100,000 tokens from your wallet, then the total sum of allocations in your JSON file should be 99,500 tokens (calculated as 100,000 * (1 - 0.5%)).

Our frontend automatically calculates the correct amount for you.

⏳ Distribution lag

Tokens become claimable at the next reward update on the target chain, which typically occurs within 8 hours. If you plan to announce the distribution, we recommend waiting until the rewards are claimable to notify your users.

Tutorial for static encompassing campaigns

If you are running a quest on your app where users become eligible to rewards after a while, it can be beneficial to create an encompassing campaign because your quest will be exposed to our user base.

However, you probably don't need to go through the trouble of developing a real API endpoint for us because the data is almost static (only updated once, at the end of the quest).

What we recommend is doing this via gists.

Data JSON

Here is an example data JSON using a gist: https://gist.githubusercontent.com/BaptistG/576bd5711fded3f44d906efbcaff80e0/raw

Reward JSON

You must first initialize the gist of the reward URL. You do this by creating a public gist of the following format:

Here is an example if you want to airdrop WETH on Ethereum: https://gist.github.com/BaptistG/e9bc9e9703a40cd6ad7e30d3e4e039a3/42921f90a660bfb7db8b6f890adc725644ad1490

You can now use the raw URL to initialize the campaign: https://gist.githubusercontent.com/BaptistG/e9bc9e9703a40cd6ad7e30d3e4e039a3/raw/ (you will notice that this URL has data in there, this is because it is the latest version of the file)

Create the campaign

You now have everything you need to create the campaign. You will need to choose the start and end dates of the campaign and commit the airdropped amount upfront.

If you don't airdrop all the tokens by the end of the campaign, you will automatically get the undistributed tokens back

Generating the payload

The Merkl Studio does not yet support creating encompassing campaigns. We recommend calling the encode batch route on the API to generate a Gnosis Safe payload for your campaign.

The Gnosis Safe payload will be under the key safePayload

Airdropping the rewards

Before the end of the campaign you created, you need to update the rewards endpoint to tell Merkl to airdrop the rewards. To do so you should go to your gist, click edit and add data. For example, if I want to airdrop the following rewards of my token that has 18 decimals to 3 users where:

  • User 1 gets 1 token

  • User 2 gets 4 tokens

  • User 3 gets 6 tokens

The gist should look like this:

Here is an example for the WETH airdrop: https://gist.github.com/BaptistG/e9bc9e9703a40cd6ad7e30d3e4e039a3

Last updated