fuels-ts 合约调用参数详解:callParams 的 forward 与 gasLimit 配置实战
在 Fuel Network 上用 fuels-ts 调用合约函数时,SDK 提供了 callParams 方法让你针对单次合约调用配置专属参数,目前支持两类:forward(向合约转发指定数量的币)和 gasLimit(限定本次合约调用可消耗的 Gas 上限)。本文以官方文档 call-parameters.md 为核心,逐参数拆解用法与示例代码,并深入 @fuel-ts/program 包源码,说明这些参数在 SDK 内部如何被解析、如何校验、又如何影响最终组装出的交易请求。
1. 支持的调用参数与适用场景
调用合约时,callParams 方法可用的调用参数目前有两个:
forward—— 在调用函数时向合约转账指定数量的币;gasLimit—— 限定本次合约调用本身可消耗的 Gas 上限(独立于交易整体 Gas)。
提示:调用合约时同样可以设置交易参数(transaction parameters),其用法参见仓库文档 Transaction Parameters。
CallParams 的类型定义位于 packages/program/src/types.ts:
export type CallParams = Partial<{
forward: CoinQuantityLike;
gasLimit: BigNumberish;
}>;
即两个字段均为可选:forward 接受"数量 + Asset ID"的组合,gasLimit 接受任意大数形态(number、string、BN 等)。
2. 文档使用的示例合约
文档示例统一基于仓库中的 return-context 合约,其实现见 apps/docs/sway/return-context/src/main.sw:
// contract;
// use std::context::msg_amount;
// abi ReturnContext {
// #[payable]
// fn return_context_amount() -> u64;
// }
impl ReturnContext for Contract {
#[payable]
fn return_context_amount() -> u64 {
msg_amount()
}
}
该合约标记为 #[payable],并把 msg_amount()(调用时转发的币数量)作为返回值,天然适合演示 forward 参数;同时它执行足够简单,可用于演示 gasLimit 过小时触发 OutOfGas 的回滚行为。对应片段代码位于 apps/docs/src/guide/contracts/snippets/call-parameters/。
3. Forward 参数:向合约转发币
forward 参数允许你在调用合约函数时向合约发送指定数量的币。这在合约函数执行需要币的场景中非常有用,例如向其他账户或合约转账。它帮助你控制分配给合约调用的资源,并保护你免受潜在的高成本操作影响。
完整可运行示例(摘自 forward.ts):
import { Provider, Wallet } from 'fuels';
import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from '../../../../env';
import { ReturnContextFactory } from '../../../../typegend';
const provider = new Provider(LOCAL_NETWORK_URL);
const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider);
const deploy = await ReturnContextFactory.deploy(wallet);
const { contract } = await deploy.waitForResult();
const amountToForward = 10;
const baseAssetId = await provider.getBaseAssetId();
const { waitForResult } = await contract.functions
.return_context_amount()
.callParams({
forward: [amountToForward, baseAssetId],
})
.call();
const { value } = await waitForResult();
console.log('forwarded amount:', value.toNumber());
// forwarded amount: 10
要点说明:
forward采用[数量, assetId]元组形式传入,assetId通过provider.getBaseAssetId()获取链上基础资产 ID;- 返回值正是合约侧
msg_amount()读到的转发金额10,验证了转发链路完整生效。
源码层面:forward 如何生效
在 packages/program/src/functions/invocation-scope.ts 的 FunctionInvocationScope.callParams 中可以看到:
- payable 校验:如果设置了
forward但目标函数没有#[payable]属性,SDK 会直接抛出FuelError(The target function ... cannot accept forwarded funds as it's not marked as 'payable'.)——这就是为什么示例合约必须标注#[payable]; - 数量归一化:
coinQuantityfy(callParams.forward)将[amount, assetId]元组转换为标准的CoinQuantity结构; - 进入交易请求:在 base-invocation-scope.ts 的
createContractCall中,forward.assetId与forward.amount分别映射到ContractCall的assetId和amount字段;getRequiredCoins再把所有非零的转发金额汇总为交易所需币种,最终在fundWithRequiredCoins阶段自动选取钱包中的 coin 作为输入并完成资金注入。
4. Gas Limit 参数:限定单次合约调用的 Gas
调用参数的 gasLimit 指的是该次合约调用本身可消耗的最大 Gas,独立于交易其余部分。
示例(摘自 gas-fee.ts):
try {
await contract.functions
.return_context_amount()
.callParams({
forward: [10, await provider.getBaseAssetId()],
gasLimit: 1,
})
.call();
} catch (e) {
console.log('error', e);
// error _FuelError: The transaction reverted with reason: "OutOfGas"
}
将 gasLimit 设为 1 会直接导致调用执行时 Gas 耗尽,交易以 "OutOfGas" 原因回滚,SDK 抛出 _FuelError。这正是该参数的价值所在:为合约调用设置成本护栏,防止意外的高成本执行。
源码层面:gasLimit 的流转与校验
callParams被调用时,gasLimit进入callParameters,并通过 base-invocation-scope.ts 中createContractCall的gas: callParameters?.gasLimit写入ContractCall;- 组装交易前,
prepareTransaction会执行checkGasLimitTotal(base-invocation-scope.ts#L228-L239):交易级gasLimit必须大于等于所有调用gasLimit之和,否则抛出Transaction's gasLimit must be equal to or greater than the combined forwarded gas of all calls.。若未设置交易gasLimit,则自动取各调用gasLimit之和; - 在
callParams内部,只要任一调用设置了gasLimit,就会置位hasCallParamsGasLimit标志(invocation-scope.ts#L77-L79),影响默认 Gas/费用推导逻辑(setDefaultTxParams),确保用户显式设置的值优先于估算值。
5. 调用参数 gasLimit vs 交易参数 gasLimit
这两个 gasLimit 作用域不同,文档的对比结论如下:
| 参数 | 作用范围 | 说明 |
|---|---|---|
调用参数 gasLimit(callParams) |
本次合约调用 | 限定合约调用本身允许消耗的最大 Gas |
交易参数 gasLimit(txParams) |
整笔交易 | 限定整个交易允许消耗的最大 Gas,并对调用参数的 gasLimit 形成约束 |
关键规则(与 base-invocation-scope.ts 的 checkGasLimitTotal 实现一致):
- 若调用参数
gasLimit大于可用的交易 Gas,则整笔可用交易 Gas 都会被分配给该合约调用执行; - 若不设置调用参数
gasLimit,则交易gasLimit会被应用(即默认全部交给调用); - 多调用场景下,所有调用的
gasLimit之和不能超过交易gasLimit,否则 SDK 在提交前即报错拦截。
6. 同时设置两类参数
你完全可以在同一次合约函数调用中同时设置调用参数与交易参数:
const contractCallGasLimit = 4_000;
const transactionGasLimit = 100_000;
const call = await contract.functions
.return_context_amount()
.callParams({
forward: [10, await provider.getBaseAssetId()],
gasLimit: contractCallGasLimit,
})
.txParams({
gasLimit: transactionGasLimit,
})
.call();
(摘自 setting-both-parameters.ts)
txParams 接受的交易参数类型见 packages/program/src/types.ts,除 gasLimit 外还包括 tip、maxFee、witnessLimit、maturity、expiration、variableOutputs 等。txParams 的赋值逻辑在 base-invocation-scope.ts#L368-L382:各字段以"用户传值优先,否则保留请求已有值"的方式合并进 ScriptTransactionRequest,因此链式调用顺序灵活,最终在 fundWithRequiredCoins 中通过 setAndValidateGasAndFeeForAssembledTx 完成 Gas/费用的最终校验与落定。
7. 小结
callParams({ forward: [amount, assetId] }):向#[payable]函数转发币,非 payable 函数会被 SDK 前置拦截;callParams({ gasLimit }):为单次合约调用设置 Gas 上限,过小时交易回滚OutOfGas;txParams({ gasLimit, ... }):约束整笔交易的 Gas 与费用参数,并对各调用的gasLimit求和校验;- 两者可在同一次调用中链式组合,SDK 会在组装交易前自动完成"调用 Gas 总和 ≤ 交易 Gas"的合法性检查,失败早于广播,便于快速定位配置问题。
参考路径:文档源文件、调用参数类型、FunctionInvocationScope、BaseInvocationScope、示例合约。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00