Skip to content

Commit

Permalink
Merge branch 'main' into fix-typo
Browse files Browse the repository at this point in the history
  • Loading branch information
Valazan authored Sep 13, 2024
2 parents bb424b0 + 8a87b1d commit d02a2c6
Show file tree
Hide file tree
Showing 10 changed files with 40,789 additions and 3,267 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Watch the Tutorial

[![Watch the video](https://github.com/user-attachments/assets/462958d6-1be5-4598-b035-95f4ef818f16)](https://www.youtube.com/watch?v=fmm2IDMuYjE)

# X-App Template for VeBetterDAO 🚀

#######
Expand Down
54 changes: 53 additions & 1 deletion apps/contracts/contracts/interfaces/IX2EarnRewardsPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,59 @@ interface IX2EarnRewardsPool {
* @param appId the app id that is emitting the reward
* @param amount the amount of B3TR token the user is rewarded with
* @param receiver the address of the user that performed the sustainable action and is rewarded
* @param proof a JSON file uploaded on IPFS by the app that adds information on the type of action that was performed
* @param proof deprecated argument, pass an empty string instead
*/
function distributeReward(bytes32 appId, uint256 amount, address receiver, string memory proof) external;

/**
* @dev Function used by x2earn apps to reward users that performed sustainable actions.
* @notice This function is depracted in favor of distributeRewardWithProof.
*
* @param appId the app id that is emitting the reward
* @param amount the amount of B3TR token the user is rewarded with
* @param receiver the address of the user that performed the sustainable action and is rewarded
* @param proof the JSON string that contains the proof and impact of the sustainable action
*/
function distributeRewardDeprecated(bytes32 appId, uint256 amount, address receiver, string memory proof) external;

/**
* @dev Function used by x2earn apps to reward users that performed sustainable actions.
*
* @param appId the app id that is emitting the reward
* @param amount the amount of B3TR token the user is rewarded with
* @param receiver the address of the user that performed the sustainable action and is rewarded
* @param proofTypes the types of the proof of the sustainable action
* @param proofValues the values of the proof of the sustainable action
* @param impactCodes the codes of the impacts of the sustainable action
* @param impactValues the values of the impacts of the sustainable action
* @param description the description of the sustainable action
*/
function distributeRewardWithProof(
bytes32 appId,
uint256 amount,
address receiver,
string[] memory proofTypes, // link, image, video, text, etc.
string[] memory proofValues, // "https://...", "Qm...", etc.,
string[] memory impactCodes, // carbon, water, etc.
uint256[] memory impactValues, // 100, 200, etc.,
string memory description
) external;

/**
* @dev Builds the JSON proof string that will be stored
* on chain regarding the proofs, impacts and description of the sustainable action.
*
* @param proofTypes the types of the proof of the sustainable action
* @param proofValues the values of the proof of the sustainable action
* @param impactCodes the codes of the impacts of the sustainable action
* @param impactValues the values of the impacts of the sustainable action
* @param description the description of the sustainable action
*/
function buildProof(
string[] memory proofTypes, // link, photo, video, text, etc.
string[] memory proofValues, // "https://...", "Qm...", etc.,
string[] memory impactCodes, // carbon, water, etc.
uint256[] memory impactValues, // 100, 200, etc.,
string memory description
) external returns (string memory);
}
148 changes: 145 additions & 3 deletions apps/contracts/contracts/mock/X2EarnRewardsPoolMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {IX2EarnAppsMock} from './interfaces/IX2EarnAppsMock.sol';
import {IX2EarnRewardsPool} from '../interfaces/IX2EarnRewardsPool.sol';
import {IERC1155Receiver} from '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol';
import {IERC721Receiver} from '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import '@openzeppelin/contracts/utils/Strings.sol';

/**
* Mock contract forked from vebetterdao-contracts.
Expand Down Expand Up @@ -77,7 +78,7 @@ contract X2EarnRewardsPoolMock is IX2EarnRewardsPool, AccessControl, ReentrancyG
/**
* @dev See {IX2EarnRewardsPool-withdraw}
*/
function withdraw(uint256 amount, bytes32 appId, string memory reason) external nonReentrant {
function withdraw(uint256 amount, bytes32 appId, string memory reason) external {
X2EarnRewardsPoolStorage storage $ = _getX2EarnRewardsPoolStorage();

require($.x2EarnApps.appExists(appId), 'X2EarnRewardsPool: app does not exist');
Expand All @@ -103,10 +104,42 @@ contract X2EarnRewardsPoolMock is IX2EarnRewardsPool, AccessControl, ReentrancyG
emit TeamWithdrawal(amount, appId, teamWalletAddress, msg.sender, reason);
}

/**
* @dev See {IX2EarnRewardsPool-distributeRewardDeprecated}
*/
function distributeRewardDeprecated(bytes32 appId, uint256 amount, address receiver, string memory) external {
_distributeReward(appId, amount, receiver);

// emit event with empty proof
emit RewardDistributed(amount, appId, receiver, '', msg.sender);
}

/**
* @dev See {IX2EarnRewardsPool-distributeReward}
*/
function distributeReward(bytes32 appId, uint256 amount, address receiver, string memory proof) external nonReentrant {
function distributeReward(bytes32 appId, uint256 amount, address receiver, string memory) external {
_distributeReward(appId, amount, receiver);
_emitProof(appId, amount, receiver, new string[](0), new string[](0), new string[](0), new uint256[](0), '');
}

/**
* @dev See {IX2EarnRewardsPool-distributeRewardWithProof}
*/
function distributeRewardWithProof(
bytes32 appId,
uint256 amount,
address receiver,
string[] memory proofTypes, // link, photo, video, text, etc.
string[] memory proofValues, // "https://...", "Qm...", etc.,
string[] memory impactCodes, // carbon, water, etc.
uint256[] memory impactValues, // 100, 200, etc.,
string memory description
) public {
_distributeReward(appId, amount, receiver);
_emitProof(appId, amount, receiver, proofTypes, proofValues, impactCodes, impactValues, description);
}

function _distributeReward(bytes32 appId, uint256 amount, address receiver) internal nonReentrant {
X2EarnRewardsPoolStorage storage $ = _getX2EarnRewardsPoolStorage();

require($.x2EarnApps.appExists(appId), 'X2EarnRewardsPool: app does not exist');
Expand All @@ -122,9 +155,118 @@ contract X2EarnRewardsPoolMock is IX2EarnRewardsPool, AccessControl, ReentrancyG
// transfer the rewards to the receiver
$.availableFunds[appId] -= amount;
require($.b3tr.transfer(receiver, amount), 'X2EarnRewardsPool: Allocation transfer to app failed');
}

/**
* @dev Emits the RewardDistributed event with the provided proofs and impacts.
*/
function _emitProof(
bytes32 appId,
uint256 amount,
address receiver,
string[] memory proofTypes,
string[] memory proofValues,
string[] memory impactCodes,
uint256[] memory impactValues,
string memory description
) internal {
// Build the JSON proof string from the proof and impact data
string memory jsonProof = buildProof(proofTypes, proofValues, impactCodes, impactValues, description);

// emit event
emit RewardDistributed(amount, appId, receiver, proof, msg.sender);
emit RewardDistributed(amount, appId, receiver, jsonProof, msg.sender);
}

/**
* @dev see {IX2EarnRewardsPool-buildProof}
*/
function buildProof(
string[] memory proofTypes,
string[] memory proofValues,
string[] memory impactCodes,
uint256[] memory impactValues,
string memory description
) public view virtual returns (string memory) {
bool hasProof = proofTypes.length > 0 && proofValues.length > 0;
bool hasImpact = impactCodes.length > 0 && impactValues.length > 0;
bool hasDescription = bytes(description).length > 0;

// If neither proof nor impact is provided, return an empty string
if (!hasProof && !hasImpact) {
return '';
}

// Initialize an empty JSON bytes array with version
bytes memory json = abi.encodePacked('{"version": 2');

// Add description if available
if (hasDescription) {
json = abi.encodePacked(json, ',"description": "', description, '"');
}

// Add proof if available
if (hasProof) {
bytes memory jsonProof = _buildProofJson(proofTypes, proofValues);

json = abi.encodePacked(json, ',"proof": ', jsonProof);
}

// Add impact if available
if (hasImpact) {
bytes memory jsonImpact = _buildImpactJson(impactCodes, impactValues);

json = abi.encodePacked(json, ',"impact": ', jsonImpact);
}

// Close the JSON object
json = abi.encodePacked(json, '}');

return string(json);
}

/**
* @dev Builds the proof JSON string from the proof data.
* @param proofTypes the proof types
* @param proofValues the proof values
*/
function _buildProofJson(string[] memory proofTypes, string[] memory proofValues) internal pure returns (bytes memory) {
require(proofTypes.length == proofValues.length, 'X2EarnRewardsPool: Mismatched input lengths for Proof');

bytes memory json = abi.encodePacked('{');

for (uint256 i; i < proofTypes.length; i++) {
json = abi.encodePacked(json, '"', proofTypes[i], '":', '"', proofValues[i], '"');
if (i < proofTypes.length - 1) {
json = abi.encodePacked(json, ',');
}
}

json = abi.encodePacked(json, '}');

return json;
}

/**
* @dev Builds the impact JSON string from the impact data.
*
* @param impactCodes the impact codes
* @param impactValues the impact values
*/
function _buildImpactJson(string[] memory impactCodes, uint256[] memory impactValues) internal pure returns (bytes memory) {
require(impactCodes.length == impactValues.length, 'X2EarnRewardsPool: Mismatched input lengths for Impact');

bytes memory json = abi.encodePacked('{');

for (uint256 i; i < impactValues.length; i++) {
json = abi.encodePacked(json, '"', impactCodes[i], '":', Strings.toString(impactValues[i]));
if (i < impactValues.length - 1) {
json = abi.encodePacked(json, ',');
}
}

json = abi.encodePacked(json, '}');

return json;
}

/**
Expand Down
Loading

0 comments on commit d02a2c6

Please sign in to comment.