Branch data Line data Source code
1 : : // SPDX-License-Identifier: UNLICENSED
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import "forge-std/Test.sol";
5 : : import "../src/contracts/PurchaseToken.sol";
6 : : import "../src/contracts/TicketNFT.sol";
7 : :
8 : : contract BaseTicketNFTTest is Test {
9 : : // TicketNFT Events
10 : : event Transfer(
11 : : address indexed from,
12 : : address indexed to,
13 : : uint256 indexed ticketID
14 : : );
15 : : event Approval(
16 : : address indexed holder,
17 : : address indexed approved,
18 : : uint256 indexed ticketID
19 : : );
20 : :
21 : : // Primary Market Events
22 : : event Purchase(address indexed holder, string indexed holderName);
23 : :
24 : : // Secondary Market Events
25 : : event Listing(
26 : : uint256 indexed ticketID,
27 : : address indexed holder,
28 : : uint256 price
29 : : );
30 : : event Purchase(
31 : : address indexed purchaser,
32 : : uint256 indexed ticketID,
33 : : uint256 price,
34 : : string newName
35 : : );
36 : : event Delisting(uint256 indexed ticketID);
37 : :
38 : : uint256 public ticketPriceEth = 1e18;
39 : : uint256 public ticketPrice = 100e18;
40 : :
41 : : PurchaseToken public token;
42 : : TicketNFT public nft;
43 : :
44 : : address public alice = makeAddr("alice");
45 : : address public bob = makeAddr("bob");
46 : : address public charlie = makeAddr("charlie");
47 : :
48 : : function setUp() public {
49 : 0 : token = new PurchaseToken();
50 : 0 : nft = new TicketNFT(token);
51 : : }
52 : :
53 : : // Add Purchase Tokens to `recipient` to afford `amount` tickets
54 : : function _topUpTokens(address recipient, uint256 amount) internal {
55 : 0 : vm.deal(recipient, amount * ticketPriceEth);
56 : 0 : vm.prank(recipient);
57 : 0 : token.mint{value: amount * ticketPriceEth}();
58 : : }
59 : :
60 : : function _buyTicket(address recipient, string memory recipientName)
61 : : internal
62 : : {
63 : 0 : _topUpTokens(recipient, 1);
64 : 0 : vm.prank(recipient);
65 : 0 : token.approve(address(nft), ticketPrice);
66 : 0 : vm.prank(recipient);
67 : 0 : nft.purchase(recipientName);
68 : : }
69 : : }
70 : :
71 : : contract TicketNFTTest is BaseTicketNFTTest {
72 : : function testMint() public {
73 : : vm.prank(address(nft));
74 : : vm.expectEmit(true, true, true, false);
75 : : emit Transfer(address(0), alice, 1);
76 : : nft.mint(alice, "alice");
77 : : assertEq(nft.balanceOf(alice), 1);
78 : : assertEq(nft.holderOf(1), alice);
79 : : assertEq(nft.getApproved(1), address(0));
80 : : assertEq(nft.holderNameOf(1), "alice");
81 : : assertEq(nft.isExpiredOrUsed(1), false);
82 : : }
83 : :
84 : : function testMintUnauthorized() public {
85 : : _topUpTokens(alice, 1);
86 : : vm.prank(alice);
87 : : vm.expectRevert("mint: can only be called by primary market");
88 : : nft.mint(alice, "alice");
89 : : assertEq(nft.balanceOf(alice), 0);
90 : : }
91 : :
92 : : function testBalanceOf() public {
93 : : assertEq(nft.balanceOf(alice), 0);
94 : : _buyTicket(alice, "alice");
95 : : assertEq(nft.balanceOf(alice), 1);
96 : : }
97 : :
98 : : function testHolderOf() public {
99 : : _buyTicket(alice, "alice");
100 : : assertEq(nft.holderOf(1), alice);
101 : : vm.expectRevert("holderOf: ticket doesn't exist");
102 : : nft.holderOf(2);
103 : : }
104 : :
105 : : function testHolderNameOf() public {
106 : : _buyTicket(alice, "alice");
107 : : assertEq(nft.holderNameOf(1), "alice");
108 : : vm.expectRevert("holderNameOf: ticket doesn't exist");
109 : : nft.holderNameOf(2);
110 : : }
111 : :
112 : : function testUpdateHolderName() public {
113 : : _buyTicket(alice, "alice1");
114 : : assertEq(nft.holderNameOf(1), "alice1");
115 : : vm.prank(alice);
116 : : nft.updateHolderName(1, "alice2");
117 : : assertEq(nft.holderNameOf(1), "alice2");
118 : : }
119 : :
120 : : function testUpdateHolderNameInvalid() public {
121 : : _buyTicket(alice, "alice1");
122 : : assertEq(nft.holderNameOf(1), "alice1");
123 : : vm.prank(alice);
124 : : vm.expectRevert("updateHolderName: ticket doesn't exist");
125 : : nft.updateHolderName(2, "alice2");
126 : : }
127 : :
128 : : function testUpdateHolderNameUnauthorized() public {
129 : : _buyTicket(alice, "alice");
130 : : assertEq(nft.holderNameOf(1), "alice");
131 : : vm.prank(bob);
132 : : vm.expectRevert("updateHolderName: msg.sender doesn't own ticket");
133 : : nft.updateHolderName(1, "bob");
134 : : assertEq(nft.holderNameOf(1), "alice");
135 : : }
136 : :
137 : : function testTransfer() public {
138 : : _buyTicket(alice, "alice");
139 : : vm.prank(alice);
140 : : vm.expectEmit(true, true, true, false);
141 : : emit Transfer(alice, bob, 1);
142 : : vm.expectEmit(true, true, true, false);
143 : : emit Approval(bob, address(0), 1);
144 : : nft.transferFrom(alice, bob, 1);
145 : : assertEq(nft.balanceOf(alice), 0);
146 : : assertEq(nft.balanceOf(bob), 1);
147 : : assertEq(nft.holderOf(1), bob);
148 : : assertEq(nft.getApproved(1), address(0));
149 : : assertEq(nft.holderNameOf(1), "alice");
150 : : assertEq(nft.isExpiredOrUsed(1), false);
151 : : }
152 : :
153 : : function testTransferInvalid() public {
154 : : _buyTicket(alice, "alice");
155 : : vm.prank(alice);
156 : : vm.expectRevert("transferFrom: from cannot be 0");
157 : : nft.transferFrom(address(0), bob, 2);
158 : : vm.prank(alice);
159 : : vm.expectRevert("transferFrom: to cannot be 0");
160 : : nft.transferFrom(alice, address(0), 2);
161 : : }
162 : :
163 : : function testTransferUnauthorized() public {
164 : : _buyTicket(alice, "alice");
165 : : vm.prank(bob);
166 : : vm.expectRevert(
167 : : "transferFrom: msg.sender must be current holder or approved sender"
168 : : );
169 : : nft.transferFrom(alice, bob, 1);
170 : : }
171 : :
172 : : function testApproval() public {
173 : : _buyTicket(alice, "alice");
174 : : vm.prank(alice);
175 : : vm.expectEmit(true, true, true, false);
176 : : emit Approval(alice, bob, 1);
177 : : nft.approve(bob, 1);
178 : : assertEq(nft.getApproved(1), bob);
179 : : }
180 : :
181 : : function testApprovalInvalid() public {
182 : : _buyTicket(alice, "alice");
183 : : vm.prank(alice);
184 : : vm.expectRevert("approve: ticket doesn't exist");
185 : : nft.approve(bob, 2);
186 : : }
187 : :
188 : : function testApprovalUnauthorized() public {
189 : : _buyTicket(alice, "alice");
190 : : vm.prank(bob);
191 : : vm.expectRevert("approve: msg.sender doesn't own ticket");
192 : : nft.approve(bob, 1);
193 : : assertEq(nft.getApproved(1), address(0));
194 : : }
195 : :
196 : : function testGetApprovedInvalid() public {
197 : : vm.expectRevert("getApproved: ticket doesn't exist");
198 : : nft.getApproved(1);
199 : : }
200 : :
201 : : function testTransferFrom() public {
202 : : _buyTicket(alice, "alice");
203 : : vm.prank(alice);
204 : : nft.approve(bob, 1);
205 : : vm.prank(bob);
206 : : vm.expectEmit(true, true, true, false);
207 : : emit Transfer(alice, charlie, 1);
208 : : vm.expectEmit(true, true, true, false);
209 : : emit Approval(charlie, address(0), 1);
210 : : nft.transferFrom(alice, charlie, 1);
211 : : assertEq(nft.balanceOf(alice), 0);
212 : : assertEq(nft.balanceOf(bob), 0);
213 : : assertEq(nft.balanceOf(charlie), 1);
214 : : assertEq(nft.holderOf(1), charlie);
215 : : assertEq(nft.getApproved(1), address(0));
216 : : }
217 : :
218 : : function testTransferFromInvalid() public {
219 : : _buyTicket(alice, "alice");
220 : : vm.prank(alice);
221 : : nft.approve(bob, 1);
222 : : assertEq(nft.getApproved(1), bob);
223 : : vm.prank(bob);
224 : : vm.expectRevert("transferFrom: from cannot be 0");
225 : : nft.transferFrom(address(0), charlie, 1);
226 : : vm.prank(bob);
227 : : vm.expectRevert("transferFrom: to cannot be 0");
228 : : nft.transferFrom(alice, address(0), 1);
229 : : vm.prank(bob);
230 : : vm.expectRevert("transferFrom: ticket not owned by from");
231 : : nft.transferFrom(bob, charlie, 1);
232 : : vm.prank(bob);
233 : : vm.expectRevert("transferFrom: ticket not owned by from");
234 : : nft.transferFrom(charlie, bob, 1);
235 : : assertEq(nft.balanceOf(alice), 1);
236 : : assertEq(nft.balanceOf(bob), 0);
237 : : assertEq(nft.balanceOf(charlie), 0);
238 : : assertEq(nft.holderOf(1), alice);
239 : : assertEq(nft.getApproved(1), bob);
240 : : }
241 : :
242 : : function testTransferFromUnauthorized() public {
243 : : _buyTicket(alice, "alice");
244 : : vm.prank(alice);
245 : : nft.approve(bob, 1);
246 : : assertEq(nft.getApproved(1), bob);
247 : : vm.prank(charlie);
248 : : vm.expectRevert(
249 : : "transferFrom: msg.sender must be current holder or approved sender"
250 : : );
251 : : nft.transferFrom(alice, charlie, 1);
252 : : assertEq(nft.balanceOf(alice), 1);
253 : : assertEq(nft.balanceOf(bob), 0);
254 : : assertEq(nft.balanceOf(charlie), 0);
255 : : assertEq(nft.holderOf(1), alice);
256 : : assertEq(nft.getApproved(1), bob);
257 : : }
258 : :
259 : : function testIsExpiredOrUsedInvalid() public {
260 : : vm.expectRevert("isExpiredOrUsed: ticket doesn't exist");
261 : : nft.isExpiredOrUsed(1);
262 : : }
263 : :
264 : : function testExpiry() public {
265 : : _buyTicket(alice, "alice");
266 : : assertEq(nft.isExpiredOrUsed(1), false);
267 : : vm.warp(block.timestamp + 10 days);
268 : : assertEq(nft.isExpiredOrUsed(1), false);
269 : : vm.warp(block.timestamp + 1);
270 : : assertEq(nft.isExpiredOrUsed(1), true);
271 : : }
272 : :
273 : : function testSetUsed() public {
274 : : _buyTicket(alice, "alice");
275 : : assertEq(nft.isExpiredOrUsed(1), false);
276 : : vm.prank(address(this));
277 : : nft.setUsed(1);
278 : : assertEq(nft.isExpiredOrUsed(1), true);
279 : : }
280 : :
281 : : function testSetUsedNonExistent() public {
282 : : vm.expectRevert("setUsed: ticket doesn't exist");
283 : : nft.setUsed(1);
284 : : }
285 : :
286 : : function testSetUsedAlreadyUsed() public {
287 : : _buyTicket(alice, "alice");
288 : : assertEq(nft.isExpiredOrUsed(1), false);
289 : : vm.prank(address(this));
290 : : nft.setUsed(1);
291 : : assertEq(nft.isExpiredOrUsed(1), true);
292 : : vm.prank(address(this));
293 : : vm.expectRevert("setUsed: ticket already used");
294 : : nft.setUsed(1);
295 : : }
296 : :
297 : : function testSetUsedExpired() public {
298 : : _buyTicket(alice, "alice");
299 : : assertEq(nft.isExpiredOrUsed(1), false);
300 : : vm.warp(block.timestamp + 10 days + 1);
301 : : vm.prank(address(this));
302 : : vm.expectRevert("setUsed: ticket expired");
303 : : nft.setUsed(1);
304 : : }
305 : :
306 : : function testSetUsedUnauthorized() public {
307 : : _buyTicket(alice, "alice");
308 : : assertEq(nft.isExpiredOrUsed(1), false);
309 : : vm.warp(block.timestamp + 10 days);
310 : : vm.prank(bob);
311 : : vm.expectRevert("setUsed: only admin can setUsed");
312 : : nft.setUsed(1);
313 : : }
314 : : }
315 : :
316 : : contract PrimaryMarketTest is BaseTicketNFTTest {
317 : : function testAdmin() public {
318 : : assertEq(address(this), nft.admin());
319 : : }
320 : :
321 : : function testPrimaryPurchase() public {
322 : : _topUpTokens(alice, 1);
323 : : vm.prank(alice);
324 : : token.approve(address(nft), ticketPrice);
325 : : vm.prank(alice);
326 : : vm.expectEmit(true, true, true, false);
327 : : emit Transfer(address(0), alice, 1);
328 : : vm.expectEmit(true, true, false, false);
329 : : emit Purchase(alice, "alice");
330 : : nft.purchase("alice");
331 : : assertEq(nft.balanceOf(alice), 1);
332 : : assertEq(nft.holderOf(1), alice);
333 : : assertEq(nft.getApproved(1), address(0));
334 : : assertEq(nft.holderNameOf(1), "alice");
335 : : assertEq(nft.isExpiredOrUsed(1), false);
336 : : }
337 : :
338 : : function testPrimaryPurchaseInsufficientBalance() public {
339 : : vm.deal(alice, ticketPriceEth);
340 : : vm.prank(alice);
341 : : token.mint{value: ticketPriceEth - 1}();
342 : : vm.prank(alice);
343 : : token.approve(address(nft), ticketPrice);
344 : : vm.prank(alice);
345 : : vm.expectRevert("ERC20: transfer amount exceeds balance");
346 : : nft.purchase("alice");
347 : : assertEq(nft.balanceOf(alice), 0);
348 : : }
349 : :
350 : : function testPrimaryPurchaseInsufficientAllowance() public {
351 : : vm.deal(alice, ticketPriceEth);
352 : : vm.prank(alice);
353 : : token.mint{value: ticketPriceEth}();
354 : : vm.prank(alice);
355 : : token.approve(address(nft), ticketPrice - 1);
356 : : vm.prank(alice);
357 : : vm.expectRevert("purchase: insufficient token allowance");
358 : : nft.purchase("alice");
359 : : assertEq(nft.balanceOf(alice), 0);
360 : : }
361 : :
362 : : function testPrimaryPurchases() public {
363 : : _topUpTokens(alice, 2);
364 : : vm.prank(alice);
365 : : token.approve(address(nft), ticketPrice * 2);
366 : : vm.prank(alice);
367 : : nft.purchase("alice");
368 : : vm.prank(alice);
369 : : vm.expectEmit(true, true, true, false);
370 : : emit Transfer(address(0), alice, 2);
371 : : vm.expectEmit(true, true, false, false);
372 : : emit Purchase(alice, "alice's plus one");
373 : : nft.purchase("alice's plus one");
374 : : assertEq(nft.balanceOf(alice), 2);
375 : : assertEq(nft.holderOf(2), alice);
376 : : assertEq(nft.getApproved(2), address(0));
377 : : assertEq(nft.holderNameOf(2), "alice's plus one");
378 : : assertEq(nft.isExpiredOrUsed(2), false);
379 : : }
380 : :
381 : : function testPurchaseLimit() public {
382 : : // Set contract totalSupply to 999 using foundry cheats rather than minting repeatedly
383 : : vm.store(address(nft), bytes32(uint256(1)), bytes32(uint256(999)));
384 : : // for (uint256 i = 0; i < 999; i++) {
385 : : // _buyTicket(alice, "alice");
386 : : // }
387 : : _buyTicket(alice, "alice"); // Buy 1000th ticket
388 : : _topUpTokens(alice, 1);
389 : : vm.prank(alice);
390 : : token.approve(address(nft), ticketPrice);
391 : : vm.prank(alice);
392 : : vm.expectRevert("purchase: maximum tickets reached");
393 : : nft.purchase("alice");
394 : : }
395 : : }
396 : :
397 : : contract SecondaryMarketTest is BaseTicketNFTTest {
398 : : function testList() public {
399 : : _buyTicket(alice, "alice");
400 : : vm.prank(alice);
401 : : vm.expectEmit(true, true, true, false);
402 : : emit Transfer(alice, address(nft), 1);
403 : : vm.expectEmit(true, true, true, false);
404 : : emit Approval(address(nft), address(0), 1);
405 : : vm.expectEmit(true, true, false, false);
406 : : emit Listing(1, alice, 200e18);
407 : : nft.listTicket(1, 200e18); // Got a flipper here :)
408 : : assertEq(nft.balanceOf(alice), 0);
409 : : assertEq(nft.balanceOf(address(nft)), 1);
410 : : assertEq(nft.holderOf(1), address(nft));
411 : : assertEq(nft.getApproved(1), address(0));
412 : : assertEq(nft.holderNameOf(1), "alice");
413 : : assertEq(nft.isExpiredOrUsed(1), false);
414 : : }
415 : :
416 : : function testListFree() public {
417 : : _buyTicket(alice, "alice");
418 : : vm.prank(alice);
419 : : vm.expectRevert("listTicket: price cannot be 0");
420 : : nft.listTicket(1, 0); // What's the opposite of a flipper?
421 : : assertEq(nft.balanceOf(alice), 1);
422 : : assertEq(nft.holderOf(1), alice);
423 : : }
424 : :
425 : : function testListUsed() public {
426 : : _buyTicket(alice, "alice");
427 : : vm.prank(address(this));
428 : : nft.setUsed(1);
429 : : vm.prank(alice);
430 : : vm.expectRevert("listTicket: ticket is expired/used");
431 : : nft.listTicket(1, 200e19);
432 : : assertEq(nft.balanceOf(alice), 1);
433 : : assertEq(nft.holderOf(1), alice);
434 : : assertEq(nft.isExpiredOrUsed(1), true);
435 : : }
436 : :
437 : : function testListExpired() public {
438 : : _buyTicket(alice, "alice");
439 : : vm.warp(block.timestamp + 10 days + 1);
440 : : vm.prank(alice);
441 : : vm.expectRevert("listTicket: ticket is expired/used");
442 : : nft.listTicket(1, 200e19);
443 : : assertEq(nft.balanceOf(alice), 1);
444 : : assertEq(nft.holderOf(1), alice);
445 : : assertEq(nft.isExpiredOrUsed(1), true);
446 : : }
447 : :
448 : : function testListUnauthorized() public {
449 : : _buyTicket(alice, "alice");
450 : : vm.prank(bob);
451 : : vm.expectRevert("listTicket: msg.sender doesn't own ticket");
452 : : nft.listTicket(1, 200e19);
453 : : assertEq(nft.balanceOf(alice), 1);
454 : : assertEq(nft.holderOf(1), alice);
455 : : }
456 : :
457 : : function testDelist() public {
458 : : _buyTicket(alice, "alice");
459 : : vm.prank(alice);
460 : : nft.listTicket(1, 200e18);
461 : : vm.prank(alice);
462 : : vm.expectEmit(true, true, true, false);
463 : : emit Transfer(address(nft), alice, 1);
464 : : vm.expectEmit(true, true, true, false);
465 : : emit Approval(alice, address(0), 1);
466 : : vm.expectEmit(true, false, false, false);
467 : : emit Delisting(1);
468 : : nft.delistTicket(1);
469 : : assertEq(nft.balanceOf(alice), 1);
470 : : assertEq(nft.balanceOf(address(nft)), 0);
471 : : assertEq(nft.holderOf(1), alice);
472 : : }
473 : :
474 : : function testDelistUnauthorized() public {
475 : : _buyTicket(alice, "alice");
476 : : vm.prank(alice);
477 : : nft.listTicket(1, 200e18);
478 : : vm.prank(bob);
479 : : vm.expectRevert("delistTicket: msg.sender didn't list ticket");
480 : : nft.delistTicket(1);
481 : : assertEq(nft.balanceOf(alice), 0);
482 : : assertEq(nft.balanceOf(bob), 0);
483 : : assertEq(nft.balanceOf(address(nft)), 1);
484 : : assertEq(nft.holderOf(1), address(nft));
485 : : }
486 : :
487 : : function testPurchase() public {
488 : : uint256 ticketResalePrice = 200e18;
489 : : uint256 ticketResaleFee = 50 * (ticketResalePrice / 1000);
490 : : uint256 ticketResaleRevenue = ticketResalePrice - ticketResaleFee;
491 : : _buyTicket(alice, "alice");
492 : : vm.prank(alice);
493 : : nft.listTicket(1, ticketResalePrice);
494 : : _topUpTokens(bob, ticketResalePrice / 100e18);
495 : : vm.prank(bob);
496 : : token.approve(address(nft), ticketResalePrice);
497 : : vm.prank(bob);
498 : : vm.expectEmit(true, true, false, true);
499 : : emit Purchase(bob, 1, ticketResalePrice, "bob");
500 : : nft.purchase(1, "bob");
501 : : assertEq(token.balanceOf(alice), ticketResaleRevenue);
502 : : assertEq(token.balanceOf(bob), 0);
503 : : assertEq(token.balanceOf(address(this)), ticketPrice + ticketResaleFee);
504 : : assertEq(nft.balanceOf(alice), 0);
505 : : assertEq(nft.balanceOf(bob), 1);
506 : : assertEq(nft.balanceOf(address(nft)), 0);
507 : : assertEq(nft.holderOf(1), bob);
508 : : assertEq(nft.getApproved(1), address(0));
509 : : assertEq(nft.holderNameOf(1), "bob");
510 : : assertEq(nft.isExpiredOrUsed(1), false);
511 : : }
512 : :
513 : : function testPurchaseUsed() public {
514 : : _buyTicket(alice, "alice");
515 : : vm.prank(alice);
516 : : nft.listTicket(1, 200e18);
517 : : _topUpTokens(bob, 2);
518 : : vm.prank(address(this));
519 : : nft.setUsed(1);
520 : : vm.prank(bob);
521 : : token.approve(address(nft), 200e18);
522 : : vm.prank(bob);
523 : : vm.expectRevert("purchase: ticket is expired/used");
524 : : nft.purchase(1, "bob");
525 : : assertEq(nft.balanceOf(alice), 0);
526 : : assertEq(nft.balanceOf(bob), 0);
527 : : assertEq(nft.balanceOf(address(nft)), 1);
528 : : }
529 : :
530 : : function testPurchaseExpired() public {
531 : : _buyTicket(alice, "alice");
532 : : vm.prank(alice);
533 : : nft.listTicket(1, 200e18);
534 : : _topUpTokens(bob, 2);
535 : : vm.warp(block.timestamp + 10 days + 1);
536 : : vm.prank(bob);
537 : : token.approve(address(nft), 200e18);
538 : : vm.prank(bob);
539 : : vm.expectRevert("purchase: ticket is expired/used");
540 : : nft.purchase(1, "bob");
541 : : assertEq(nft.balanceOf(alice), 0);
542 : : assertEq(nft.balanceOf(bob), 0);
543 : : assertEq(nft.balanceOf(address(nft)), 1);
544 : : }
545 : :
546 : : function testPurchaseInsufficientBalance() public {
547 : : _buyTicket(alice, "alice");
548 : : vm.prank(alice);
549 : : nft.listTicket(1, 200e18);
550 : : _topUpTokens(bob, 1);
551 : : vm.prank(bob);
552 : : token.approve(address(nft), 200e18);
553 : : vm.prank(bob);
554 : : vm.expectRevert("ERC20: transfer amount exceeds balance");
555 : : nft.purchase(1, "bob");
556 : : assertEq(nft.balanceOf(alice), 0);
557 : : assertEq(nft.balanceOf(bob), 0);
558 : : assertEq(nft.balanceOf(address(nft)), 1);
559 : : }
560 : :
561 : : function testPurchaseInsufficientAllowance() public {
562 : : _buyTicket(alice, "alice");
563 : : vm.prank(alice);
564 : : nft.listTicket(1, 200e18);
565 : : _topUpTokens(bob, 2);
566 : : vm.prank(bob);
567 : : token.approve(address(nft), 100e18);
568 : : vm.prank(bob);
569 : : vm.expectRevert("purchase: insufficient token allowance");
570 : : nft.purchase(1, "bob");
571 : : assertEq(nft.balanceOf(alice), 0);
572 : : assertEq(nft.balanceOf(bob), 0);
573 : : assertEq(nft.balanceOf(address(nft)), 1);
574 : : }
575 : :
576 : : function testPurchaseUnlisted() public {
577 : : _buyTicket(alice, "alice");
578 : : vm.prank(alice);
579 : : nft.listTicket(1, 200e18);
580 : : vm.prank(alice);
581 : : nft.delistTicket(1);
582 : : _topUpTokens(bob, 2);
583 : : vm.prank(bob);
584 : : token.approve(address(nft), 200e18);
585 : : vm.prank(bob);
586 : : vm.expectRevert(
587 : : "purchase: ticket is not listed, missing lister address or price"
588 : : );
589 : : nft.purchase(1, "bob");
590 : : assertEq(nft.balanceOf(alice), 1);
591 : : assertEq(nft.balanceOf(bob), 0);
592 : : assertEq(nft.balanceOf(address(nft)), 0);
593 : : }
594 : : }
|