Uniswap v4 훅은 왜 ‘플러그인’이 아니라 실행 경계인가
Uniswap v4 훅을 붙인 풀에서 사용자가 실제로 신뢰하는 코드는 PoolManager인가, 훅인가, 아니면 둘 사이의 콜백 순서인가?
Uniswap v4 훅은 왜 ‘플러그인’이 아니라 실행 경계인가
- 카테고리: blockchain_dev
- 예상 읽기 시간: 10분
- 오늘의 질문: Uniswap v4 훅을 붙인 풀에서 사용자가 실제로 신뢰하는 코드는 PoolManager인가, 훅인가, 아니면 둘 사이의 콜백 순서인가?
- 핵심 출처:
- Uniswap Blog - Uniswap v4 is Here - 게시일 미표기, 확인일 2026-06-16
- Uniswap Developers - Hooks - 게시일 미표기, 확인일 2026-06-16
- Uniswap Developers - Hook Deployment - 게시일 미표기, 확인일 2026-06-16
- Uniswap Developers - v4 Security Framework - 게시일 미표기, 확인일 2026-06-16
- Uniswap v4-core Hooks.sol - GitHub main, 확인일 2026-06-16
- Composable Security SCSVS - C9 Uniswap V4 Hook - GitHub master, 확인일 2026-06-16
1. 왜 지금 봐야 하나
Uniswap v4는 이미 “새 AMM 버전”이라기보다 개발자가 풀의 실행 흐름을 확장하는 플랫폼에 가깝다. Uniswap 공식 글은 v4가 live 상태이며, 훅을 통해 풀·스왑·수수료·LP 포지션에 커스텀 로직을 붙일 수 있고, 150개 이상의 훅이 이미 개발됐다고 설명한다. 동시에 v4는 9개 감사, 대규모 보안 경쟁, 최대 1,550만 달러 버그 바운티를 거쳤다고 밝힌다.
하지만 여기서 개발자가 놓치기 쉬운 점이 있다. “코어가 많이 감사됐다”는 말은 “내가 붙인 훅도 안전하다”는 뜻이 아니다. v4 훅은 단순 이벤트 리스너가 아니라 beforeSwap, afterSwap, beforeAddLiquidity, afterRemoveLiquidity 같은 실행 지점에서 PoolManager의 흐름 안으로 들어온다. 훅이 가격, 수수료, 토큰 이동, 외부 프로토콜 호출, 사용자별 회계를 바꾸면 사용자가 실제로 신뢰하는 경계는 v4 코어 밖으로 넓어진다.
최근 이 공부방에서는 PeerDAS, EIP-7928, Solana finality, FOCIL, ZK Gateway, ProxyAdmin, gas/block size, OP Stack interop를 다뤘다. 오늘은 L1/L2 합의나 브리지 메시지 대신, DeFi 프로토콜을 “확장 가능한 콜백 시스템”으로 만들 때 어떤 보안 가정이 새로 생기는지 보자.
2. 핵심 개념
오늘의 핵심 개념은 **실행 경계(execution boundary)**다. 어떤 컨트랙트가 다른 컨트랙트를 콜백으로 실행할 때, “상태가 언제 바뀌고 누가 그 상태를 믿는가”가 보안 경계가 된다.
Uniswap v4 문서에 따르면 각 풀은 하나의 훅 컨트랙트를 가질 수 있고, 하나의 훅은 여러 풀에서 재사용될 수 있다. 훅은 풀 초기화, 유동성 추가·제거, 스왑, donation 전후에 호출될 수 있다. 중요한 점은 훅 권한이 컨트랙트 주소의 하위 비트에 인코딩된다는 점이다. Hooks.sol의 주석과 Hook Deployment 문서는 v4가 훅 주소의 least significant bits를 보고 어떤 콜백을 호출할지 결정한다고 설명한다. 예를 들어 BEFORE_SWAP_FLAG, AFTER_SWAP_FLAG 같은 플래그가 주소에 맞아야 PoolManager가 해당 함수를 호출한다.
이 설계는 “훅이 무엇을 할 수 있는지”를 배포 주소 자체에 묶는다. 그래서 실전 배포에서는 CREATE2와 salt mining으로 원하는 비트 패턴의 주소를 찾아야 한다. 이건 신기한 배포 트릭이 아니라 보안 모델의 일부다. 주소가 잘못되면 예상한 훅이 호출되지 않거나, 반대로 원치 않는 훅 권한이 켜질 수 있다.
또 하나의 핵심은 훅이 풀의 storage를 직접 바꾸지 못해도 사용자의 operation 결과는 바꿀 수 있다는 점이다. SCSVS의 C9 문서는 훅이 PoolManager storage에 직접 영향은 못 주지만 사용자 operation의 상태를 바꿀 수 있고, 여러 풀이 같은 훅 storage와 로직을 공유할 수 있으며, 외부 컨트랙트에 의존하면 그 리스크도 상속한다고 정리한다.
3. 최신 이슈와 연결
v4 공식 보안 프레임워크는 훅 리스크를 꽤 직접적으로 나눈다. 회계·토큰 처리 실패, 외부 호출과 reentrancy, 수학 정밀도, 외부 의존성, upgradeability, OPSEC가 핵심 축이다. 특히 문서는 훅이 swap 실행 파이프라인 안에 있기 때문에 안전하지 않은 가정이 풀 무결성, 가격, LP 손실로 이어질 수 있다고 경고한다.
이 말은 v4 훅 개발자가 단순히 “Solidity 컨트랙트 하나를 잘 짠다” 수준에서 멈추면 안 된다는 뜻이다.
- dynamic fee 훅은 fee 계산식이 oracle, volatility, timestamp, inventory 상태에 의존할 수 있다.
- lending 훅은 swap 또는 liquidity callback 중 외부 lending protocol의 금리·담보·상환 상태 변화를 상속한다.
- LST/LRT 훅은 rebasing, share price, unwrap rate, rounding error를 처리해야 한다.
- cross-chain 훅은 메시지 지연, 중복, 순서 뒤바뀜, finality 가정을 가져온다.
- upgradeable 훅은 admin key, timelock, storage layout, 사용자 고지 문제를 풀 안으로 끌고 온다.
OpenZeppelin의 v4 core audit 설명도 비슷한 결론을 준다. 훅은 pool initialization 시 지정되고 PoolManager가 사용자 행동 전후에 호출한다. 일부 훅은 PoolManager의 control flow에 영향을 줄 수 있으며, 낮은 주소 비트가 어떤 훅이 켜지는지 결정한다. 또한 악의적 훅은 사용자와 LP의 토큰을 여러 방식으로 훔칠 수 있고, 사용자 slippage 보호만으로는 LP 리스크가 충분히 완화되지 않는다고 설명한다.
즉 v4의 확장성은 “새 기능을 빨리 붙이는 자유”이면서 동시에 “풀마다 서로 다른 trust profile이 생기는 비용”이다.
4. 개발자 관점 해석
첫째, 훅 주소는 배포 산물이 아니라 권한 선언이다. 일반 컨트랙트에서는 주소가 “어디에 배포됐는가” 정도의 의미지만, v4 훅에서는 주소 하위 비트가 “어떤 콜백이 실행되는가”를 결정한다. CI에서 validateHookPermissions 또는 동등한 검증을 빠뜨리면 테스트넷과 메인넷 배포 주소 차이가 곧 실행 경로 차이가 된다.
둘째, msg.sender 감각이 흔들린다. 훅 함수는 PoolManager가 호출한다. SCSVS는 훅 함수의 sender 파라미터를 실제 사용자로 취급하지 말고, 사용자는 신뢰할 수 있는 PoolOperator가 hook data로 전달해야 한다고 경고한다. “이 함수는 PoolManager만 부르니까 안전하다”와 “이 operation의 원래 사용자가 누구인가”는 다른 질문이다.
셋째, 같은 훅이 여러 풀에서 쓰이면 storage 격리가 설계 문제가 된다. 풀 A의 누적 값, 사용자별 quota, oracle snapshot, timelock 상태가 풀 B와 섞이면 공격자는 싼 풀이나 가짜 풀을 통해 훅 상태를 오염시킨 뒤 비싼 풀에서 이득을 볼 수 있다. 그래서 hook state key에는 pool id, currency pair, fee tier, tick spacing, operator trust boundary를 명시적으로 포함해야 한다.
넷째, reentrancy는 “다시 들어온다”보다 넓다. v4 보안 프레임워크는 외부 호출이 들어가면 같은 풀, 다른 풀, 같은 훅을 공유하는 풀, 외부 프로토콜 상태가 callback sequence 중 바뀔 수 있다고 본다. 단순 nonReentrant 하나로 충분한지보다 “콜백 전 상태를 콜백 후에도 믿어도 되는가”를 테스트해야 한다.
다섯째, upgradeable 훅은 LP에게 사실상 moving target이다. 코어가 immutable이어도 훅이 proxy라면 풀의 정책은 나중에 바뀔 수 있다. 이 경우 사용자는 “Uniswap v4 풀”이 아니라 “특정 admin이 바꿀 수 있는 훅이 붙은 풀”에 유동성을 넣는 것이다. timelock, pause, opt-out window, 코드 변경 고지가 제품 UX의 일부가 되어야 한다.
5. 내 프로젝트에 적용할 체크포인트
- 훅 권한: 배포 주소의 하위 비트가 의도한
before/after플래그와 일치하는지 테스트와 배포 스크립트에서 검증하는가? - 호출자 검증: 훅 함수,
unlockCallback, 내부 callback helper가 오직 PoolManager 또는 신뢰한 operator만 호출 가능하도록 제한되는가? - 사용자 식별: 훅의
sender파라미터,msg.sender, hookData의 user를 혼동하지 않는가? - 풀 격리: storage key에 pool identity를 충분히 포함하는가? 같은 훅을 여러 풀에서 쓸 때 상태가 섞이지 않는가?
- 토큰 회계: fee-on-transfer, rebasing, ERC-777 callback, pausable/freezable token, rounding drift를 테스트했는가?
- 외부 의존성: oracle, lending, bridge, LST rate, sequencer 상태가 멈추거나 조작될 때 훅이 revert, degrade, pause 중 무엇을 하는가?
- LP 보호: swappers의 slippage protection 말고 LP가 훅 변경·수수료 변경·출금 제한·upgrade를 감지하고 빠져나갈 수 있는가?
- 운영 권한: admin key, timelock, emergency pause, monitoring alert, bug bounty 범위가 훅까지 포함되는가?
6. 오늘 10분 액션
오늘은 코드 없이도 할 수 있는 훅 리스크 맵을 만들어보자.
- 관심 있는 v4 훅 하나를 고른다. 없다면 가상의 dynamic fee 훅을 상상해도 된다.
- 표를 5열로 만든다:
콜백,읽는 상태,쓰는 상태,외부 호출,실패 시 피해자. beforeSwap,afterSwap,beforeAddLiquidity,afterRemoveLiquidity를 행으로 넣는다.- 각 행에 “이 시점에 믿는 값”을 적는다. 예: oracle price, pool liquidity, user balance, hook quota, LST exchange rate.
- 마지막 열에 피해자를 쓴다. swapper인지, LP인지, hook admin인지, 다른 풀의 사용자까지 번지는지 표시한다.
- 표 아래에 한 줄을 추가한다. “이 훅이 upgradeable이면 누가 언제 이 표를 바꿀 수 있는가?”
10분 뒤에 남아야 하는 문장은 이것이다. 훅은 기능 목록이 아니라 콜백 순서 안에서 상태를 믿는 방식이다.
7. 더 볼 자료
- Uniswap v4 Security Framework
- 훅 리스크를 accounting, external call, math, dependency, upgradeability, OPSEC로 나눠 자체 점검할 수 있다.
- Hook Deployment
- CREATE2와 주소 비트가 왜 훅 권한 검증의 일부인지 확인하기 좋다.
- Hooks.sol
- 실제 플래그, permission struct, return delta 처리, hook call validation을 코드로 볼 수 있다.
- SCSVS C9: Uniswap V4 Hook
- 훅 전용 보안 검증 항목을 체크리스트로 바꾸기 좋다.
- OpenZeppelin - Uniswap v4 Core Audit
- v4 core 관점에서 훅과 singleton PoolManager가 어떤 리스크를 만드는지 감사 관점으로 볼 수 있다.
중복 회피 메모
최근 blockchain_dev 글은 PeerDAS/data availability, EIP-7928 병렬 실행 전제, Solana Alpenglow finality, FOCIL inclusion list, ZK Gateway settlement layer, 멀티시그 ProxyAdmin, Ethereum gas/block size limit, OP Stack interop의 cross-chain state 안전성을 다뤘다. 2026-06-06 글은 native account abstraction과 delegation/revoke를 다뤘다. 이번 글은 지갑·브리지·합의가 아니라 Uniswap v4 훅을 사례로 컨트랙트 콜백이 풀 실행 경계와 LP 신뢰 가정을 어떻게 바꾸는가에 집중해 중복을 피했다.
핵심 출처
로그인하면 이 글을 북마크하고, 나만 보는 한 줄 메모를 남길 수 있어요.
댓글 0
최신순 ▾혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)