// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "../TixSellReservationLibrary.sol"; import "./TixSellEventLibrary.sol"; import "../interfaces/ITicketTypeContract.sol"; import "../interfaces/IEventContract.sol"; //import "hardhat/console.sol"; contract TicketReservationContract is Ownable, AccessControl { bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); address[] public admins; uint256 private nbReservationAsked =0; IEventContract public eventContract; mapping(uint256 => TixSellReservationLibrary.TicketReservation) ticketsReserved; mapping(string => uint256) reservations; event NewReservation(uint256 ticketTypeId, uint256 amount,address owner,string reservationNumber); //1 smart contract par organisateur modifier onlyFounders() { require(hasRole(ADMIN_ROLE, msg.sender), "Only founders can do that"); _; } modifier onlyAdmin() { require( msg.sender == owner() || hasRole(ADMIN_ROLE, msg.sender), "Only admins can do that" ); _; } modifier onlyReservationOwner(string memory _reservationNumber){ uint256 idReservation = reservations[_reservationNumber]; if (compare(ticketsReserved[idReservation].id,_reservationNumber)){ require((ticketsReserved[reservations[_reservationNumber]].owner==tx.origin),"Not your reservation"); } else{ revert("Reservation not exists"); } _; } constructor(address initialOwner,address[] memory _admins, address _eventContract) Ownable(initialOwner) { for (uint256 i = 0; i < _admins.length; ++i) { _grantRole(ADMIN_ROLE, _admins[i]); _grantRole(DEFAULT_ADMIN_ROLE, _admins[i]); } admins = _admins; eventContract = IEventContract(_eventContract); } function compare(string memory str1, string memory str2) public pure returns (bool) { if (bytes(str1).length != bytes(str2).length) { return false; } return keccak256(abi.encodePacked(str1)) == keccak256(abi.encodePacked(str2)); } // systeme de ticket de réservation par type de billets // user address => nb billets réservés // date reservation , date expiration // si expiration => remet le nb de billets réservés dans la file disponible // createReservationNumber(address, number) function createReservationNumber(string memory _reservationNumber,address _owner, uint256 _ticketTypeId, uint256 _amount,uint256 _existingBalance) external { uint256 idReservation = reservations[_reservationNumber]; if (compare(ticketsReserved[idReservation].id,_reservationNumber)){ revert("Reservation number already exists"); } //check event is not cancelled TixSellEventLibrary.Event memory theEvent = eventContract.getEvent(); require(!theEvent.canceled,"Event cancelled"); // check still availables uint256 nbMinted = eventContract.getTicketTypesNbMinted(_ticketTypeId); // check totalSupply not reached TixSellLibrary.TicketType memory theTicketType = ITicketTypeContract(eventContract.getTicketTypeContract()).getTicketTypeInfo(_ticketTypeId); require(theTicketType.maxTickets>0,"TicketType does'nt exists"); // check bookinStartDate started require(theTicketType.bookingStartDate <= block.timestamp,"Booking not started yet"); // check bookingEndDate not reached if (!theEvent.openBookings){ require(block.timestamp < theTicketType.bookingEndDate ,"Booking ended"); } require (nbMinted< theTicketType.maxTickets,"No more tickets"); require(nbMinted + _amount <= theTicketType.maxTickets,"Amount too high no more tickets"); require(_amount <= theTicketType.maxTicketsPerUser,"Amount per user too high"); require(_amount > 0,"Must buy 1 ticket at least"); // Doit vérifie si user a déjà acheté des tickets et si oui que nb acheté + amount voulu < max ticket per user if (hasRole(ADMIN_ROLE, msg.sender)==false){ require(_amount+_existingBalance <= theTicketType.maxTicketsPerUser,"Amount per user reached"); } // Maintenant iterate sur les réservations en cours et vérifie le nombre uint256 currentIndex = nbReservationAsked; uint256 activeReservationCount = 0; for (uint256 i = 0; i