Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,32 @@ Deployment scripts are located in the `/script` directory. Example:
forge script script/DeployHostItTickets.s.sol --rpc-url <YOUR_RPC_URL> --private-key <YOUR_PRIVATE_KEY> --broadcast
```

## Dimensional Units

The inline `// {unit}` comments throughout the Solidity source annotate dimensional types to prevent unit-mismatch bugs.

### Base Units

| Unit | Meaning |
|------|---------|
| `{tok}` | Token amounts (ETH or ERC20), in the smallest unit of the payment token selected via `FeeType` |
| `{s}` | Timestamps and durations in seconds (Unix epoch for timestamps, raw seconds for durations) |
| `{1}` | Dimensionless quantities (basis-point ratios, boolean flags, counters) |
| `{ticket}` | Ticket token IDs and counts (NFT minting counters, `maxTickets`, `soldTickets`) |
| `{ticketId}` | Ticket type identifiers (sequential `uint64` IDs assigned by the factory) |
| `{day}` | Day index offset from event start (used in check-in tracking, derived from seconds) |
| `{addr}` | Ethereum addresses (token, admin, buyer) |

### Derived Units

| Unit | Meaning |
|------|---------|
| `{1/1}` | Fee fraction: `HOSTIT_FEE_BPS / FEE_BASIS_POINTS` = 300 / 10,000 = 0.03 |

### Precision

- **BPS** -- Basis points (1/10,000). `FEE_BASIS_POINTS = 10_000`, `HOSTIT_FEE_BPS = 300` (3%).

## Security
- All contracts are licensed under AGPL-3.0-only.
- Uses OpenZeppelin libraries and patterns for security.
Expand Down
11 changes: 11 additions & 0 deletions src/facets/FactoryFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ contract FactoryFacet is IFactory {
// EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @param _fees {tok} per-ticket prices in each fee token
/// @return {ticketId}
function createTicket(TicketData calldata _ticketData, FeeType[] calldata _feeTypes, uint256[] calldata _fees)
external
returns (uint64)
{
return _ticketData._createTicket(_feeTypes, _fees);
}

/// @param _ticketId {ticketId}
function updateTicket(TicketData calldata _ticketData, uint64 _ticketId) external {
_ticketData._updateTicket(_ticketId);
}
Expand All @@ -28,14 +31,17 @@ contract FactoryFacet is IFactory {
// VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @return {ticketId} total ticket type count
function ticketCount() public view returns (uint64) {
return LibFactory._getTicketCount();
}

/// @param _ticketId {ticketId}
function ticketExists(uint64 _ticketId) public view returns (bool) {
return _ticketId._ticketExists();
}

/// @param _ticketId {ticketId}
function ticketData(uint64 _ticketId) public view returns (FullTicketData memory) {
return _ticketId._getFullTicketData();
}
Expand All @@ -44,10 +50,12 @@ contract FactoryFacet is IFactory {
return LibFactory._getAllFullTicketData();
}

/// @param _ticketAdmin {addr}
function adminTickets(address _ticketAdmin) public view returns (uint64[] memory) {
return _ticketAdmin._getAdminTicketIds();
}

/// @param _ticketAdmin {addr}
function adminTicketData(address _ticketAdmin) public view returns (FullTicketData[] memory) {
return _ticketAdmin._getAdminFullTicketData();
}
Expand All @@ -60,14 +68,17 @@ contract FactoryFacet is IFactory {
return LibFactory._getHostItTicketHash();
}

/// @param _ticketId {ticketId}
function ticketHash(uint64 _ticketId) public pure returns (bytes32) {
return _ticketId._generateTicketHash();
}

/// @param _ticketId {ticketId}
function mainAdminRole(uint64 _ticketId) public pure returns (uint256) {
return _ticketId._generateMainTicketAdminRole();
}

/// @param _ticketId {ticketId}
function ticketAdminRole(uint64 _ticketId) public pure returns (uint256) {
return _ticketId._generateTicketAdminRole();
}
Expand Down
10 changes: 10 additions & 0 deletions src/facets/MarketplaceFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ contract MarketplaceFacet is IMarketplace {
// EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @inheritdoc IMarketplace
function mintTicket(uint64 _ticketId, FeeType _feeType, address _buyer) external payable returns (uint40) {
// {ticket}
return _ticketId._mintTicket(_feeType, _buyer);
}

Expand All @@ -36,18 +38,22 @@ contract MarketplaceFacet is IMarketplace {
// VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

// @return {1}
function isFeeEnabled(uint64 _ticketId, FeeType _feeType) external view returns (bool) {
return _ticketId._isFeeEnabled(_feeType);
}

// @return {addr}
function getFeeTokenAddress(FeeType _feeType) external view returns (address) {
return _feeType._getFeeTokenAddress();
}

// @return {tok}
function getTicketFee(uint64 _ticketId, FeeType _feeType) external view returns (uint256) {
return _ticketId._getTicketFee(_feeType);
}

// @return ticketFee_ {tok}, hostItFee_ {tok}, totalFee_ {tok}
function getAllFees(uint64 _ticketId, FeeType _feeType)
external
view
Expand All @@ -56,10 +62,12 @@ contract MarketplaceFacet is IMarketplace {
return _ticketId._getFees(_feeType);
}

// @return {tok}
function getTicketBalance(uint64 _ticketId, FeeType _feeType) external view returns (uint256) {
return _ticketId._getTicketBalance(_feeType);
}

// @return {tok}
function getHostItBalance(FeeType _feeType) external view returns (uint256) {
return _feeType._getHostItBalance();
}
Expand All @@ -68,10 +76,12 @@ contract MarketplaceFacet is IMarketplace {
// PURE FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

// @param _fee {tok} @return {tok}
function getHostItFee(uint256 _fee) external pure returns (uint256) {
return _fee._getHostItFee();
}

// @return {s}
function getRefundPeriod() external pure returns (uint256) {
return LibMarketplace.REFUND_PERIOD;
}
Expand Down
2 changes: 2 additions & 0 deletions src/inits/HostItInit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {LibMarketplace} from "@ticket/libs/LibMarketplace.sol";
event HostItInitialized(address ticketProxy, FeeType[] feeTypes, address[] tokens);

contract HostItInit {
/// @param _ticketProxy {addr} ticket implementation proxy
/// @param _tokens {addr} ERC20 token addresses for each fee type
function initHostIt(address _ticketProxy, FeeType[] calldata _feeTypes, address[] calldata _tokens) public {
LibFactory._factoryStorage().ticketProxy = _ticketProxy;
LibMarketplace._setFeeTokenAddresses(_feeTypes, _tokens);
Expand Down
22 changes: 11 additions & 11 deletions src/interfaces/IFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ interface IFactory {
/// @notice Creates a new ticket
/// @param _ticketData The ticket data
/// @param _feeTypes The fee types
/// @param _fees The fees
/// @param _fees {tok} The fees (per-ticket prices in each fee token)
function createTicket(TicketData calldata _ticketData, FeeType[] calldata _feeTypes, uint256[] calldata _fees)
external
returns (uint64);
returns (uint64); // {ticketId}

/// @notice Updates an existing ticket
/// @param _ticketData The ticket data
/// @param _ticketId The ID of the ticket to update
/// @param _ticketId {ticketId} The ID of the ticket to update
function updateTicket(TicketData calldata _ticketData, uint64 _ticketId) external;

//*//////////////////////////////////////////////////////////////////////////
// VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @notice Gets the total number of tickets
/// @return The total number of tickets
/// @return {ticketId} The total number of tickets
function ticketCount() external view returns (uint64);

/// @notice Checks if a ticket exists
/// @param _ticketId The ID of the ticket to check
/// @param _ticketId {ticketId} The ID of the ticket to check
/// @return Whether the ticket exists
function ticketExists(uint64 _ticketId) external view returns (bool);

/// @notice Gets the ticket data for a ticket
/// @param _ticketId The ID of the ticket to get data for
/// @param _ticketId {ticketId} The ID of the ticket to get data for
/// @return The ticket data
function ticketData(uint64 _ticketId) external view returns (FullTicketData memory);

Expand All @@ -47,12 +47,12 @@ interface IFactory {
function allTicketData() external view returns (FullTicketData[] memory);

/// @notice Gets the list of tickets for a ticket admin
/// @param _ticketAdmin The ticket admin to get tickets for
/// @param _ticketAdmin {addr} The ticket admin to get tickets for
/// @return The list of tickets for the ticket admin
function adminTickets(address _ticketAdmin) external view returns (uint64[] memory);

/// @notice Gets the ticket data for a ticket admin
/// @param _ticketAdmin The ticket admin to get ticket data for
/// @param _ticketAdmin {addr} The ticket admin to get ticket data for
/// @return The ticket data for the ticket admin
function adminTicketData(address _ticketAdmin) external view returns (FullTicketData[] memory);

Expand All @@ -65,17 +65,17 @@ interface IFactory {
function hostItTicketHash() external pure returns (bytes32);

/// @notice Gets the hash of a ticket
/// @param _ticketId The ID of the ticket to get the hash for
/// @param _ticketId {ticketId} The ID of the ticket to get the hash for
/// @return The hash of the ticket
function ticketHash(uint64 _ticketId) external pure returns (bytes32);

/// @notice Gets the main admin role for a ticket
/// @param _ticketId The ID of the ticket to get the main admin role for
/// @param _ticketId {ticketId} The ID of the ticket to get the main admin role for
/// @return The main admin role for the ticket
function mainAdminRole(uint64 _ticketId) external pure returns (uint256);

/// @notice Gets the ticket admin role for a ticket
/// @param _ticketId The ID of the ticket to get the ticket admin role for
/// @param _ticketId {ticketId} The ID of the ticket to get the ticket admin role for
/// @return The ticket admin role for the ticket
function ticketAdminRole(uint64 _ticketId) external pure returns (uint256);
}
52 changes: 26 additions & 26 deletions src/interfaces/IMarketplace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,89 +12,89 @@ interface IMarketplace {
//////////////////////////////////////////////////////////////////////////*//

/// @notice Mints a ticket for the specified buyer
/// @param ticketId The ID of the ticket to mint
/// @param ticketId {ticketId} The ID of the ticket to mint
/// @param feeType The type of fee to use for the ticket
/// @param buyer The address of the buyer
/// @return The token ID of the minted ticket
/// @param buyer {addr} The address of the buyer
/// @return {ticket} The token ID of the minted ticket
function mintTicket(uint64 ticketId, FeeType feeType, address buyer) external payable returns (uint40);

/// @notice Sets the fees for the specified ticket
/// @param ticketId The ID of the ticket to set fees for
/// @param ticketId {ticketId} The ID of the ticket to set fees for
/// @param feeTypes The types of fees to set
/// @param fees The fees to set
/// @param fees {tok} The fees to set
function setTicketFees(uint64 ticketId, FeeType[] calldata feeTypes, uint256[] calldata fees) external;

/// @notice Claims a refund for the specified ticket
/// @param ticketId The ID of the ticket to claim a refund for
/// @param ticketId {ticketId} The ID of the ticket to claim a refund for
/// @param feeType The type of fee to claim a refund for
/// @param tokenId The token ID of the ticket to claim a refund for
/// @param to The address to send the refund to
/// @param tokenId {ticket} The token ID of the ticket to claim a refund for
/// @param to {addr} The address to send the refund to
function claimRefund(uint64 ticketId, FeeType feeType, uint256 tokenId, address to) external;

/// @notice Withdraws the ticket balance for the specified ticket
/// @param ticketId The ID of the ticket to withdraw the balance for
/// @param ticketId {ticketId} The ID of the ticket to withdraw the balance for
/// @param feeType The type of fee to withdraw the balance for
/// @param to The address to send the balance to
/// @param to {addr} The address to send the balance to
function withdrawTicketBalance(uint64 ticketId, FeeType feeType, address to) external;

/// @notice Withdraws the HostIt balance for the specified fee type
/// @param feeType The type of fee to withdraw the balance for
/// @param to The address to send the balance to
/// @param to {addr} The address to send the balance to
function withdrawHostItBalance(FeeType feeType, address to) external;

//*//////////////////////////////////////////////////////////////////////////
// VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @notice Checks if the specified fee type is enabled for the specified ticket
/// @param ticketId The ID of the ticket to check
/// @param ticketId {ticketId} The ID of the ticket to check
/// @param feeType The type of fee to check
/// @return True if the fee type is enabled, false otherwise
/// @return {1} True if the fee type is enabled, false otherwise
function isFeeEnabled(uint64 ticketId, FeeType feeType) external view returns (bool);

/// @notice Gets the address of the fee token for the specified fee type
/// @param feeType The type of fee to get the address for
/// @return The address of the fee token
/// @return {addr} The address of the fee token
function getFeeTokenAddress(FeeType feeType) external view returns (address);

/// @notice Gets the fee for the specified ticket and fee type
/// @param ticketId The ID of the ticket to get the fee for
/// @param ticketId {ticketId} The ID of the ticket to get the fee for
/// @param feeType The type of fee to get
/// @return The fee for the ticket and fee type
/// @return {tok} The fee for the ticket and fee type
function getTicketFee(uint64 ticketId, FeeType feeType) external view returns (uint256);

/// @notice Gets the fees for the specified ticket
/// @param ticketId The ID of the ticket to get the fees for
/// @param ticketId {ticketId} The ID of the ticket to get the fees for
/// @param feeType The type of fee to get
/// @return ticketFee The ticket fee for the ticket
/// @return hostItFee The HostIt fee for the ticket
/// @return totalFee The total fee for the ticket
/// @return ticketFee {tok} The ticket fee for the ticket
/// @return hostItFee {tok} The HostIt fee for the ticket
/// @return totalFee {tok} The total fee for the ticket
function getAllFees(uint64 ticketId, FeeType feeType)
external
view
returns (uint256 ticketFee, uint256 hostItFee, uint256 totalFee);

/// @notice Gets the balance of the specified ticket for the specified fee type
/// @param ticketId The ID of the ticket to get the balance for
/// @param ticketId {ticketId} The ID of the ticket to get the balance for
/// @param feeType The type of fee to get the balance for
/// @return The balance of the ticket for the fee type
/// @return {tok} The balance of the ticket for the fee type
function getTicketBalance(uint64 ticketId, FeeType feeType) external view returns (uint256);

/// @notice Gets the balance of HostIt for the specified fee type
/// @param feeType The type of fee to get the balance for
/// @return The balance of HostIt for the fee type
/// @return {tok} The balance of HostIt for the fee type
function getHostItBalance(FeeType feeType) external view returns (uint256);

//*//////////////////////////////////////////////////////////////////////////
// PURE FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @notice Calculates the HostIt fee for the specified fee
/// @param fee The fee to calculate the HostIt fee for
/// @return The HostIt fee for the fee
/// @param fee {tok} The fee to calculate the HostIt fee for
/// @return {tok} The HostIt fee for the fee
function getHostItFee(uint256 fee) external pure returns (uint256);

/// @notice Gets the refund period
/// @return The refund period
/// @return {s} The refund period
function getRefundPeriod() external pure returns (uint256);
}
8 changes: 7 additions & 1 deletion src/libs/LibCheckIn.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ library LibCheckIn {
// INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*//

/// @param _ticketId {ticketId}
/// @param _ticketOwner {addr}
/// @param _tokenId {ticket}
function _checkin(uint64 _ticketId, address _ticketOwner, uint40 _tokenId) internal onlyTicketAdmin(_ticketId) {
_ticketId._checkTicketExists();

uint40 time = uint40(block.timestamp);
uint40 time = uint40(block.timestamp); // {s}
ExtraTicketData memory ticketData = _ticketId._getExtraTicketData();

if (time < ticketData.startTime) revert TicketUsePeriodNotStarted();
Expand All @@ -54,6 +57,7 @@ library LibCheckIn {

cs.checkedIn[_ticketId].add(_ticketOwner);

// {day} = ({s} - {s}) / {s}
uint8 day = uint8((time - ticketData.startTime) / 1 days);
if (!cs.checkedInByDay[_ticketId][day].add(_ticketOwner)) revert AlreadyCheckedInForDay(day);

Expand Down Expand Up @@ -93,6 +97,7 @@ library LibCheckIn {
return _checkInStorage().checkedIn[_ticketId].contains(_ticketOwner);
}

/// @param _day {day}
function _isCheckedInForDay(uint64 _ticketId, uint8 _day, address _ticketOwner) internal view returns (bool) {
return _checkInStorage().checkedInByDay[_ticketId][_day].contains(_ticketOwner);
}
Expand All @@ -101,6 +106,7 @@ library LibCheckIn {
return _checkInStorage().checkedIn[_ticketId].values();
}

/// @param _day {day}
function _getCheckedInForDay(uint64 _ticketId, uint8 _day) internal view returns (address[] memory) {
return _checkInStorage().checkedInByDay[_ticketId][_day].values();
}
Expand Down
Loading