|
1 | 1 | // SPDX-License-Identifier: MIT |
2 | 2 | pragma solidity ^0.8.23; |
3 | 3 |
|
| 4 | +import "@openzeppelin/contracts/access/Ownable.sol"; |
4 | 5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; |
5 | | -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; |
6 | | -import "./MasterOwnerModifier.sol"; |
7 | | - |
8 | | -contract EventContract is ERC721Enumerable { |
9 | | - address public eventOwner; |
10 | | - address public treasuryContract; |
11 | | - IERC20 public usdcToken; |
12 | | - MasterOwnerModifier public masterOwnerModifier; |
| 6 | +import "./ITicketManager.sol"; |
13 | 7 |
|
| 8 | +contract EventContract is ERC721Enumerable, Ownable { |
| 9 | + address public immutable usdcToken; |
| 10 | + address public immutable treasury; |
| 11 | + address public immutable masterOwnerModifier; |
| 12 | + |
14 | 13 | string public eventName; |
15 | | - bytes32[] public ticketTypes; |
16 | | - |
| 14 | + bytes32 public nftSymbol; |
17 | 15 | uint256 public eventStart; |
18 | 16 | uint256 public eventEnd; |
19 | | - uint256 public eventTiketStartSale; |
20 | | - uint256 public eventTiketEndSale; |
21 | | - uint256 public totalRevenue; |
22 | | - uint256 private _nextTokenId = 1; |
23 | | - |
| 17 | + uint256 public ticketStartSale; |
| 18 | + uint256 public ticketEndSale; |
24 | 19 | bool public isCancelled = false; |
25 | 20 |
|
26 | | - struct Ticket { |
27 | | - bytes32 ticketType; |
28 | | - uint256 price; |
29 | | - uint256 maxSupply; |
30 | | - uint256 minted; |
31 | | - } |
32 | | - |
33 | | - mapping(bytes32 => Ticket) public tickets; |
34 | | - mapping(uint256 => bytes32) public ticketTypesById; |
35 | | - mapping(address => bool) public additionalEventOwners; |
| 21 | + ITicketManager public ticketManager; |
36 | 22 |
|
37 | 23 | event EventCancelled(string reason); |
38 | | - event FundsWithdrawn(address indexed vendor, uint256 vendorAmount, uint256 treasuryAmount); |
39 | | - event TicketMinted(address indexed buyer, bytes32 ticketType, uint256 tokenId); |
40 | | - event TicketRefunded(address indexed buyer, uint256 tokenId, uint256 amount); |
41 | | - event TicketUsed(uint256 tokenId); |
| 24 | + event TicketUsed(uint256 indexed tokenId); |
42 | 25 |
|
43 | | - error EventNotCancel(); |
44 | | - error TicketSoldOut(); |
| 26 | + error EventNotCancelled(); |
45 | 27 | error TicketSaleNotActive(); |
46 | | - error PaymentFailed(); |
47 | 28 | error NotTicketOwner(); |
48 | 29 | error EventNotOver(); |
49 | | - error NoFundsAvailable(); |
50 | | - error InvalidAddress(); |
51 | | - error NotEventOwner(); |
52 | | - error NotMasterOwner(); |
53 | | - error NotMasterOrEventOwner(); |
54 | 30 |
|
55 | | - modifier onlyEventOwner() { |
56 | | - if (msg.sender != eventOwner && !additionalEventOwners[msg.sender]) revert NotEventOwner(); |
57 | | - _; |
58 | | - } |
59 | | - |
60 | | - modifier onlyMasterOwner() { |
61 | | - if (!masterOwnerModifier.isMasterOwner(msg.sender)) revert NotMasterOwner(); |
62 | | - _; |
63 | | - } |
64 | | - |
65 | | - modifier onlyVendorOrOwner() { |
66 | | - if (msg.sender != eventOwner && !masterOwnerModifier.isMasterOwner(msg.sender)) revert NotMasterOrEventOwner(); |
67 | | - _; |
68 | | - } |
69 | | - |
70 | | - /** |
71 | | - * @dev Constructor to initialize the contract. |
72 | | - * @param _vendor Address of the event vendor. |
73 | | - * @param _usdcToken Address of the USDC token contract. |
74 | | - * @param _treasuryContract Address of the treasury contract. |
75 | | - * @param _name Name of the event. |
76 | | - * @param _nftSymbol Symbol of the NFT. |
77 | | - * @param _start Start timestamp of the event. |
78 | | - * @param _end End timestamp of the event. |
79 | | - * @param _startSale Start timestamp of the ticket sale. |
80 | | - * @param _endSale End timestamp of the ticket sale. |
81 | | - */ |
82 | 31 | constructor( |
83 | | - address _vendor, |
| 32 | + address _owner, |
84 | 33 | address _usdcToken, |
85 | | - address _treasuryContract, |
86 | | - address _ownerModifierAddress, |
87 | | - bytes32 _name, |
| 34 | + address _treasury, |
| 35 | + address _masterOwnerModifier, |
| 36 | + ITicketManager _ticketManager, |
| 37 | + string memory _eventName, |
88 | 38 | bytes32 _nftSymbol, |
89 | 39 | uint256 _start, |
90 | 40 | uint256 _end, |
91 | 41 | uint256 _startSale, |
92 | 42 | uint256 _endSale |
93 | | - ) ERC721(string(abi.encodePacked(_name)), string(abi.encodePacked(_nftSymbol))) { |
94 | | - eventOwner = _vendor; |
95 | | - usdcToken = IERC20(_usdcToken); |
96 | | - treasuryContract = _treasuryContract; |
97 | | - masterOwnerModifier = MasterOwnerModifier(_ownerModifierAddress); |
98 | | - eventName = string(abi.encodePacked(_name)); |
| 43 | + ) ERC721(_eventName, string(abi.encodePacked(_nftSymbol))) Ownable(_owner) { |
| 44 | + usdcToken = _usdcToken; |
| 45 | + treasury = _treasury; |
| 46 | + masterOwnerModifier = _masterOwnerModifier; |
| 47 | + ticketManager = _ticketManager; |
| 48 | + eventName = _eventName; |
| 49 | + nftSymbol = _nftSymbol; |
99 | 50 | eventStart = _start; |
100 | 51 | eventEnd = _end; |
101 | | - eventTiketStartSale = _startSale; |
102 | | - eventTiketEndSale = _endSale; |
103 | | - |
| 52 | + ticketStartSale = _startSale; |
| 53 | + ticketEndSale = _endSale; |
104 | 54 | } |
105 | 55 |
|
106 | | - function addTickets(bytes32[] calldata _ticketTypes, uint256[] calldata _prices, uint256[] calldata _maxSupplies |
107 | | - ) external onlyEventOwner { |
108 | | - require(_ticketTypes.length == _prices.length && _ticketTypes.length == _maxSupplies.length, "Invalid ticket data"); |
109 | | - |
110 | | - for (uint256 i = 0; i < _ticketTypes.length; i++) { |
111 | | - tickets[_ticketTypes[i]] = Ticket({ |
112 | | - ticketType: _ticketTypes[i], |
113 | | - price: _prices[i], |
114 | | - maxSupply: _maxSupplies[i], |
115 | | - minted: 0 |
116 | | - }); |
117 | | - ticketTypes.push(_ticketTypes[i]); |
118 | | - } |
| 56 | + modifier onlyDuringSale() { |
| 57 | + if (block.timestamp < ticketStartSale || block.timestamp > ticketEndSale) revert TicketSaleNotActive(); |
| 58 | + _; |
119 | 59 | } |
120 | 60 |
|
| 61 | + modifier onlyTicketOwner(uint256 _tokenId) { |
| 62 | + if (ownerOf(_tokenId) != msg.sender) revert NotTicketOwner(); |
| 63 | + _; |
| 64 | + } |
121 | 65 |
|
122 | | - /** |
123 | | - * @dev Function to mint a new ticket. |
124 | | - * @param _ticketType The type of the ticket to be minted. |
125 | | - */ |
126 | | - function mintTicket(bytes32 _ticketType) external { |
127 | | - if (isCancelled) revert EventNotCancel(); |
128 | | - if (block.timestamp < eventTiketStartSale || block.timestamp > eventTiketEndSale) revert TicketSaleNotActive(); |
129 | | - |
130 | | - Ticket storage ticket = tickets[_ticketType]; |
131 | | - if (ticket.minted >= ticket.maxSupply) revert TicketSoldOut(); |
132 | | - if (!usdcToken.transferFrom(msg.sender, address(this), ticket.price)) revert PaymentFailed(); |
133 | | - |
134 | | - uint256 tokenId = _nextTokenId++; |
135 | | - _safeMint(msg.sender, tokenId); |
136 | | - ticketTypesById[tokenId] = _ticketType; |
137 | | - ticket.minted++; |
138 | | - totalRevenue += ticket.price; |
139 | | - |
140 | | - emit TicketMinted(msg.sender, _ticketType, tokenId); |
| 66 | + function mintTicket(bytes32 _ticketType) external onlyDuringSale { |
| 67 | + ticketManager.mintTicket(msg.sender, _ticketType); |
141 | 68 | } |
142 | 69 |
|
143 | | - /** |
144 | | - * @dev Function to get all tickets owned by a user. |
145 | | - * @param _user The address of the user. |
146 | | - * @return ticketIds Array of ticket IDs owned by the user. |
147 | | - * @return ticketTypesArray Array of ticket types owned by the user. |
148 | | - */ |
149 | 70 | function getUserTickets(address _user) external view returns (uint256[] memory, bytes32[] memory) { |
150 | | - uint256 balance = balanceOf(_user); |
151 | | - uint256[] memory ticketIds = new uint256[](balance); |
152 | | - bytes32[] memory ticketTypesArray = new bytes32[](balance); |
153 | | - |
154 | | - for (uint256 i = 0; i < balance; i++) { |
155 | | - uint256 tokenId = tokenOfOwnerByIndex(_user, i); |
156 | | - ticketIds[i] = tokenId; |
157 | | - ticketTypesArray[i] = ticketTypesById[tokenId]; |
158 | | - } |
159 | | - |
160 | | - return (ticketIds, ticketTypesArray); |
| 71 | + return ticketManager.getUserTickets(_user); |
161 | 72 | } |
162 | 73 |
|
163 | | - /** |
164 | | - * @dev Function to use a ticket. |
165 | | - * @param _tokenId The ID of the ticket to be used. |
166 | | - */ |
167 | | - function useTicket(uint256 _tokenId) external { |
168 | | - if (ownerOf(_tokenId) != msg.sender) revert NotTicketOwner(); |
| 74 | + function useTicket(uint256 _tokenId) external onlyTicketOwner(_tokenId) { |
169 | 75 | _burn(_tokenId); |
170 | 76 | emit TicketUsed(_tokenId); |
171 | 77 | } |
172 | 78 |
|
173 | | - /** |
174 | | - * @dev Function to modify the max supply of a ticket type. |
175 | | - * @param _ticketType The type of the ticket to be modified. |
176 | | - * @param _newMaxSupply The new max supply for the ticket type. |
177 | | - */ |
178 | | - function modifyTicketMaxSupply(bytes32 _ticketType, uint256 _newMaxSupply) external onlyEventOwner { |
179 | | - if (_newMaxSupply == 0) revert("Max supply must be greater than zero"); |
180 | | - Ticket storage ticket = tickets[_ticketType]; |
181 | | - if (ticket.maxSupply == 0) revert("Ticket type does not exist"); |
182 | | - if (_newMaxSupply < ticket.minted) revert("New max supply cannot be less than minted tickets"); |
183 | | - |
184 | | - ticket.maxSupply = _newMaxSupply; |
185 | | - } |
186 | | - |
187 | | - /** |
188 | | - * @dev Function to withdraw funds after the event ends. |
189 | | - */ |
190 | | - function withdrawFunds() external onlyVendorOrOwner { |
191 | | - if (block.timestamp <= eventEnd) revert EventNotOver(); |
192 | | - if (isCancelled) revert EventNotCancel(); |
193 | | - if (totalRevenue == 0) revert NoFundsAvailable(); |
194 | | - |
195 | | - uint256 treasuryAmount = totalRevenue / 100; // 1% for treasury |
196 | | - uint256 vendorAmount = totalRevenue - treasuryAmount; |
197 | | - |
198 | | - if (!usdcToken.transfer(eventOwner, vendorAmount)) revert PaymentFailed(); |
199 | | - if (!usdcToken.transfer(treasuryContract, treasuryAmount)) revert PaymentFailed(); |
200 | | - |
201 | | - emit FundsWithdrawn(eventOwner, vendorAmount, treasuryAmount); |
202 | | - totalRevenue = 0; |
203 | | - } |
204 | | - |
205 | | - /** |
206 | | - * @dev Function to cancel the event and refund all ticket holders. |
207 | | - * @param reason The reason for cancelling the event. |
208 | | - */ |
209 | | - function cancelEventAndAutoRefund(string calldata reason) external onlyVendorOrOwner { |
210 | | - if (isCancelled) revert EventNotCancel(); |
| 79 | + function cancelEvent(string calldata reason) external onlyOwner { |
211 | 80 | isCancelled = true; |
| 81 | + ticketManager.refundAll(); |
212 | 82 | emit EventCancelled(reason); |
213 | | - // Refund all ticket holders |
214 | | - uint256 totalSupply = totalSupply(); |
215 | | - for (uint256 i = 0; i < totalSupply; i++) { |
216 | | - |
217 | | - uint256 tokenId = tokenByIndex(i); |
218 | | - address ticketOwner = ownerOf(tokenId); |
219 | | - bytes32 ticketType = ticketTypesById[tokenId]; |
220 | | - uint256 refundAmount = tickets[ticketType].price; |
221 | | - |
222 | | - _burn(tokenId); |
223 | | - if (!usdcToken.transfer(ticketOwner, refundAmount)) revert PaymentFailed(); |
224 | | - emit TicketRefunded(ticketOwner, tokenId, refundAmount); |
225 | | - } |
226 | | - totalRevenue = 0; |
227 | | - } |
228 | | - |
229 | | - function getTicketDetails(bytes32 ticketType) public view returns (uint256 price, uint256 supply) { |
230 | | - return (tickets[ticketType].price, tickets[ticketType].maxSupply); |
231 | 83 | } |
232 | 84 | } |
0 commit comments