Token-2022 전송 훅(Transfer-Hook) 스캐폴드
전송 훅은 Token-2022 확장 중 올바르게 구현하기 가장 까다로운 부분입니다. 프로그램은 Anchor가 생성하지 않는 인터페이스 식별자를 노출하고, 바이트 단위로 정확한 순서의
ExtraAccountMetaList를 배치하며, out-of-band 호출에 저항해야 합니다. 작은 실수도 불투명한 런타임 오류로 나타납니다. 이 스킬은 안전을 기본값으로 하는 경로로, 컴파일되는 프로그램과 LiteSVM 공격 테스트로 뒷받침됩니다.토큰 확장 스킬과의 차이점:
solana-token-extensions/token-2022-extensions는 훅을 하나의 기능으로 취급합니다(단일 정적 예제와 한 경우 체크리스트 감사). 이 스킬은 전용 훅 도구입니다. 주문에 따라 새로운 보안 훅을 생성하는(scaffold.sh) 유일한 도구이며, 통과하는 공격 테스트로 감사 기능을 뒷받침합니다. 상호 보완적입니다. 실제로 훅을 구축하거나 강화할 때 함께 설치하세요.
이 스킬을 사용하는 경우
- 전송 훅 구축: 화이트리스트/KYC 게이팅, 로열티 징수, 수수료 라우팅, 전송별 회계/제한, 소울바운드 규칙.
- 훅 디버깅:
AccountNotFound,NotEnoughAccountKeys,IncorrectAccountAddress, 또는 "훅 없이 전송되나 훅 있으면 실패" 현상. - 기존 훅 프로그램 검토/감사: 일반적인 실수 확인.
- 훅을 가리키는 Token-2022 민트 생성 및 클라이언트 전송 연결.
통합자 참고: 소비 측면(훅이 있는 타사 민트 수용)이라면 다른 문제입니다. 대부분의 통합자는 알 수 없는 훅 민트를 거부해야 합니다. 함께 제공되는 token2022-integration-guard 스킬을 참조하세요.
개념 모델 (먼저 읽으세요)
- 훅 프로그램은
Execute(SPL 전송-훅 인터페이스)를 구현하며, Token-2022는 모든 전송 시 이를 CPI 호출합니다. Anchor는sha256("global:<ix>")로 디스패치하는데, 이는 인터페이스 식별자와 일치하지 않습니다. 따라서fallback을 추가하여 인터페이스 명령을 디코딩하고 인-프로세스로 디스패치합니다(절대 self-CPI 안 됨). → program.md - 훅은 추가 계정을 요구할 수 있습니다. 이를
ExtraAccountMetaListPDA(["extra-account-metas", mint])에 한 번 선언하면 Token-2022가 읽어Execute에 해당 계정을 전달하며, 전송 시 시드 기반 PDA를 해결합니다. 순서가 중요합니다. → extra-account-metas.md - 클라이언트는
createTransferCheckedWithTransferHookInstruction으로 전송을 구성해야 합니다(일반transferChecked는 추가 계정을 생략하여 되돌립니다). → client-wiring.md - 훅은 공격자에게 노출됩니다. 보호하세요. → security.md
- 훅을 통해 전송하는 테스트로 증명하세요. → testing.md
라우팅 테이블
| 사용자가... | 읽을 문서 |
|---|---|
| 훅 프로그램 작성(Execute, fallback, 메타 리스트 초기화) | program.md |
| ExtraAccountMetaList / 불투명한 계정 오류 해결 | extra-account-metas.md |
| 민트 + 클라이언트 전송 연결 | client-wiring.md |
| 보안 강화 / 감사 | security.md |
| 훅 테스트 작성 | testing.md |
| 새 훅 워크스페이스 스캐폴딩 | 실행 /transfer-hook:scaffold |
| 기존 훅 프로그램 감사 | 실행 /transfer-hook:audit |
| 출처 / 추가 자료 | resources.md |
이 스킬에 포함된 내용
| 아티팩트 | 경로 | 설명 |
|---|---|---|
| 참조 훅 프로그램 | examples/hook/ | 컴파일되는 Anchor 1.0 훅: 화이트리스트 게이트 + 민트별 카운터, fallback 라우터, is_transferring 가드. |
| 공격 테스트 | examples/hook/tests/ | LiteSVM 테스트. 훅을 통해 전송: 화이트리스트 통과(카운터 증가), 비화이트리스트 차단, 직접 Execute 호출 거부. |
| 스캐폴드 스크립트 | scripts/scaffold.sh | 참조에서 새 훅 워크스페이스 생성. |
고정 스택 (2026)
Anchor 1.0, anchor-spl 1.0.2, spl-transfer-hook-interface =2.1.0, spl-tlv-account-resolution 0.11, @solana/spl-token 0.4.14, litesvm 1.2 (키트 네이티브, Token-2022 사전 로드). 참조 프로그램은 이 스택에서 빌드 및 테스트 통과.
비협상 규칙
fallback추가:TransferHookInstruction::Execute를 디코딩하고 인-프로세스로 디스패치(__private::__global::transfer_hook) — 절대invoke로 자신의 프로그램 호출 금지.- 첫 전송 전에
ExtraAccountMetaList초기화,Vec<ExtraAccountMeta>순서를Execute계정 구조체와 동일하게 유지. is_transferring으로Execute보호 — 실제 전송 외 호출 거부.- 모든 주입 계정을 PDA 시드에 바인딩(
Account<T>+seeds), 절대UncheckedAccount사용 금지 — 공격자가 화이트리스트를 위조할 수 있음. - 훅을 최소화하고 완전(total)하게 유지 — 모든 전송 시 실행되며, 패닉/과다 CU는 토큰을 망가뜨림.
- 전송 경로 테스트, 단위 로직만 테스트하지 마세요 — 컴파일되는 훅도 실행 시 실패할 수 있음.