diff --git a/coverage/amber.png b/coverage/amber.png new file mode 100644 index 0000000..2cab170 Binary files /dev/null and b/coverage/amber.png differ diff --git a/coverage/emerald.png b/coverage/emerald.png new file mode 100644 index 0000000..38ad4f4 Binary files /dev/null and b/coverage/emerald.png differ diff --git a/coverage/gcov.css b/coverage/gcov.css new file mode 100644 index 0000000..bfd0a83 --- /dev/null +++ b/coverage/gcov.css @@ -0,0 +1,519 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #FFFFFF; +} + +/* All views: standard link format*/ +a:link +{ + color: #284FA8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00CB40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #FF0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #DAE7FE; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #A7FC9D; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FFEA20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FF0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688D4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #FFFFFF; + background-color: #6688D4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #FFFFFF; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #DAE7FE; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #EFE383; +} + +/* Source code view: format for lines which were executed */ +td.lineCov, +span.lineCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #CAD7FE; +} + +/* Source code view: format for lines which were not executed */ +td.lineNoCov, +span.lineNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #FF6230; +} + +/* Source code view (function table): standard link - visited format */ +td.lineNoCov > a:visited, +td.lineCov > a:visited +{ + color: black; + text-decoration: underline; +} + +/* Source code view: format for lines which were executed only in a + previous version */ +span.lineDiffCov +{ + background-color: #B5F7AF; +} + +/* Source code view: format for branches which were executed + * and taken */ +span.branchCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for branches which were executed + * but not taken */ +span.branchNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for branches which were not executed */ +span.branchNoExec +{ + background-color: #FF6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #FF0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #FFEA20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #A7FC9D; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FF0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FFEA20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #A7FC9D; +} diff --git a/coverage/glass.png b/coverage/glass.png new file mode 100644 index 0000000..e1abc00 Binary files /dev/null and b/coverage/glass.png differ diff --git a/coverage/index-sort-b.html b/coverage/index-sort-b.html new file mode 100644 index 0000000..5aab2d8 --- /dev/null +++ b/coverage/index-sort-b.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:TicketNFT CoverageLines:11314080.7 %
Date:2023-02-21 16:00:17Functions:313881.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
src/contracts +
86.9%86.9%
+
86.9 %113 / 13088.6 %31 / 3586.5 %64 / 74
test +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/index-sort-f.html b/coverage/index-sort-f.html new file mode 100644 index 0000000..8fdf986 --- /dev/null +++ b/coverage/index-sort-f.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:TicketNFT CoverageLines:11314080.7 %
Date:2023-02-21 16:00:17Functions:313881.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
test +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
src/contracts +
86.9%86.9%
+
86.9 %113 / 13088.6 %31 / 3586.5 %64 / 74
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/index-sort-l.html b/coverage/index-sort-l.html new file mode 100644 index 0000000..f114350 --- /dev/null +++ b/coverage/index-sort-l.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:TicketNFT CoverageLines:11314080.7 %
Date:2023-02-21 16:00:17Functions:313881.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
test +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
src/contracts +
86.9%86.9%
+
86.9 %113 / 13088.6 %31 / 3586.5 %64 / 74
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/index.html b/coverage/index.html new file mode 100644 index 0000000..7b9130a --- /dev/null +++ b/coverage/index.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:TicketNFT CoverageLines:11314080.7 %
Date:2023-02-21 16:00:17Functions:313881.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
src/contracts +
86.9%86.9%
+
86.9 %113 / 13088.6 %31 / 3586.5 %64 / 74
test +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/ruby.png b/coverage/ruby.png new file mode 100644 index 0000000..991b6d4 Binary files /dev/null and b/coverage/ruby.png differ diff --git a/coverage/snow.png b/coverage/snow.png new file mode 100644 index 0000000..2cdae10 Binary files /dev/null and b/coverage/snow.png differ diff --git a/coverage/src/contracts/PurchaseToken.sol.func-sort-c.html b/coverage/src/contracts/PurchaseToken.sol.func-sort-c.html new file mode 100644 index 0000000..d87ca6e --- /dev/null +++ b/coverage/src/contracts/PurchaseToken.sol.func-sort-c.html @@ -0,0 +1,172 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts/PurchaseToken.sol - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contracts - PurchaseToken.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:425971.2 %
Date:2023-02-21 16:00:17Functions:172181.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:122254.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
Context._msgData0
PurchaseToken._burn0
PurchaseToken.decreaseAllowance0
PurchaseToken.increaseAllowance0
PurchaseToken.decimals1
PurchaseToken.name1
PurchaseToken.symbol1
PurchaseToken.transfer2
PurchaseToken.totalSupply4
PurchaseToken.balanceOf12
PurchaseToken._spendAllowance43
PurchaseToken.transferFrom43
PurchaseToken._transfer44
PurchaseToken.allowance45
PurchaseToken.approve48
PurchaseToken._mint52
PurchaseToken.mint52
PurchaseToken._approve90
PurchaseToken._afterTokenTransfer92
Context._msgSender93
PurchaseToken._beforeTokenTransfer95
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/PurchaseToken.sol.func.html b/coverage/src/contracts/PurchaseToken.sol.func.html new file mode 100644 index 0000000..3ec6898 --- /dev/null +++ b/coverage/src/contracts/PurchaseToken.sol.func.html @@ -0,0 +1,172 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts/PurchaseToken.sol - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contracts - PurchaseToken.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:425971.2 %
Date:2023-02-21 16:00:17Functions:172181.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:122254.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
Context._msgData0
Context._msgSender93
PurchaseToken._afterTokenTransfer92
PurchaseToken._approve90
PurchaseToken._beforeTokenTransfer95
PurchaseToken._burn0
PurchaseToken._mint52
PurchaseToken._spendAllowance43
PurchaseToken._transfer44
PurchaseToken.allowance45
PurchaseToken.approve48
PurchaseToken.balanceOf12
PurchaseToken.decimals1
PurchaseToken.decreaseAllowance0
PurchaseToken.increaseAllowance0
PurchaseToken.mint52
PurchaseToken.name1
PurchaseToken.symbol1
PurchaseToken.totalSupply4
PurchaseToken.transfer2
PurchaseToken.transferFrom43
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/PurchaseToken.sol.gcov.html b/coverage/src/contracts/PurchaseToken.sol.gcov.html new file mode 100644 index 0000000..3175989 --- /dev/null +++ b/coverage/src/contracts/PurchaseToken.sol.gcov.html @@ -0,0 +1,543 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts/PurchaseToken.sol + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contracts - PurchaseToken.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:425971.2 %
Date:2023-02-21 16:00:17Functions:172181.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:122254.5 %
+
+ + + + + + + + +

+
           Branch data     Line data    Source code
+
+       1                 :            : // SPDX-License-Identifier: MIT
+       2                 :            : // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
+       3                 :            : pragma solidity ^0.8.10;
+       4                 :            : 
+       5                 :            : import "../interfaces/IERC20.sol";
+       6                 :            : 
+       7                 :            : /**
+       8                 :            :  * @dev Provides information about the current execution context, including the
+       9                 :            :  * sender of the transaction and its data. While these are generally available
+      10                 :            :  * via msg.sender and msg.data, they should not be accessed in such a direct
+      11                 :            :  * manner, since when dealing with meta-transactions the account sending and
+      12                 :            :  * paying for execution may not be the actual sender (as far as an application
+      13                 :            :  * is concerned).
+      14                 :            :  *
+      15                 :            :  * This contract is only required for intermediate, library-like contracts.
+      16                 :            :  */
+      17                 :            : abstract contract Context {
+      18                 :            :     function _msgSender() internal view virtual returns (address) {
+      19                 :         93 :         return msg.sender;
+      20                 :            :     }
+      21                 :            : 
+      22                 :            :     function _msgData() internal view virtual returns (bytes calldata) {
+      23                 :          0 :         return msg.data;
+      24                 :            :     }
+      25                 :            : }
+      26                 :            : 
+      27                 :            : /**
+      28                 :            :  * @dev Implementation of the {IERC20} interface.
+      29                 :            :  *
+      30                 :            :  * This implementation is agnostic to the way tokens are created. This means
+      31                 :            :  * that a supply mechanism has to be added in a derived contract using {_mint}.
+      32                 :            :  * For a generic mechanism see {ERC20PresetMinterPauser}.
+      33                 :            :  *
+      34                 :            :  * TIP: For a detailed writeup see our guide
+      35                 :            :  * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
+      36                 :            :  * to implement supply mechanisms].
+      37                 :            :  *
+      38                 :            :  * The default value of {decimals} is 18. To change this, you should override
+      39                 :            :  * this function so it returns a different value.
+      40                 :            :  *
+      41                 :            :  * We have followed general OpenZeppelin Contracts guidelines: functions revert
+      42                 :            :  * instead returning `false` on failure. This behavior is nonetheless
+      43                 :            :  * conventional and does not conflict with the expectations of ERC20
+      44                 :            :  * applications.
+      45                 :            :  *
+      46                 :            :  * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
+      47                 :            :  * This allows applications to reconstruct the allowance for all accounts just
+      48                 :            :  * by listening to said events. Other implementations of the EIP may not emit
+      49                 :            :  * these events, as it isn't required by the specification.
+      50                 :            :  *
+      51                 :            :  * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
+      52                 :            :  * functions have been added to mitigate the well-known issues around setting
+      53                 :            :  * allowances. See {IERC20-approve}.
+      54                 :            :  */
+      55                 :            : contract PurchaseToken is Context, IERC20, IERC20Metadata {
+      56                 :            :     mapping(address => uint256) private _balances;
+      57                 :            : 
+      58                 :            :     mapping(address => mapping(address => uint256)) private _allowances;
+      59                 :            : 
+      60                 :            :     uint256 private _totalSupply;
+      61                 :            : 
+      62                 :            :     string private _name;
+      63                 :            :     string private _symbol;
+      64                 :            : 
+      65                 :            :     /**
+      66                 :            :      * @dev Sets the values for {name} and {symbol}.
+      67                 :            :      *
+      68                 :            :      * All two of these values are immutable: they can only be set once during
+      69                 :            :      * construction.
+      70                 :            :      */
+      71                 :            :     constructor() {
+      72                 :            :         _name = "PurchaseToken";
+      73                 :            :         _symbol = "PT";
+      74                 :            :     }
+      75                 :            : 
+      76                 :            :     /**
+      77                 :            :      * @dev Returns the name of the token.
+      78                 :            :      */
+      79                 :            :     function name() public view virtual override returns (string memory) {
+      80                 :          1 :         return _name;
+      81                 :            :     }
+      82                 :            : 
+      83                 :            :     /**
+      84                 :            :      * @dev Returns the symbol of the token, usually a shorter version of the
+      85                 :            :      * name.
+      86                 :            :      */
+      87                 :            :     function symbol() public view virtual override returns (string memory) {
+      88                 :          1 :         return _symbol;
+      89                 :            :     }
+      90                 :            : 
+      91                 :            :     /**
+      92                 :            :      * @dev Returns the number of decimals used to get its user representation.
+      93                 :            :      * For example, if `decimals` equals `18`, a balance of `5e18` tokens should
+      94                 :            :      * be displayed to a user as `5.00` (`5e18 / 10 ** 18`).
+      95                 :            :      *
+      96                 :            :      * Tokens usually opt for a value of 18, imitating the relationship between
+      97                 :            :      * Ether and Wei. This is the default value returned by this function, unless
+      98                 :            :      * it's overridden.
+      99                 :            :      *
+     100                 :            :      */
+     101                 :            :     function decimals() public view virtual override returns (uint8) {
+     102                 :          1 :         return 18;
+     103                 :            :     }
+     104                 :            : 
+     105                 :            :     /**
+     106                 :            :      * @dev See {IERC20-totalSupply}.
+     107                 :            :      */
+     108                 :            :     function totalSupply() public view virtual override returns (uint256) {
+     109                 :          4 :         return _totalSupply;
+     110                 :            :     }
+     111                 :            : 
+     112                 :            :     /**
+     113                 :            :      * @dev See {IERC20-balanceOf}.
+     114                 :            :      */
+     115                 :            :     function balanceOf(address account)
+     116                 :            :         public
+     117                 :            :         view
+     118                 :            :         virtual
+     119                 :            :         override
+     120                 :            :         returns (uint256)
+     121                 :            :     {
+     122                 :         12 :         return _balances[account];
+     123                 :            :     }
+     124                 :            : 
+     125                 :            :     /**
+     126                 :            :      * @dev This allows users to mint ERC20 tokens by sending ETH to this contract.
+     127                 :            :      * The amount of ERC20 tokens minted will be 100 times the amount of ETH sent.
+     128                 :            :      */
+     129                 :            :     function mint() external payable {
+     130                 :         52 :         uint256 amountToMint = msg.value * 100;
+     131                 :         52 :         _mint(msg.sender, amountToMint);
+     132                 :            :     }
+     133                 :            : 
+     134                 :            :     /**
+     135                 :            :      * @dev See {IERC20-transfer}.
+     136                 :            :      *
+     137                 :            :      * Requirements:
+     138                 :            :      *
+     139                 :            :      * - `to` cannot be the zero address.
+     140                 :            :      * - the caller must have a balance of at least `amount`.
+     141                 :            :      */
+     142                 :            :     function transfer(address to, uint256 amount)
+     143                 :            :         public
+     144                 :            :         virtual
+     145                 :            :         override
+     146                 :            :         returns (bool)
+     147                 :            :     {
+     148                 :          2 :         address owner = _msgSender();
+     149                 :          2 :         _transfer(owner, to, amount);
+     150                 :          1 :         return true;
+     151                 :            :     }
+     152                 :            : 
+     153                 :            :     /**
+     154                 :            :      * @dev See {IERC20-allowance}.
+     155                 :            :      */
+     156                 :            :     function allowance(address owner, address spender)
+     157                 :            :         public
+     158                 :            :         view
+     159                 :            :         virtual
+     160                 :            :         override
+     161                 :            :         returns (uint256)
+     162                 :            :     {
+     163                 :         88 :         return _allowances[owner][spender];
+     164                 :            :     }
+     165                 :            : 
+     166                 :            :     /**
+     167                 :            :      * @dev See {IERC20-approve}.
+     168                 :            :      *
+     169                 :            :      * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
+     170                 :            :      * `transferFrom`. This is semantically equivalent to an infinite approval.
+     171                 :            :      *
+     172                 :            :      * Requirements:
+     173                 :            :      *
+     174                 :            :      * - `spender` cannot be the zero address.
+     175                 :            :      */
+     176                 :            :     function approve(address spender, uint256 amount)
+     177                 :            :         public
+     178                 :            :         virtual
+     179                 :            :         override
+     180                 :            :         returns (bool)
+     181                 :            :     {
+     182                 :         48 :         address owner = _msgSender();
+     183                 :         48 :         _approve(owner, spender, amount);
+     184                 :         48 :         return true;
+     185                 :            :     }
+     186                 :            : 
+     187                 :            :     /**
+     188                 :            :      * @dev See {IERC20-transferFrom}.
+     189                 :            :      *
+     190                 :            :      * Emits an {Approval} event indicating the updated allowance. This is not
+     191                 :            :      * required by the EIP. See the note at the beginning of {ERC20}.
+     192                 :            :      *
+     193                 :            :      * NOTE: Does not update the allowance if the current allowance
+     194                 :            :      * is the maximum `uint256`.
+     195                 :            :      *
+     196                 :            :      * Requirements:
+     197                 :            :      *
+     198                 :            :      * - `from` and `to` cannot be the zero address.
+     199                 :            :      * - `from` must have a balance of at least `amount`.
+     200                 :            :      * - the caller must have allowance for ``from``'s tokens of at least
+     201                 :            :      * `amount`.
+     202                 :            :      */
+     203                 :            :     function transferFrom(
+     204                 :            :         address from,
+     205                 :            :         address to,
+     206                 :            :         uint256 amount
+     207                 :            :     ) public virtual override returns (bool) {
+     208                 :         43 :         address spender = _msgSender();
+     209                 :         43 :         _spendAllowance(from, spender, amount);
+     210                 :         42 :         _transfer(from, to, amount);
+     211                 :         40 :         return true;
+     212                 :            :     }
+     213                 :            : 
+     214                 :            :     /**
+     215                 :            :      * @dev Atomically increases the allowance granted to `spender` by the caller.
+     216                 :            :      *
+     217                 :            :      * This is an alternative to {approve} that can be used as a mitigation for
+     218                 :            :      * problems described in {IERC20-approve}.
+     219                 :            :      *
+     220                 :            :      * Emits an {Approval} event indicating the updated allowance.
+     221                 :            :      *
+     222                 :            :      * Requirements:
+     223                 :            :      *
+     224                 :            :      * - `spender` cannot be the zero address.
+     225                 :            :      */
+     226                 :            :     function increaseAllowance(address spender, uint256 addedValue)
+     227                 :            :         public
+     228                 :            :         virtual
+     229                 :            :         returns (bool)
+     230                 :            :     {
+     231                 :          0 :         address owner = _msgSender();
+     232                 :          0 :         _approve(owner, spender, allowance(owner, spender) + addedValue);
+     233                 :          0 :         return true;
+     234                 :            :     }
+     235                 :            : 
+     236                 :            :     /**
+     237                 :            :      * @dev Atomically decreases the allowance granted to `spender` by the caller.
+     238                 :            :      *
+     239                 :            :      * This is an alternative to {approve} that can be used as a mitigation for
+     240                 :            :      * problems described in {IERC20-approve}.
+     241                 :            :      *
+     242                 :            :      * Emits an {Approval} event indicating the updated allowance.
+     243                 :            :      *
+     244                 :            :      * Requirements:
+     245                 :            :      *
+     246                 :            :      * - `spender` cannot be the zero address.
+     247                 :            :      * - `spender` must have allowance for the caller of at least
+     248                 :            :      * `subtractedValue`.
+     249                 :            :      */
+     250                 :            :     function decreaseAllowance(address spender, uint256 subtractedValue)
+     251                 :            :         public
+     252                 :            :         virtual
+     253                 :            :         returns (bool)
+     254                 :            :     {
+     255                 :          0 :         address owner = _msgSender();
+     256                 :          0 :         uint256 currentAllowance = allowance(owner, spender);
+     257         [ #  # ]:          0 :         require(
+     258                 :            :             currentAllowance >= subtractedValue,
+     259                 :            :             "ERC20: decreased allowance below zero"
+     260                 :            :         );
+     261                 :            :         unchecked {
+     262                 :          0 :             _approve(owner, spender, currentAllowance - subtractedValue);
+     263                 :            :         }
+     264                 :            : 
+     265                 :          0 :         return true;
+     266                 :            :     }
+     267                 :            : 
+     268                 :            :     /**
+     269                 :            :      * @dev Moves `amount` of tokens from `from` to `to`.
+     270                 :            :      *
+     271                 :            :      * This internal function is equivalent to {transfer}, and can be used to
+     272                 :            :      * e.g. implement automatic token fees, slashing mechanisms, etc.
+     273                 :            :      *
+     274                 :            :      * Emits a {Transfer} event.
+     275                 :            :      *
+     276                 :            :      * Requirements:
+     277                 :            :      *
+     278                 :            :      * - `from` cannot be the zero address.
+     279                 :            :      * - `to` cannot be the zero address.
+     280                 :            :      * - `from` must have a balance of at least `amount`.
+     281                 :            :      */
+     282                 :            :     function _transfer(
+     283                 :            :         address from,
+     284                 :            :         address to,
+     285                 :            :         uint256 amount
+     286                 :            :     ) internal virtual {
+     287         [ #  + ]:         44 :         require(from != address(0), "ERC20: transfer from the zero address");
+     288         [ #  + ]:         44 :         require(to != address(0), "ERC20: transfer to the zero address");
+     289                 :            : 
+     290                 :         44 :         _beforeTokenTransfer(from, to, amount);
+     291                 :            : 
+     292                 :         44 :         uint256 fromBalance = _balances[from];
+     293         [ +  + ]:         44 :         require(
+     294                 :            :             fromBalance >= amount,
+     295                 :            :             "ERC20: transfer amount exceeds balance"
+     296                 :            :         );
+     297                 :            :         unchecked {
+     298                 :         41 :             _balances[from] = fromBalance - amount;
+     299                 :            :             // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
+     300                 :            :             // decrementing then incrementing.
+     301                 :         41 :             _balances[to] += amount;
+     302                 :            :         }
+     303                 :            : 
+     304                 :         41 :         emit Transfer(from, to, amount);
+     305                 :            : 
+     306                 :         41 :         _afterTokenTransfer(from, to, amount);
+     307                 :            :     }
+     308                 :            : 
+     309                 :            :     /** @dev Creates `amount` tokens and assigns them to `account`, increasing
+     310                 :            :      * the total supply.
+     311                 :            :      *
+     312                 :            :      * Emits a {Transfer} event with `from` set to the zero address.
+     313                 :            :      *
+     314                 :            :      * Requirements:
+     315                 :            :      *
+     316                 :            :      * - `account` cannot be the zero address.
+     317                 :            :      */
+     318                 :            :     function _mint(address account, uint256 amount) internal virtual {
+     319         [ +  + ]:         52 :         require(account != address(0), "ERC20: mint to the zero address");
+     320                 :            : 
+     321                 :         51 :         _beforeTokenTransfer(address(0), account, amount);
+     322                 :            : 
+     323                 :         51 :         _totalSupply += amount;
+     324                 :            :         unchecked {
+     325                 :            :             // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
+     326                 :         51 :             _balances[account] += amount;
+     327                 :            :         }
+     328                 :         51 :         emit Transfer(address(0), account, amount);
+     329                 :            : 
+     330                 :         51 :         _afterTokenTransfer(address(0), account, amount);
+     331                 :            :     }
+     332                 :            : 
+     333                 :            :     /**
+     334                 :            :      * @dev Destroys `amount` tokens from `account`, reducing the
+     335                 :            :      * total supply.
+     336                 :            :      *
+     337                 :            :      * Emits a {Transfer} event with `to` set to the zero address.
+     338                 :            :      *
+     339                 :            :      * Requirements:
+     340                 :            :      *
+     341                 :            :      * - `account` cannot be the zero address.
+     342                 :            :      * - `account` must have at least `amount` tokens.
+     343                 :            :      */
+     344                 :            :     function _burn(address account, uint256 amount) internal virtual {
+     345         [ #  # ]:          0 :         require(account != address(0), "ERC20: burn from the zero address");
+     346                 :            : 
+     347                 :          0 :         _beforeTokenTransfer(account, address(0), amount);
+     348                 :            : 
+     349                 :          0 :         uint256 accountBalance = _balances[account];
+     350         [ #  # ]:          0 :         require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
+     351                 :            :         unchecked {
+     352                 :          0 :             _balances[account] = accountBalance - amount;
+     353                 :            :             // Overflow not possible: amount <= accountBalance <= totalSupply.
+     354                 :          0 :             _totalSupply -= amount;
+     355                 :            :         }
+     356                 :            : 
+     357                 :          0 :         emit Transfer(account, address(0), amount);
+     358                 :            : 
+     359                 :          0 :         _afterTokenTransfer(account, address(0), amount);
+     360                 :            :     }
+     361                 :            : 
+     362                 :            :     /**
+     363                 :            :      * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
+     364                 :            :      *
+     365                 :            :      * This internal function is equivalent to `approve`, and can be used to
+     366                 :            :      * e.g. set automatic allowances for certain subsystems, etc.
+     367                 :            :      *
+     368                 :            :      * Emits an {Approval} event.
+     369                 :            :      *
+     370                 :            :      * Requirements:
+     371                 :            :      *
+     372                 :            :      * - `owner` cannot be the zero address.
+     373                 :            :      * - `spender` cannot be the zero address.
+     374                 :            :      */
+     375                 :            :     function _approve(
+     376                 :            :         address owner,
+     377                 :            :         address spender,
+     378                 :            :         uint256 amount
+     379                 :            :     ) internal virtual {
+     380         [ #  + ]:         90 :         require(owner != address(0), "ERC20: approve from the zero address");
+     381         [ #  + ]:         90 :         require(spender != address(0), "ERC20: approve to the zero address");
+     382                 :            : 
+     383                 :         90 :         _allowances[owner][spender] = amount;
+     384                 :         90 :         emit Approval(owner, spender, amount);
+     385                 :            :     }
+     386                 :            : 
+     387                 :            :     /**
+     388                 :            :      * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
+     389                 :            :      *
+     390                 :            :      * Does not update the allowance amount in case of infinite allowance.
+     391                 :            :      * Revert if not enough allowance is available.
+     392                 :            :      *
+     393                 :            :      * Might emit an {Approval} event.
+     394                 :            :      */
+     395                 :            :     function _spendAllowance(
+     396                 :            :         address owner,
+     397                 :            :         address spender,
+     398                 :            :         uint256 amount
+     399                 :            :     ) internal virtual {
+     400                 :         43 :         uint256 currentAllowance = allowance(owner, spender);
+     401         [ +  + ]:         43 :         if (currentAllowance != type(uint256).max) {
+     402         [ +  + ]:         43 :             require(
+     403                 :            :                 currentAllowance >= amount,
+     404                 :            :                 "ERC20: insufficient allowance"
+     405                 :            :             );
+     406                 :            :             unchecked {
+     407                 :         42 :                 _approve(owner, spender, currentAllowance - amount);
+     408                 :            :             }
+     409                 :            :         }
+     410                 :            :     }
+     411                 :            : 
+     412                 :            :     /**
+     413                 :            :      * @dev Hook that is called before any transfer of tokens. This includes
+     414                 :            :      * minting and burning.
+     415                 :            :      *
+     416                 :            :      * Calling conditions:
+     417                 :            :      *
+     418                 :            :      * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+     419                 :            :      * will be transferred to `to`.
+     420                 :            :      * - when `from` is zero, `amount` tokens will be minted for `to`.
+     421                 :            :      * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
+     422                 :            :      * - `from` and `to` are never both zero.
+     423                 :            :      *
+     424                 :            :      * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     425                 :            :      */
+     426                 :            :     function _beforeTokenTransfer(
+     427                 :            :         address from,
+     428                 :            :         address to,
+     429                 :            :         uint256 amount
+     430                 :            :     ) internal virtual {}
+     431                 :            : 
+     432                 :            :     /**
+     433                 :            :      * @dev Hook that is called after any transfer of tokens. This includes
+     434                 :            :      * minting and burning.
+     435                 :            :      *
+     436                 :            :      * Calling conditions:
+     437                 :            :      *
+     438                 :            :      * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+     439                 :            :      * has been transferred to `to`.
+     440                 :            :      * - when `from` is zero, `amount` tokens have been minted for `to`.
+     441                 :            :      * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
+     442                 :            :      * - `from` and `to` are never both zero.
+     443                 :            :      *
+     444                 :            :      * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     445                 :            :      */
+     446                 :            :     function _afterTokenTransfer(
+     447                 :            :         address from,
+     448                 :            :         address to,
+     449                 :            :         uint256 amount
+     450                 :            :     ) internal virtual {}
+     451                 :            : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/TicketNFT.sol.func-sort-c.html b/coverage/src/contracts/TicketNFT.sol.func-sort-c.html new file mode 100644 index 0000000..1b11f66 --- /dev/null +++ b/coverage/src/contracts/TicketNFT.sol.func-sort-c.html @@ -0,0 +1,144 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts/TicketNFT.sol - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contracts - TicketNFT.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:7171100.0 %
Date:2023-02-21 16:00:17Functions:1414100.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:5252100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
TicketNFT.admin1
TicketNFT.delistTicket3
TicketNFT.updateHolderName3
TicketNFT.approve6
TicketNFT.setUsed8
TicketNFT.holderNameOf13
TicketNFT.listTicket13
TicketNFT.getApproved14
TicketNFT.holderOf17
TicketNFT.isExpiredOrUsed18
TicketNFT.transferFrom22
TicketNFT.mint39
TicketNFT.purchase46
TicketNFT.balanceOf48
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/TicketNFT.sol.func.html b/coverage/src/contracts/TicketNFT.sol.func.html new file mode 100644 index 0000000..90b45c5 --- /dev/null +++ b/coverage/src/contracts/TicketNFT.sol.func.html @@ -0,0 +1,144 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts/TicketNFT.sol - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contracts - TicketNFT.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:7171100.0 %
Date:2023-02-21 16:00:17Functions:1414100.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:5252100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
TicketNFT.admin1
TicketNFT.approve6
TicketNFT.balanceOf48
TicketNFT.delistTicket3
TicketNFT.getApproved14
TicketNFT.holderNameOf13
TicketNFT.holderOf17
TicketNFT.isExpiredOrUsed18
TicketNFT.listTicket13
TicketNFT.mint39
TicketNFT.purchase46
TicketNFT.setUsed8
TicketNFT.transferFrom22
TicketNFT.updateHolderName3
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/TicketNFT.sol.gcov.html b/coverage/src/contracts/TicketNFT.sol.gcov.html new file mode 100644 index 0000000..ea768db --- /dev/null +++ b/coverage/src/contracts/TicketNFT.sol.gcov.html @@ -0,0 +1,304 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts/TicketNFT.sol + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contracts - TicketNFT.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:7171100.0 %
Date:2023-02-21 16:00:17Functions:1414100.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:5252100.0 %
+
+ + + + + + + + +

+
           Branch data     Line data    Source code
+
+       1                 :            : // SPDX-License-Identifier: UNLICENSED
+       2                 :            : pragma solidity ^0.8.10;
+       3                 :            : 
+       4                 :            : import "../interfaces/IERC20.sol";
+       5                 :            : import "../interfaces/ITicketNFT.sol";
+       6                 :            : import "../interfaces/IPrimaryMarket.sol";
+       7                 :            : import "../interfaces/ISecondaryMarket.sol";
+       8                 :            : 
+       9                 :            : contract TicketNFT is ITicketNFT, IPrimaryMarket, ISecondaryMarket {
+      10                 :            :     address _admin;
+      11                 :            :     uint256 _totalSupply;
+      12                 :            :     IERC20 public _purchaseToken;
+      13                 :            :     mapping(uint256 => address) _approvals;
+      14                 :            :     mapping(address => uint256) _balances;
+      15                 :            :     mapping(uint256 => uint256) public _expiryTimes;
+      16                 :            :     mapping(uint256 => string) _holderNames;
+      17                 :            :     mapping(uint256 => address) _holders;
+      18                 :            :     mapping(uint256 => address) _listers;
+      19                 :            :     mapping(uint256 => uint256) _prices;
+      20                 :            :     mapping(uint256 => bool) _ticketUsed;
+      21                 :            :     uint256 immutable _purchasePrice = 100e18;
+      22                 :            :     uint256 immutable _saleFee = 50;
+      23                 :            : 
+      24                 :            :     constructor(IERC20 purchaseToken) {
+      25                 :            :         _admin = msg.sender;
+      26                 :            :         _totalSupply = 0;
+      27                 :            :         _purchaseToken = purchaseToken;
+      28                 :            :     }
+      29                 :            : 
+      30                 :            :     function mint(address holder, string memory holderName) external {
+      31         [ +  + ]:         39 :         require(
+      32                 :            :             msg.sender == address(this),
+      33                 :            :             "mint: can only be called by primary market"
+      34                 :            :         ); // Limits to being called by this contract and only purchase function calls mint
+      35                 :         38 :         uint256 ticketId = _totalSupply + 1;
+      36                 :         38 :         _balances[holder] += 1;
+      37                 :         38 :         _expiryTimes[ticketId] = block.timestamp + 10 days;
+      38                 :         38 :         _holderNames[ticketId] = holderName;
+      39                 :         38 :         _holders[ticketId] = holder;
+      40                 :         38 :         _ticketUsed[ticketId] = false;
+      41                 :         38 :         _totalSupply = ticketId;
+      42                 :         38 :         emit Transfer(address(0), holder, ticketId);
+      43                 :            :     }
+      44                 :            : 
+      45                 :            :     function balanceOf(address holder) external view returns (uint256) {
+      46                 :         48 :         return _balances[holder];
+      47                 :            :     }
+      48                 :            : 
+      49                 :            :     function holderOf(uint256 ticketID) external view returns (address) {
+      50         [ +  + ]:         17 :         require(ticketID <= _totalSupply, "holderOf: ticket doesn't exist");
+      51                 :         16 :         return _holders[ticketID];
+      52                 :            :     }
+      53                 :            : 
+      54                 :            :     function transferFrom(
+      55                 :            :         address from,
+      56                 :            :         address to,
+      57                 :            :         uint256 ticketID
+      58                 :            :     ) external {
+      59         [ +  + ]:         22 :         require(from != address(0), "transferFrom: from cannot be 0");
+      60         [ +  + ]:         20 :         require(to != address(0), "transferFrom: to cannot be 0");
+      61         [ +  + ]:         18 :         require(
+      62                 :            :             msg.sender == _holders[ticketID] ||
+      63                 :            :                 msg.sender == _approvals[ticketID] ||
+      64                 :            :                 (msg.sender == address(this) &&
+      65                 :            :                     (from == _holders[ticketID] ||
+      66                 :            :                         from == _approvals[ticketID])),
+      67                 :            :             "transferFrom: msg.sender must be current holder or approved sender"
+      68                 :            :         );
+      69         [ +  + ]:         16 :         require(
+      70                 :            :             from == _holders[ticketID],
+      71                 :            :             "transferFrom: ticket not owned by from"
+      72                 :            :         );
+      73                 :         14 :         _approvals[ticketID] = address(0);
+      74                 :         14 :         _balances[from] -= 1;
+      75                 :         14 :         _balances[to] += 1;
+      76                 :         14 :         _holders[ticketID] = to;
+      77                 :         14 :         emit Transfer(from, to, ticketID);
+      78                 :         14 :         emit Approval(to, address(0), ticketID);
+      79                 :            :     }
+      80                 :            : 
+      81                 :            :     function approve(address to, uint256 ticketID) external {
+      82         [ +  + ]:          6 :         require(ticketID <= _totalSupply, "approve: ticket doesn't exist");
+      83         [ +  + ]:          5 :         require(
+      84                 :            :             msg.sender == _holders[ticketID],
+      85                 :            :             "approve: msg.sender doesn't own ticket"
+      86                 :            :         );
+      87                 :          4 :         _approvals[ticketID] = to;
+      88                 :          4 :         emit Approval(msg.sender, to, ticketID);
+      89                 :            :     }
+      90                 :            : 
+      91                 :            :     function getApproved(uint256 ticketID) external view returns (address) {
+      92         [ +  + ]:         14 :         require(ticketID <= _totalSupply, "getApproved: ticket doesn't exist");
+      93                 :         13 :         return _approvals[ticketID];
+      94                 :            :     }
+      95                 :            : 
+      96                 :            :     function holderNameOf(uint256 ticketID)
+      97                 :            :         external
+      98                 :            :         view
+      99                 :            :         returns (string memory)
+     100                 :            :     {
+     101         [ +  + ]:         13 :         require(ticketID <= _totalSupply, "holderNameOf: ticket doesn't exist");
+     102                 :         12 :         return _holderNames[ticketID];
+     103                 :            :     }
+     104                 :            : 
+     105                 :            :     function updateHolderName(uint256 ticketID, string calldata newName)
+     106                 :            :         external
+     107                 :            :     {
+     108         [ +  + ]:          3 :         require(
+     109                 :            :             ticketID <= _totalSupply,
+     110                 :            :             "updateHolderName: ticket doesn't exist"
+     111                 :            :         );
+     112         [ +  + ]:          2 :         require(
+     113                 :            :             msg.sender == _holders[ticketID],
+     114                 :            :             "updateHolderName: msg.sender doesn't own ticket"
+     115                 :            :         );
+     116                 :          1 :         _holderNames[ticketID] = newName;
+     117                 :            :     }
+     118                 :            : 
+     119                 :            :     function setUsed(uint256 ticketID) external {
+     120         [ +  + ]:          8 :         require(msg.sender == _admin, "setUsed: only admin can setUsed");
+     121         [ +  + ]:          7 :         require(ticketID <= _totalSupply, "setUsed: ticket doesn't exist");
+     122         [ +  + ]:          6 :         require(_ticketUsed[ticketID] == false, "setUsed: ticket already used");
+     123         [ +  + ]:          5 :         require(
+     124                 :            :             _expiryTimes[ticketID] >= block.timestamp,
+     125                 :            :             "setUsed: ticket expired"
+     126                 :            :         );
+     127                 :          4 :         _ticketUsed[ticketID] = true;
+     128                 :            :     }
+     129                 :            : 
+     130                 :            :     function isExpiredOrUsed(uint256 ticketID) external view returns (bool) {
+     131         [ +  + ]:         18 :         require(
+     132                 :            :             ticketID <= _totalSupply,
+     133                 :            :             "isExpiredOrUsed: ticket doesn't exist"
+     134                 :            :         );
+     135                 :         17 :         return (_ticketUsed[ticketID] ||
+     136                 :            :             _expiryTimes[ticketID] < block.timestamp);
+     137                 :            :     }
+     138                 :            : 
+     139                 :            :     function admin() external view returns (address) {
+     140                 :          1 :         return _admin;
+     141                 :            :     }
+     142                 :            : 
+     143                 :            :     function purchase(string memory holderName) external {
+     144         [ +  + ]:         40 :         require(_totalSupply < 1000, "purchase: maximum tickets reached");
+     145         [ +  + ]:         39 :         require(
+     146                 :            :             _purchaseToken.allowance(msg.sender, address(this)) >=
+     147                 :            :                 _purchasePrice,
+     148                 :            :             "purchase: insufficient token allowance"
+     149                 :            :         );
+     150                 :         38 :         _purchaseToken.transferFrom(msg.sender, _admin, _purchasePrice);
+     151                 :         37 :         this.mint(msg.sender, holderName);
+     152                 :         37 :         emit Purchase(msg.sender, holderName);
+     153                 :            :     }
+     154                 :            : 
+     155                 :            :     function listTicket(uint256 ticketID, uint256 price) external {
+     156         [ +  + ]:         13 :         require(
+     157                 :            :             msg.sender == _holders[ticketID],
+     158                 :            :             "listTicket: msg.sender doesn't own ticket"
+     159                 :            :         );
+     160         [ +  + ]:         12 :         require(
+     161                 :            :             _ticketUsed[ticketID] == false &&
+     162                 :            :                 _expiryTimes[ticketID] >= block.timestamp,
+     163                 :            :             "listTicket: ticket is expired/used"
+     164                 :            :         );
+     165         [ +  + ]:         10 :         require(price > 0, "listTicket: price cannot be 0");
+     166                 :          9 :         _listers[ticketID] = msg.sender;
+     167                 :          9 :         _prices[ticketID] = price;
+     168                 :          9 :         this.transferFrom(msg.sender, address(this), ticketID);
+     169                 :          9 :         emit Listing(ticketID, msg.sender, price);
+     170                 :            :     }
+     171                 :            : 
+     172                 :            :     function purchase(uint256 ticketID, string calldata name) external {
+     173         [ +  + ]:          6 :         require(
+     174                 :            :             _listers[ticketID] != address(0) && _prices[ticketID] != 0,
+     175                 :            :             "purchase: ticket is not listed, missing lister address or price"
+     176                 :            :         );
+     177                 :          5 :         uint256 ticketPrice = _prices[ticketID];
+     178                 :          5 :         uint256 ticketFee = _saleFee * (ticketPrice / 1000);
+     179                 :          5 :         uint256 ticketRevenue = ticketPrice - ticketFee;
+     180         [ +  + ]:          5 :         require(
+     181                 :            :             _ticketUsed[ticketID] == false &&
+     182                 :            :                 _expiryTimes[ticketID] >= block.timestamp,
+     183                 :            :             "purchase: ticket is expired/used"
+     184                 :            :         );
+     185         [ +  + ]:          3 :         require(
+     186                 :            :             _purchaseToken.allowance(msg.sender, address(this)) >= ticketPrice,
+     187                 :            :             "purchase: insufficient token allowance"
+     188                 :            :         );
+     189                 :          2 :         _purchaseToken.transferFrom(
+     190                 :            :             msg.sender,
+     191                 :            :             _listers[ticketID],
+     192                 :            :             ticketRevenue
+     193                 :            :         );
+     194                 :          1 :         _purchaseToken.transferFrom(msg.sender, _admin, ticketFee);
+     195                 :          1 :         this.transferFrom(address(this), msg.sender, ticketID);
+     196                 :          1 :         _listers[ticketID] = address(0);
+     197                 :          1 :         _prices[ticketID] = 0;
+     198                 :          1 :         _holderNames[ticketID] = name;
+     199                 :          1 :         emit Purchase(msg.sender, ticketID, ticketPrice, name);
+     200                 :            :     }
+     201                 :            : 
+     202                 :            :     function delistTicket(uint256 ticketID) external {
+     203         [ +  + ]:          3 :         require(
+     204                 :            :             msg.sender == _listers[ticketID],
+     205                 :            :             "delistTicket: msg.sender didn't list ticket"
+     206                 :            :         );
+     207                 :          2 :         _listers[ticketID] = address(0);
+     208                 :          2 :         _prices[ticketID] = 0;
+     209                 :          2 :         this.transferFrom(address(this), msg.sender, ticketID);
+     210                 :          2 :         emit Delisting(ticketID);
+     211                 :            :     }
+     212                 :            : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/index-sort-b.html b/coverage/src/contracts/index-sort-b.html new file mode 100644 index 0000000..b9c814b --- /dev/null +++ b/coverage/src/contracts/index-sort-b.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contractsHitTotalCoverage
Test:TicketNFT CoverageLines:11313086.9 %
Date:2023-02-21 16:00:17Functions:313588.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
PurchaseToken.sol +
71.2%71.2%
+
71.2 %42 / 5981.0 %17 / 2154.5 %12 / 22
TicketNFT.sol +
100.0%
+
100.0 %71 / 71100.0 %14 / 14100.0 %52 / 52
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/index-sort-f.html b/coverage/src/contracts/index-sort-f.html new file mode 100644 index 0000000..6330c2e --- /dev/null +++ b/coverage/src/contracts/index-sort-f.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contractsHitTotalCoverage
Test:TicketNFT CoverageLines:11313086.9 %
Date:2023-02-21 16:00:17Functions:313588.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
PurchaseToken.sol +
71.2%71.2%
+
71.2 %42 / 5981.0 %17 / 2154.5 %12 / 22
TicketNFT.sol +
100.0%
+
100.0 %71 / 71100.0 %14 / 14100.0 %52 / 52
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/index-sort-l.html b/coverage/src/contracts/index-sort-l.html new file mode 100644 index 0000000..a5fa620 --- /dev/null +++ b/coverage/src/contracts/index-sort-l.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contractsHitTotalCoverage
Test:TicketNFT CoverageLines:11313086.9 %
Date:2023-02-21 16:00:17Functions:313588.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
PurchaseToken.sol +
71.2%71.2%
+
71.2 %42 / 5981.0 %17 / 2154.5 %12 / 22
TicketNFT.sol +
100.0%
+
100.0 %71 / 71100.0 %14 / 14100.0 %52 / 52
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/src/contracts/index.html b/coverage/src/contracts/index.html new file mode 100644 index 0000000..0792467 --- /dev/null +++ b/coverage/src/contracts/index.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - TicketNFT Coverage - src/contracts + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src/contractsHitTotalCoverage
Test:TicketNFT CoverageLines:11313086.9 %
Date:2023-02-21 16:00:17Functions:313588.6 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:647486.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
PurchaseToken.sol +
71.2%71.2%
+
71.2 %42 / 5981.0 %17 / 2154.5 %12 / 22
TicketNFT.sol +
100.0%
+
100.0 %71 / 71100.0 %14 / 14100.0 %52 / 52
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/TicketNFT.t.sol.func-sort-c.html b/coverage/test/TicketNFT.t.sol.func-sort-c.html new file mode 100644 index 0000000..f564d0e --- /dev/null +++ b/coverage/test/TicketNFT.t.sol.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - TicketNFT Coverage - test/TicketNFT.t.sol - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - test - TicketNFT.t.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:00-
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
BaseTicketNFTTest._buyTicket0
BaseTicketNFTTest._topUpTokens0
BaseTicketNFTTest.setUp0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/TicketNFT.t.sol.func.html b/coverage/test/TicketNFT.t.sol.func.html new file mode 100644 index 0000000..29a1ec1 --- /dev/null +++ b/coverage/test/TicketNFT.t.sol.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - TicketNFT Coverage - test/TicketNFT.t.sol - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - test - TicketNFT.t.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:00-
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
BaseTicketNFTTest._buyTicket0
BaseTicketNFTTest._topUpTokens0
BaseTicketNFTTest.setUp0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/TicketNFT.t.sol.gcov.html b/coverage/test/TicketNFT.t.sol.gcov.html new file mode 100644 index 0000000..9a089d0 --- /dev/null +++ b/coverage/test/TicketNFT.t.sol.gcov.html @@ -0,0 +1,686 @@ + + + + + + + LCOV - TicketNFT Coverage - test/TicketNFT.t.sol + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - test - TicketNFT.t.sol (source / functions)HitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Lines: + hit + not hit + | Branches: + + taken + - not taken + # not executed +Branches:00-
+
+ + + + + + + + +

+
           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                 :            : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/index-sort-b.html b/coverage/test/index-sort-b.html new file mode 100644 index 0000000..d652e7a --- /dev/null +++ b/coverage/test/index-sort-b.html @@ -0,0 +1,111 @@ + + + + + + + LCOV - TicketNFT Coverage - test + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - testHitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
TicketNFT.t.sol +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/index-sort-f.html b/coverage/test/index-sort-f.html new file mode 100644 index 0000000..31d8f77 --- /dev/null +++ b/coverage/test/index-sort-f.html @@ -0,0 +1,111 @@ + + + + + + + LCOV - TicketNFT Coverage - test + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - testHitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
TicketNFT.t.sol +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/index-sort-l.html b/coverage/test/index-sort-l.html new file mode 100644 index 0000000..ea4a2c1 --- /dev/null +++ b/coverage/test/index-sort-l.html @@ -0,0 +1,111 @@ + + + + + + + LCOV - TicketNFT Coverage - test + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - testHitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
TicketNFT.t.sol +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/test/index.html b/coverage/test/index.html new file mode 100644 index 0000000..f89f7ed --- /dev/null +++ b/coverage/test/index.html @@ -0,0 +1,111 @@ + + + + + + + LCOV - TicketNFT Coverage - test + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - testHitTotalCoverage
Test:TicketNFT CoverageLines:0100.0 %
Date:2023-02-21 16:00:17Functions:030.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +Branches:00-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverageBranches Sort by branch coverage
TicketNFT.t.sol +
0.0%
+
0.0 %0 / 100.0 %0 / 3-0 / 0
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/coverage/updown.png b/coverage/updown.png new file mode 100644 index 0000000..aa56a23 Binary files /dev/null and b/coverage/updown.png differ