The Rewards Metadata feature allows applications to enrich reward distributions with additional contextual information. This is facilitated through the distributeRewardWithProofAndMetadata function, which accepts a JSON-formatted string as metadata.
The provided metadata is then emitted via the RewardMetadata event, enabling off-chain services to efficiently index, analyze, and utilize the data for tracking and reporting purposes.
To maintain consistency across applications, it's recommended to follow a standardized metadata structure. Below is an example of a JSON-formatted metadata string:
{
"location": {
"city": "Berlin",
"country": "Germany",
"region": "EU"
},
"referral_source": "social_media",
"campaign_id": "earth_day_2025"
}
{% hint style="warning" %} Keep in mind that including location metadata may require updating your privacy policy and terms of service. {% endhint %}
To provide metadata you need to distribute the rewards through the X2EarnRewardsPool contract with the following function:
{% tabs %} {% tab title="JavaScript" %}
import { ProviderInternalHDWallet, ThorClient, VeChainProvider, VeChainSigner } from "@vechain/sdk-network";
import { X2EarnRewardsPool } from "@vechain/vebetterdao-contracts";
const thor = ThorClient.fromUrl("https://mainnet.vechain.org");
const provider = new VeChainProvider(
thor,
new ProviderInternalHDWallet("your space separated mnemonic".split(" "))
);
const rootSigner = await provider.getSigner();
// Define metadata as an object
const metadata = {
"location": {
"city": "Berlin",
"country": "Germany",
"region": "EU"
},
"referral_source": "social_media",
"campaign_id": "earth_day_2025"
};
// Call the method
const x2EarnRewardsPoolContract = thor.contracts.load(
X2EarnRewardsPool.address.mainnet,
X2EarnRewardsPool.abi,
rootSigner as VeChainSigner
);
const tx = await x2EarnRewardsPoolContract.transact.distributeRewardWithProofAndMetadata(
APP_ID,
amount,
receiverAddress,
["link", "image"],
["https://link-to-proof.com", "https://link-to-image.com/1.png"],
["waste_mass"],
[100],
"User performed a sustainable action on my app",
JSON.stringify(metadata) // Convert metadata object to JSON string
);
await tx.wait();{% endtab %}
{% tab title="Solidity" %}
import "./interfaces/IX2EarnRewardsPool.sol";
contract MyContract {
function sendRewardWithMetadata() onlyAdmin {
// this declaration is needed because solidity has
// an issue with dynamic vs fixed-size arrays
string[] memory proofTypes = new string[](1);
proofTypes[0] = "link";
string[] memory proofUrls = new string[](1);
proofUrls[0] = action.proofUrl;
string[] memory impactTypes = new string[](1);
impactTypes[0] = "waste_mass";
uint256[] memory impactValues = new uint256[](1);
// let's pretend you have another function that calculates your impact
impactValues[0] = calculateWasteMass(
challenge.litterSize,
challenge.litterCount
);
IX2EarnRewardsPool x2EarnRewardsPool = IX2EarnRewardsPool(x2EarnRewardsPoolAddress);
// Constructing metadata JSON string
string memory metadata = '{"location":{"city":"Berlin","country":"Germany","region":"EU"},"referral_source":"social_media","campaign_id":"earth_day_2025"}';
// If distributeReward fails, it will revert
x2EarnRewardsPool.distributeRewardWithProofAndMetadata(
VBD_APP_ID,
rewardAmount,
receiver,
proofTypes,
proofUrls,
impactTypes,
impactValues,
"User participated in a solo cleanup",
metadata
);
}
}{% endtab %} {% endtabs %}
Upon successful execution of the distributeRewardWithProofAndMetadata function, the RewardMetadata event is emitted with the following parameters:
- amount (
uint256): The distributed reward amount. - appId (
bytes32): The application identifier. - receiver (
address): The address receiving the reward. - metadata (
string): The JSON-formatted metadata string. - distributor (
address): The address initiating the distribution.
This event allows off-chain systems to listen for and process reward distributions along with their associated metadata.
- Optional Usage: The
metadatais optional. If your application doesn't require additional context, you can continue using the existingdistributeRewardWithProoffunction. - Standardization: Adhere to the suggested metadata structure to ensure consistency and facilitate seamless data integration across the ecosystem.
- Data Validation: Implement validation checks to ensure the metadata JSON is correctly formatted and contains relevant information before invoking the distribution function.