> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana Gas 赞助

> 使用 svmSponsor 为用户支付 Solana 交易手续费：由你出资的赞助账户作为手续费支付方，用户只需为自己的代币签名。

Solana gas 赞助让用户无需持有 SOL 来支付手续费，就能从 Solana 发起交换或 bridge。你将一个由你控制的 Solana 账户公钥作为 `svmSponsor` 传入，LI.FI 会把该账户设为交易的手续费支付方（fee payer）来构建交易。赞助账户和用户钱包对同一笔交易签名，由赞助方支付网络手续费。

这是手续费支付方替换，不是中继。LI.FI 不持有赞助账户的私钥，不为赞助账户出资，也不会替你提交交易。由你为该账户出资、用它签名，并支付它所覆盖的费用。

> [!NOTE]
>
> 赞助仅适用于从 Solana 发起的交易。EVM 上的对应机制由 LI.FI 中继并从输入金额中回收成本，请参阅[无 gas 交易](https://docs.li.fi/guides/gasless-transactions.md)。各种 gas 机制的对比请参阅 [Gas 选项](https://docs.li.fi/guides/gas-options.md)。

***

## 工作原理

**1. 携带 svmSponsor 发起请求**

在报价请求中加入赞助方公钥，或同时加入路由请求和 stepTransaction 请求。响应的 `transactionRequest.data` 中是一笔未签名、base64 编码的 Solana 交易，手续费支付方为赞助账户。

**2. 检查手续费支付方**

反序列化交易，确认手续费支付方（第一个账户公钥）是你的赞助账户。如果它是用户地址，说明该请求构建时没有带上赞助方。请参阅下文"在每个请求中传入"一节。

**3. 收集签名**

赞助方和用户对同一条消息签名，顺序不限，每个签名填入各自的位置。两次签名之间不要重建或修改交易。

**4. 在 blockhash 过期前提交**

将签名完整的交易发送到 Solana RPC，然后像其他转账一样用 `GET /v1/status` 跟踪状态。

***

## 在每个请求中传入

`svmSponsor` 接受 base58 格式的 Solana 公钥，其他格式会返回 `400`。

| 请求 | `svmSponsor` 的位置 |
| - | - |
| `GET /v1/quote` | 查询参数。返回的交易可直接收集两方签名。 |
| `GET /v1/quote/toAmount` | 查询参数，同上。 |
| `POST /v1/advanced/routes` | 请求体中的 `options.svmSponsor`。路由会据此筛选 bridge，请参阅下文"从 Solana 出发的 bridge"一节。 |
| `POST /v1/advanced/stepTransaction` | 查询参数：`?svmSponsor=<pubkey>`。这里必须再次传入。 |
| SDK | 在 `createConfig` 中设置 `routeOptions.svmSponsor`，请参阅下文 SDK 一节。 |

> [!WARNING]
>
> 在 `stepTransaction` 中漏传 `svmSponsor` 不会报错，返回的交易会以用户为手续费支付方。路由响应虽然在 `includedSteps[].action` 中带回了赞助方，但 stepTransaction 不会从提交的 step 中读取它，只读取查询参数。

```bash Quote with a sponsor theme={"system"}
curl -G "https://li.quest/v1/quote" \
  -H "x-lifi-api-key: $LIFI_API_KEY" \
  --data-urlencode "fromChain=SOL" \
  --data-urlencode "toChain=SOL" \
  --data-urlencode "fromToken=USDC" \
  --data-urlencode "toToken=USDT" \
  --data-urlencode "fromAmount=5000000" \
  --data-urlencode "fromAddress=<USER_PUBKEY>" \
  --data-urlencode "svmSponsor=<SPONSOR_PUBKEY>"
```

```bash Routes, then stepTransaction theme={"system"}
# 1. Request routes with the sponsor in options
curl -X POST "https://li.quest/v1/advanced/routes" \
  -H "Content-Type: application/json" \
  -H "x-lifi-api-key: $LIFI_API_KEY" \
  -d '{
    "fromChainId": 1151111081099710,
    "toChainId": 42161,
    "fromTokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "toTokenAddress": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
    "fromAmount": "20000000",
    "fromAddress": "<USER_PUBKEY>",
    "toAddress": "<EVM_RECIPIENT>",
    "options": { "svmSponsor": "<SPONSOR_PUBKEY>" }
  }'

# 2. Post the chosen step, and pass the sponsor again as a query parameter
curl -X POST "https://li.quest/v1/advanced/stepTransaction?svmSponsor=<SPONSOR_PUBKEY>" \
  -H "Content-Type: application/json" \
  -H "x-lifi-api-key: $LIFI_API_KEY" \
  -d @step.json
```

***

## 签名时不要重建交易

返回的是版本化（v0）Solana 交易。必须签名的账户排在消息账户列表的最前面：

* 赞助方，作为手续费支付方；
* 用户，作为输入代币的所有者；
* 在部分路由上，还有一个一次性密钥，你拿到交易时它的签名已经在交易中。我们在 `mayanFastMCTP` 上观察到了这种情况。

不要假设签名数量一定是两个，也不要假设签名列表一定为空。

Solana 签名针对序列化后的消息，所以每个签名方签的是同一份字节。反序列化、加上自己的签名、再序列化，然后把字节传给下一方。不要重新编译消息：消息一旦改变，已有的所有签名都会失效，包括 LI.FI 已添加的签名。

```typescript Sponsor signing service (sketch) theme={"system"}
import { Keypair, VersionedTransaction } from '@solana/web3.js'

export function sponsorSign(base64Tx: string, sponsor: Keypair): string {
  const tx = VersionedTransaction.deserialize(Buffer.from(base64Tx, 'base64'))

  // Refuse anything where your sponsor is not the fee payer
  if (!tx.message.staticAccountKeys[0].equals(sponsor.publicKey)) {
    throw new Error('Sponsor is not the fee payer')
  }

  tx.sign([sponsor]) // fills the sponsor's slot, keeps the other signatures
  return Buffer.from(tx.serialize()).toString('base64')
}
```

赞助签名服务签下的每一笔交易都由它付费。只为你自己的后端向 LI.FI 请求、且属于你所服务用户的交易签名，并在签名前检查手续费支付方。

### 签名时间窗口

交易中带有 LI.FI 构建时获取的近期 blockhash。如果 blockhash 已超过 150 个区块，Solana 会拒绝该交易。[Solana 文档](https://solana.com/developers/cookbook/transactions/confirmation)给出的时间约为 60 到 90 秒。请在这个窗口内收集两方签名并提交。如果已过期，重新请求报价或 stepTransaction，并对新交易签名。赞助方签名环节应保持快速且自动化。

***

## 赞助方承担的费用

| 费用 | 由谁承担 |
| - | - |
| 交易基础费（每个签名 5,000 lamports） | 赞助方，作为手续费支付方。Solana 将全部基础费计入手续费支付方。 |
| 优先费，由 `svmPriorityFeeLevel` 设置 | 赞助方，作为手续费支付方。 |
| 路由创建的账户租金，例如接收方的代币账户 | 赞助方，前提是该路由允许由它为账户出资。 |
| 直接调用 Pump 的路由上的 Pump volume 账户押金 | 赞助方。Pump 要求由用户为该账户付费，因此 LI.FI 会加入一笔从赞助方到用户、金额恰好相等的 SOL 转账。它在 `estimate.feeCosts` 中显示为 `Pump Volume Account Deposit`。 |
| LI.FI 费用、集成商费用、bridge 和中继费用 | 用户，与其他路由一样以输入代币支付，并在 `estimate.feeCosts` 中逐项列出。 |

`estimate.gasCosts` 给出发送这笔交易所需的 SOL 成本。结合 `estimate.feeCosts`，可以计量每个用户给你带来的成本。两者都是构建交易时的估算值。

***

## 从 Solana 出发的 bridge

设置了 `svmSponsor` 且输入代币不是原生 SOL 时，路由只保留支持独立手续费支付方的 Solana 出发 bridge。截至本文撰写时，它们是 `relaydepository`、`across`、`gasZipBridge`、`unit`、`near`、`mayanFastMCTP`、`layerswap`、`lifiIntents` 和 `cctp`。随着更多 bridge 加入支持，该列表会变化。

想知道某个 bridge 为什么在你的请求中被排除，请查看路由响应中的 `unavailableRoutes.filteredOut[].reason`。被排除的 bridge 会带有类似这样的原因：

```
Bridge mayan from Solana is not supported when gasless transactions (svmSponsor) are requested. Only relaydepository, across, gasZipBridge, unit, near, mayanFastMCTP, layerswap, lifiIntents, cctp support gasless transactions.
```

不要用程序解析原因文本。列表中的 bridge 只是具备资格，并不保证一定可用：它仍需支持该代币对和金额。

同链 Solana 交换不做筛选：LI.FI 认为它路由经过的所有 Solana 交易所都能接受独立的手续费支付方。

***

## 原生 SOL 输入

当输入代币是原生 SOL 时，路由不会应用上述 bridge 筛选。用户本身已持有 SOL，路由可能使用不支持独立手续费支付方的 bridge，例如 `mayan` 或 `chainflip`。

如果用户不持有 SOL，请使用 USDC 等 SPL 代币作为输入。当输出代币是原生 SOL 时，赞助方仍然是手续费支付方。

***

## SDK

在 `createConfig` 中一次性设置赞助方：

```typescript theme={"system"}
import { createConfig } from '@lifi/sdk'

createConfig({
  integrator: 'your-integrator-name',
  routeOptions: {
    svmSponsor: '<SPONSOR_PUBKEY>',
  },
})
```

SDK 会把 `routeOptions` 合并进 `getRoutes`。`executeRoute` 使用的 `getStepTransaction` 只从这个配置中读取 `svmSponsor`，并在 Solana 步骤中把它加到 stepTransaction 请求里。如果你只在某次 `getRoutes` 调用的 options 中传入 `svmSponsor`，路由会按赞助方筛选，但实际执行的交易会以用户为手续费支付方构建。对于 `getQuote`，请把 `svmSponsor` 作为请求参数传入。

`executeRoute` 执行 Solana 步骤时，会把交易交给 `SolanaProvider` 的 `getWallet` 返回的钱包，并要求返回的交易中已经带有手续费支付方的签名。有赞助方时，仅靠用户钱包无法提供这个签名。请给 provider 提供一个钱包，使它的 `signTransaction` 在返回交易前也取得赞助方签名，例如从你的赞助签名服务获取。

***

## 需要提前考虑的限制

> [accordion] 报价时不检查赞助方余额
>
> LI.FI 在构建交易时不检查赞助方余额，余额为 0 SOL 的赞助方也能拿到报价，失败会发生在提交时。请监控赞助账户，并在余额不足前充值。

> [accordion] 手续费支付方按请求决定
>
> 每笔交易都按该请求中指定的赞助方构建。路由请求带了赞助方、stepTransaction 请求没带，得到的就是由用户付费的交易。签名前请检查每笔交易的手续费支付方。

> [accordion] 仅限从 Solana 发起
>
> `svmSponsor` 只影响从 Solana 发起的交易。从其他链转入 Solana 的交易在源链上发送，不受影响。

> [accordion] 交易所的行为可能变化
>
> 赞助依赖各交易所和 bridge 构建指令的方式。如果某笔赞助交易表现异常，例如用户的 SOL 余额发生变化，请附上交易签名报告给 LI.FI。

***

## 后续步骤

> [card] [Gas 选项](https://docs.li.fi/guides/gas-options.md)
>
> 所有 gas 机制，以及各自由谁付费。

> [card] [Solana 生态系统](https://docs.li.fi/introduction/solana-ecosystem.md)
>
> Solana 上可用的 bridge、交易所和功能。

> [card] [Gas 与费用成本](https://docs.li.fi/guides/gas-and-fee-costs.md)
>
> 如何读取报价中的 `gasCosts` 和 `feeCosts`。

> [card] [状态跟踪](https://docs.li.fi/introduction/user-flows-and-examples/status-tracking.md)
>
> 提交后如何跟踪转账。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.