dossinstitute / sidequest

Apache License 2.0
0 stars 0 forks source link

Checkout & Redeem #13

Open russlive215 opened 2 weeks ago

russlive215 commented 2 weeks ago

New Ticket: Points Redemption System

Description: Enhance the Event Ambassador Quest contract by adding a checkout system that allows users to redeem their accumulated points for rewards.

Acceptance Criteria:

  1. Points Redemption Implementation:
    • Implement a function that allows users to redeem their points for specified rewards.
    • Define various rewards and their corresponding point costs within the contract.
    • Deduct the correct number of points from the user's balance upon successful redemption.
    • Ensure users have sufficient points for the redemption.
  2. Reward Management:
    • Admin should be able to add, update, and remove rewards and their point costs.
    • Ensure rewards are correctly managed and retrievable.
  3. Smart Contract Code:
    • Implement the points redemption functionality using Solidity.
    • Ensure the points balance is updated correctly and securely upon redemption.
    • Implement necessary events to log successful redemptions.
  4. Security and Validations:
    • Validate that users cannot redeem more points than they have.
    • Ensure the integrity of the points balance and reward distribution.
    • Prevent re-entrancy attacks and other potential security vulnerabilities.

Solidity Code Example:

solidity

Copy code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract EventAmbassadorQuest {
    struct Quest {
        uint256 eventId;
        uint256 startDate;
        uint256 endDate;
        uint256 requiredInteractions;
        uint256 rewardPoints;
        bool isCompleted;
    }

    struct User {
        uint256 points;
        uint256 completedQuests;
        mapping(uint256 => bool) questCompleted;
    }

    struct Reward {
        string name;
        uint256 pointCost;
        bool isAvailable;
    }

    address public admin;
    mapping(address => User) public users;
    mapping(uint256 => Quest) public quests;
    mapping(uint256 => Reward) public rewards;
    address[] public userAddresses;

    event QuestCompleted(address indexed user, uint256 indexed questId, uint256 pointsAwarded);
    event RewardRedeemed(address indexed user, uint256 indexed rewardId, string rewardName);
    event RewardAdded(uint256 indexed rewardId, string rewardName, uint256 pointCost);
    event RewardUpdated(uint256 indexed rewardId, string rewardName, uint256 pointCost);
    event RewardRemoved(uint256 indexed rewardId);

    modifier onlyAdmin() {
        require(msg.sender == admin, "Only admin can perform this action");
        _;
    }

    constructor() {
        admin = msg.sender;
    }

    function createQuest(
        uint256 questId,
        uint256 eventId,
        uint256 startDate,
        uint256 endDate,
        uint256 requiredInteractions,
        uint256 rewardPoints
    ) external onlyAdmin {
        quests[questId] = Quest(eventId, startDate, endDate, requiredInteractions, rewardPoints, false);
    }

    function registerUser(address user) external onlyAdmin {
        if (users[user].completedQuests == 0) {
            userAddresses.push(user);
        }
    }

    function completeQuest(address user, uint256 questId) external onlyAdmin {
        require(!quests[questId].isCompleted, "Quest already completed");
        require(!users[user].questCompleted[questId], "User already completed this quest");

        users[user].points += quests[questId].rewardPoints;
        users[user].completedQuests += 1;
        users[user].questCompleted[questId] = true;
        quests[questId].isCompleted = true;

        emit QuestCompleted(user, questId, quests[questId].rewardPoints);
    }

    function addReward(uint256 rewardId, string memory name, uint256 pointCost) external onlyAdmin {
        rewards[rewardId] = Reward(name, pointCost, true);
        emit RewardAdded(rewardId, name, pointCost);
    }

    function updateReward(uint256 rewardId, string memory name, uint256 pointCost) external onlyAdmin {
        require(rewards[rewardId].isAvailable, "Reward does not exist");
        rewards[rewardId] = Reward(name, pointCost, true);
        emit RewardUpdated(rewardId, name, pointCost);
    }

    function removeReward(uint256 rewardId) external onlyAdmin {
        require(rewards[rewardId].isAvailable, "Reward does not exist");
        rewards[rewardId].isAvailable = false;
        emit RewardRemoved(rewardId);
    }

    function redeemReward(uint256 rewardId) external {
        require(rewards[rewardId].isAvailable, "Reward not available");
        require(users[msg.sender].points >= rewards[rewardId].pointCost, "Insufficient points");

        users[msg.sender].points -= rewards[rewardId].pointCost;

        emit RewardRedeemed(msg.sender, rewardId, rewards[rewardId].name);
    }

    function getLeaderboard(uint256 topN) external view returns (address[] memory, uint256[] memory) {
        require(topN <= userAddresses.length, "Requested topN exceeds number of users");

        address[] memory topUsers = new address[](topN);
        uint256[] memory topPoints = new uint256[](topN);

        for (uint256 i = 0; i < userAddresses.length; i++) {
            for (uint256 j = i + 1; j < userAddresses.length; j++) {
                if (users[userAddresses[j]].points > users[userAddresses[i]].points) {
                    address tempAddress = userAddresses[i];
                    userAddresses[i] = userAddresses[j];
                    userAddresses[j] = tempAddress;
                }
            }
        }

        for (uint256 i = 0; i < topN; i++) {
            topUsers[i] = userAddresses[i];
            topPoints[i] = users[userAddresses[i]].points;
        }

        return (topUsers, topPoints);
    }
}

Testing:

By following this ticket and implementing the provided Solidity code, the Event Ambassador Quest contract will be enhanced with a checkout system for users to redeem their accumulated points for rewards, adding further incentive and utility for participants.

4o

wvwatson commented 2 weeks ago

points: 1, 2, 3, 5, 8, 13, 21

@russlive215 8 @Fr0z0n3 5 @noireconnect2024 5 @wvwatson 8 @tierra-d 5

points: 5