# 全面掌握 Solana Transfer Hook 扩展：从入门到实战

By [amyzhou07](https://paragraph.com/@amyzhou07) · 2025-10-09

---

> **关键术语**：Transfer Hook、Token Extensions、Anchor 框架、SOL 费用、CPI 跨合约调用、PDA

为什么需要 Transfer Hook？
--------------------

Solana Token 2022 引入的 **Transfer Hook** 扩展允许开发者在每一笔转账发生时自动触发自定义逻辑，从而：

*   **强制版税**：NFT 二级市场自动收取创作分成
    
*   **黑白名单**：只允许预设地址收发代币
    
*   **灵活手续费**：按笔或按比例扣费
    
*   **链上统计**：记录转账次数、金额、来源等数据
    

其要点在于把「转账」这一孤立动作变成可编程事件，令整个代币生命周期更具可延展性。

* * *

Transfer Hook 执行原理
------------------

1.  Token Program 执行 `transfer` 时检测到 Mint 启用了 Transfer Hook 扩展。
    
2.  Token Program 通过 CPI 调用程序员编写的 **Transfer Hook 程序**。
    
3.  所有原始转账账户都会被设为 **只读**，防止特权滥用。
    
4.  Hook 逻辑成功执行则转账继续；失败则整个交易回滚。
    

* * *

快速上手：Hello Transfer Hook
------------------------

👉 [5 分钟在线体验零代码转账追踪示例](https://okxdog.com/)

### 步骤细节

1.  打开 [Solana Playground](https://beta.solpg.io/github.com/solana-developers/anchor-transfer-hook/tree/hello_world) 并点击 **Import**。
    
2.  在终端依次输入：
    
        build  
        deploy  
        test
        
    
3.  终端将打印四次成功日志，验证转账 Hook 正常工作。
    

示例代码（Rust，无额外账户）：

    pub fn transfer_hook(_ctx: Context<TransferHook>, amount: u64) -> Result<()> {
        msg!("Hello Transfer Hook! 转账金额 {}", amount);
        Ok(())
    }
    

* * *

进阶计数器：追踪每笔转账
------------

目标：为代币新增 **全局转账计数器**。

### 关键技术点

*   使用 PDA (`["counter"]`) 存储计数器。
    
*   需在 `InitializeExtraAccountMetaList` 中声明额外账户。
    
*   Hook 中务必检查 `assert_is_transferring`，防止恶意调用。
    

示例核心函数：

    pub fn transfer_hook(ctx: Context<TransferHook>, _amount: u64) -> Result<()> {
        assert_is_transferring(&ctx)?; // 防重放
        let counter = &mut ctx.accounts.counter_account;
        counter.value = counter.value.checked_add(1).unwrap();
        msg!("累计转账次数 {}", counter.value);
        Ok(())
    }
    

* * *

高级实战：wSOL 转账手续费
---------------

现在，我们将代币转账与 **自动 wSOL 手续费** 相结合：每一次转账，Hook 程序将等值的 wSOL 从发送者扣走并转给指定地址。

👉 [解锁完整实战源码，点此立即体验](https://okxdog.com/)

### 部署总览

> 以下每一步均可直接在 [Playground 模板](https://beta.solpg.io/github.com/solana-developers/anchor-transfer-hook/tree/main) 中完成。

#### 1\. 配置额外账户

*   `wsol_mint`：Wrapped SOL 铸币账户
    
*   `delegate PDA`：负责代扣手续费的「代理人」
    
*   `sender_wsol_ata` & `delegate_wsol_ata`：双方 token account
    

#### 2\. 编写 transfer\_hook

    transfer_checked(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            TransferChecked {
                from: ctx.accounts.sender_wsol_token_account.to_account_info(),
                mint: ctx.accounts.wsol_mint.to_account_info(),
                to: ctx.accounts.delegate_wsol_token_account.to_account_info(),
                authority: ctx.accounts.delegate.to_account_info(),
            },
        )
        .with_signer(&[&[b"delegate", &[ctx.bumps.delegate]]]),
        amount,
        ctx.accounts.wsol_mint.decimals,
    )?;
    

**权限说明**：发币者必须 `approve` delegate 代扣 wSOL，否则交易失败。

* * *

FAQ：常见疑问一次解决
------------

1.  \*\*Q：为何需要 fallback 指令？\*\*A：Token Program 使用原生指令鉴别器，与 Anchor 生成的 Mac 指令识别不一致，需要在 `fallback` 手动匹配 `Execute`。
    
2.  \*\*Q：wSOL 需预存多少？\*\*A：Hook 的手续费与转账金额成正比，确保 wallet 内存 **至少等于转账数额 + 交易费**。
    
3.  \*\*Q：能限制只白名单钱包转账吗？\*\*A：在 Hook 读取 `destination_token.owner` 并校验黑名单/白名单即可。
    
4.  \*\*Q：如何测试失败场景？\*\*A：本地测试把 `if` 条件抛出错误，如 `AmountTooBig`，并在 JS 端 `try-catch` 验证失败回滚。
    
5.  \*\*Q：能一次部署多个 Hook 程序？\*\*A：每个 Mint 只能指定一个 Hook Program，可部署多个程序用不同 Mint 使用。
    
6.  \*\*Q：生产环境 gas 成本会很高吗？\*\*A：一次 Transfer Hook 额外花费 ≈ 0.0003 SOL，主要用于新建 PDA 与 wSOL transfer，实际成本极低。
    

* * *

代码仓库与下一步
--------

*   所有演示源码已开源：[**GitHub → solana-developers/anchor-transfer-hook**](https://beta.solpg.io/github.com/solana-developers/anchor-transfer-hook/tree/main)
    
*   推荐阅读
    
    *   Token Extensions 官方文档
        
    *   Anchor Lang Book – Native CPI 章节
        

带着 Transfer Hook ，你可以把任何代币体验升级成「可编程资产」。现在就动手，为项目加一枚自定义逻辑的特洛伊木马吧！

---

*Originally published on [amyzhou07](https://paragraph.com/@amyzhou07/solana-transfer-hook)*
