A Uniswap v4 hook for a double-or-nothing game built into swap flow—matched stakes from two swaps, then an on-chain ruleset decides payouts. This repo uses Rock-Paper-Scissors (commit–reveal) as that ruleset; the design is DoN-on-Uniswap, not RPS-specific. The creator stakes 3% of the swap’s specified leg; the joiner matches in that same asset. The winner takes 2× the pot; a tie refunds both stakes.
-
Create – Creator swaps with hookData
(1, expiryParam, commit). 3% of the swap (specified side) is escrowed for the game.commit = keccak256(abi.encodePacked(move, salt)). -
Join – Joiner swaps with hookData
(2, gameId, joinerMove). The hook only accepts the join if this swap’s input currency matches the game’s staked token and the swap moves at least the stake amount on that leg. Moves:0= Rock,1= Paper,2= Scissors. -
Resolve – Creator calls
gameContract.resolveGame(gameId, move, salt). RPS picks the winner: tie → both stakes returned; win → winner gets 2× stake. -
Forfeit – If the creator does not reveal before the deadline (3 days after join), the joiner calls
gameContract.claimForfeit(gameId)and receives 2× stake. -
Withdraw – If nobody joins before expiry, the creator calls
gameContract.withdraw(gameId)to reclaim their stake.
- DonGameHook – Uniswap v4 hook:
beforeSwap/afterSwapcreate or join games; stakes move to the game contract viatake(). - RockPaperScissors – Escrows tokens, tracks game state, and implements
resolveGame,claimForfeit, andwithdraw.
| Action | First byte | abi.encode payload |
|---|---|---|
| Create | 1 |
(uint256 expiryParam, bytes32 commit) |
| Join | 2 |
(uint256 gameId, uint8 joinerMove) |
joinerMove:0= Rock,1= Paper,2= ScissorsexpiryParam: seconds until the creator may withdraw if no joiner (0→ 1h default; min 5 min, max 7 days)
- Create / join – Encode hookData and pass it on the pool
swapcall. - Resolve / forfeit / withdraw – Call
gameContract.resolveGame,claimForfeit, orwithdrawdirectly. - State –
gameContract.getGame(gameId)for on-chain game state.
Any pool currency is supported, including native ETH (Currency.wrap(address(0)) in Uniswap v4).
forge build
forge test- Not audited; for experiments only.
- 3% is fixed in code. Users are still mostly just swapping.
- No separate “bet” field. The stake is 3% of the swap amount on the specified side—whatever you put in the swap.
- Joining: your swap must pay in the same token as the game, with at least the stake. If not, the hook skips the game.
- Hook creates the game when it deploys. For safety concern, only that hook may open or join games. Simple and safe for a small demo; a real system might use a factory or clearer access control.