Solana 上的 WithdrawExcessLamports:SPL Token 与 Token-2022 指南
定价和功能依据已核实 2026年9月3日.
WithdrawExcessLamports 是代币程序指令 38。它解决一个具体问题:铸币账户、代币账户或多签账户可能持有超过免租所需额度的 lamport,但这些 lamport 无法通过普通代币转账来转移。
WithdrawExcessLamports 有什么作用?
WithdrawExcessLamports 仅转移代币程序账户实时免租最低余额以上的 SOL。源账户保持开放,其代币或铸币数据不会变化。必要签名者取决于源账户是代币账户、铸币账户还是代币多签账户。
该指令在传统 SPL Token Program 和 Token-2022 中均可用。在 2026 租金提案之前,它可用于回收误转入代币程序所有账户的 lamport。降低租金最低余额后,其用途更广:旧账户可以保留原有余额,同时仅需更少的储备金。
权威行为说明和当前客户端示例位于 Solana 的 Withdraw Excess Lamports 文档。处理器实现也 在代币程序代码库中公开提供.
该指令需要哪些账户?
| 账户 | 是否可写? | 是否签名? | 用途 |
|---|---|---|---|
source | 是 | 有时 | 持有盈余 lamport 的代币账户、铸币账户或多签账户 |
destination | 是 | 否 | 接收提取的 lamport |
authority | 否 | 取决于源账户类型 | 证明有权提取 |
multiSigners | 否 | 使用时需要 | 满足已配置的代币多签阈值 |
处理器会读取源账户的数据长度和当前租金设置,计算其最低余额,然后转移差额。它不接受调用方提供的储备金额度,因为该数值可能已过时或遭到操纵。
每种源账户类型必须由谁签名?
| 源账户 | 必要权限方 |
|---|---|
| 由钱包所有者持有的代币账户 | 代币账户所有者 |
| 由代币多签账户持有的代币账户 | 所需的 M-of-N 多签成员 |
| 具有有效铸币权限的铸币账户 | 当前铸币权限方 |
| 没有铸币权限方的铸币账户 | 源铸币账户本身 |
| 多签源账户 | 已配置的 M-of-N 名成员 |
铸币权限已撤销的情况需要特别注意。如果源铸币账户由曲线上的密钥对创建,则必须由该原始密钥对签名。如果它不在曲线上,则其控制程序必须使用正确的 PDA 签名种子调用代币程序。代币持有者或原铸币权限方均无法替代源账户签名。
如何使用 Solana 客户端构建该指令?
当前官方示例使用 @solana-program/token ,并配置 @solana/kit 客户端:
import { getWithdrawExcessLamportsInstruction } from "@solana-program/token";
const instruction = getWithdrawExcessLamportsInstruction({
source,
destination,
authority,
});
await client.sendTransaction([instruction]);
此处 authority 是一个 TransactionSigner 且适合该源账户。对于多签权限方,请通过以下方式加入其共同签名者: multiSigners。生产环境中应锁定软件包版本,并针对实际使用的客户端确切版本进行编译;即使链上账户合约未发生变化,客户端类型也可能改变。
切勿硬编码 0.00203928 SOL 作为储备金。该数值是标准 165 字节代币账户的旧版最低余额,并非当前通用值。应在构建或预览交易前,根据源账户的实际数据长度查询当前最低余额。
SPL Token 与 Token-2022 在此处有何不同?
该指令的核心效果相同,但在 Token-2022 中,对数据长度作出假设的风险尤其大。铸币账户和账户扩展会增加序列化后的大小,从而提高所需储备金。若集成对每个源账户都采用标准的 82 或 165 字节大小,可能会高估盈余。
Token-2022 的 CPI Guard 是封装器的另一个实际差异。当 Guard 锁定时,即使钱包原本是有效权限方,跨程序调用也可能被拒绝。Sol Incinerator 会跳过这些源账户,而不是将一个必然失败的操作放入更大的清理交易中。
原生封装 SOL 代币账户会被拒绝,并返回 NativeNotSupported。解封原生 SOL 使用的是另一种关闭账户流程,并非提取多余 lamport。
Sol Incinerator API 如何封装该指令?
Sol Incinerator 的 v2 API 通过 Assetcinerator 构建代币程序调用,从而在链上执行协议费和可选的合作方费用。此封装器属于产品层;原始代币程序指令本身并不收取 Sol Incinerator 的费用。
在请求用户签名前,请使用经过身份验证的预览:
curl -X POST https://v2.api.sol-incinerator.com/withdraw-excess-lamports/preview \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"userPublicKey": "DESTINATION_WALLET",
"sourceAccount": "TOKEN_ACCOUNT_MINT_OR_MULTISIG"
}'
相关的交易和指令路由如下:
POST /withdraw-excess-lamportsPOST /withdraw-excess-lamports-instructions
userPublicKey 是目标钱包和默认权限方。请提供 authorityPublicKey ,适用于必须由其他铸币权限方、源账户或多签权限方签名的情况。最多提供 11 multisigSignerPublicKeys ,用于构建代币多签流程。所有私钥均保留在本地;API 会返回供必要签名者批准的材料。
基础协议费为 200 bps。直接集成方可以添加 partnerFeeAccount 和 partnerFeeBps,而常规的 Solana 交易费则另行计算。请使用返回的 feeLamports 和回收字段,而不要重复使用缓存的百分比计算结果。
集成应处理哪些失败情况?
- 无盈余: 源账户余额已达到当前储备金额度。
- 账户所有者或布局错误: 源账户不是受支持的代币程序账户。
- 权限无效: 所提供的签名者与解码后的源账户状态不匹配。
- 多签不完整: 提供的有效已配置签名者数量不足。
- 原生账户: 封装的 SOL 使用另一项操作。
- 锁定的 CPI Guard: Token-2022 会拒绝封装器 CPI。
- 状态已变化: 预览后,余额、权限或租金设置发生了变化。
- 交易成本超过价值: 扣除网络费后,金额过小的提取可能并不划算。
状态可能发生变化时应重新预览,确保源账户选择具有幂等性,并且切勿将已知不符合条件的源账户与其他有效操作放入同一批次。
相关阅读
常见问题
Solana 上的 WithdrawExcessLamports 有什么作用?
WithdrawExcessLamports 会将代币程序账户当前免租最低余额以上的 lamport 转移到目标钱包。源账户可以是代币账户、铸币账户或多签账户。该指令不会改变代币数量、铸币供应量、权限、扩展及其他所有序列化账户数据。
哪个权限方应为 WithdrawExcessLamports 签名?
代币账户使用其所有者或已配置的多签签名者。具有有效铸币权限的铸币账户使用该权限方。没有铸币权限方时,必须由源铸币账户本身签名,即使用其密钥对,或由控制曲线外铸币账户的程序通过 CPI 签名路径完成。
WithdrawExcessLamports 是否支持 Token-2022?
支持。该指令适用于传统 SPL Token 和 Token-2022 的账户、铸币账户及多签账户。集成必须根据源账户的实际数据长度计算租金,因为 Token-2022 扩展可能增大账户,而锁定的 CPI Guard 可能阻止通过封装器执行。
WithdrawExcessLamports 能否将代币账户余额提取到低于免租额度?
不能。代币程序会计算源账户所需的最低余额,并且只转移高于该额度的差额。原生封装 SOL 代币账户会被拒绝。应用仍应预览实时状态,因为账户余额、数据长度、租金设置和可用权限都可能在提交前发生变化。
