보안
가치를 담고 있는 것
- 풀의 ETH와 토큰, 누구도 뺄 수 없는 포지션 안에 있습니다. 진영의 ETH는 그 진영이 해당 풀에 팔릴 때만 풀을 떠납니다. 트레이더가 팔거나, 거래로 세 가격이 벌어진 뒤 훅의 재정렬이 파는 경우입니다.
- 팟, 크리에이터 수수료, 프로토콜 수수료, 훅이 Uniswap V4 PoolManager 안의 ETH 청구권으로 보관하며, 대결마다 따로 기록됩니다.
무엇이 지키나
- 잠긴 유동성. 팩토리만 등록된 풀을 열고 런칭 유동성을 더할 수 있습니다. 인출과 기부는 되돌려집니다.
- 제한된 수령인. 팟은 해당 대결의 승자만 바이백하고 크리에이터 수수료는 대결의 크리에이터, 즉 런칭한 지갑이나 그 지갑이 역할을 넘기고 상대가 수락한 주소에게만 갑니다. 프로토콜 수수료는 현재 재무 주소로 지급됩니다. 팩토리 소유자는 48시간 뒤 이 주소를 바꿀 수 있으며, 이미 쌓인 프로토콜 수수료에도 적용됩니다.
- 제한된 팩토리 권한. 토큰에는 소유자나 민팅 함수가 없으며, 훅은 업그레이드나 일시 중지가 불가능합니다. 소유자는 새 런칭을 일시 중지하거나, 앞으로의 대결에 한도 안의 조건을 제안하거나, 지연 후 재무 주소를 바꿀 수 있습니다. 또한 소유자는 모든 대결의 스왑 수수료에서 프로토콜 몫을 즉시 0까지 낮추거나 다시 올릴 수 있지만, 대결의 조건을 넘을 수는 없습니다. 프로토콜이 가져가지 않는 몫은 팟으로 갑니다. 소유자는 이 권한을 영구히 포기할 수 있습니다(
renounceOwnership). 그러면 조건, 재무 주소, 프로토콜 요율, 일시 중지 상태가 그대로 유지되며, 이미 제안된 변경만 지연 후 누구나 적용할 수 있습니다. - 스왑 전 정산. 마감 후 첫 스왑은 거래 전에 끝난 평균을 정산합니다. 바이백 상한은 틱보다 세밀한 정밀도로 유지되는 기준 가격보다 약 10% 높습니다. 기준 가격은 ETH 풀 틱의 30분 지수 평균이되, 현재 틱을 하한으로 삼아 가격이 내려갈 때는 곧바로 따라갑니다.
- ETH만 사용하는 라운드. 비율과 평균은 두 ETH 풀을 사용합니다. ETH 가격을 움직이지 않는 A/B 전환은 신호나 조용하던 라운드의 활동을 바꾸지 않습니다.
- 전체 체결에 대한 수수료. 수수료를 미리 받는 스왑은 요청량을 전부 체결하지 못하면 되돌려집니다. 네트워크 가스비는 별도입니다.
- 분리된 재정렬. 토큰을 사들이는 풀의 ETH 한도 안에서 수익성 있는 루프만 유지합니다. 실패한 시도는 되돌리고 건너뜁니다. 가스가 모자라 실패하면 스왑이
ArbitrageStarved로 되돌려지므로, 호출자가 가스를 아껴 재정렬을 건너뛸 수 없습니다. 가격 일치나 모든 거래 손실에 대한 보호를 보장하지는 않습니다. - 모든 경로에 같은 규칙. Duel 라우터든 다른 V4 라우터든 훅이 수수료, 세금, 소각을 처리합니다.
팩토리는 런칭이 일시 중지된 상태로 시작합니다. paused()가 true인 동안에는 owner()만 대결을 런칭할 수 있으며, 다른 호출자는 CreationPaused로 되돌려집니다. 소유자는 setPaused(false)로 런칭을 엽니다. 기존 대결은 계속 거래됩니다.
사이트가 보여 주는 것
- 사이트에서만 오는 이미지. 페이지는 대결 이미지를 Duel 자체 주소에서만, 그리고 사이트가 처리한 이미지만 보여 줍니다. 먼저 헤더로 읽은 JPEG, PNG, WebP(최대 1536 × 1536픽셀, 5MB)를 WebAssembly로 디코딩하고, 1024픽셀 안에 맞춘 뒤 메타데이터 없이 WebP로 다시 인코딩합니다. 페이지의 보안 정책은 다른 곳에서 이미지를 불러오지 못하게 합니다.
- 따로 떨어진 코덱. 이미지는 별도의 Worker에서 디코딩됩니다. 이 Worker는 사이트만 호출할 수 있고, 키도 저장소도 갖고 있지 않습니다. 코덱에 결함이 있어도 닿을 수 있는 것은 읽고 있는 이미지뿐입니다. 사이트는 이 Worker가 돌려준 결과(예상한 크기의 정지 WebP)를 확인한 뒤에야 보관하며, C로 작성된 디코더는 이미지마다 새로 시작합니다.
- 컨트랙트에서 바로 런칭한 대결. 세부 정보에 어떤 주소든 적을 수 있습니다. 사이트는 https 이미지를 보여 주지 않습니다. IPFS 이미지는 공개 게이트웨이에서 한 번만(최대 5MB, 10초) 가져와 업로드와 같이 처리한 뒤 자체 사본을 보여 주며, 그렇지 못하면 진영의 이니셜을 보여 줍니다.
- 제한된 업로드. 사이트는 자체 페이지에서 보낸 이미지만 받습니다. 한 주소에서 1분에 10개, 하루에는 정해진 수까지입니다. 어떤 대결도 쓰지 않는 이미지는 하루 뒤 삭제됩니다.
어떻게 검증했나
- 자동화 테스트는 컨트랙트 동작, 웹 앱, 알림 봇을 다룹니다. 커버리지는 테스트 지표이며 모든 가능한 동작의 안전성을 증명하지는 않습니다.
- 포크 테스트는 Universal Router, Permit2, V4 Quoter를 포함한 Robinhood Chain의 배포된 Uniswap V4 컨트랙트와의 통합을 확인합니다.
- 회귀 테스트는 수수료 회계, 런칭 경계 사례, 정산, 고갈된 풀 등 내부 검토에서 찾은 사례를 유지합니다.
- 불변식 테스트는 무작위 거래·정산·청구 순서의 회계를 확인합니다. ETH 청구권은 지급할 금액과 일치해야 하며, 중간 토큰이 훅, 팩토리, 라우터에 남아서는 안 됩니다. 설정된 실행을 통과했다고 모든 가능한 순서의 안전성이 입증되는 것은 아닙니다.
내부 검토에서는 정확한 출력량 스왑으로 안티 스나이프 세금을 피해 가는 경로, 혼자 매수된 진영을 따라가지 못하던 비율, 바이백 기준 가격이 잘못 읽던 매진된 풀, 대결 메타데이터의 안전하지 않은 링크를 찾아 고쳤습니다.
취약점 제보
취약점을 발견하셨다면, 시간을 내어 알려 주셔서 감사합니다. 텔레그램 @chatwithdivine으로 비공개로 연락해 주시고, 발견하신 내용과 가능하다면 재현 방법을 함께 알려 주세요. 공개하시기 전에 저희가 검토할 시간을 주시면 감사하겠습니다. 빠르게 답변드리고 진행 상황을 계속 알려 드리겠습니다.
저희가 먼저 연락하는 일은 없습니다. @chatwithdivine만 믿어 주세요.