Pattern 1: Use Only Smart Contracts

In this example, we assume that you are building a smart contract where users can submit some sustainable action that is being approved/rejected by some moderator. If the action is approved the user can claim his rewards. No backend is involved.

1) Import interface

Create an interfaces folder in your project and add the IX2EarnRewardsPool.sol interface (look here for the most updated version).

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

/**
 * @title IX2EarnRewardsPool
 * @dev Interface designed to be used by a contract that allows x2Earn apps to reward users that performed sustainable actions.
 * Funds can be deposited into this contract by specifying the app ID that can access the funds.
 * Admins of x2EarnApps can withdraw funds from the rewards pool, which are sent to the team wallet.
 */
interface IX2EarnRewardsPool {
  event NewDeposit(uint256 amount, bytes32 indexed appId, address indexed depositor);

  event TeamWithdrawal(
    uint256 amount,
    bytes32 indexed appId,
    address indexed teamWallet,
    address withdrawer,
    string reason
  );

  event RewardDistributed(
    uint256 amount,
    bytes32 indexed appId,
    address indexed receiver,
    string proof,
    address indexed distributor
  );

  function version() external pure returns (string memory);

  function deposit(uint256 amount, bytes32 appId) external returns (bool);

  function withdraw(uint256 amount, bytes32 appId, string memory reason) external;

  function availableFunds(bytes32 appId) external view returns (uint256);

  function distributeReward(bytes32 appId, uint256 amount, address receiver, string memory proof) external;
}

2) Import the interface in your contract and set the address of the X2EarnRewardsPool

You can find this address in the Smart Contracts section. For testnet addresses you can find it both in the vebetterdao-contracts repo and in the testnet governance app inside the Admin section.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "./interfaces/IX2EarnRewardsPool.sol";

/**
 * Example contract with key functionality to interact with the x2Earn rewards pool
 * and distribute rewards.
 */
contract MySustainableAppContract {
    IX2EarnRewardsPool public x2EarnRewardsPool;

    constructor(IX2EarnRewardsPool _x2EarnRewardsPool) {
        x2EarnRewardsPool = _x2EarnRewardsPool;
    }
}

3) Generate an APP_ID

Look at how to use the Test Environment to generate an APP_ID. Once you have the APP_ID add it to the smart contract.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "./interfaces/IX2EarnRewardsPool.sol";

/**
 * Example contract with key functionality to interact with the x2Earn rewards pool
 * and distribute rewards.
 */
contract MySustainableAppContract {
    IX2EarnRewardsPool public x2EarnRewardsPool;
    bytes32 public VBD_APP_ID;

    constructor(IX2EarnRewardsPool _x2EarnRewardsPool, bytes32 _VBD_APP_ID) {
        x2EarnRewardsPool = _x2EarnRewardsPool;
        VBD_APP_ID = _VBD_APP_ID;
    }
}

4) Call X2EarnRewardsPool to distribute the reward

To distribute the rewards call the X2EarnRewardsPool contract with your APP_ID, the receiver address, the amount to distribute, and the proof of the sustainable action the used performed.

Your contract should look like this:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "./interfaces/IX2EarnRewardsPool.sol";

/**
 * Example contract with key functionality to interact with the x2Earn rewards pool
 * and distribute rewards.
 */
contract MySustainableAppContract {
    IX2EarnRewardsPool public x2EarnRewardsPool;
    bytes32 public VBD_APP_ID;

    constructor(IX2EarnRewardsPool _x2EarnRewardsPool, bytes32 _VBD_APP_ID) {
        x2EarnRewardsPool = _x2EarnRewardsPool;
        VBD_APP_ID = _VBD_APP_ID;
    }

    /**
     * A function that allows users to claim a reward for a specific
     * sustainable action that they performed.
     */
    function claimReward(uint256 _actionId) external {
        // ... some code to check if the action is valid and user can claim

        // If distributeReward fails, it will revert
        x2EarnRewardsPool.distributeReward(
            VBD_APP_ID,
            actions[_actionId].rewardAmount,
            msg.sender, // this is the user calling the claimReward function
            actions[_actionId].ipfsProof
        );

        rewardClaimed[_actionId] = true;

        emit RewardClaimed(_actionId, msg.sender);
    }
}

5) Allow your contract to distribute rewards

Only specific addresses can access the funds and call the distributeReward function. To allow your contract to perform this action you will need to first deploy your contract then go to your app management section in the VeBetterDAO dApp and add the address where your contract was deployed as a Reward Distributor.

Last updated