Documentation Index
Fetch the complete documentation index at: https://docs.haus25.live/llms.txt
Use this file to discover all available pages before exploring further.
Core Functionality
Event NFT Management
EventFactory mints unique ERC721 tokens for each event, where ownership determines control rights:
function createEvent(
uint256 startDate,
uint256 eventDuration,
uint256 reservePrice,
string calldata metadataURI,
string calldata artCategory,
uint256 ticketsAmount,
uint256 ticketPrice
) external returns (uint256 eventId)
Each event NFT represents a live performance asset that can be transferred through tipping competition.
Per-Event Contract Deployment
The factory deploys dedicated contracts for each event using CREATE2 for deterministic addresses:
Storage Optimization
The contract uses optimized storage packing to minimize gas costs:
struct EventData {
address creator; // 20 bytes (slot 0)
address KioskAddress; // 20 bytes (slot 1)
address curationAddress; // 20 bytes (slot 2)
uint96 startDate; // 12 bytes (packed with creator)
uint96 eventDuration; // 12 bytes (packed with KioskAddress)
uint96 reservePrice; // 12 bytes (packed with curationAddress)
bool finalized; // 1 byte (packed with reservePrice)
string metadataURI; // separate slot
string artCategory; // separate slot
}
This packing reduces storage from 9 slots to 5 slots per event, saving approximately 80,000 gas per event creation.
Permission Architecture
Access Control Model
The EventFactory implements a permission delegation system through the EventManager:
- Event Creator: Original NFT holder, full control
- EventManager: Authorized contract for metadata and price updates
- Delegated Addresses: Granted specific permissions through delegation proxies
Authorized Operations
Only the EventManager can call restricted functions:
function setMetadataURI(uint256 eventId, string memory newMetadataURI) external {
if (msg.sender != eventManagerContract) revert OnlyEventManager();
if (events[eventId].finalized) revert EventAlreadyFinalized();
events[eventId].metadataURI = newMetadataURI;
_setTokenURI(eventId, newMetadataURI);
emit MetadataUpdated(eventId, newMetadataURI);
}
Event Finalization Logic
The factory handles the complex logic for transferring NFTs based on tipping results:
function finalizeAndTransfer(uint256 eventId) external {
if (msg.sender != eventManagerContract) revert OnlyEventManager();
EventData storage eventData = events[eventId];
// Verify event has ended
uint256 eventEndTime = eventData.startDate + (eventData.eventDuration * 60);
if (block.timestamp <= eventEndTime) revert EventNotEndedYet();
// Check reserve price through LiveTipping
ILiveTipping tippingContract = ILiveTipping(liveTippingContract);
uint256 totalTips = tippingContract.getTotalTips(eventId);
if (totalTips < eventData.reservePrice) revert ReservePriceNotMet();
address highestTipper = tippingContract.getHighestTipper(eventId);
if (highestTipper == address(0)) revert NoTippers();
// Transfer NFT to highest tipper
eventData.finalized = true;
_transfer(eventData.creator, highestTipper, eventId);
emit EventFinalizedAndTransferred(eventId, highestTipper);
}
Curation Integration
EventFactory provides optional curation contract deployment:
function deployCurationForEvent(
uint256 eventId,
uint256 scope,
string calldata description
) external returns (address curationAddress) {
require(events[eventId].creator == msg.sender, "Only event creator");
require(events[eventId].curationAddress == address(0), "Already deployed");
require(scope >= 1 && scope <= 3, "Invalid scope");
// Deploy using CREATE2 for deterministic address
curationAddress = EventFactoryLib.deployCuration(
eventId, address(this), msg.sender, scope, description, distributorContract
);
events[eventId].curationAddress = curationAddress;
// Auto-register with Distributor
EventFactoryLib.registerCurationWithDistributor(
eventId, curationAddress, distributorContract
);
emit CurationDeployed(eventId, msg.sender, curationAddress, scope);
}
Gas Optimization Features
Deterministic Contract Deployment
Using CREATE2 enables predictable addresses and reduces lookup costs:
// TicketKiosk deployment
bytes32 salt = keccak256(abi.encodePacked(eventId, "ticketkiosk"));
address ticketKioskAddress = Create2.deploy(0, salt, bytecode);
// Curation deployment
bytes32 salt = keccak256(abi.encodePacked(eventId, "curation"));
address curationAddress = Create2.deploy(0, salt, bytecode);
Library Separation
EventFactoryLib contains deployment logic to keep the main contract under the 24KB limit:
library EventFactoryLib {
function deployTicketKiosk(...) external returns (address) {
bytes memory bytecode = abi.encodePacked(
type(TicketKiosk).creationCode,
abi.encode(eventId, factoryAddress, creator, ...)
);
return Create2.deploy(0, salt, bytecode);
}
}
Integration Points
External Contract Registration
During event creation, the factory automatically registers with dependent contracts:
function registerWithExternalContracts(
uint256 eventId,
address creator,
uint256 startDate,
uint256 eventDuration,
uint256 reservePrice,
address distributorContract,
address liveTippingContract
) external {
// Register for revenue distribution
IDistributor(distributorContract).registerEvent(eventId, creator);
// Register for tipping competition
ILiveTipping(liveTippingContract).registerEvent(
eventId, creator, startDate, eventDuration, reservePrice
);
}
Query Interface
The factory provides comprehensive view functions for frontend integration:
// Get complete event data
function getEvent(uint256 eventId) external view returns (EventData memory);
// Get creator's events
function getCreatorEvents(address creator) external view returns (uint256[] memory);
// Get all deployed kiosks
function getAllTicketKiosks() external view returns (uint256[] memory, address[] memory);
Design Advantages
- Single Source of Truth: All event data flows through one contract
- Automatic Integration: Contract registration handled during creation
- Gas Efficient: Storage packing and CREATE2 deployment optimization
- Flexible Metadata: Dynamic URI updates through authorized managers
- Creator-Friendly: Simple interface with complex logic handled internally
Testnet Considerations
Centralization
- Owner controls treasury receiver and can update contract addresses, this will be decentralized through multi-sig on main net.
- EventManager authorization is binary - either full access or none - this will be improved through dynamic, deterministic proxies.
Technical Limitations
- 96-bit limitations on dates and prices may become insufficient over time, storage will be expanded before main net release, after additional bytecode size optimizations (read below).
- String storage for metadata and categories is not gas-optimized - this will substantially reduce EventFactory’s size, allowing further improvements (see storage limitation above)
- No batch operations for multiple event management. This can be improved in a v2/v3, once implemented app-wide account abstraction.
As it is at its first release, current EventFactory’s design prioritizes flexibility - this allows us to iterate and scale faster before landing to a more stable, governance-led release of the protocol.