From a2d855872e3175723598e18cb6e5c5e9988c03fa Mon Sep 17 00:00:00 2001 From: David Dada Date: Wed, 10 Sep 2025 03:47:17 +0100 Subject: [PATCH 01/23] chore: update dependencies --- lib/contracts | 2 +- lib/erc2535-diamond-template | 2 +- lib/forge-std | 2 +- lib/solady | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/contracts b/lib/contracts index 2bd70ff..bce75f9 160000 --- a/lib/contracts +++ b/lib/contracts @@ -1 +1 @@ -Subproject commit 2bd70ff3fb5f1c0e562425b4d5312f619d9f2720 +Subproject commit bce75f985558fad3d06ee1b86f224f0cfb783631 diff --git a/lib/erc2535-diamond-template b/lib/erc2535-diamond-template index cbc0de4..ac991b3 160000 --- a/lib/erc2535-diamond-template +++ b/lib/erc2535-diamond-template @@ -1 +1 @@ -Subproject commit cbc0de4c7e72210150a56b69a00bf03f2c22a9b2 +Subproject commit ac991b3dca8fa854a850de039bb94be4886136fc diff --git a/lib/forge-std b/lib/forge-std index 8bbcf6e..551a2d3 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 8bbcf6e3f8f62f419e5429a0bd89331c85c37824 +Subproject commit 551a2d30d7fecba7092ab45a587b5268149a48fb diff --git a/lib/solady b/lib/solady index 33b4b98..208e4f3 160000 --- a/lib/solady +++ b/lib/solady @@ -1 +1 @@ -Subproject commit 33b4b98e350bbcba6aa85642957c313e98b5f911 +Subproject commit 208e4f31cfae26e4983eb95c3488a14fdc497ad7 From 59f8440ade4dbb359f5c3e36ef12c6c274687dce Mon Sep 17 00:00:00 2001 From: David Dada Date: Sun, 12 Oct 2025 15:24:25 +0100 Subject: [PATCH 02/23] Update .gitignore to exclude broadcast files Added '*broadcast/' to .gitignore to ensure all broadcast directories are ignored --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 864e093..52f6b95 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ out/ !/broadcast /broadcast/*/31337/ /broadcast/**/dry-run/ +*broadcast/ # Docs docs/ From b4560cacae61e9eeb13e0864b7d0a95cbbeceefa Mon Sep 17 00:00:00 2001 From: David Dada Date: Sun, 12 Oct 2025 16:03:39 +0100 Subject: [PATCH 03/23] Add Crytic export directory to .gitignore Added 'crytic-export/' to .gitignore to prevent Crytic analysis output files from being tracked in version control. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 52f6b95..4985413 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ out/ /broadcast/**/dry-run/ *broadcast/ +# Crytic +crytic-export/ + # Docs docs/ From f55f2af5bcc50235e33f715da60a2c3c09928d16 Mon Sep 17 00:00:00 2001 From: David Dada Date: Sun, 12 Oct 2025 18:26:18 +0100 Subject: [PATCH 04/23] Sort Imports --- foundry.toml | 3 +++ script/DeployHostItTickets.s.sol | 14 +++++++------- script/helper/DeployHostItTicketsHelper.sol | 4 ++-- src/facets/FactoryFacet.sol | 5 +++-- src/facets/MarketplaceFacet.sol | 2 +- src/inits/HostItInit.sol | 2 +- src/interfaces/IFactory.sol | 2 +- src/interfaces/ITicket.sol | 2 +- src/libs/LibCheckIn.sol | 6 +++--- src/libs/LibFactory.sol | 16 ++++++++-------- src/libs/LibMarketplace.sol | 10 +++++----- src/libs/Ticket.sol | 20 +++++++++++--------- test/Factory.t.sol | 4 ++-- test/Marketplace.t.sol | 4 ++-- test/Ticket.t.sol | 8 ++++---- test/states/DeployedHostItTickets.sol | 14 +++++++------- 16 files changed, 61 insertions(+), 55 deletions(-) diff --git a/foundry.toml b/foundry.toml index c6a2dc8..dfe8a8d 100644 --- a/foundry.toml +++ b/foundry.toml @@ -16,6 +16,9 @@ remappings = [ ffi = true optimizer_runs = 30_000 +[fmt] +sort_imports = true + [rpc_endpoints] # mainnet eth-mainnet = "${ETH_MAINNET_URL}" diff --git a/script/DeployHostItTickets.s.sol b/script/DeployHostItTickets.s.sol index 2e6c611..456bf8c 100644 --- a/script/DeployHostItTickets.s.sol +++ b/script/DeployHostItTickets.s.sol @@ -1,22 +1,22 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {Script} from "forge-std/Script.sol"; import {DiamondCutFacet} from "@diamond/facets/DiamondCutFacet.sol"; import {DiamondLoupeFacet} from "@diamond/facets/DiamondLoupeFacet.sol"; import {OwnableRolesFacet} from "@diamond/facets/OwnableRolesFacet.sol"; -import {MultiInit} from "@diamond/initializers/MultiInit.sol"; import {ERC165Init} from "@diamond/initializers/ERC165Init.sol"; -import {HostItInit} from "@ticket/inits/HostItInit.sol"; +import {MultiInit} from "@diamond/initializers/MultiInit.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {DeployHostItTicketsHelper} from "@ticket-script/helper/DeployHostItTicketsHelper.sol"; +import {LibAddressesAndFees} from "@ticket-script/helper/LibAddressesAndFees.sol"; import {HostItTickets} from "@ticket/HostItTickets.sol"; -import {FactoryFacet} from "@ticket/facets/FactoryFacet.sol"; import {CheckInFacet} from "@ticket/facets/CheckInFacet.sol"; +import {FactoryFacet} from "@ticket/facets/FactoryFacet.sol"; import {MarketplaceFacet} from "@ticket/facets/MarketplaceFacet.sol"; -import {AddressesAndFees} from "@ticket-script/helper/AddressesAndFees.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {HostItInit} from "@ticket/inits/HostItInit.sol"; import {Ticket} from "@ticket/libs/Ticket.sol"; import {TicketProxy} from "@ticket/libs/TicketProxy.sol"; -import {DeployHostItTicketsHelper} from "@ticket-script/helper/DeployHostItTicketsHelper.sol"; +import {Script} from "forge-std/Script.sol"; contract DeployHostItTicketsTest is Script, DeployHostItTicketsHelper { function run() public returns (address hostIt_) { diff --git a/script/helper/DeployHostItTicketsHelper.sol b/script/helper/DeployHostItTicketsHelper.sol index 786eb37..51d9916 100644 --- a/script/helper/DeployHostItTicketsHelper.sol +++ b/script/helper/DeployHostItTicketsHelper.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {HelperContract} from "@diamond-test/helpers/HelperContract.sol"; +import {DiamondArgs, FacetCut, FacetCutAction} from "@diamond-storage/DiamondStorage.sol"; +import {GetSelectors} from "@diamond-test/helpers/GetSelectors.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; -import {FacetCut, FacetCutAction, DiamondArgs} from "@diamond-storage/DiamondStorage.sol"; abstract contract DeployHostItTicketsHelper is HelperContract, Context { function _createFacetCuts( diff --git a/src/facets/FactoryFacet.sol b/src/facets/FactoryFacet.sol index f5bb3f0..fc1aa83 100644 --- a/src/facets/FactoryFacet.sol +++ b/src/facets/FactoryFacet.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {LibFactory} from "@ticket/libs/LibFactory.sol"; -import {TicketData, FullTicketData} from "@ticket-storage/FactoryStorage.sol"; +import {FullTicketData, TicketData} from "@ticket-storage/FactoryStorage.sol"; import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; +import {IFactory} from "@ticket/interfaces/IFactory.sol"; +import {LibFactory} from "@ticket/libs/LibFactory.sol"; contract FactoryFacet { using LibFactory for *; diff --git a/src/facets/MarketplaceFacet.sol b/src/facets/MarketplaceFacet.sol index 01c931a..e20db52 100644 --- a/src/facets/MarketplaceFacet.sol +++ b/src/facets/MarketplaceFacet.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; +import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; import {IMarketplace} from "@ticket/interfaces/IMarketplace.sol"; import {LibMarketplace} from "@ticket/libs/LibMarketplace.sol"; -import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; contract MarketplaceFacet is IMarketplace { using LibMarketplace for *; diff --git a/src/inits/HostItInit.sol b/src/inits/HostItInit.sol index b3de94c..458c138 100644 --- a/src/inits/HostItInit.sol +++ b/src/inits/HostItInit.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.30; import {LibDiamond} from "@diamond/libraries/LibDiamond.sol"; +import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; import {ITicket} from "@ticket/interfaces/ITicket.sol"; import {LibFactory} from "@ticket/libs/LibFactory.sol"; import {LibMarketplace} from "@ticket/libs/LibMarketplace.sol"; -import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; event HostItInitialized(); diff --git a/src/interfaces/IFactory.sol b/src/interfaces/IFactory.sol index 19cf6f6..c7fb45e 100644 --- a/src/interfaces/IFactory.sol +++ b/src/interfaces/IFactory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {TicketData, FullTicketData} from "@ticket-storage/FactoryStorage.sol"; +import {FullTicketData, TicketData} from "@ticket-storage/FactoryStorage.sol"; import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; interface IFactory { diff --git a/src/interfaces/ITicket.sol b/src/interfaces/ITicket.sol index 0ef43dd..e626ba1 100644 --- a/src/interfaces/ITicket.sol +++ b/src/interfaces/ITicket.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; +import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; interface ITicket is IERC721Metadata, IERC721Enumerable { /// @notice Emitted when the base URI is updated diff --git a/src/libs/LibCheckIn.sol b/src/libs/LibCheckIn.sol index 82299e1..fc7829b 100644 --- a/src/libs/LibCheckIn.sol +++ b/src/libs/LibCheckIn.sol @@ -3,10 +3,10 @@ pragma solidity 0.8.30; import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {CheckInStorage, CHECKIN_STORAGE_LOCATION} from "@ticket-storage/CheckInStorage.sol"; -import {LibFactory} from "@ticket/libs/LibFactory.sol"; -import {ITicket} from "@ticket/interfaces/ITicket.sol"; +import {CHECKIN_STORAGE_LOCATION, CheckInStorage} from "@ticket-storage/CheckInStorage.sol"; import {ExtraTicketData} from "@ticket-storage/FactoryStorage.sol"; +import {ITicket} from "@ticket/interfaces/ITicket.sol"; +import {LibFactory} from "@ticket/libs/LibFactory.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) import "@ticket-errors/CheckInErrors.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) diff --git a/src/libs/LibFactory.sol b/src/libs/LibFactory.sol index a5b1b2f..68f4538 100644 --- a/src/libs/LibFactory.sol +++ b/src/libs/LibFactory.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; +import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol"; +import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {TicketCreated, TicketUpdated} from "@ticket-logs/FactoryLogs.sol"; import { - FactoryStorage, - TicketData, ExtraTicketData, + FACTORY_STORAGE_LOCATION, + FactoryStorage, FullTicketData, - FACTORY_STORAGE_LOCATION + TicketData } from "@ticket-storage/FactoryStorage.sol"; -import {LibMarketplace} from "@ticket/libs/LibMarketplace.sol"; import {FeeType, MarketplaceStorage} from "@ticket-storage/MarketplaceStorage.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol"; -import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +import {ITicket} from "@ticket/interfaces/ITicket.sol"; import {LibContext} from "@ticket/libs/LibContext.sol"; -import {Ticket} from "@ticket/libs/Ticket.sol"; +import {LibMarketplace} from "@ticket/libs/LibMarketplace.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) import "@ticket-errors/FactoryErrors.sol"; diff --git a/src/libs/LibMarketplace.sol b/src/libs/LibMarketplace.sol index 26a3190..fd5e369 100644 --- a/src/libs/LibMarketplace.sol +++ b/src/libs/LibMarketplace.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; +import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol"; +import {ACCOUNT_V3_IMPLEMENTATION, ERC6551_REGISTRY} from "@ticket-script/helper/LibAddressesAndFees.sol"; +import {ExtraTicketData} from "@ticket-storage/FactoryStorage.sol"; +import {FeeType, MARKETPLACE_STORAGE_LOCATION, MarketplaceStorage} from "@ticket-storage/MarketplaceStorage.sol"; import {ITicket} from "@ticket/interfaces/ITicket.sol"; import {LibContext} from "@ticket/libs/LibContext.sol"; import {LibFactory} from "@ticket/libs/LibFactory.sol"; -import {ExtraTicketData} from "@ticket-storage/FactoryStorage.sol"; -import {FeeType, MarketplaceStorage, MARKETPLACE_STORAGE_LOCATION} from "@ticket-storage/MarketplaceStorage.sol"; import {IERC6551Registry} from "erc6551/src/interfaces/IERC6551Registry.sol"; -import {ACCOUNT_V3_IMPLEMENTATION, ERC6551_REGISTRY} from "@ticket-script/helper/AddressesAndFees.sol"; +import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) import "@ticket-logs/MarketplaceLogs.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) diff --git a/src/libs/Ticket.sol b/src/libs/Ticket.sol index 01008fc..d21da2c 100644 --- a/src/libs/Ticket.sol +++ b/src/libs/Ticket.sol @@ -1,17 +1,19 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -import {ERC721EnumerableUpgradeable} from - "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; -import {ERC721RoyaltyUpgradeable} from - "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721RoyaltyUpgradeable.sol"; -import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import { + ERC721EnumerableUpgradeable +} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import { + ERC721RoyaltyUpgradeable +} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721RoyaltyUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {ITicket} from "@ticket/interfaces/ITicket.sol"; /* diff --git a/test/Factory.t.sol b/test/Factory.t.sol index 8b717e6..bae50d7 100644 --- a/test/Factory.t.sol +++ b/test/Factory.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {TicketData, ExtraTicketData, FullTicketData} from "@ticket-storage/FactoryStorage.sol"; -import {DeployedHostItTickets} from "@ticket-test/states/DeployedHostItTickets.sol"; import {TicketCreated, TicketUpdated} from "@ticket-logs/FactoryLogs.sol"; +import {ExtraTicketData, FullTicketData, TicketData} from "@ticket-storage/FactoryStorage.sol"; +import {DeployedHostItTickets} from "@ticket-test/states/DeployedHostItTickets.sol"; contract FactoryTest is DeployedHostItTickets { function test_createFreeTicket() public { diff --git a/test/Marketplace.t.sol b/test/Marketplace.t.sol index 69b0a89..440cddd 100644 --- a/test/Marketplace.t.sol +++ b/test/Marketplace.t.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.30; import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; -import {ITicket} from "@ticket/interfaces/ITicket.sol"; -import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; import {FullTicketData} from "@ticket-storage/FactoryStorage.sol"; +import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; import {DeployedHostItTickets} from "@ticket-test/states/DeployedHostItTickets.sol"; +import {ITicket} from "@ticket/interfaces/ITicket.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) import "@ticket-logs/MarketplaceLogs.sol"; diff --git a/test/Ticket.t.sol b/test/Ticket.t.sol index 892169b..48975ca 100644 --- a/test/Ticket.t.sol +++ b/test/Ticket.t.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {Test} from "forge-std/Test.sol"; -import {Ticket} from "@ticket/libs/Ticket.sol"; -import {ITicket} from "@ticket/interfaces/ITicket.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol"; +import {ITicket} from "@ticket/interfaces/ITicket.sol"; +import {Ticket} from "@ticket/libs/Ticket.sol"; +import {Test} from "forge-std/Test.sol"; contract TicketTest is Test { using Clones for address; diff --git a/test/states/DeployedHostItTickets.sol b/test/states/DeployedHostItTickets.sol index 544bf3b..40a20fa 100644 --- a/test/states/DeployedHostItTickets.sol +++ b/test/states/DeployedHostItTickets.sol @@ -1,18 +1,18 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; import {IDiamondCut} from "@diamond/interfaces/IDiamondCut.sol"; import {IDiamondLoupe} from "@diamond/interfaces/IDiamondLoupe.sol"; -import {IFactory} from "@ticket/interfaces/IFactory.sol"; +import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; +import {DeployHostItTicketsTest} from "@ticket-script/DeployHostItTickets.s.sol"; +import {ERC6551_REGISTRY} from "@ticket-script/helper/LibAddressesAndFees.sol"; +import {TicketData} from "@ticket-storage/FactoryStorage.sol"; +import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; import {ICheckIn} from "@ticket/interfaces/ICheckIn.sol"; +import {IFactory} from "@ticket/interfaces/IFactory.sol"; import {IMarketplace} from "@ticket/interfaces/IMarketplace.sol"; -import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; -import {TicketData} from "@ticket-storage/FactoryStorage.sol"; -import {DeployHostItTicketsTest} from "@ticket-script/DeployHostItTickets.s.sol"; -import {HelperContract} from "@diamond-test/helpers/HelperContract.sol"; import {ERC6551Registry} from "erc6551/src/ERC6551Registry.sol"; -import {ERC6551_REGISTRY} from "@ticket-script/helper/AddressesAndFees.sol"; +import {Test} from "forge-std/Test.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) import "@ticket-logs/MarketplaceLogs.sol"; From 13f8b0017aa5d8075d97bebacb205bf7c6a55981 Mon Sep 17 00:00:00 2001 From: David Dada Date: Sun, 12 Oct 2025 18:27:51 +0100 Subject: [PATCH 05/23] Rearrange rpc endpoints and verifier urls --- foundry.toml | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/foundry.toml b/foundry.toml index dfe8a8d..7de02d2 100644 --- a/foundry.toml +++ b/foundry.toml @@ -20,31 +20,25 @@ optimizer_runs = 30_000 sort_imports = true [rpc_endpoints] -# mainnet -eth-mainnet = "${ETH_MAINNET_URL}" -base = "${BASE_MAINNET_URL}" -lisk = "${LISK_MAINNET_URL}" -arbitrum-one = "${ARBITRUM_MAINNET_URL}" -avalanche = "${AVALANCHE_MAINNET_URL}" -# testnets +mainnet = "${ETH_MAINNET_URL}" sepolia = "${ETH_SEPOLIA_URL}" +base = "${BASE_MAINNET_URL}" base-sepolia = "${BASE_SEPOLIA_URL}" +lisk = "${LISK_MAINNET_URL}" lisk-sepolia = "${LISK_SEPOLIA_URL}" +arbitrum-one = "${ARBITRUM_MAINNET_URL}" arbitrum-sepolia = "${ARBITRUM_SEPOLIA_URL}" +avalanche = "${AVALANCHE_MAINNET_URL}" avalanche-fuji = "${AVALANCHE_FUJI_URL}" [etherscan] -# mainnet -eth-mainnet = { key = "${ETHERSCAN_API_KEY}" } -base = { key = "${ETHERSCAN_API_KEY}" } -lisk = { key = "123", url = "${LISK_VERIFIER_URL}" } -arbitrum-one = { key = "${ETHERSCAN_API_KEY}" } -avalanche = { key = "verifyContract", url = "${AVALANCHE_VERIFIER_URL}" } -# testnets +mainnet = { key = "${ETHERSCAN_API_KEY}" } sepolia = { key = "${ETHERSCAN_API_KEY}" } +base = { key = "${ETHERSCAN_API_KEY}" } base-sepolia = { key = "${ETHERSCAN_API_KEY}" } +lisk = { key = "123", url = "${LISK_VERIFIER_URL}" } lisk-sepolia = { key = "123", url = "${LISK_SEPOLIA_VERIFIER_URL}" } +arbitrum-one = { key = "${ETHERSCAN_API_KEY}" } arbitrum-sepolia = { key = "${ETHERSCAN_API_KEY}" } +avalanche = { key = "verifyContract", url = "${AVALANCHE_VERIFIER_URL}" } avalanche-fuji = { key = "verifyContract", url = "${AVALANCHE_FUJI_VERIFIER_URL}" } - -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options From fbe6ec0479c71813a29e2504fc73cf1f7b127b07 Mon Sep 17 00:00:00 2001 From: David Dada Date: Sun, 12 Oct 2025 23:31:22 +0100 Subject: [PATCH 06/23] Increase ticketId to uint64 --- src/facets/CheckInFacet.sol | 16 +++--- src/facets/FactoryFacet.sol | 16 +++--- src/facets/MarketplaceFacet.sol | 14 +++--- src/interfaces/ICheckIn.sol | 14 +++--- src/interfaces/IFactory.sol | 16 +++--- src/interfaces/IMarketplace.sol | 14 +++--- src/libs/LibCheckIn.sol | 23 ++++----- src/libs/LibFactory.sol | 66 ++++++++++++++----------- src/libs/LibMarketplace.sol | 22 ++++----- src/libs/errors/FactoryErrors.sol | 2 +- src/libs/logs/CheckInLogs.sol | 6 +-- src/libs/logs/FactoryLogs.sol | 4 +- src/libs/logs/MarketplaceLogs.sol | 6 +-- src/libs/storage/CheckInStorage.sol | 4 +- src/libs/storage/FactoryStorage.sol | 8 +-- src/libs/storage/MarketplaceStorage.sol | 6 +-- test/CheckIn.t.sol | 6 +-- test/Factory.t.sol | 14 +++--- test/Marketplace.t.sol | 16 +++--- test/states/DeployedHostItTickets.sol | 8 +-- 20 files changed, 141 insertions(+), 140 deletions(-) diff --git a/src/facets/CheckInFacet.sol b/src/facets/CheckInFacet.sol index cee36d1..686fa1a 100644 --- a/src/facets/CheckInFacet.sol +++ b/src/facets/CheckInFacet.sol @@ -4,21 +4,21 @@ pragma solidity 0.8.30; import {LibCheckIn} from "@ticket/libs/LibCheckIn.sol"; contract CheckInFacet { - using LibCheckIn for uint56; + using LibCheckIn for uint64; //*////////////////////////////////////////////////////////////////////////// // EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function checkIn(uint56 _ticketId, address _ticketOwner, uint256 _tokenId) external { + function checkIn(uint64 _ticketId, address _ticketOwner, uint256 _tokenId) external { _ticketId._checkin(_ticketOwner, _tokenId); } - function addTicketAdmins(uint56 _ticketId, address[] calldata _admins) external { + function addTicketAdmins(uint64 _ticketId, address[] calldata _admins) external { _ticketId._addTicketAdmins(_admins); } - function removeTicketAdmins(uint56 _ticketId, address[] calldata _admins) external { + function removeTicketAdmins(uint64 _ticketId, address[] calldata _admins) external { _ticketId._removeTicketAdmins(_admins); } @@ -26,19 +26,19 @@ contract CheckInFacet { // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function isCheckedIn(uint56 _ticketId, address _ticketOwner) external view returns (bool) { + function isCheckedIn(uint64 _ticketId, address _ticketOwner) external view returns (bool) { return _ticketId._isCheckedIn(_ticketOwner); } - function isCheckedInForDay(uint56 _ticketId, uint8 _day, address _ticketOwner) external view returns (bool) { + function isCheckedInForDay(uint64 _ticketId, uint8 _day, address _ticketOwner) external view returns (bool) { return _ticketId._isCheckedInForDay(_day, _ticketOwner); } - function getCheckedIn(uint56 _ticketId) external view returns (address[] memory) { + function getCheckedIn(uint64 _ticketId) external view returns (address[] memory) { return _ticketId._getCheckedIn(); } - function getCheckedInForDay(uint56 _ticketId, uint8 _day) external view returns (address[] memory) { + function getCheckedInForDay(uint64 _ticketId, uint8 _day) external view returns (address[] memory) { return _ticketId._getCheckedInForDay(_day); } } diff --git a/src/facets/FactoryFacet.sol b/src/facets/FactoryFacet.sol index fc1aa83..8edd7cc 100644 --- a/src/facets/FactoryFacet.sol +++ b/src/facets/FactoryFacet.sol @@ -19,7 +19,7 @@ contract FactoryFacet { _ticketData._createTicket(_feeTypes, _fees); } - function updateTicket(TicketData calldata _ticketData, uint56 _ticketId) external { + function updateTicket(TicketData calldata _ticketData, uint64 _ticketId) external { _ticketData._updateTicket(_ticketId); } @@ -27,15 +27,15 @@ contract FactoryFacet { // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function ticketCount() public view returns (uint56) { + function ticketCount() public view returns (uint64) { return LibFactory._getTicketCount(); } - function ticketExists(uint56 _ticketId) public view returns (bool) { + function ticketExists(uint64 _ticketId) public view returns (bool) { return _ticketId._ticketExists(); } - function ticketData(uint56 _ticketId) public view returns (FullTicketData memory) { + function ticketData(uint64 _ticketId) public view returns (FullTicketData memory) { return _ticketId._getFullTicketData(); } @@ -43,7 +43,7 @@ contract FactoryFacet { return LibFactory._getAllFullTicketData(); } - function adminTickets(address _ticketAdmin) public view returns (uint56[] memory) { + function adminTickets(address _ticketAdmin) public view returns (uint64[] memory) { return _ticketAdmin._getAdminTicketIds(); } @@ -59,15 +59,15 @@ contract FactoryFacet { return LibFactory._getHostItTicketHash(); } - function ticketHash(uint56 _ticketId) public pure returns (bytes32) { + function ticketHash(uint64 _ticketId) public pure returns (bytes32) { return _ticketId._generateTicketHash(); } - function mainAdminRole(uint56 _ticketId) public pure returns (uint256) { + function mainAdminRole(uint64 _ticketId) public pure returns (uint256) { return _ticketId._generateMainTicketAdminRole(); } - function ticketAdminRole(uint56 _ticketId) public pure returns (uint256) { + function ticketAdminRole(uint64 _ticketId) public pure returns (uint256) { return _ticketId._generateTicketAdminRole(); } } diff --git a/src/facets/MarketplaceFacet.sol b/src/facets/MarketplaceFacet.sol index e20db52..a79558f 100644 --- a/src/facets/MarketplaceFacet.sol +++ b/src/facets/MarketplaceFacet.sol @@ -12,15 +12,15 @@ contract MarketplaceFacet is IMarketplace { // EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function mintTicket(uint56 _ticketId, FeeType _feeType, address _buyer) external payable returns (uint40) { + function mintTicket(uint64 _ticketId, FeeType _feeType, address _buyer) external payable returns (uint40) { return _ticketId._mintTicket(_feeType, _buyer); } - function setTicketFees(uint56 _ticketId, FeeType[] calldata _feeTypes, uint256[] calldata _fees) external { + function setTicketFees(uint64 _ticketId, FeeType[] calldata _feeTypes, uint256[] calldata _fees) external { _ticketId._setTicketFees(_feeTypes, _fees); } - function withdrawTicketBalance(uint56 _ticketId, FeeType _feeType, address _to) external { + function withdrawTicketBalance(uint64 _ticketId, FeeType _feeType, address _to) external { _ticketId._withdrawTicketBalance(_feeType, _to); } @@ -32,7 +32,7 @@ contract MarketplaceFacet is IMarketplace { // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function isFeeEnabled(uint56 _ticketId, FeeType _feeType) external view returns (bool) { + function isFeeEnabled(uint64 _ticketId, FeeType _feeType) external view returns (bool) { return _ticketId._isFeeEnabled(_feeType); } @@ -40,11 +40,11 @@ contract MarketplaceFacet is IMarketplace { return _feeType._getFeeTokenAddress(); } - function getTicketFee(uint56 _ticketId, FeeType _feeType) external view returns (uint256) { + function getTicketFee(uint64 _ticketId, FeeType _feeType) external view returns (uint256) { return _ticketId._getTicketFee(_feeType); } - function getAllFees(uint56 _ticketId, FeeType _feeType) + function getAllFees(uint64 _ticketId, FeeType _feeType) external view returns (uint256 ticketFee_, uint256 hostItFee_, uint256 totalFee_) @@ -52,7 +52,7 @@ contract MarketplaceFacet is IMarketplace { return _ticketId._getFees(_feeType); } - function getTicketBalance(uint56 _ticketId, FeeType _feeType) external view returns (uint256) { + function getTicketBalance(uint64 _ticketId, FeeType _feeType) external view returns (uint256) { return _ticketId._getTicketBalance(_feeType); } diff --git a/src/interfaces/ICheckIn.sol b/src/interfaces/ICheckIn.sol index beec373..b66548c 100644 --- a/src/interfaces/ICheckIn.sol +++ b/src/interfaces/ICheckIn.sol @@ -6,21 +6,21 @@ interface ICheckIn { // EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function checkIn(uint56 _ticketId, address _ticketOwner, uint256 _tokenId) external; + function checkIn(uint64 _ticketId, address _ticketOwner, uint256 _tokenId) external; - function addTicketAdmins(uint56 _ticketId, address[] calldata _admins) external; + function addTicketAdmins(uint64 _ticketId, address[] calldata _admins) external; - function removeTicketAdmins(uint56 _ticketId, address[] calldata _admins) external; + function removeTicketAdmins(uint64 _ticketId, address[] calldata _admins) external; //*////////////////////////////////////////////////////////////////////////// // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function isCheckedIn(uint56 _ticketId, address _ticketOwner) external view returns (bool); + function isCheckedIn(uint64 _ticketId, address _ticketOwner) external view returns (bool); - function isCheckedInForDay(uint56 _ticketId, uint8 _day, address _ticketOwner) external view returns (bool); + function isCheckedInForDay(uint64 _ticketId, uint8 _day, address _ticketOwner) external view returns (bool); - function getCheckedIn(uint56 _ticketId) external view returns (address[] memory); + function getCheckedIn(uint64 _ticketId) external view returns (address[] memory); - function getCheckedInForDay(uint56 _ticketId, uint8 _day) external view returns (address[] memory); + function getCheckedInForDay(uint64 _ticketId, uint8 _day) external view returns (address[] memory); } diff --git a/src/interfaces/IFactory.sol b/src/interfaces/IFactory.sol index c7fb45e..c74b804 100644 --- a/src/interfaces/IFactory.sol +++ b/src/interfaces/IFactory.sol @@ -12,21 +12,21 @@ interface IFactory { function createTicket(TicketData calldata _ticketData, FeeType[] calldata _feeTypes, uint256[] calldata _fees) external; - function updateTicket(TicketData calldata _ticketData, uint56 _ticketId) external; + function updateTicket(TicketData calldata _ticketData, uint64 _ticketId) external; //*////////////////////////////////////////////////////////////////////////// // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function ticketCount() external view returns (uint56); + function ticketCount() external view returns (uint64); - function ticketExists(uint56 _ticketId) external view returns (bool); + function ticketExists(uint64 _ticketId) external view returns (bool); - function ticketData(uint56 _ticketId) external view returns (FullTicketData memory); + function ticketData(uint64 _ticketId) external view returns (FullTicketData memory); function allTicketData() external view returns (FullTicketData[] memory); - function adminTickets(address _ticketAdmin) external view returns (uint56[] memory); + function adminTickets(address _ticketAdmin) external view returns (uint64[] memory); function adminTicketData(address _ticketAdmin) external view returns (FullTicketData[] memory); @@ -36,9 +36,9 @@ interface IFactory { function hostItTicketHash() external pure returns (bytes32); - function ticketHash(uint56 _ticketId) external pure returns (bytes32); + function ticketHash(uint64 _ticketId) external pure returns (bytes32); - function mainAdminRole(uint56 _ticketId) external pure returns (uint256); + function mainAdminRole(uint64 _ticketId) external pure returns (uint256); - function ticketAdminRole(uint56 _ticketId) external pure returns (uint256); + function ticketAdminRole(uint64 _ticketId) external pure returns (uint256); } diff --git a/src/interfaces/IMarketplace.sol b/src/interfaces/IMarketplace.sol index f4457ee..2e8e72b 100644 --- a/src/interfaces/IMarketplace.sol +++ b/src/interfaces/IMarketplace.sol @@ -8,11 +8,11 @@ interface IMarketplace { // EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function mintTicket(uint56 ticketId, FeeType feeType, address buyer) external payable returns (uint40); + function mintTicket(uint64 ticketId, FeeType feeType, address buyer) external payable returns (uint40); - function setTicketFees(uint56 ticketId, FeeType[] calldata feeTypes, uint256[] calldata fees) external; + function setTicketFees(uint64 ticketId, FeeType[] calldata feeTypes, uint256[] calldata fees) external; - function withdrawTicketBalance(uint56 ticketId, FeeType feeType, address to) external; + function withdrawTicketBalance(uint64 ticketId, FeeType feeType, address to) external; function withdrawHostItBalance(FeeType feeType, address to) external; @@ -20,17 +20,17 @@ interface IMarketplace { // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function isFeeEnabled(uint56 ticketId, FeeType feeType) external view returns (bool); + function isFeeEnabled(uint64 ticketId, FeeType feeType) external view returns (bool); function getFeeTokenAddress(FeeType feeType) external view returns (address); - function getTicketFee(uint56 ticketId, FeeType feeType) external view returns (uint256); - function getAllFees(uint56 ticketId, FeeType feeType) + function getTicketFee(uint64 ticketId, FeeType feeType) external view returns (uint256); + function getAllFees(uint64 ticketId, FeeType feeType) external view returns (uint256 ticketFee, uint256 hostItFee, uint256 totalFee); - function getTicketBalance(uint56 ticketId, FeeType feeType) external view returns (uint256); + function getTicketBalance(uint64 ticketId, FeeType feeType) external view returns (uint256); function getHostItBalance(FeeType feeType) external view returns (uint256); diff --git a/src/libs/LibCheckIn.sol b/src/libs/LibCheckIn.sol index fc7829b..fbaab62 100644 --- a/src/libs/LibCheckIn.sol +++ b/src/libs/LibCheckIn.sol @@ -13,7 +13,7 @@ import "@ticket-errors/CheckInErrors.sol"; import "@ticket-logs/CheckInLogs.sol"; library LibCheckIn { - using LibFactory for uint56; + using LibFactory for uint64; using LibOwnableRoles for *; using EnumerableSet for EnumerableSet.AddressSet; @@ -31,7 +31,7 @@ library LibCheckIn { // INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function _checkin(uint56 _ticketId, address _ticketOwner, uint256 _tokenId) internal onlyTicketAdmin(_ticketId) { + function _checkin(uint64 _ticketId, address _ticketOwner, uint256 _tokenId) internal onlyTicketAdmin(_ticketId) { _ticketId._checkTicketExists(); uint40 time = uint40(block.timestamp); @@ -60,7 +60,7 @@ library LibCheckIn { emit CheckedIn(_ticketId, _ticketOwner, _tokenId); } - function _addTicketAdmins(uint56 _ticketId, address[] calldata _admins) internal onlyMainTicketAdmin(_ticketId) { + function _addTicketAdmins(uint64 _ticketId, address[] calldata _admins) internal onlyMainTicketAdmin(_ticketId) { _ticketId._checkTicketExists(); uint256 adminsLength = _admins.length; @@ -73,10 +73,7 @@ library LibCheckIn { } } - function _removeTicketAdmins(uint56 _ticketId, address[] calldata _admins) - internal - onlyMainTicketAdmin(_ticketId) - { + function _removeTicketAdmins(uint64 _ticketId, address[] calldata _admins) internal onlyMainTicketAdmin(_ticketId) { _ticketId._checkTicketExists(); uint256 adminsLength = _admins.length; @@ -92,19 +89,19 @@ library LibCheckIn { //*////////////////////////////////////////////////////////////////////////// // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function _isCheckedIn(uint56 _ticketId, address _ticketOwner) internal view returns (bool) { + function _isCheckedIn(uint64 _ticketId, address _ticketOwner) internal view returns (bool) { return _checkInStorage().checkedIn[_ticketId].contains(_ticketOwner); } - function _isCheckedInForDay(uint56 _ticketId, uint8 _day, address _ticketOwner) internal view returns (bool) { + function _isCheckedInForDay(uint64 _ticketId, uint8 _day, address _ticketOwner) internal view returns (bool) { return _checkInStorage().checkedInByDay[_ticketId][_day].contains(_ticketOwner); } - function _getCheckedIn(uint56 _ticketId) internal view returns (address[] memory) { + function _getCheckedIn(uint64 _ticketId) internal view returns (address[] memory) { return _checkInStorage().checkedIn[_ticketId].values(); } - function _getCheckedInForDay(uint56 _ticketId, uint8 _day) internal view returns (address[] memory) { + function _getCheckedInForDay(uint64 _ticketId, uint8 _day) internal view returns (address[] memory) { return _checkInStorage().checkedInByDay[_ticketId][_day].values(); } @@ -112,12 +109,12 @@ library LibCheckIn { // MODIFIERS //////////////////////////////////////////////////////////////////////////*// - modifier onlyMainTicketAdmin(uint56 _ticketId) { + modifier onlyMainTicketAdmin(uint64 _ticketId) { LibFactory._checkMainTicketAdminRole(_ticketId); _; } - modifier onlyTicketAdmin(uint56 _ticketId) { + modifier onlyTicketAdmin(uint64 _ticketId) { LibFactory._checkTicketAdminRole(_ticketId); _; } diff --git a/src/libs/LibFactory.sol b/src/libs/LibFactory.sol index 68f4538..38e0ca3 100644 --- a/src/libs/LibFactory.sol +++ b/src/libs/LibFactory.sol @@ -60,8 +60,8 @@ library LibFactory { } if (_ticketData.maxTickets == 0) revert MaxTicketsIsZero(); - FactoryStorage storage $ = _factoryStorage(); - uint56 ticketId = ++$.ticketId; + FactoryStorage storage fs = _factoryStorage(); + uint64 ticketId = ++fs.ticketId; address ticketAdmin = LibContext._msgSender(); _grantTicketAdminRoles(ticketAdmin, ticketId); @@ -86,7 +86,7 @@ library LibFactory { emit TicketCreated(ticketId, ticketAdmin, extraTicketData); } - function _updateTicket(TicketData calldata _ticketData, uint56 _ticketId) internal { + function _updateTicket(TicketData calldata _ticketData, uint64 _ticketId) internal { _checkTicketExists(_ticketId); _generateMainTicketAdminRole(_ticketId)._checkRoles(); @@ -142,16 +142,22 @@ library LibFactory { emit TicketUpdated(_ticketId, LibContext._msgSender(), extraTicketData); } - function _grantTicketAdminRoles(address _ticketAdmin, uint56 _ticketId) internal { + //*////////////////////////////////////////////////////////////////////////// + // INTERNAL HELPER FUNCTIONS + //////////////////////////////////////////////////////////////////////////*// + + function _grantTicketAdminRoles(address _ticketAdmin, uint64 _ticketId) private { _ticketAdmin._grantRoles(_generateMainTicketAdminRole(_ticketId)); _ticketAdmin._grantRoles(_generateTicketAdminRole(_ticketId)); } - function _createExtraTicketData(TicketData calldata _ticketData, uint56 _ticketId, address _ticketAdmin) - internal - returns (ExtraTicketData memory extraTicketData_) - { - address ticketProxy = _factoryStorage().ticketProxy; + function _createExtraTicketData( + FactoryStorage storage _fs, + TicketData calldata _ticketData, + uint64 _ticketId, + address _ticketAdmin + ) private returns (ExtraTicketData memory extraTicketData_) { + address ticketProxy = _fs.ticketProxy; if (ticketProxy.code.length == 0) revert TicketImplementationNotSet(); address ticketAddress = ticketProxy.cloneDeterministic(_generateTicketHash(_ticketId)); Ticket(ticketAddress).initialize(address(this), _ticketData.name, _ticketData.symbol, _ticketData.uri); @@ -175,20 +181,24 @@ library LibFactory { // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function _getTicketCount() internal view returns (uint56) { + function _getTicketCount() internal view returns (uint64) { return LibFactory._factoryStorage().ticketId; } - function _ticketExists(uint56 _ticketId) internal view returns (bool) { + function _ticketExists(uint64 _ticketId) internal view returns (bool) { return _ticketId > 0 && _ticketId <= _getTicketCount(); } - function _getExtraTicketData(uint56 _ticketId) internal view returns (ExtraTicketData memory extraTicketData_) { + function _checkTicketExists(uint64 _ticketId) internal view { + if (!_ticketExists(_ticketId)) revert TicketDoesNotExist(_ticketId); + } + + function _getExtraTicketData(uint64 _ticketId) internal view returns (ExtraTicketData memory) { _checkTicketExists(_ticketId); - extraTicketData_ = _factoryStorage().ticketIdToData[_ticketId]; + return _factoryStorage().ticketIdToData[_ticketId]; } - function _getFullTicketData(uint56 _ticketId) internal view returns (FullTicketData memory fullTicketData_) { + function _getFullTicketData(uint64 _ticketId) internal view returns (FullTicketData memory) { ExtraTicketData memory extraTicketData = _getExtraTicketData(_ticketId); Ticket ticket = Ticket(extraTicketData.ticketAddress); fullTicketData_ = FullTicketData({ @@ -210,15 +220,15 @@ library LibFactory { } function _getAllFullTicketData() internal view returns (FullTicketData[] memory fullTicketData_) { - uint56 ticketCount = _getTicketCount(); + uint64 ticketCount = _getTicketCount(); fullTicketData_ = new FullTicketData[](ticketCount); - for (uint56 i; i < ticketCount; ++i) { + for (uint64 i; i < ticketCount; ++i) { fullTicketData_[i] = _getFullTicketData(i + 1); } } - function _getAdminTicketIds(address _ticketAdmin) internal view returns (uint56[] memory adminTicketIds_) { + function _getAdminTicketIds(address _ticketAdmin) internal view returns (uint64[] memory adminTicketIds_) { uint256[] memory adminTicketIds = _factoryStorage().adminTicketIds[_ticketAdmin].values(); assembly { adminTicketIds_ := adminTicketIds @@ -230,27 +240,23 @@ library LibFactory { view returns (FullTicketData[] memory fullTicketData_) { - uint56[] memory adminTicketIds = _getAdminTicketIds(_ticketAdmin); - uint56 ticketCount = uint56(adminTicketIds.length); + uint64[] memory adminTicketIds = _getAdminTicketIds(_ticketAdmin); + uint64 ticketCount = uint64(adminTicketIds.length); fullTicketData_ = new FullTicketData[](ticketCount); - for (uint56 i; i < ticketCount; ++i) { + for (uint64 i; i < ticketCount; ++i) { fullTicketData_[i] = _getFullTicketData(adminTicketIds[i]); } } - function _checkTicketExists(uint56 _ticketId) internal view { - if (!_ticketExists(_ticketId)) revert TicketDoesNotExist(_ticketId); - } - - function _isTicketFree(uint56 _ticketId) internal view returns (bool) { + function _isTicketFree(uint64 _ticketId) internal view returns (bool) { return _factoryStorage().ticketIdToData[_ticketId].isFree; } - function _checkMainTicketAdminRole(uint56 _ticketId) internal view { + function _checkMainTicketAdminRole(uint64 _ticketId) internal view { _generateMainTicketAdminRole(_ticketId)._checkRoles(); } - function _checkTicketAdminRole(uint56 _ticketId) internal view { + function _checkTicketAdminRole(uint64 _ticketId) internal view { _generateTicketAdminRole(_ticketId)._checkRoles(); } @@ -262,7 +268,7 @@ library LibFactory { return HOST_IT_TICKET; } - function _generateTicketHash(uint56 _ticketId) internal pure returns (bytes32 ticketHash_) { + function _generateTicketHash(uint64 _ticketId) internal pure returns (bytes32 ticketHash_) { assembly { let ptr := mload(0x40) mstore(ptr, HOST_IT_TICKET) @@ -271,7 +277,7 @@ library LibFactory { } } - function _generateMainTicketAdminRole(uint56 _ticketId) internal pure returns (uint256 mainTicketAdminRole_) { + function _generateMainTicketAdminRole(uint64 _ticketId) internal pure returns (uint256 mainTicketAdminRole_) { assembly { let ptr := mload(0x40) mstore(ptr, HOST_IT_MAIN_TICKET_ADMIN) @@ -280,7 +286,7 @@ library LibFactory { } } - function _generateTicketAdminRole(uint56 _ticketId) internal pure returns (uint256 ticketAdminRole_) { + function _generateTicketAdminRole(uint64 _ticketId) internal pure returns (uint256 ticketAdminRole_) { assembly { let ptr := mload(0x40) mstore(ptr, HOST_IT_TICKET_ADMIN) diff --git a/src/libs/LibMarketplace.sol b/src/libs/LibMarketplace.sol index fd5e369..5d932a1 100644 --- a/src/libs/LibMarketplace.sol +++ b/src/libs/LibMarketplace.sol @@ -18,7 +18,7 @@ import "@ticket-logs/MarketplaceLogs.sol"; import "@ticket-errors/MarketplaceErrors.sol"; library LibMarketplace { - using LibFactory for uint56; + using LibFactory for uint64; using SafeTransferLib for address; using SafeERC20 for IERC20; @@ -42,7 +42,7 @@ library LibMarketplace { // INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function _mintTicket(uint56 _ticketId, FeeType _feeType, address _buyer) internal returns (uint40 tokenId_) { + function _mintTicket(uint64 _ticketId, FeeType _feeType, address _buyer) internal returns (uint40 tokenId_) { _ticketId._checkTicketExists(); ExtraTicketData memory ticketData = _ticketId._getExtraTicketData(); @@ -84,7 +84,7 @@ library LibMarketplace { emit TicketMinted(_ticketId, _feeType, totalFee, tokenId_); } - function _setTicketFees(uint56 _ticketId, FeeType[] calldata _feeTypes, uint256[] calldata _fees) + function _setTicketFees(uint64 _ticketId, FeeType[] calldata _feeTypes, uint256[] calldata _fees) internal onlyMainTicketAdmin(_ticketId) { @@ -107,14 +107,14 @@ library LibMarketplace { } // TODO - // function _requestRefund(uint56 _ticketId, FeeType _feeType, uint256 _tokenId) internal { - // _ticketId._checkTicketExists(); - // } + function _requestRefund(uint64 _ticketId, FeeType _feeType, uint256 _tokenId) internal { + _ticketId._checkTicketExists(); + } // TODO - // function _fulfillRefund(uint56 _ticketId, FeeType _feeType) internal onlyRoleOrOwner {} + // function _fulfillRefund(uint64 _ticketId, FeeType _feeType) internal onlyRoleOrOwner {} - function _withdrawTicketBalance(uint56 _ticketId, FeeType _feeType, address _to) + function _withdrawTicketBalance(uint64 _ticketId, FeeType _feeType, address _to) internal onlyMainTicketAdmin(_ticketId) { @@ -186,8 +186,6 @@ library LibMarketplace { // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function _isFeeEnabled(uint56 _ticketId, FeeType _feeType) internal view returns (bool) { - return _marketplaceStorage().feeEnabled[_ticketId][_feeType]; } function _getFeeTokenAddress(FeeType _feeType) internal view returns (address tokenAddress_) { @@ -199,7 +197,7 @@ library LibMarketplace { return _marketplaceStorage().ticketFee[_ticketId][_feeType]; } - function _getFees(uint56 _ticketId, FeeType _feeType) + function _getFees(uint64 _ticketId, FeeType _feeType) internal view returns (uint256 ticketFee_, uint256 hostItFee_, uint256 totalFee_) @@ -233,7 +231,7 @@ library LibMarketplace { // MODIFIERS //////////////////////////////////////////////////////////////////////////*// - modifier onlyMainTicketAdmin(uint56 _ticketId) { + modifier onlyMainTicketAdmin(uint64 _ticketId) { LibFactory._checkMainTicketAdminRole(_ticketId); _; } diff --git a/src/libs/errors/FactoryErrors.sol b/src/libs/errors/FactoryErrors.sol index 5678805..45031a9 100644 --- a/src/libs/errors/FactoryErrors.sol +++ b/src/libs/errors/FactoryErrors.sol @@ -12,7 +12,7 @@ error MaxTicketsIsZero(); error ArrayMismatch(); error FeeAlreadySet(FeeType); error ZeroFee(FeeType); -error TicketDoesNotExist(uint56); +error TicketDoesNotExist(uint64); error TicketUseHasCommenced(); error MaxTicketsShouldEqualSupply(); error TicketImplementationNotSet(); diff --git a/src/libs/logs/CheckInLogs.sol b/src/libs/logs/CheckInLogs.sol index 4009f34..4526b09 100644 --- a/src/libs/logs/CheckInLogs.sol +++ b/src/libs/logs/CheckInLogs.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; -event CheckedIn(uint56 indexed ticketId, address indexed ticketOwner, uint256 tokenId); +event CheckedIn(uint64 indexed ticketId, address indexed ticketOwner, uint256 tokenId); -event TicketAdminAdded(uint56 indexed ticketId, address indexed admin); +event TicketAdminAdded(uint64 indexed ticketId, address indexed admin); -event TicketAdminRemoved(uint56 indexed ticketId, address indexed admin); +event TicketAdminRemoved(uint64 indexed ticketId, address indexed admin); diff --git a/src/libs/logs/FactoryLogs.sol b/src/libs/logs/FactoryLogs.sol index 6fd0cc3..e73d9e1 100644 --- a/src/libs/logs/FactoryLogs.sol +++ b/src/libs/logs/FactoryLogs.sol @@ -3,6 +3,6 @@ pragma solidity 0.8.30; import {ExtraTicketData} from "@ticket-storage/FactoryStorage.sol"; -event TicketCreated(uint56 indexed ticketId, address indexed ticketAdmin, ExtraTicketData ticketData); +event TicketCreated(uint64 indexed ticketId, address indexed ticketAdmin, ExtraTicketData ticketData); -event TicketUpdated(uint56 indexed ticketId, address indexed ticketAdmin, ExtraTicketData ticketData); +event TicketUpdated(uint64 indexed ticketId, address indexed ticketAdmin, ExtraTicketData ticketData); diff --git a/src/libs/logs/MarketplaceLogs.sol b/src/libs/logs/MarketplaceLogs.sol index cc1ec38..9f37618 100644 --- a/src/libs/logs/MarketplaceLogs.sol +++ b/src/libs/logs/MarketplaceLogs.sol @@ -3,13 +3,13 @@ pragma solidity 0.8.30; import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; -event TicketFeeSet(uint56 indexed ticketId, FeeType indexed feeType, uint256 fee); +event TicketFeeSet(uint64 indexed ticketId, FeeType indexed feeType, uint256 fee); event TicketFeeAddressSet(FeeType indexed feeType, address indexed token); -event TicketMinted(uint56 indexed ticketId, FeeType indexed feeType, uint256 fee, uint40 tokenId); +event TicketMinted(uint64 indexed ticketId, FeeType indexed feeType, uint256 fee, uint40 tokenId); -event TicketBalanceWithdrawn(uint56 indexed ticketId, FeeType indexed feeType, uint256 fee, address indexed to); +event TicketBalanceWithdrawn(uint64 indexed ticketId, FeeType indexed feeType, uint256 fee, address indexed to); event HostItBalanceWithdrawn(FeeType indexed feeType, uint256 fee, address indexed to); diff --git a/src/libs/storage/CheckInStorage.sol b/src/libs/storage/CheckInStorage.sol index ffb3435..f42e1d3 100644 --- a/src/libs/storage/CheckInStorage.sol +++ b/src/libs/storage/CheckInStorage.sol @@ -7,6 +7,6 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet bytes32 constant CHECKIN_STORAGE_LOCATION = 0xe193d680ae43ded63724eb4ee4d68fd7efbded9778d44414c0bab0177a079700; struct CheckInStorage { - mapping(uint56 => EnumerableSet.AddressSet) checkedIn; - mapping(uint56 => mapping(uint8 => EnumerableSet.AddressSet)) checkedInByDay; + mapping(uint64 => EnumerableSet.AddressSet) checkedIn; + mapping(uint64 => mapping(uint8 => EnumerableSet.AddressSet)) checkedInByDay; } diff --git a/src/libs/storage/FactoryStorage.sol b/src/libs/storage/FactoryStorage.sol index db8d042..399a66a 100644 --- a/src/libs/storage/FactoryStorage.sol +++ b/src/libs/storage/FactoryStorage.sol @@ -8,8 +8,8 @@ bytes32 constant FACTORY_STORAGE_LOCATION = 0x610b7ed6689c503e651500bb8179583591 struct FactoryStorage { address ticketProxy; - uint56 ticketId; - mapping(uint56 => ExtraTicketData) ticketIdToData; + uint64 ticketId; + mapping(uint64 => ExtraTicketData) ticketIdToData; mapping(address => EnumerableSet.UintSet) adminTicketIds; } @@ -25,12 +25,12 @@ struct TicketData { } struct ExtraTicketData { - uint56 id; uint40 createdAt; uint40 updatedAt; uint40 startTime; uint40 endTime; uint40 purchaseStartTime; + uint64 id; uint40 maxTickets; uint40 soldTickets; bool isFree; @@ -39,12 +39,12 @@ struct ExtraTicketData { } struct FullTicketData { - uint56 id; uint40 createdAt; uint40 updatedAt; uint40 startTime; uint40 endTime; uint40 purchaseStartTime; + uint64 id; uint40 maxTickets; uint40 soldTickets; bool isFree; diff --git a/src/libs/storage/MarketplaceStorage.sol b/src/libs/storage/MarketplaceStorage.sol index 7b321e2..b0556d6 100644 --- a/src/libs/storage/MarketplaceStorage.sol +++ b/src/libs/storage/MarketplaceStorage.sol @@ -5,10 +5,10 @@ pragma solidity 0.8.30; bytes32 constant MARKETPLACE_STORAGE_LOCATION = 0x3f09c55b469305b27ecae2a46b3f364669f622316549d801837d9eeba9778d00; struct MarketplaceStorage { - mapping(uint56 => mapping(FeeType => bool)) feeEnabled; - mapping(uint56 => mapping(FeeType => uint256)) ticketFee; + mapping(uint64 => mapping(FeeType => bool)) feeEnabled; + mapping(uint64 => mapping(FeeType => uint256)) ticketFee; mapping(FeeType => address) feeTokenAddress; - mapping(uint56 => mapping(FeeType => uint256)) ticketBalance; + mapping(uint64 => mapping(FeeType => uint256)) ticketBalance; mapping(FeeType => uint256) hostItBalance; } diff --git a/test/CheckIn.t.sol b/test/CheckIn.t.sol index be7a9e2..bbc4b30 100644 --- a/test/CheckIn.t.sol +++ b/test/CheckIn.t.sol @@ -7,7 +7,7 @@ import "@ticket-logs/CheckInLogs.sol"; contract CheckInTest is DeployedHostItTickets { function test_checkIn() public { - (uint56 ticketId, uint40 tokenId) = _mintTicketFree(); + (uint64 ticketId, uint40 tokenId) = _mintTicketFree(); vm.warp(1 days + 1); vm.expectEmit(true, true, true, true, hostIt); emit CheckedIn(ticketId, alice, tokenId); @@ -23,7 +23,7 @@ contract CheckInTest is DeployedHostItTickets { } function test_addTicketAdmins() public { - (uint56 ticketId,) = _mintTicketFree(); + (uint64 ticketId,) = _mintTicketFree(); address[] memory admins = new address[](2); admins[0] = bob; admins[1] = charlie; @@ -41,7 +41,7 @@ contract CheckInTest is DeployedHostItTickets { } function test_removeTicketAdmins() public { - (uint56 ticketId,) = _mintTicketFree(); + (uint64 ticketId,) = _mintTicketFree(); address[] memory admins = new address[](1); admins[0] = bob; checkInFacet.addTicketAdmins(ticketId, admins); diff --git a/test/Factory.t.sol b/test/Factory.t.sol index bae50d7..c67e856 100644 --- a/test/Factory.t.sol +++ b/test/Factory.t.sol @@ -11,7 +11,7 @@ contract FactoryTest is DeployedHostItTickets { vm.expectEmit(true, true, true, false, hostIt); emit TicketCreated(1, owner, extraTicketData); _createFreeTicket(); - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); TicketData memory ticketData = _getFreeTicketData(); FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); assertTrue(factoryFacet.ticketExists(ticketId)); @@ -34,7 +34,7 @@ contract FactoryTest is DeployedHostItTickets { function test_updateFreeTicket() public { _createFreeTicket(); - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); TicketData memory ticketData = _getFreeUpdatedTicketData(); vm.warp(10000); ExtraTicketData memory extraTicketData; @@ -58,7 +58,7 @@ contract FactoryTest is DeployedHostItTickets { vm.expectEmit(true, true, true, false, hostIt); emit TicketCreated(1, owner, extraTicketData); _createPaidTicket(); - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); TicketData memory ticketData = _getPaidTicketData(); FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); assertEq(fullTicketData.name, ticketData.name); @@ -74,7 +74,7 @@ contract FactoryTest is DeployedHostItTickets { function test_updatePaidTicket() public { _createPaidTicket(); - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); TicketData memory ticketData = _getPaidUpdatedTicketData(); vm.warp(10000); ExtraTicketData memory extraTicketData; @@ -151,19 +151,19 @@ contract FactoryTest is DeployedHostItTickets { } function test_ticketHash() public view { - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); bytes32 ticketHash = factoryFacet.ticketHash(ticketId); assertEq(ticketHash, keccak256(abi.encode(keccak256("host.it.ticket"), ticketId))); } function test_mainAdminRole() public view { - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); uint256 mainAdminRole = factoryFacet.mainAdminRole(ticketId); assertEq(mainAdminRole, uint256(keccak256(abi.encode(keccak256("host.it.ticket.main.admin"), ticketId)))); } function test_ticketAdminRole() public view { - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); uint256 ticketAdminRole = factoryFacet.ticketAdminRole(ticketId); assertEq(ticketAdminRole, uint256(keccak256(abi.encode(keccak256("host.it.ticket.admin"), ticketId)))); } diff --git a/test/Marketplace.t.sol b/test/Marketplace.t.sol index 440cddd..eff3dbc 100644 --- a/test/Marketplace.t.sol +++ b/test/Marketplace.t.sol @@ -12,7 +12,7 @@ import "@ticket-logs/MarketplaceLogs.sol"; contract MarketplaceTest is DeployedHostItTickets { function test_mintFreeTicket() public { vm.prank(alice); - (uint56 ticketId, uint40 tokenId) = _mintTicketFree(); + (uint64 ticketId, uint40 tokenId) = _mintTicketFree(); FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); ITicket ticket = ITicket(fullTicketData.ticketAddress); assertEq(ticket.ownerOf(tokenId), alice); @@ -20,7 +20,7 @@ contract MarketplaceTest is DeployedHostItTickets { } function test_mintPaidTicketETH() public { - (uint56 ticketId, uint40 tokenId, uint256 fee, uint256 hostItFee) = _mintTicketETH(); + (uint64 ticketId, uint40 tokenId, uint256 fee, uint256 hostItFee) = _mintTicketETH(); FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); ITicket ticket = ITicket(fullTicketData.ticketAddress); assertEq(ticket.ownerOf(tokenId), alice); @@ -30,7 +30,7 @@ contract MarketplaceTest is DeployedHostItTickets { } function test_mintPaidTicketUSDT() public { - (uint56 ticketId, uint40 tokenId, uint256 fee, uint256 hostItFee,) = _mintTicketUSDT(); + (uint64 ticketId, uint40 tokenId, uint256 fee, uint256 hostItFee,) = _mintTicketUSDT(); FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); ITicket ticket = ITicket(fullTicketData.ticketAddress); assertEq(ticket.ownerOf(tokenId), alice); @@ -40,7 +40,7 @@ contract MarketplaceTest is DeployedHostItTickets { } function test_mintPaidTicketUSDC() public { - (uint56 ticketId, uint40 tokenId, uint256 fee, uint256 hostItFee,) = _mintTicketUSDC(); + (uint64 ticketId, uint40 tokenId, uint256 fee, uint256 hostItFee,) = _mintTicketUSDC(); FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); ITicket ticket = ITicket(fullTicketData.ticketAddress); assertEq(ticket.ownerOf(tokenId), alice); @@ -51,7 +51,7 @@ contract MarketplaceTest is DeployedHostItTickets { function test_setTicketFees() public { _createFreeTicket(); - uint56 ticketId = factoryFacet.ticketCount(); + uint64 ticketId = factoryFacet.ticketCount(); marketplaceFacet.setTicketFees(ticketId, _getFeeTypes(), _getFees()); assertEq(marketplaceFacet.getTicketFee(ticketId, FeeType.ETH), _getFees()[0]); assertEq(marketplaceFacet.getTicketFee(ticketId, FeeType.USDT), _getFees()[1]); @@ -59,7 +59,7 @@ contract MarketplaceTest is DeployedHostItTickets { } function test_withdrawTicketBalanceETH() public { - (uint56 ticketId,, uint256 ethFee,) = _mintTicketETH(); + (uint64 ticketId,, uint256 ethFee,) = _mintTicketETH(); // Check platform balances before withdraw // Withdraw FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); @@ -74,7 +74,7 @@ contract MarketplaceTest is DeployedHostItTickets { } function test_withdrawTicketBalanceUSDT() public { - (uint56 ticketId,, uint256 usdtFee,, ERC20Mock usdt) = _mintTicketUSDT(); + (uint64 ticketId,, uint256 usdtFee,, ERC20Mock usdt) = _mintTicketUSDT(); // Check platform balances before withdraw assertEq(marketplaceFacet.getTicketBalance(ticketId, FeeType.USDT), usdtFee); // Withdraw @@ -90,7 +90,7 @@ contract MarketplaceTest is DeployedHostItTickets { } function test_withdrawTicketBalanceUSDC() public { - (uint56 ticketId,, uint256 usdcFee,, ERC20Mock usdc) = _mintTicketUSDC(); + (uint64 ticketId,, uint256 usdcFee,, ERC20Mock usdc) = _mintTicketUSDC(); // Check platform balances before withdraw FullTicketData memory fullTicketData = factoryFacet.ticketData(ticketId); vm.warp(fullTicketData.endTime + marketplaceFacet.getRefundPeriod()); diff --git a/test/states/DeployedHostItTickets.sol b/test/states/DeployedHostItTickets.sol index 40a20fa..f251675 100644 --- a/test/states/DeployedHostItTickets.sol +++ b/test/states/DeployedHostItTickets.sol @@ -83,7 +83,7 @@ abstract contract DeployedHostItTickets is HelperContract { factoryFacet.updateTicket(_getPaidUpdatedTicketData(), _ticketId); } - function _mintTicketFree() internal returns (uint56 ticketId_, uint40 tokenId_) { + function _mintTicketFree() internal returns (uint64 ticketId_, uint40 tokenId_) { _createFreeTicket(); ticketId_ = factoryFacet.ticketCount(); vm.expectEmit(true, true, true, true, hostIt); @@ -92,7 +92,7 @@ abstract contract DeployedHostItTickets is HelperContract { } /// forge-lint: disable-next-line(mixed-case-function) - function _mintTicketETH() internal returns (uint56 ticketId_, uint40 tokenId_, uint256 fee_, uint256 hostItFee_) { + function _mintTicketETH() internal returns (uint64 ticketId_, uint40 tokenId_, uint256 fee_, uint256 hostItFee_) { _createPaidTicket(); ticketId_ = factoryFacet.ticketCount(); (uint256 fee, uint256 hostItFee, uint256 totalFee) = marketplaceFacet.getAllFees(ticketId_, FeeType.ETH); @@ -111,7 +111,7 @@ abstract contract DeployedHostItTickets is HelperContract { /// forge-lint: disable-next-line(mixed-case-function) function _mintTicketUSDT() internal - returns (uint56 ticketId_, uint40 tokenId_, uint256 fee_, uint256 hostItFee_, ERC20Mock usdt_) + returns (uint64 ticketId_, uint40 tokenId_, uint256 fee_, uint256 hostItFee_, ERC20Mock usdt_) { _createPaidTicket(); ticketId_ = factoryFacet.ticketCount(); @@ -131,7 +131,7 @@ abstract contract DeployedHostItTickets is HelperContract { /// forge-lint: disable-next-line(mixed-case-function) function _mintTicketUSDC() internal - returns (uint56 ticketId_, uint40 tokenId_, uint256 fee_, uint256 hostItFee_, ERC20Mock usdc_) + returns (uint64 ticketId_, uint40 tokenId_, uint256 fee_, uint256 hostItFee_, ERC20Mock usdc_) { _createPaidTicket(); ticketId_ = factoryFacet.ticketCount(); From 5cd08bee929af837e68bd33b2bb37aa48ec9be2f Mon Sep 17 00:00:00 2001 From: David Dada Date: Sun, 12 Oct 2025 23:35:02 +0100 Subject: [PATCH 07/23] Use GetSelectors --- script/helper/DeployHostItTicketsHelper.sol | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/script/helper/DeployHostItTicketsHelper.sol b/script/helper/DeployHostItTicketsHelper.sol index 51d9916..e7dcd81 100644 --- a/script/helper/DeployHostItTicketsHelper.sol +++ b/script/helper/DeployHostItTicketsHelper.sol @@ -5,7 +5,7 @@ import {DiamondArgs, FacetCut, FacetCutAction} from "@diamond-storage/DiamondSto import {GetSelectors} from "@diamond-test/helpers/GetSelectors.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; -abstract contract DeployHostItTicketsHelper is HelperContract, Context { +abstract contract DeployHostItTicketsHelper is GetSelectors, Context { function _createFacetCuts( address _diamondCutFacet, address _diamondLoupeFacet, @@ -14,43 +14,38 @@ abstract contract DeployHostItTicketsHelper is HelperContract, Context { address _checkInFacet, address _marketplaceFacet ) internal returns (FacetCut[] memory cuts_) { - // Create an array of FacetCut entries for standard facets cuts_ = new FacetCut[](6); cuts_[0] = FacetCut({ facetAddress: _diamondCutFacet, action: FacetCutAction.Add, - functionSelectors: _generateSelectors("DiamondCutFacet") + functionSelectors: _getSelectors("DiamondCutFacet") }); cuts_[1] = FacetCut({ facetAddress: _diamondLoupeFacet, action: FacetCutAction.Add, - functionSelectors: _generateSelectors("DiamondLoupeFacet") + functionSelectors: _getSelectors("DiamondLoupeFacet") }); cuts_[2] = FacetCut({ facetAddress: _ownableRolesFacet, action: FacetCutAction.Add, - functionSelectors: _generateSelectors("OwnableRolesFacet") + functionSelectors: _getSelectors("OwnableRolesFacet") }); cuts_[3] = FacetCut({ - facetAddress: _factoryFacet, - action: FacetCutAction.Add, - functionSelectors: _generateSelectors("FactoryFacet") + facetAddress: _factoryFacet, action: FacetCutAction.Add, functionSelectors: _getSelectors("FactoryFacet") }); cuts_[4] = FacetCut({ - facetAddress: _checkInFacet, - action: FacetCutAction.Add, - functionSelectors: _generateSelectors("CheckInFacet") + facetAddress: _checkInFacet, action: FacetCutAction.Add, functionSelectors: _getSelectors("CheckInFacet") }); cuts_[5] = FacetCut({ facetAddress: _marketplaceFacet, action: FacetCutAction.Add, - functionSelectors: _generateSelectors("MarketplaceFacet") + functionSelectors: _getSelectors("MarketplaceFacet") }); } @@ -71,7 +66,6 @@ abstract contract DeployHostItTicketsHelper is HelperContract, Context { initData[1] = abi.encodeWithSignature("initHostIt(address,uint8[],address[])", _ticketProxy, _feeTypes, _addresses); - // Prepare DiamondArgs: owner and init data args_ = DiamondArgs({ owner: _msgSender(), init: _multiInit, From 608d11eddafb87bdc6f028eaba387f66ee6b2e1d Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:37:09 +0100 Subject: [PATCH 08/23] Rename and extend AddressesAndFees library Renamed AddressesAndFees.sol to LibAddressesAndFees.sol and added _getAddressesAndFeesByChainId function to retrieve addresses and fee types based on chain ID. This improves modularity and chain support in the helper library. --- ...sesAndFees.sol => LibAddressesAndFees.sol} | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) rename script/helper/{AddressesAndFees.sol => LibAddressesAndFees.sol} (88%) diff --git a/script/helper/AddressesAndFees.sol b/script/helper/LibAddressesAndFees.sol similarity index 88% rename from script/helper/AddressesAndFees.sol rename to script/helper/LibAddressesAndFees.sol index 60d5ed6..27679a9 100644 --- a/script/helper/AddressesAndFees.sol +++ b/script/helper/LibAddressesAndFees.sol @@ -4,7 +4,49 @@ pragma solidity ^0.8.4; import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; -library AddressesAndFees { +library LibAddressesAndFees { + function _getAddressesAndFeesByChainId(uint256 _chainId) + internal + returns (address[] memory addresses_, uint8[] memory feeTypes_) + { + if (_chainId == 1) { + addresses_ = _getEthereumAddresses(); + feeTypes_ = _getEthereumFeeTypes(); + } else if (_chainId == 8453) { + addresses_ = _getBaseAddresses(); + feeTypes_ = _getBaseFeeTypes(); + } else if (_chainId == 43114) { + addresses_ = _getAvalancheAddresses(); + feeTypes_ = _getAvalancheFeeTypes(); + } else if (_chainId == 42161) { + addresses_ = _getArbitrumOneAddresses(); + feeTypes_ = _getArbitrumOneFeeTypes(); + } else if (_chainId == 1135) { + addresses_ = _getLiskAddresses(); + feeTypes_ = _getLiskFeeTypes(); + } else if (_chainId == 11155111) { + addresses_ = _getEthereumSepoliaAddresses(); + feeTypes_ = _getEthereumSepoliaFeeTypes(); + } else if (_chainId == 84532) { + addresses_ = _getBaseSepoliaAddresses(); + feeTypes_ = _getBaseSepoliaFeeTypes(); + } else if (_chainId == 43113) { + addresses_ = _getAvalancheFujiAddresses(); + feeTypes_ = _getAvalancheFujiFeeTypes(); + } else if (_chainId == 421614) { + addresses_ = _getArbitrumSepoliaAddresses(); + feeTypes_ = _getArbitrumSepoliaFeeTypes(); + } else if (_chainId == 4202) { + addresses_ = _getLiskSepoliaAddresses(); + feeTypes_ = _getLiskSepoliaFeeTypes(); + } else if (_chainId == 31337) { + addresses_ = _getMockAddresses(); + feeTypes_ = _getMockFeeTypes(); + } else { + revert("Chain not supported"); + } + } + //*////////////////////////////////////////////////////////////////////////// // MAINNET ADDRESSES //////////////////////////////////////////////////////////////////////////*// From fe4a0b371fc749682103724a2369e309f104ff40 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:38:38 +0100 Subject: [PATCH 09/23] Implement interfaces for CheckInFacet and FactoryFacet Both CheckInFacet and FactoryFacet contracts now explicitly implement their respective interfaces (ICheckIn and IFactory). This change improves type safety and ensures interface compliance for these facets. --- src/facets/CheckInFacet.sol | 3 ++- src/facets/FactoryFacet.sol | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/facets/CheckInFacet.sol b/src/facets/CheckInFacet.sol index 686fa1a..85cd4d6 100644 --- a/src/facets/CheckInFacet.sol +++ b/src/facets/CheckInFacet.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.30; +import {ICheckIn} from "@ticket/interfaces/ICheckIn.sol"; import {LibCheckIn} from "@ticket/libs/LibCheckIn.sol"; -contract CheckInFacet { +contract CheckInFacet is ICheckIn { using LibCheckIn for uint64; //*////////////////////////////////////////////////////////////////////////// diff --git a/src/facets/FactoryFacet.sol b/src/facets/FactoryFacet.sol index 8edd7cc..3636655 100644 --- a/src/facets/FactoryFacet.sol +++ b/src/facets/FactoryFacet.sol @@ -6,7 +6,7 @@ import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; import {IFactory} from "@ticket/interfaces/IFactory.sol"; import {LibFactory} from "@ticket/libs/LibFactory.sol"; -contract FactoryFacet { +contract FactoryFacet is IFactory { using LibFactory for *; //*////////////////////////////////////////////////////////////////////////// From a178447a9b511b598689586c0900d7dec3aee385 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:39:04 +0100 Subject: [PATCH 10/23] Add hostItFeeBps to MarketplaceStorage struct Introduces a new uint16 field, hostItFeeBps, to the MarketplaceStorage struct for storing fee basis points. Also reorders FeeType enum values for improved clarity. --- src/libs/storage/MarketplaceStorage.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/storage/MarketplaceStorage.sol b/src/libs/storage/MarketplaceStorage.sol index b0556d6..cf93a83 100644 --- a/src/libs/storage/MarketplaceStorage.sol +++ b/src/libs/storage/MarketplaceStorage.sol @@ -10,6 +10,7 @@ struct MarketplaceStorage { mapping(FeeType => address) feeTokenAddress; mapping(uint64 => mapping(FeeType => uint256)) ticketBalance; mapping(FeeType => uint256) hostItBalance; + uint16 hostItFeeBps; } enum FeeType { @@ -18,10 +19,9 @@ enum FeeType { WETH, USDT, USDC, - EURC, USDT0, + EURC, GHO, LINK, - LSK, - DISCOUNT + LSK } From 6d49887a30c5477e7e84a03bf3b5fae4375dfc24 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:39:21 +0100 Subject: [PATCH 11/23] Update ticket structs with new fields and types Expanded TicketData, ExtraTicketData, and FullTicketData structs to include maxTicketsPerUser and isRefundable fields. Changed several time-related fields from uint40 to uint48 for increased range. --- src/libs/storage/FactoryStorage.sol | 32 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/libs/storage/FactoryStorage.sol b/src/libs/storage/FactoryStorage.sol index 399a66a..7d7d139 100644 --- a/src/libs/storage/FactoryStorage.sol +++ b/src/libs/storage/FactoryStorage.sol @@ -14,40 +14,46 @@ struct FactoryStorage { } struct TicketData { - uint40 startTime; - uint40 endTime; - uint40 purchaseStartTime; + uint48 startTime; + uint48 endTime; + uint48 purchaseStartTime; uint40 maxTickets; + uint8 maxTicketsPerUser; bool isFree; + bool isRefundable; string name; string symbol; string uri; } struct ExtraTicketData { - uint40 createdAt; - uint40 updatedAt; - uint40 startTime; - uint40 endTime; - uint40 purchaseStartTime; uint64 id; + uint48 createdAt; + uint48 updatedAt; + uint48 startTime; + uint48 endTime; + uint48 purchaseStartTime; uint40 maxTickets; uint40 soldTickets; + uint8 maxTicketsPerUser; bool isFree; + bool isRefundable; address ticketAdmin; address ticketAddress; } struct FullTicketData { - uint40 createdAt; - uint40 updatedAt; - uint40 startTime; - uint40 endTime; - uint40 purchaseStartTime; uint64 id; + uint48 createdAt; + uint48 updatedAt; + uint48 startTime; + uint48 endTime; + uint48 purchaseStartTime; uint40 maxTickets; uint40 soldTickets; + uint8 maxTicketsPerUser; bool isFree; + bool isRefundable; address ticketAdmin; address ticketAddress; string name; From 176006505fe44d70c5d5d735b7f04fa26d6e1f64 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:40:29 +0100 Subject: [PATCH 12/23] Add medusa.json to .gitignore medusa.json is now ignored to prevent it from being tracked in version control. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4985413..239da05 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ out/ # Crytic crytic-export/ +medusa.json # Docs docs/ From d44d5b410132c6b647b35a360f55c1625c3090ab Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:41:11 +0100 Subject: [PATCH 13/23] Refactor fee/address retrieval in deployment script Updated DeployHostItTickets.s.sol to use LibAddressesAndFees._getAddressesAndFeesByChainId for dynamic fee and address retrieval based on chain ID. Removed DeployHostItTicketsLisk.s.sol as its logic is now handled generically in the main deployment script. --- script/DeployHostItTickets.s.sol | 12 ++--- script/DeployHostItTicketsLisk.s.sol | 65 ---------------------------- 2 files changed, 4 insertions(+), 73 deletions(-) delete mode 100644 script/DeployHostItTicketsLisk.s.sol diff --git a/script/DeployHostItTickets.s.sol b/script/DeployHostItTickets.s.sol index 456bf8c..23f4c70 100644 --- a/script/DeployHostItTickets.s.sol +++ b/script/DeployHostItTickets.s.sol @@ -43,20 +43,16 @@ contract DeployHostItTicketsTest is Script, DeployHostItTicketsHelper { // Deploy Ticket Proxy address ticketProxy = address(new TicketProxy(ticketBeacon)); + (address[] memory addresses, uint8[] memory feeTypes) = + LibAddressesAndFees._getAddressesAndFeesByChainId(block.chainid); + // Deploy HostItTickets diamond hostIt_ = address( new HostItTickets( _createFacetCuts( diamondCutFacet, diamondLoupeFacet, ownableRolesFacet, factoryFacet, checkInFacet, marketplaceFacet ), - _createDiamondArgs( - multiInit, - erc165Init, - hostItInit, - ticketProxy, - AddressesAndFees._getMockFeeTypes(), - AddressesAndFees._getMockAddresses() - ) + _createDiamondArgs(multiInit, erc165Init, hostItInit, ticketProxy, feeTypes, addresses) ) ); vm.stopBroadcast(); diff --git a/script/DeployHostItTicketsLisk.s.sol b/script/DeployHostItTicketsLisk.s.sol deleted file mode 100644 index d62c304..0000000 --- a/script/DeployHostItTicketsLisk.s.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.30; - -import {Script} from "forge-std/Script.sol"; -import {DiamondCutFacet} from "@diamond/facets/DiamondCutFacet.sol"; -import {DiamondLoupeFacet} from "@diamond/facets/DiamondLoupeFacet.sol"; -import {OwnableRolesFacet} from "@diamond/facets/OwnableRolesFacet.sol"; -import {MultiInit} from "@diamond/initializers/MultiInit.sol"; -import {ERC165Init} from "@diamond/initializers/ERC165Init.sol"; -import {HostItInit} from "@ticket/inits/HostItInit.sol"; -import {HostItTickets} from "@ticket/HostItTickets.sol"; -import {FactoryFacet} from "@ticket/facets/FactoryFacet.sol"; -import {CheckInFacet} from "@ticket/facets/CheckInFacet.sol"; -import {MarketplaceFacet} from "@ticket/facets/MarketplaceFacet.sol"; -import {Ticket} from "@ticket/libs/Ticket.sol"; -import {AddressesAndFees} from "@ticket-script/helper/AddressesAndFees.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; -import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; -import {DeployHostItTicketsHelper} from "@ticket-script/helper/DeployHostItTicketsHelper.sol"; - -contract DeployHostItTicketsLiskSep is Script, DeployHostItTicketsHelper { - function run() public returns (address hostIt_) { - // vm.createSelectFork("lisk-sepolia"); - vm.startBroadcast(); - // Deploy facets - address diamondCutFacet = address(new DiamondCutFacet()); - address diamondLoupeFacet = address(new DiamondLoupeFacet()); - address ownableRolesFacet = address(new OwnableRolesFacet()); - address factoryFacet = address(new FactoryFacet()); - address checkInFacet = address(new CheckInFacet()); - address marketplaceFacet = address(new MarketplaceFacet()); - - // Deploy initializers - address multiInit = address(new MultiInit()); - address erc165Init = address(new ERC165Init()); - address hostItInit = address(new HostItInit()); - - // Deploy Ticket Impl - address ticketImpl = address(new Ticket()); - - // Deploy Ticket Beacon - address ticketBeacon = address(new UpgradeableBeacon(ticketImpl, _msgSender())); - - // Deploy Ticket Proxy - address ticketProxy = address(new BeaconProxy(ticketBeacon, "")); - - // Deploy HostItTickets diamond - hostIt_ = address( - new HostItTickets( - _createFacetCuts( - diamondCutFacet, diamondLoupeFacet, ownableRolesFacet, factoryFacet, checkInFacet, marketplaceFacet - ), - _createDiamondArgs( - multiInit, - erc165Init, - hostItInit, - ticketProxy, - AddressesAndFees._getLiskSepoliaFeeTypes(), - AddressesAndFees._getLiskSepoliaAddresses() - ) - ) - ); - vm.stopBroadcast(); - } -} From 79a6c1767f3e1b07e2e8b5ba03bdf485aca9f05f Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:41:31 +0100 Subject: [PATCH 14/23] Update ASCII art in HostItTickets and TicketProxy Replaced the large ASCII art blocks in HostItTickets.sol and TicketProxy.sol with a more compact version. No functional code changes were made. --- src/HostItTickets.sol | 52 +++++++++++++++++++++------------------- src/libs/TicketProxy.sol | 49 ++++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/HostItTickets.sol b/src/HostItTickets.sol index 4415814..ece991f 100644 --- a/src/HostItTickets.sol +++ b/src/HostItTickets.sol @@ -1,32 +1,36 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.30; -import {Diamond} from "@diamond/Diamond.sol"; -import {DiamondArgs, FacetCut} from "@diamond-storage/DiamondStorage.sol"; +import {Diamond, DiamondArgs, FacetCut} from "@diamond/Diamond.sol"; /* -⣾⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡿⠿⢿⣿⣿⣗⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣽⣿⣿⠿⠿⠿⢿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠈⢿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⠏⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠈⠻⣿⣿⣿⣷⣤⣀⡀⠀⠀⠀⠀⢀⣠⣤⣿⣿⣿⡿⠋⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠿⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢨⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡜⠀⠀⠀⠀⢸⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣯⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢨⣛⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣛⠦⠀⠀⠀⠀⢸⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣄⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣷⣀⣀⣀⣀⡀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣇⣀⣀⣀⣀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢘⠶⣙⠯⣖⢤⣀⡀⠀⠀⠀⠀⣀⣀⢤⡲⢏⡶⣩⠗⠀⠀⠀⠀⢸⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣦⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⢀⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣄⡀⠀⠀⠀⠀⠀⢀⣰⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⡄⠀⠀⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡅⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢸⡹⢭⡳⢎⡗⣮⢹⡭⣛⡼⣹⠖⣭⢞⡱⣏⢶⡹⣚⠀⠀⠀⠀⢸⣿⣿⣏⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣷⣂⠀⠀⠀⠀⣼⣿⣿⣿⣿⡿⠿⠿⠿⣿⣿⣿⡟⠁⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠆⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⢘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢰⢫⡳⢭⣛⡼⢎⣧⠳⣝⡼⣱⠻⣜⢮⢳⠭⣞⡱⢧⠀⠀⠀⠀⢸⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⣼⣿⣿⣿⣿⠟⠉⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⡄⠀⠀⢈⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠉⠉⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢨⡳⢭⣓⠧⠚⠉⠀⠉⠈⠈⠁⠉⠘⠃⠯⣛⡴⣫⢳⠀⠀⠀⠀⢸⣿⣿⡷⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⢰⣿⣿⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣯⠀⠀⠀⠹⣿⣿⣿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢰⢫⠇⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⢧⢏⠀⠀⠀⠀⢸⣿⣿⣟⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⠁⠀⠀⠀⠉⠻⢿⣿⣿⣿⣿⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢈⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠀⠀⠀⠀⢸⣿⣿⣯⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣏⠁⠀⠀⠀⠀⠀⠀⠈⠉⠛⠻⠿⣿⣿⣿⣿⣷⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⢻⣿⣿⣿⣿⣷⣄⡀⠀⠀⠀⢀⣠⣾⣿⣿⣿⣿⠁⠀⠀⠀⢀⣤⣀⡀⠀⠀⠀⠀⠀⣹⣿⣿⣿⣿⡇⠀⠀⠀⢸⣿⣿⣿⣿⣿⡀⠀⠀⣀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⣧⡀⠀⢀⣀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣤⣤⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⠀⠀⢠⣾⣿⣿⣿⣿⣶⣶⣶⣾⣿⣿⣿⣿⡿⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⡧⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠰⢿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⣠⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠈⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠉⠛⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⠿⠃⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠘⠿⣿⣿⣿⣿⣿⣿⣿⠿⠂ -⣿⣿⣿⡇⠀⠀⠀⣠⣾⣿⣿⣿⠿⠛⠉⠉⠉⠉⠉⠙⠛⠿⣿⣿⣿⣷⡄⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⣴⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣿⣿⣿⣆⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⣷⣶⣾⣿⣿⡟⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣶⣶⣶⣾⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⣾⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆ +⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇ +⣿⣿⣿⣿⠉⠉⠹⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⣿⣿⣿⡟⠉⠉⠉⢹⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠹⣿⣿⣿⣿⣧⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⠟⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣷⣦⣄⣀⣀⣀⣀⣀⣀⣀⣤⣶⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣷⣦⣄⣀⡀⠀⠀⠀⠀⠀⢀⣀⣤⣶⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠛⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⡿⠟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⢠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⢀⣼⣿⣿⣿⣿⡿⠟⠉⠉⠀⠀⠀⠀⠈⠉⠙⠻⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⣰⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⣄⣀⣰⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣷⣤⣤⣤⣸⣿⣿⣿⡇ +⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇ +⠻⠿⠿⠿⠿⠿⠿⠿⠿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠿⠿⠿⠿⠿⠿⠿⠿⠿⠃ */ /// @title HostIt Tickets diff --git a/src/libs/TicketProxy.sol b/src/libs/TicketProxy.sol index 62bb165..5615ffd 100644 --- a/src/libs/TicketProxy.sol +++ b/src/libs/TicketProxy.sol @@ -4,28 +4,33 @@ pragma solidity 0.8.30; import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; /* -⣾⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡿⠿⢿⣿⣿⣗⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣽⣿⣿⠿⠿⠿⢿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠈⢿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⠏⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠈⠻⣿⣿⣿⣷⣤⣀⡀⠀⠀⠀⠀⢀⣠⣤⣿⣿⣿⡿⠋⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠿⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢨⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡜⠀⠀⠀⠀⢸⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣯⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢨⣛⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣛⠦⠀⠀⠀⠀⢸⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣄⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣷⣀⣀⣀⣀⡀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣇⣀⣀⣀⣀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢘⠶⣙⠯⣖⢤⣀⡀⠀⠀⠀⠀⣀⣀⢤⡲⢏⡶⣩⠗⠀⠀⠀⠀⢸⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣦⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⢀⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣄⡀⠀⠀⠀⠀⠀⢀⣰⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⡄⠀⠀⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡅⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢸⡹⢭⡳⢎⡗⣮⢹⡭⣛⡼⣹⠖⣭⢞⡱⣏⢶⡹⣚⠀⠀⠀⠀⢸⣿⣿⣏⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣷⣂⠀⠀⠀⠀⣼⣿⣿⣿⣿⡿⠿⠿⠿⣿⣿⣿⡟⠁⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠆⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⢘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢰⢫⡳⢭⣛⡼⢎⣧⠳⣝⡼⣱⠻⣜⢮⢳⠭⣞⡱⢧⠀⠀⠀⠀⢸⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⣼⣿⣿⣿⣿⠟⠉⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⡄⠀⠀⢈⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠉⠉⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢨⡳⢭⣓⠧⠚⠉⠀⠉⠈⠈⠁⠉⠘⠃⠯⣛⡴⣫⢳⠀⠀⠀⠀⢸⣿⣿⡷⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⢰⣿⣿⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣯⠀⠀⠀⠹⣿⣿⣿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢰⢫⠇⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⢧⢏⠀⠀⠀⠀⢸⣿⣿⣟⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⠁⠀⠀⠀⠉⠻⢿⣿⣿⣿⣿⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⢈⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠀⠀⠀⠀⢸⣿⣿⣯⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣏⠁⠀⠀⠀⠀⠀⠀⠈⠉⠛⠻⠿⣿⣿⣿⣿⣷⠀⠀⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢾⣿⣿⣿⣿⡇⠀⠀⠀⠀⢻⣿⣿⣿⣿⣷⣄⡀⠀⠀⠀⢀⣠⣾⣿⣿⣿⣿⠁⠀⠀⠀⢀⣤⣀⡀⠀⠀⠀⠀⠀⣹⣿⣿⣿⣿⡇⠀⠀⠀⢸⣿⣿⣿⣿⣿⡀⠀⠀⣀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⣧⡀⠀⢀⣀⠀⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣤⣤⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⠀⠀⢠⣾⣿⣿⣿⣿⣶⣶⣶⣾⣿⣿⣿⣿⡿⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⡧⠀⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠰⢿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀ -⣿⣿⣿⡇⠀⠀⠀⠀⠀⣠⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠈⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠉⠛⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⠿⠃⠀⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠘⠿⣿⣿⣿⣿⣿⣿⣿⠿⠂ -⣿⣿⣿⡇⠀⠀⠀⣠⣾⣿⣿⣿⠿⠛⠉⠉⠉⠉⠉⠙⠛⠿⣿⣿⣿⣷⡄⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠀⠀⠀ -⣿⣿⣿⡇⠀⠀⣴⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣿⣿⣿⣆⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⣷⣶⣾⣿⣿⡟⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣶⣶⣶⣾⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⣾⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆ +⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇ +⣿⣿⣿⣿⠉⠉⠹⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⣿⣿⣿⡟⠉⠉⠉⢹⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠹⣿⣿⣿⣿⣧⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⠟⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣷⣦⣄⣀⣀⣀⣀⣀⣀⣀⣤⣶⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣷⣦⣄⣀⡀⠀⠀⠀⠀⠀⢀⣀⣤⣶⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠛⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⣿⣿⡿⠟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢿⣿⣿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⢠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⠀⢀⣼⣿⣿⣿⣿⡿⠟⠉⠉⠀⠀⠀⠀⠈⠉⠙⠻⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⠀⠀⠀⣰⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⡇ +⣿⣿⣿⣿⣄⣀⣰⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣷⣤⣤⣤⣸⣿⣿⣿⡇ +⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇ +⠻⠿⠿⠿⠿⠿⠿⠿⠿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠿⠿⠿⠿⠿⠿⠿⠿⠿⠃ */ /// @title TicketProxy From 34e20ab773198c0fbf50bf8969991dba1a722424 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:42:05 +0100 Subject: [PATCH 15/23] Update visibility and comments for view functions Changed baseURI function visibility from external to public and added comments to the paused function for clarity. These updates improve the contract's interface and documentation. --- src/libs/Ticket.sol | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libs/Ticket.sol b/src/libs/Ticket.sol index d21da2c..d3f994c 100644 --- a/src/libs/Ticket.sol +++ b/src/libs/Ticket.sol @@ -183,14 +183,16 @@ contract Ticket is super.safeTransferFrom(from, to, tokenId, data); } - function paused() public view override(ITicket, PausableUpgradeable) returns (bool) { - return PausableUpgradeable.paused(); - } - //*////////////////////////////////////////////////////////////////////////// // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// + /// @notice Returns whether the contract is paused + /// @return Whether the contract is paused + function paused() public view override(ITicket, PausableUpgradeable) returns (bool) { + return PausableUpgradeable.paused(); + } + /// @notice Returns the metadata URI for the TicketNFT /// @dev This function returns the base URI set for the NFT collection, which is used /// @param _tokenId The ID of the token @@ -210,7 +212,7 @@ contract Ticket is /// @dev This function returns the base URI set for the NFT collection, which is used /// @return The URI pointing to the collection's metadata /// forge-lint: disable-next-line(mixed-case-function) - function baseURI() external view returns (string memory) { + function baseURI() public view returns (string memory) { return _baseURI(); } From 3555d31a74ecfcb2c8709d78c066f33cf7a582eb Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:43:55 +0100 Subject: [PATCH 16/23] Enhance ticket creation and error handling in LibFactory Refactored ticket creation logic for improved validation and error handling. Added new error TicketInitializationFailed, updated ExtraTicketData structure, and replaced Ticket with ITicket interface for better abstraction. Improved input checks and initialization process for ticket contracts. --- src/libs/LibFactory.sol | 73 ++++++++++++++++++++----------- src/libs/errors/FactoryErrors.sol | 1 + 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/libs/LibFactory.sol b/src/libs/LibFactory.sol index 38e0ca3..b49cb24 100644 --- a/src/libs/LibFactory.sol +++ b/src/libs/LibFactory.sol @@ -50,32 +50,42 @@ library LibFactory { function _createTicket(TicketData calldata _ticketData, FeeType[] calldata _feeTypes, uint256[] calldata _fees) internal { - if (bytes(_ticketData.name).length == 0) revert EmptyName(); - if (bytes(_ticketData.uri).length == 0) revert EmptyURI(); + { + if (bytes(_ticketData.name).length == 0) revert EmptyName(); + if (bytes(_ticketData.uri).length == 0) revert EmptyURI(); - if (_ticketData.startTime < block.timestamp) revert StartTimeShouldBeAhead(); - if (_ticketData.endTime < _ticketData.startTime + 1 days) revert EndTimeShouldBeOneDayAfterStartTime(); - if (_ticketData.purchaseStartTime > _ticketData.startTime - 1 days) { - revert PurchaseStartTimeShouldBeOneDayBeforeStartTime(); + if (_ticketData.startTime < block.timestamp) { + revert StartTimeShouldBeAhead(); + } + if (_ticketData.endTime < _ticketData.startTime + 1 days) { + revert EndTimeShouldBeOneDayAfterStartTime(); + } + if (_ticketData.purchaseStartTime > _ticketData.startTime - 1 days) { + revert PurchaseStartTimeShouldBeOneDayBeforeStartTime(); + } + if (_ticketData.maxTickets == 0) revert MaxTicketsIsZero(); } - if (_ticketData.maxTickets == 0) revert MaxTicketsIsZero(); FactoryStorage storage fs = _factoryStorage(); uint64 ticketId = ++fs.ticketId; address ticketAdmin = LibContext._msgSender(); _grantTicketAdminRoles(ticketAdmin, ticketId); - ExtraTicketData memory extraTicketData = _createExtraTicketData(_ticketData, ticketId, ticketAdmin); - $.ticketIdToData[ticketId] = extraTicketData; - $.adminTicketIds[ticketAdmin].add(ticketId); + ExtraTicketData memory extraTicketData = _createExtraTicketData(fs, _ticketData, ticketId, ticketAdmin); + fs.ticketIdToData[ticketId] = extraTicketData; + fs.adminTicketIds[ticketAdmin].add(ticketId); if (!_ticketData.isFree) { uint256 feeTypesLength = _feeTypes.length; - if (feeTypesLength == 0 || feeTypesLength != _fees.length) revert ArrayMismatch(); + if (feeTypesLength == 0 || feeTypesLength != _fees.length) { + revert ArrayMismatch(); + } MarketplaceStorage storage mps = LibMarketplace._marketplaceStorage(); for (uint256 i; i < feeTypesLength; ++i) { FeeType feeType = _feeTypes[i]; - if (mps.feeEnabled[ticketId][feeType]) revert FeeAlreadySet(feeType); + if (mps.feeEnabled[ticketId][feeType]) { + revert FeeAlreadySet(feeType); + } if (_fees[i] == 0) revert ZeroFee(feeType); mps.feeEnabled[ticketId][feeType] = true; @@ -93,12 +103,16 @@ library LibFactory { ExtraTicketData memory extraTicketData = _getExtraTicketData(_ticketId); if (_ticketData.startTime > 0) { - if (_ticketData.startTime < uint40(block.timestamp)) revert StartTimeShouldBeAhead(); + if (_ticketData.startTime < uint40(block.timestamp)) { + revert StartTimeShouldBeAhead(); + } extraTicketData.startTime = _ticketData.startTime; } if (_ticketData.endTime > 0) { - if (_ticketData.endTime < _ticketData.startTime + 1 days) revert EndTimeShouldBeOneDayAfterStartTime(); + if (_ticketData.endTime < _ticketData.startTime + 1 days) { + revert EndTimeShouldBeOneDayAfterStartTime(); + } extraTicketData.endTime = _ticketData.endTime; } @@ -109,9 +123,11 @@ library LibFactory { extraTicketData.purchaseStartTime = _ticketData.purchaseStartTime; } - Ticket ticket = Ticket(extraTicketData.ticketAddress); + ITicket ticket = ITicket(extraTicketData.ticketAddress); if (_ticketData.maxTickets > 0) { - if (_ticketData.maxTickets < ticket.totalSupply()) revert MaxTicketsShouldEqualSupply(); + if (_ticketData.maxTickets < ticket.totalSupply()) { + revert MaxTicketsShouldEqualSupply(); + } extraTicketData.maxTickets = _ticketData.maxTickets; } @@ -160,20 +176,25 @@ library LibFactory { address ticketProxy = _fs.ticketProxy; if (ticketProxy.code.length == 0) revert TicketImplementationNotSet(); address ticketAddress = ticketProxy.cloneDeterministic(_generateTicketHash(_ticketId)); - Ticket(ticketAddress).initialize(address(this), _ticketData.name, _ticketData.symbol, _ticketData.uri); + try ITicket(ticketAddress).initialize(address(this), _ticketData.name, _ticketData.symbol, _ticketData.uri) {} + catch { + revert TicketInitializationFailed(); + } extraTicketData_ = ExtraTicketData({ id: _ticketId, - createdAt: uint40(block.timestamp), + createdAt: uint48(block.timestamp), updatedAt: 0, - startTime: uint40(_ticketData.startTime), - endTime: uint40(_ticketData.endTime), + startTime: _ticketData.startTime, + endTime: _ticketData.endTime, purchaseStartTime: _ticketData.purchaseStartTime, - maxTickets: uint40(_ticketData.maxTickets), + maxTickets: _ticketData.maxTickets, soldTickets: 0, + maxTicketsPerUser: _ticketData.maxTicketsPerUser, + isFree: _ticketData.isFree, + isRefundable: _ticketData.isRefundable, ticketAdmin: _ticketAdmin, - ticketAddress: ticketAddress, - isFree: _ticketData.isFree + ticketAddress: ticketAddress }); } @@ -200,8 +221,8 @@ library LibFactory { function _getFullTicketData(uint64 _ticketId) internal view returns (FullTicketData memory) { ExtraTicketData memory extraTicketData = _getExtraTicketData(_ticketId); - Ticket ticket = Ticket(extraTicketData.ticketAddress); - fullTicketData_ = FullTicketData({ + ITicket ticket = ITicket(extraTicketData.ticketAddress); + return FullTicketData({ id: extraTicketData.id, createdAt: extraTicketData.createdAt, updatedAt: extraTicketData.updatedAt, @@ -210,7 +231,9 @@ library LibFactory { purchaseStartTime: extraTicketData.purchaseStartTime, maxTickets: extraTicketData.maxTickets, soldTickets: extraTicketData.soldTickets, + maxTicketsPerUser: extraTicketData.maxTicketsPerUser, isFree: extraTicketData.isFree, + isRefundable: extraTicketData.isRefundable, ticketAdmin: extraTicketData.ticketAdmin, ticketAddress: extraTicketData.ticketAddress, name: ticket.name(), diff --git a/src/libs/errors/FactoryErrors.sol b/src/libs/errors/FactoryErrors.sol index 45031a9..255981b 100644 --- a/src/libs/errors/FactoryErrors.sol +++ b/src/libs/errors/FactoryErrors.sol @@ -19,3 +19,4 @@ error TicketImplementationNotSet(); error UpdateNameFailed(); error UpdateSymbolFailed(); error UpdateURIFailed(); +error TicketInitializationFailed(); From b517bebd70eee01af9ed70faa0203d345e8b738b Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:44:14 +0100 Subject: [PATCH 17/23] Refactor fee logic and error handling in LibMarketplace Updated fee calculation to use dynamic basis points from storage, refactored functions to accept MarketplaceStorage as a parameter, and improved error handling with new error types. Added SafeCast usage, replaced FatalErrorTicketMismatch with TicketAccountingMismatch, and introduced CreateERC6551AccountFailed error for ERC6551 account creation failures. --- src/libs/LibMarketplace.sol | 137 ++++++++++++++++++-------- src/libs/errors/MarketplaceErrors.sol | 3 +- 2 files changed, 99 insertions(+), 41 deletions(-) diff --git a/src/libs/LibMarketplace.sol b/src/libs/LibMarketplace.sol index 5d932a1..866c8d4 100644 --- a/src/libs/LibMarketplace.sol +++ b/src/libs/LibMarketplace.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.30; import {LibOwnableRoles} from "@diamond/libraries/LibOwnableRoles.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {ACCOUNT_V3_IMPLEMENTATION, ERC6551_REGISTRY} from "@ticket-script/helper/LibAddressesAndFees.sol"; import {ExtraTicketData} from "@ticket-storage/FactoryStorage.sol"; import {FeeType, MARKETPLACE_STORAGE_LOCATION, MarketplaceStorage} from "@ticket-storage/MarketplaceStorage.sol"; @@ -19,6 +20,7 @@ import "@ticket-errors/MarketplaceErrors.sol"; library LibMarketplace { using LibFactory for uint64; + using SafeCast for uint256; using SafeTransferLib for address; using SafeERC20 for IERC20; @@ -26,11 +28,10 @@ library LibMarketplace { // STORAGE //////////////////////////////////////////////////////////////////////////*// - uint256 private constant MAX_TICKETS_PER_HOLDER = 0; uint256 internal constant REFUND_PERIOD = 3 days; - uint256 private constant HOSTIT_FEE_BPS = 3_000; // 3% fee in basis points - uint256 private constant FEE_BASIS_POINTS = 100_000; // 100,000 basis points + uint256 private constant HOSTIT_FEE_BPS = 300; // 3% fee in basis points + uint256 private constant FEE_BASIS_POINTS = 10_000; // 10,000 basis points function _marketplaceStorage() internal pure returns (MarketplaceStorage storage ms_) { assembly { @@ -47,25 +48,25 @@ library LibMarketplace { ExtraTicketData memory ticketData = _ticketId._getExtraTicketData(); - uint40 time = uint40(block.timestamp); + uint48 time = block.timestamp.toUint48(); if (time < ticketData.purchaseStartTime) revert PurchaseTimeNotReached(); if (time > ticketData.endTime) revert PurchaseTimeNotReached(); if (ticketData.soldTickets == ticketData.maxTickets) revert TicketSoldOut(); ITicket ticket = ITicket(ticketData.ticketAddress); - if (ticket.balanceOf(_buyer) > MAX_TICKETS_PER_HOLDER) revert MaxTicketsHeld(); + if (ticket.balanceOf(_buyer) > ticketData.maxTicketsPerUser) revert MaxTicketsHeld(); - (uint256 fee, uint256 hostItFee, uint256 totalFee) = _getFees(_ticketId, _feeType); + MarketplaceStorage storage ms = _marketplaceStorage(); + (uint256 fee, uint256 hostItFee, uint256 totalFee) = _getFees(ms, _ticketId, _feeType); if (!ticketData.isFree) { - if (!_isFeeEnabled(_ticketId, _feeType)) revert FeeNotEnabled(); + if (!_isFeeEnabled(ms, _ticketId, _feeType)) revert FeeNotEnabled(); if (_feeType == FeeType.ETH) { - if (msg.value != totalFee) revert InsufficientBalance(address(0), _feeType, totalFee); + if (msg.value < totalFee) revert InsufficientBalance(address(0), _feeType, totalFee); } else { - _payWithToken(_feeType, totalFee); + _payWithToken(ms, _feeType, totalFee); } - MarketplaceStorage storage ms = _marketplaceStorage(); ms.ticketBalance[_ticketId][_feeType] += fee; ms.hostItBalance[_feeType] += hostItFee; } @@ -73,17 +74,25 @@ library LibMarketplace { tokenId_ = uint40(ticket.mint(_buyer)); ++LibFactory._factoryStorage().ticketIdToData[_ticketId].soldTickets; if (tokenId_ != LibFactory._factoryStorage().ticketIdToData[_ticketId].soldTickets) { - revert FatalErrorTicketMismatch(); + revert TicketAccountingMismatch(); } - // Create ERC6551 Account - IERC6551Registry(ERC6551_REGISTRY).createAccount( - ACCOUNT_V3_IMPLEMENTATION, "", block.chainid, ticketData.ticketAddress, tokenId_ - ); - emit TicketMinted(_ticketId, _feeType, totalFee, tokenId_); } + function _createErc6551Account(address _ticketAddress, uint256 _tokenId) internal { + try IERC6551Registry(ERC6551_REGISTRY) + .createAccount( + ACCOUNT_V3_IMPLEMENTATION, "", block.chainid, _ticketAddress, _tokenId + ) returns (address account) { + if (account == address(0)) { + revert CreateERC6551AccountFailed(); + } + } catch { + revert CreateERC6551AccountFailed(); + } + } + function _setTicketFees(uint64 _ticketId, FeeType[] calldata _feeTypes, uint256[] calldata _fees) internal onlyMainTicketAdmin(_ticketId) @@ -160,6 +169,18 @@ library LibMarketplace { emit HostItBalanceWithdrawn(_feeType, balance, _to); } + function _payWithToken(MarketplaceStorage storage _ms, FeeType _feeType, uint256 _totalFee) internal { + address caller = LibContext._msgSender(); + IERC20 token = IERC20(_getFeeTokenAddress(_ms, _feeType)); + if (token.balanceOf(caller) < _totalFee) revert InsufficientBalance(address(token), _feeType, _totalFee); + if (token.allowance(caller, address(this)) < _totalFee) { + revert InsufficientAllowance(address(token), _feeType, _totalFee); + } + if (!token.trySafeTransferFrom(caller, address(this), _totalFee)) { + revert TicketPurchaseFailed(_feeType, _totalFee); + } + } + function _setFeeTokenAddresses(FeeType[] calldata _feeTypes, address[] calldata _tokenAddresses) internal { uint256 feeTypesLength = _feeTypes.length; if (feeTypesLength != _tokenAddresses.length && feeTypesLength > 0) revert InvalidFeeConfig(); @@ -170,31 +191,45 @@ library LibMarketplace { } } - function _payWithToken(FeeType _feeType, uint256 _totalFee) internal { - address buyer = LibContext._msgSender(); - IERC20 token = IERC20(_getFeeTokenAddress(_feeType)); - if (token.balanceOf(buyer) < _totalFee) revert InsufficientBalance(address(token), _feeType, _totalFee); - if (token.allowance(buyer, address(this)) < _totalFee) { - revert InsufficientAllowance(address(token), _feeType, _totalFee); - } - if (!token.trySafeTransferFrom(buyer, address(this), _totalFee)) { - revert TicketPurchaseFailed(_feeType, _totalFee); - } - } - //*////////////////////////////////////////////////////////////////////////// // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// + function _isFeeEnabled(uint64 _ticketId, FeeType _feeType) internal view returns (bool) { + return _isFeeEnabled(_marketplaceStorage(), _ticketId, _feeType); + } + + function _isFeeEnabled(MarketplaceStorage storage _ms, uint64 _ticketId, FeeType _feeType) + internal + view + returns (bool) + { + return _ms.feeEnabled[_ticketId][_feeType]; + } + + function _getFeeTokenAddress(FeeType _feeType) internal view returns (address) { + return _getFeeTokenAddress(_marketplaceStorage(), _feeType); } - function _getFeeTokenAddress(FeeType _feeType) internal view returns (address tokenAddress_) { - tokenAddress_ = _marketplaceStorage().feeTokenAddress[_feeType]; + function _getFeeTokenAddress(MarketplaceStorage storage _ms, FeeType _feeType) + internal + view + returns (address tokenAddress_) + { + tokenAddress_ = _ms.feeTokenAddress[_feeType]; if (tokenAddress_ == address(0)) revert TokenAddressZero(); } - function _getTicketFee(uint56 _ticketId, FeeType _feeType) internal view returns (uint256) { - return _marketplaceStorage().ticketFee[_ticketId][_feeType]; + function _getTicketFee(uint64 _ticketId, FeeType _feeType) internal view returns (uint256) { + return _getTicketFee(_marketplaceStorage(), _ticketId, _feeType); + } + + function _getTicketFee(MarketplaceStorage storage _ms, uint64 _ticketId, FeeType _feeType) + internal + view + returns (uint256) + { + return _ms.ticketFee[_ticketId][_feeType]; } function _getFees(uint64 _ticketId, FeeType _feeType) @@ -207,24 +242,46 @@ library LibMarketplace { totalFee_ = ticketFee_ + hostItFee_; } - function _getTicketBalance(uint56 _ticketId, FeeType _feeType) internal view returns (uint256) { - return _marketplaceStorage().ticketBalance[_ticketId][_feeType]; + function _getFees(MarketplaceStorage storage _ms, uint64 _ticketId, FeeType _feeType) + internal + view + returns (uint256 ticketFee_, uint256 hostItFee_, uint256 totalFee_) + { + ticketFee_ = _getTicketFee(_ms, _ticketId, _feeType); + hostItFee_ = _calculateHostItFee(_ms, ticketFee_); + totalFee_ = ticketFee_ + hostItFee_; + } + + function _getTicketBalance(uint64 _ticketId, FeeType _feeType) internal view returns (uint256) { + return _getTicketBalance(_marketplaceStorage(), _ticketId, _feeType); + } + + function _getTicketBalance(MarketplaceStorage storage _ms, uint64 _ticketId, FeeType _feeType) + internal + view + returns (uint256) + { + return _ms.ticketBalance[_ticketId][_feeType]; } function _getHostItBalance(FeeType _feeType) internal view returns (uint256) { - return _marketplaceStorage().hostItBalance[_feeType]; + return _getHostItBalance(_marketplaceStorage(), _feeType); + } + + function _getHostItBalance(MarketplaceStorage storage _ms, FeeType _feeType) internal view returns (uint256) { + return _ms.hostItBalance[_feeType]; } function _checkIfContract(address _address) internal view { if (_address.code.length > 0) revert ContractNotAllowed(); } - //*////////////////////////////////////////////////////////////////////////// - // PURE FUNCTIONS - //////////////////////////////////////////////////////////////////////////*// + function _calculateHostItFee(uint256 _fee) internal view returns (uint256) { + return _calculateHostItFee(_marketplaceStorage(), _fee); + } - function _calculateHostItFee(uint256 _fee) internal pure returns (uint256) { - return (_fee * HOSTIT_FEE_BPS / FEE_BASIS_POINTS); + function _calculateHostItFee(MarketplaceStorage storage _ms, uint256 _fee) internal view returns (uint256) { + return ((_fee * _ms.hostItFeeBps) / FEE_BASIS_POINTS); } //*////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/errors/MarketplaceErrors.sol b/src/libs/errors/MarketplaceErrors.sol index 0bd870d..05e5786 100644 --- a/src/libs/errors/MarketplaceErrors.sol +++ b/src/libs/errors/MarketplaceErrors.sol @@ -17,5 +17,6 @@ error InsufficientAllowance(address, FeeType, uint256); error WithdrawPeriodNotReached(); error InsufficientWithdrawBalance(); error TicketPurchaseFailed(FeeType, uint256); -error FatalErrorTicketMismatch(); +error TicketAccountingMismatch(); error TicketUnpauseFailed(); +error CreateERC6551AccountFailed(); From 81bbc93b9f38c5a89c2a2f140a5b82ea1b8f23f1 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:45:06 +0100 Subject: [PATCH 18/23] Refactor DeployedHostItTickets contract and update ticket data Changed base contract from HelperContract to Test for improved test integration. Moved ticket creation and update helper functions for better code organization. Updated TicketData structures to include maxTicketsPerUser and isRefundable fields, enhancing ticket configuration for tests. --- test/states/DeployedHostItTickets.sol | 56 ++++++++++++++------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/test/states/DeployedHostItTickets.sol b/test/states/DeployedHostItTickets.sol index f251675..754222d 100644 --- a/test/states/DeployedHostItTickets.sol +++ b/test/states/DeployedHostItTickets.sol @@ -16,7 +16,7 @@ import {Test} from "forge-std/Test.sol"; /// forge-lint: disable-next-line(unaliased-plain-import) import "@ticket-logs/MarketplaceLogs.sol"; -abstract contract DeployedHostItTickets is HelperContract { +abstract contract DeployedHostItTickets is Test { address public hostIt; DeployHostItTicketsTest public deployHostItTickets; IFactory public factoryFacet; @@ -34,12 +34,7 @@ abstract contract DeployedHostItTickets is HelperContract { /// @notice List of facet contract names used in deployment. string[6] public facetNames = [ - "DiamondCutFacet", - "DiamondLoupeFacet", - "OwnableRolesFacet", - "FactoryFacet", - "CheckInFacet", - "MarketplaceFacet" + "DiamondCutFacet", "DiamondLoupeFacet", "OwnableRolesFacet", "FactoryFacet", "CheckInFacet", "MarketplaceFacet" ]; address owner = address(this); @@ -67,22 +62,6 @@ abstract contract DeployedHostItTickets is HelperContract { vm.etch(ERC6551_REGISTRY, address(new ERC6551Registry()).code); } - function _createFreeTicket() internal { - factoryFacet.createTicket(_getFreeTicketData(), _getZeroFeeType(), _getZeroFee()); - } - - function _updateFreeTicket(uint40 _ticketId) internal { - factoryFacet.updateTicket(_getFreeUpdatedTicketData(), _ticketId); - } - - function _createPaidTicket() internal { - factoryFacet.createTicket(_getPaidTicketData(), _getFeeTypes(), _getFees()); - } - - function _updatePaidTicket(uint40 _ticketId) internal { - factoryFacet.updateTicket(_getPaidUpdatedTicketData(), _ticketId); - } - function _mintTicketFree() internal returns (uint64 ticketId_, uint40 tokenId_) { _createFreeTicket(); ticketId_ = factoryFacet.ticketCount(); @@ -99,9 +78,10 @@ abstract contract DeployedHostItTickets is HelperContract { hoax(alice, totalFee); vm.expectEmit(true, true, true, true, hostIt); emit TicketMinted(ticketId_, FeeType.ETH, totalFee, 1); - (bool success, bytes memory result) = address(marketplaceFacet).call{value: totalFee}( - abi.encodeWithSelector(marketplaceFacet.mintTicket.selector, ticketId_, FeeType.ETH, alice) - ); + (bool success, bytes memory result) = address(marketplaceFacet) + .call{ + value: totalFee + }(abi.encodeWithSelector(marketplaceFacet.mintTicket.selector, ticketId_, FeeType.ETH, alice)); assertTrue(success); tokenId_ = abi.decode(result, (uint40)); fee_ = fee; @@ -148,13 +128,31 @@ abstract contract DeployedHostItTickets is HelperContract { hostItFee_ = hostItFee; } + function _createFreeTicket() internal { + factoryFacet.createTicket(_getFreeTicketData(), _getZeroFeeType(), _getZeroFee()); + } + + function _updateFreeTicket(uint40 _ticketId) internal { + factoryFacet.updateTicket(_getFreeUpdatedTicketData(), _ticketId); + } + + function _createPaidTicket() internal { + factoryFacet.createTicket(_getPaidTicketData(), _getFeeTypes(), _getFees()); + } + + function _updatePaidTicket(uint40 _ticketId) internal { + factoryFacet.updateTicket(_getPaidUpdatedTicketData(), _ticketId); + } + function _getFreeTicketData() internal view returns (TicketData memory ticketData_) { ticketData_ = TicketData({ startTime: uint40(block.timestamp + 1 days), endTime: uint40(block.timestamp + 2 days), purchaseStartTime: _currentTime, maxTickets: type(uint40).max, + maxTicketsPerUser: 0, isFree: true, + isRefundable: false, name: "Free Ticket", symbol: "", uri: "ipfs://" @@ -167,7 +165,9 @@ abstract contract DeployedHostItTickets is HelperContract { endTime: uint40(block.timestamp + 2 days), purchaseStartTime: _currentTime, maxTickets: 100, + maxTicketsPerUser: 1, isFree: true, + isRefundable: false, name: "Updated Free Ticket", symbol: "UFT", uri: "ipfs://2" @@ -180,7 +180,9 @@ abstract contract DeployedHostItTickets is HelperContract { endTime: uint40(block.timestamp + 2 days), purchaseStartTime: _currentTime, maxTickets: type(uint40).max, + maxTicketsPerUser: 0, isFree: false, + isRefundable: false, name: "Paid Ticket", symbol: "", uri: "ipfs://$" @@ -193,7 +195,9 @@ abstract contract DeployedHostItTickets is HelperContract { endTime: uint40(block.timestamp + 2 days), purchaseStartTime: _currentTime, maxTickets: type(uint40).max, + maxTicketsPerUser: 0, isFree: false, + isRefundable: true, name: "Updated Paid Ticket", symbol: "UPT", uri: "ipfs://$$" From 467f04e25b9063ca58742bc7358f8290ac912869 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:45:20 +0100 Subject: [PATCH 19/23] Update adminTickets test and add fuzz test stubs Replaces the test_adminTickets function to use uint64 instead of uint56 for ticket IDs and moves its position in the file. Adds commented-out fuzz test stubs for createTicket and updateTicket to prepare for future property-based testing. --- test/Factory.t.sol | 52 +++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/test/Factory.t.sol b/test/Factory.t.sol index c67e856..8d09e0b 100644 --- a/test/Factory.t.sol +++ b/test/Factory.t.sol @@ -117,6 +117,20 @@ contract FactoryTest is DeployedHostItTickets { assertEq(fullTicketDatas[2].id, 3); } + function test_adminTickets() public { + _createFreeTicket(); + _createFreeTicket(); + vm.prank(alice); + _createPaidTicket(); + uint64[] memory ownerTickets = factoryFacet.adminTickets(owner); + uint64[] memory aliceTickets = factoryFacet.adminTickets(alice); + assertEq(ownerTickets.length, 2); + assertEq(aliceTickets.length, 1); + assertEq(ownerTickets[0], 1); + assertEq(ownerTickets[1], 2); + assertEq(aliceTickets[0], 3); + } + function test_adminTicketData() public { _createFreeTicket(); _createFreeTicket(); @@ -131,20 +145,6 @@ contract FactoryTest is DeployedHostItTickets { assertEq(aliceTicketDatas[0].id, 3); } - function test_adminTickets() public { - _createFreeTicket(); - _createFreeTicket(); - vm.prank(alice); - _createPaidTicket(); - uint56[] memory ownerTickets = factoryFacet.adminTickets(owner); - uint56[] memory aliceTickets = factoryFacet.adminTickets(alice); - assertEq(ownerTickets.length, 2); - assertEq(aliceTickets.length, 1); - assertEq(ownerTickets[0], 1); - assertEq(ownerTickets[1], 2); - assertEq(aliceTickets[0], 3); - } - function test_hostItTicketHash() public view { bytes32 hostItTicketHash = factoryFacet.hostItTicketHash(); assertEq(hostItTicketHash, keccak256("host.it.ticket")); @@ -167,4 +167,28 @@ contract FactoryTest is DeployedHostItTickets { uint256 ticketAdminRole = factoryFacet.ticketAdminRole(ticketId); assertEq(ticketAdminRole, uint256(keccak256(abi.encode(keccak256("host.it.ticket.admin"), ticketId)))); } + + //*////////////////////////////////////////////////////////////////////////// + // FUZZ TESTS + //////////////////////////////////////////////////////////////////////////*// + + // /// forge-config: default.fuzz.runs = 20 + // /// forge-config: default.fuzz.max-test-rejects = 100_000_000 + // function test_fuzz_createTicket(TicketData memory _ticketData) public { + // vm.assume(_ticketData.endTime > bound(_ticketData.startTime, 0, type(uint48).max - 2 days)); + // bound(_ticketData.purchaseStartTime, 0, _currentTime); + // bound(_ticketData.maxTickets, 0, type(uint8).max); + // factoryFacet.createTicket(_ticketData, _getFeeTypes(), _getFees()); + // } + + // /// forge-config: default.fuzz.runs = 256 + // /// forge-config: default.fuzz.max-test-rejects = 4_000_000 + // function test_fuzz_updateTicket(TicketData memory _ticketData) public { + // bound(_ticketData.startTime, 0, type(uint48).max - 2 days); + // vm.assume(_ticketData.endTime == type(uint48).max - 1 days); + // bound(_ticketData.purchaseStartTime, 0, _currentTime); + // bound(_ticketData.maxTickets, 0, type(uint8).max); + // _createPaidTicket(); + // factoryFacet.updateTicket(_ticketData, 1); + // } } From 461fb0d364113b5d64d6380cf67a2bde30195c1b Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:45:36 +0100 Subject: [PATCH 20/23] Update foundry.toml optimizer and fuzz settings Increased optimizer_runs to 999,999 and added fuzz section with runs set to 10,000 and max_test_rejects to 999,999 for improved testing configuration. --- foundry.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/foundry.toml b/foundry.toml index 7de02d2..9937afa 100644 --- a/foundry.toml +++ b/foundry.toml @@ -14,11 +14,15 @@ remappings = [ "@tokenbound/=lib/contracts/src/" ] ffi = true -optimizer_runs = 30_000 +optimizer_runs = 999_999 [fmt] sort_imports = true +[fuzz] +runs = 10_000 +max_test_rejects = 999_999 + [rpc_endpoints] mainnet = "${ETH_MAINNET_URL}" sepolia = "${ETH_SEPOLIA_URL}" From 98da0352a3bb7c5175e56820711419295e2a5278 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:48:30 +0100 Subject: [PATCH 21/23] Specify nightly version for Foundry installation Updates the GitHub Actions workflow to install the nightly version of Foundry using the foundry-toolchain action. This ensures the workflow uses the latest nightly features and fixes. --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4481ec6..dfd97a0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,6 +19,8 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly - name: Show Forge version run: | From 726148723502afb905d3be02655b8807351b4c92 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 12:52:59 +0100 Subject: [PATCH 22/23] Change calculateHostItFee to view function Updated the calculateHostItFee function from pure to view to reflect its dependency on contract state. This ensures correct function visibility and usage. --- src/facets/MarketplaceFacet.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/facets/MarketplaceFacet.sol b/src/facets/MarketplaceFacet.sol index a79558f..eb3f8ef 100644 --- a/src/facets/MarketplaceFacet.sol +++ b/src/facets/MarketplaceFacet.sol @@ -60,14 +60,14 @@ contract MarketplaceFacet is IMarketplace { return _feeType._getHostItBalance(); } + function calculateHostItFee(uint256 _fee) external view returns (uint256) { + return _fee._calculateHostItFee(); + } + //*////////////////////////////////////////////////////////////////////////// // PURE FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function calculateHostItFee(uint256 _fee) external pure returns (uint256) { - return _fee._calculateHostItFee(); - } - function getRefundPeriod() external pure returns (uint256) { return LibMarketplace.REFUND_PERIOD; } From 5ecc02f6654e4c02488efe7d4e4e7dcd67ad5e00 Mon Sep 17 00:00:00 2001 From: David Dada Date: Mon, 13 Oct 2025 13:52:35 +0100 Subject: [PATCH 23/23] Add HostIt fee basis points configuration Introduces the ability to set HostIt fee basis points via an admin function in LibMarketplace, updates initialization to set the fee, adds related error and event definitions, and adjusts the IMarketplace interface for fee calculation. This enhances fee management flexibility for the marketplace. --- src/inits/HostItInit.sol | 1 + src/interfaces/IMarketplace.sol | 3 ++- src/libs/LibMarketplace.sol | 10 ++++++++++ src/libs/errors/MarketplaceErrors.sol | 1 + src/libs/logs/MarketplaceLogs.sol | 2 ++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/inits/HostItInit.sol b/src/inits/HostItInit.sol index 458c138..f032754 100644 --- a/src/inits/HostItInit.sol +++ b/src/inits/HostItInit.sol @@ -14,6 +14,7 @@ contract HostItInit { LibDiamond._diamondStorage().supportedInterfaces[type(ITicket).interfaceId] = true; LibFactory._factoryStorage().ticketProxy = _ticketProxy; LibMarketplace._setFeeTokenAddresses(_feeTypes, _tokens); + LibMarketplace._setHostItFeeBps(300); emit HostItInitialized(); } } diff --git a/src/interfaces/IMarketplace.sol b/src/interfaces/IMarketplace.sol index 2e8e72b..9d60913 100644 --- a/src/interfaces/IMarketplace.sol +++ b/src/interfaces/IMarketplace.sol @@ -34,10 +34,11 @@ interface IMarketplace { function getHostItBalance(FeeType feeType) external view returns (uint256); + function calculateHostItFee(uint256 fee) external view returns (uint256); + //*////////////////////////////////////////////////////////////////////////// // PURE FUNCTIONS //////////////////////////////////////////////////////////////////////////*// - function calculateHostItFee(uint256 fee) external pure returns (uint256); function getRefundPeriod() external pure returns (uint256); } diff --git a/src/libs/LibMarketplace.sol b/src/libs/LibMarketplace.sol index 866c8d4..499ba61 100644 --- a/src/libs/LibMarketplace.sol +++ b/src/libs/LibMarketplace.sol @@ -181,6 +181,10 @@ library LibMarketplace { } } + //*////////////////////////////////////////////////////////////////////////// + // ADMIN FUNCTIONS + //////////////////////////////////////////////////////////////////////////*// + function _setFeeTokenAddresses(FeeType[] calldata _feeTypes, address[] calldata _tokenAddresses) internal { uint256 feeTypesLength = _feeTypes.length; if (feeTypesLength != _tokenAddresses.length && feeTypesLength > 0) revert InvalidFeeConfig(); @@ -191,6 +195,12 @@ library LibMarketplace { } } + function _setHostItFeeBps(uint16 _hostItFeePercentage) internal { + if (_hostItFeePercentage > HOSTIT_FEE_BPS) revert InvalidHostItFeeBps(); + _marketplaceStorage().hostItFeeBps = _hostItFeePercentage; + emit HostItFeeBpsSet(_hostItFeePercentage); + } + //*////////////////////////////////////////////////////////////////////////// // VIEW FUNCTIONS //////////////////////////////////////////////////////////////////////////*// diff --git a/src/libs/errors/MarketplaceErrors.sol b/src/libs/errors/MarketplaceErrors.sol index 05e5786..3cfa869 100644 --- a/src/libs/errors/MarketplaceErrors.sol +++ b/src/libs/errors/MarketplaceErrors.sol @@ -20,3 +20,4 @@ error TicketPurchaseFailed(FeeType, uint256); error TicketAccountingMismatch(); error TicketUnpauseFailed(); error CreateERC6551AccountFailed(); +error InvalidHostItFeeBps(); diff --git a/src/libs/logs/MarketplaceLogs.sol b/src/libs/logs/MarketplaceLogs.sol index 9f37618..ffa5488 100644 --- a/src/libs/logs/MarketplaceLogs.sol +++ b/src/libs/logs/MarketplaceLogs.sol @@ -5,6 +5,8 @@ import {FeeType} from "@ticket-storage/MarketplaceStorage.sol"; event TicketFeeSet(uint64 indexed ticketId, FeeType indexed feeType, uint256 fee); +event HostItFeeBpsSet(uint16 indexed hostItFeeBps); + event TicketFeeAddressSet(FeeType indexed feeType, address indexed token); event TicketMinted(uint64 indexed ticketId, FeeType indexed feeType, uint256 fee, uint40 tokenId);