Release Ticket (token symbol TIKT) on Sepolia as a univ4_hook launch. Token: Ticket (TIKT), total supply 1,000,000,000 TIKT with 18 decimals, minted once to the deployer. Hook: SwapLotteryHook, a Uniswap v4 hook on the token's native-ETH pool that runs an hourly swap lottery. Rounds: per pool, round = block.timestamp / 3,600 (UTC hours). Pot: 50 bps (0.5%) of every swap's ETH leg, charged with the ETH-leg mechanics below, goes to the current round's pot. Tickets: each swap whose ETH leg is at least 0.001 ETH pushes one ticket for its identity (rule below) onto the current round's list; swaps without one pay the fee but get no ticket. A swap after round r ends always lands in a later round, so a closed round never gains tickets. Draw: after round r ends, anyone calls seal(poolKey, r), which records targetBlock = block.number + 1 once. Then, while targetBlock < block.number <= targetBlock + 256, anyone calls draw(poolKey, r): winner = tickets[uint256(keccak256(abi.encode(blockhash(targetBlock), poolId, r))) % ticketCount], credited the whole pot as a claimable balance. If the round has no tickets, or draw is first called after targetBlock + 256, the pot rolls into the round current at that call. Each round draws or rolls exactly once. claim() pays msg.sender its winnings, zeroed first, through the hook's unlockCallback. Randomness: a future blockhash can be biased by the Sepolia proposer withholding a block; that is acceptable only because pots are test-toy sized, and the README says so. No VRF, oracle or keeper. Events: Ticket(poolId, round, holder, index), Sealed, Drawn(poolId, round, winner, pot), RolledOver, Claimed. Views: pot, ticketCount, ticketsOf(poolId, round, user), roundState. ETH-leg fee mechanics (as live launch 170's MedallionHook): a buy is zeroForOne (ETH in), a sell oneForZero (ETH out), and the swapper's specified amount is always honoured exactly. With ETH specified (exact-in buys, exact-out sells) the fee is a positive specified BeforeSwapDelta in beforeSwap of floor(|amountSpecified| x bps / 10,000); with ETH unspecified (exact-out buys, exact-in sells) it is a positive unspecified delta in afterSwap of floor(ETH the pool moved x bps / 10,000). That fee base is the swap's ETH leg. A partial fill (price limit hit) reverts with PartialFill. The hook settles each fee by minting itself ERC-6909 ETH claims (poolManager.mint) inside the swap, never take() or an ETH transfer in a callback, so the first buy into the ETH-less pool works; every payout burns claims and takes ETH in the hook's own unlockCallback, balance zeroed first (CEI). A fee that rounds to 0 is 0, so dust never reverts. Invariant: the hook's ETH claims at the PoolManager equal everything it still owes. Identity: the address abi.decode(hookData, (address)) when hookData is exactly 32 bytes and non-zero; any other swap credits nobody. Deploy shape (as live Sepolia hook launches 170, 183 and 186, constructor per the context): every rate, window and threshold is a source constant; no admin, setter, pause, upgrade or sweep. Permissions are exactly beforeSwap, afterSwap, beforeSwapReturnDelta and afterSwapReturnDelta (address bits 0x00CC), all others false, checked by Hooks.validateHookPermissions in the constructor with a CREATE2 salt mined for those bits. The factory initializes the pool (currency0 native ETH, currency1 TIKT, fee 3000, tickSpacing 60) and seeds one-sided TIKT liquidity; the hook must revert neither, and the first buy lands in a pool with no ETH. State is keyed by PoolId; a pool whose currency0 is not native ETH gets zero deltas and no other effect. Every callback requires msg.sender == PoolManager. Tests (Foundry, a real v4-core PoolManager deployed in the test, hook at a mined address): a launch rehearsal that initializes at the manifest price, seeds one-sided liquidity like the factory and makes the first buy into the ETH-less pool; all four swap modes; dust; a non-ETH pool; non-PoolManager callers revert; fuzzed sizes; and the cases the write-foundry-tests step lists (the ticket threshold, seal timing, the targetBlock + 1 / + 256 / + 257 window, empty rounds, double seal or draw, pots == claims). The independent adversarial review (read-only) attacks blockhash-window off-by-ones, timing games around seal, ticket index bias, round-boundary assignment, rollover double counting, claim reentrancy and ticket-array gas in swaps; its step lists each target. Website: one static page (dist/index.html) reading the hook's views and events, with a buy/sell form that swaps through the Sepolia PoolSwapTest router named in the site step and puts the connected wallet in hookData; it shows the current hour's pot and ticket count, the connected wallet's tickets, a countdown, seal and draw buttons when due, past winners from Drawn events and a claim button. Ticket is a Sepolia test toy: its token and any pot have no value, and nothing here promises a return.