Event Access Token Contract

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract EventAccessTokenContract is ERC721URIStorage, AccessControl, ReentrancyGuard {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdCounter;

    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant EVENT_MANAGER_ROLE = keccak256("EVENT_MANAGER_ROLE");
    bytes32 public constant UMBRELLA_CONTRACT_ROLE = keccak256("UMBRELLA_CONTRACT_ROLE");

    // Metadata for event access
    struct EventAccessDetails {
        uint256 expirationTimestamp; // Expiration time for one-time use tokens
        bool isMultiUse; // Whether the token supports multiple entries
    }

    // Mapping from token ID to event access details
    mapping(uint256 => EventAccessDetails) public eventAccessDetails;

    // Events
    event EventAccessTokenMinted(address indexed to, uint256 tokenId, bool isMultiUse, uint256 expiration);
    event EventAccessTokenBurned(uint256 tokenId);

    // Instead of a constructor, using an initialize function to allow deployment by the umbrella contract
    /**
     * @dev Initialize the Event Access Token Contract.
     * @param name The name of the token (e.g., "DAO Event Token").
     * @param symbol The symbol of the token (e.g., "DAE").
     * @param umbrellaContract The address of the umbrella contract deploying this instance.
     * Note: Ensure these variables are set properly during deployment for specific events.
     */
    function initialize(string memory name, string memory symbol, address umbrellaContract) external {
        require(hasRole(UMBRELLA_CONTRACT_ROLE, _msgSender()), "Caller is not the umbrella contract");
        _setupRole(DEFAULT_ADMIN_ROLE, umbrellaContract);
        _setupRole(ADMIN_ROLE, umbrellaContract);
        _setupRole(EVENT_MANAGER_ROLE, umbrellaContract);
        _tokenIdCounter.increment(); // Start token IDs at 1

        // Setting up ERC721 name and symbol
        _name = name;
        _symbol = symbol;
    }

    /**
     * @dev Mint a new Event Access Token.
     * Only an address with the EVENT_MANAGER_ROLE can mint new tokens.
     * @param to The address that will receive the minted token.
     * @param isMultiUse Indicates whether the token supports multiple uses (true for multi-use, false for single-use).
     * @param duration The duration in seconds for which the token is valid (for one-time use tokens).
     * Note: Ensure to adjust "duration" based on the event's timeline when deploying.
     */
    function mintEventAccessToken(address to, bool isMultiUse, uint256 duration) external onlyRole(EVENT_MANAGER_ROLE) nonReentrant {
        // Verify that the contract was approved by the umbrella contract before minting
        require(hasRole(UMBRELLA_CONTRACT_ROLE, _msgSender()), "Contract must be approved by umbrella contract");

        uint256 tokenId = _tokenIdCounter.current();
        _safeMint(to, tokenId);

        // Set URI for metadata (to be replaced with actual URI)
        _setTokenURI(tokenId, "https://metadata.uri/for/EventAccessToken"); // TODO: Replace with actual metadata URI for the specific event

        // Set event access details
        uint256 expirationTimestamp = isMultiUse ? 0 : block.timestamp + duration;
        eventAccessDetails[tokenId] = EventAccessDetails({
            expirationTimestamp: expirationTimestamp,
            isMultiUse: isMultiUse
        });

        _tokenIdCounter.increment();
        emit EventAccessTokenMinted(to, tokenId, isMultiUse, expirationTimestamp);
    }

    /**
     * @dev Burn an Event Access Token.
     * Only the token owner or an admin can burn the token.
     * @param tokenId The ID of the token to be burned.
     * Note: Ensure token holders are aware of the conditions under which tokens may be burned.
     */
    function burnEventAccessToken(uint256 tokenId) external nonReentrant {
        require(_isApprovedOrOwner(_msgSender(), tokenId) || hasRole(ADMIN_ROLE, _msgSender()), "Unauthorized to burn");
        _burn(tokenId);
        delete eventAccessDetails[tokenId];
        emit EventAccessTokenBurned(tokenId);
    }

    /**
     * @dev Check if a token is still valid.
     * Multi-use tokens do not expire, while one-time use tokens have an expiration time.
     * @param tokenId The ID of the token to check.
     * @return True if the token is still valid, false otherwise.
     * Note: Useful for determining event entry eligibility.
     */
    function isTokenValid(uint256 tokenId) external view returns (bool) {
        require(_exists(tokenId), "Token does not exist");
        if (eventAccessDetails[tokenId].isMultiUse) {
            return true;
        } else {
            return block.timestamp <= eventAccessDetails[tokenId].expirationTimestamp;
        }
    }

    /**
     * @dev Override transfer function to prevent transfers of event access tokens.
     * Event access tokens are non-transferable.
     * @param from Address from which token is being transferred.
     * @param to Address to which token is being transferred.
     * @param tokenId ID of the token being transferred.
     * Note: Event tokens are non-transferable to prevent unauthorized access.
     */
    function _transfer(address from, address to, uint256 tokenId) internal pure override {
        revert("Event Access Tokens are non-transferable");
    }
}

/*
 Key Features:
 - **Event Access Token Contract**: Manages tokens for one-time or recurring events, such as concerts, seminars, and community meetups.
 - **Umbrella Contract Integration**: This contract is intended to be deployed and initialized by the **Umbrella Access Token Contract**.
 - **Role-Based Access Control**: Uses role-based control with ADMIN_ROLE, EVENT_MANAGER_ROLE, and UMBRELLA_CONTRACT_ROLE to manage minting, burning, and overall contract administration.
 - **Minting and Burning Mechanisms**: Only event managers can mint tokens, while only the token owner or admins can burn them.
 - **Multi-Use vs. One-Time Use**: Tokens can be issued as either **multi-use** (no expiration) or **one-time use** with a defined expiration duration.
 - **Non-Transferable**: Event access tokens cannot be transferred between users, maintaining control over event participation.
 - **Validity Checks**: Includes functionality to determine if a token is still valid based on its expiration for one-time use tokens.
 - **Security Features**: Implements ReentrancyGuard to prevent reentrancy attacks, adding another layer of security to mint and burn processes.
 - **Deployment Considerations**: The following variables should be set during deployment:
   - **name** and **symbol** during `initialize()` for event-specific token identification.
   - **duration** parameter in `mintEventAccessToken()` to match the event timeline.
   - **metadata URI** in `_setTokenURI()` to provide accurate details for the event.
*/

The Event Access Token Contract is a sub-component of the broader Built By DAO ecosystem. It is designed to manage token issuance for one-time or recurring events, such as concerts, seminars, community meetups, and other engagement activities. This contract must be deployed and initialized through the Umbrella Access Token Contract to ensure compliance and uniformity across all access token systems within the DAO. This guide will walk through the purpose, features, and process of using this contract effectively.

Overview and Purpose

The Event Access Token Contract is a non-transferable ERC721-based solution intended to provide temporary or continuous access permissions for DAO members. The key benefit of using this contract lies in its flexibility to offer either multi-use or single-use access tokens, ensuring that the unique needs of different events are covered.

The contract is built with various access control mechanisms, using roles like ADMIN_ROLE and EVENT_MANAGER_ROLE, and features security-focused components like ReentrancyGuard to prevent vulnerabilities. Furthermore, only authorized administrators and event managers can create or modify tokens, which helps in safeguarding the system's integrity.

Key Features Explained

1. Umbrella Contract Integration

The Event Access Token Contract is integrated within the DAO ecosystem through an Umbrella Access Token Contract. This umbrella contract is responsible for deploying and initializing the Event Access Token Contract. By centralizing the deployment process, it ensures consistency across different types of access tokens while enabling secure, standardized, and auditable token management.

The initialize() function is used during deployment to define the name, symbol, and umbrellaContract address for the token. This initialization process ensures that the contract is properly linked to the umbrella contract, allowing for subsequent minting and management of tokens by authorized users.

Deployment Note: During deployment, the initialize() function parameters need to be set for:

  • name (e.g., "DAO Event Token").

  • symbol (e.g., "DAE").

  • umbrellaContract address to identify the contract responsible for managing the sub-contract's operations.

2. Role-Based Access Control

The contract employs role-based access control to determine who can mint, manage, or burn event access tokens. The following roles are included:

  • UMBRELLA_CONTRACT_ROLE: Grants authority to deploy and initialize this sub-contract.

  • ADMIN_ROLE: Users with this role can burn tokens and manage high-level operations.

  • EVENT_MANAGER_ROLE: Users with this role can mint new tokens, thereby controlling who can gain access to specific events.

Role assignments must be defined through the Umbrella Access Token Contract to maintain consistent governance, minimizing the risk of unauthorized token creation or deletion.

3. Minting Event Access Tokens

The mintEventAccessToken() function allows minting of Event Access Tokens. Only those assigned the EVENT_MANAGER_ROLE can mint tokens. This function requires the following parameters:

  • to: The address that will receive the token.

  • isMultiUse: Boolean value indicating whether the token can be used multiple times or not.

  • duration: Specifies the length of time the token is valid (for one-time tokens).

The minted token will also have a metadata URI associated with it, which provides detailed information related to the event. For example, it could contain the event date, location, and description. During deployment, replace the placeholder URI ("https://metadata.uri/for/EventAccessToken") with an actual URL pointing to the event's metadata.

Minting Considerations:

  • Multi-Use Tokens: No expiration is set for multi-use tokens (expirationTimestamp = 0).

  • Single-Use Tokens: Expire based on the provided duration, starting from the moment of minting (block.timestamp + duration).

4. Non-Transferable Tokens

The Event Access Tokens are non-transferable. This means they cannot be traded, transferred, or sold to another user. This is an intentional feature to preserve the security and exclusivity of event participation. The transfer function (_transfer()) has been overridden to ensure that any transfer attempt fails, maintaining strict control over who has access to specific events.

5. Burning Tokens

Tokens can be burned via the burnEventAccessToken() function, which can only be called by the token owner or an admin. This feature ensures that expired or invalid tokens can be removed from circulation, avoiding unnecessary clutter and ensuring that only valid tokens are in use.

Usage Note: Burning is essential for managing single-use tokens after the event is over or if the holder no longer requires access. The burn operation helps keep the system clean and secure.

6. Token Validity Checks

The isTokenValid() function can be used to determine whether a token is still valid. This is especially useful for verifying event access at the gate.

  • Multi-Use Tokens are always valid unless explicitly burned.

  • Single-Use Tokens have an expiration timestamp and are only valid until that time elapses.

How to Deploy and Use the Clone

To deploy a clone of the Event Access Token Contract, follow these steps:

Step 1: Deploy the Umbrella Access Token Contract

First, deploy the Umbrella Access Token Contract. This contract will be responsible for managing all access tokens within the DAO, including the event access tokens. Assign appropriate roles such as DEFAULT_ADMIN_ROLE and REVIEWER_ROLE for controlling future deployments.

Step 2: Deploy the Event Access Token Contract

Deploy the Event Access Token Contract by cloning it through the Umbrella Access Token Contract.

  • During deployment, use the initialize() function to set up the contract's name, symbol, and link it to the umbrellaContract.

  • Ensure that only authorized addresses—like those holding the UMBRELLA_CONTRACT_ROLE—are used for deployment to avoid unauthorized contract creation.

Step 3: Mint Tokens

After deployment, mint tokens using the mintEventAccessToken() function.

  • Ensure the person minting the tokens has the EVENT_MANAGER_ROLE.

  • Set to, isMultiUse, and duration as per event requirements.

  • Replace the placeholder metadata URI with event-specific information for proper identification.

Step 4: Manage Tokens

Once tokens are minted, they can be used to manage event participation.

  • Check Validity: Use isTokenValid() to determine if the token is eligible for event access.

  • Burn Tokens: Tokens can be burned post-event or when no longer needed using burnEventAccessToken().

Example Use Case

Suppose the DAO is organizing a Community Skill Workshop:

  1. Deploy the Event Access Token Contract via the Umbrella Access Token Contract.

  2. Use the initialize() function to name it "DAO Workshop Token" and symbolize it as "DWT".

  3. An authorized event manager then mints single-use tokens with a specific duration for the duration of the workshop.

  4. Participants can use their tokens to gain entry, which will be validated by checking the token’s expiration timestamp.

  5. Post-event, admins or the token holders can burn the tokens to finalize the process.

Summary

The Event Access Token Contract is designed to provide secure and flexible access to DAO events, with features like non-transferability, multi-use vs. single-use options, and strict role-based access control. By utilizing this contract under the Umbrella Access Token Contract, the DAO can ensure that event access remains exclusive, auditable, and compliant with community standards.

To use the clone effectively, always start by deploying the Umbrella Contract, initialize the sub-contract properly, and assign roles to the relevant members of the DAO to manage minting and burning operations securely. This ensures streamlined and transparent access control for events within the DAO ecosystem, facilitating a well-governed and community-focused operational environment.

Last updated

Logo

© Built By DAO Holdings LLC