Event Planning Escrow Contract

What it does:
Holds payments for events in escrow, releasing funds automatically to organizers or vendors when predefined conditions are met, or refunding participants if conditions fail.

Why it matters:
Provides trust and security for event participants, prevents disputes, ensures fair distribution of funds, and automates payment processes.

How it works:

  • Participants pay for tickets, deposits, or services into an escrow smart contract

  • Organizer sets milestones or event conditions (e.g., event completion, service delivery)

  • Smart contract releases payments automatically when conditions are verified by oracles or validators

  • Refunds are issued automatically if event is canceled or milestones are not met

  • Integrates with NFT Tickets, Virtual Event Access Control, or Creator Collaboration Revenue Split

  • Dashboards track escrow balances, milestone status, and payout history

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

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title EventPlanningEscrow
 * @author Nam
 * @notice Holds and manages event payments, releasing funds based on milestones or refunds
 */
contract EventPlanningEscrow is Ownable {

    struct Event {
        string name;
        address payable organizer;
        uint256 totalFunds;
        bool completed;
        bool canceled;
    }

    mapping(uint256 => Event) public events;
    mapping(uint256 => mapping(address => uint256)) public participantBalances;

    uint256 public eventCount;
    mapping(address => bool) public authorizedValidators;

    // -------------------- EVENTS --------------------

    event ValidatorApproved(address validator);
    event ValidatorRevoked(address validator);
    event EventCreated(uint256 indexed eventId, string name, address organizer);
    event PaymentDeposited(uint256 indexed eventId, address participant, uint256 amount);
    event EventCompleted(uint256 indexed eventId);
    event EventCanceled(uint256 indexed eventId);
    event FundsReleased(uint256 indexed eventId, address organizer, uint256 amount);
    event RefundIssued(uint256 indexed eventId, address participant, uint256 amount);

    // -------------------- VALIDATOR MANAGEMENT --------------------

    function approveValidator(address _validator) external onlyOwner {
        authorizedValidators[_validator] = true;
        emit ValidatorApproved(_validator);
    }

    function revokeValidator(address _validator) external onlyOwner {
        authorizedValidators[_validator] = false;
        emit ValidatorRevoked(_validator);
    }

    modifier onlyValidator() {
        require(authorizedValidators[msg.sender], "Not authorized validator");
        _;
    }

    // -------------------- EVENT MANAGEMENT --------------------

    function createEvent(string calldata _name) external {
        eventCount += 1;
        events[eventCount] = Event({
            name: _name,
            organizer: payable(msg.sender),
            totalFunds: 0,
            completed: false,
            canceled: false
        });

        emit EventCreated(eventCount, _name, msg.sender);
    }

    function depositPayment(uint256 _eventId) external payable {
        Event storage e = events[_eventId];
        require(!e.completed && !e.canceled, "Event inactive");
        require(msg.value > 0, "Payment must be >0");

        participantBalances[_eventId][msg.sender] += msg.value;
        e.totalFunds += msg.value;

        emit PaymentDeposited(_eventId, msg.sender, msg.value);
    }

    // -------------------- EVENT OUTCOME MANAGEMENT --------------------

    function markEventCompleted(uint256 _eventId) external onlyValidator {
        Event storage e = events[_eventId];
        require(!e.completed && !e.canceled, "Event already finalized");

        e.completed = true;
        e.organizer.transfer(e.totalFunds);

        emit EventCompleted(_eventId);
        emit FundsReleased(_eventId, e.organizer, e.totalFunds);
    }

    function cancelEvent(uint256 _eventId) external onlyValidator {
        Event storage e = events[_eventId];
        require(!e.completed && !e.canceled, "Event already finalized");

        e.canceled = true;
        // Refund all participants
        for (uint256 i = 0; i  0, "No funds to refund");

        participantBalances[_eventId][msg.sender] = 0;
        payable(msg.sender).transfer(amount);

        emit RefundIssued(_eventId, msg.sender, amount);
    }

    // -------------------- VIEW FUNCTIONS --------------------

    function getParticipantBalance(uint256 _eventId, address _participant) external view returns (uint256) {
        return participantBalances[_eventId][_participant];
    }
}