拓冰建站拓冰建站
首页 / 资讯中心 / 正文

fuels-ts 多合约调用实战指南:用 multiCall 在单笔交易中批量调用合约函数

fuels-ts 多合约调用实战指南用 multiCall 在单笔交易中批量调用合约函数【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts本文基于 fuels-ts 官方文档《Multiple Contract Calls》multi-contract-calls.md编写讲解如何在 Fuel Network TypeScript SDK 中通过multiCall方法在单笔交易中执行多个合约调用——既可以调用同一合约的多个函数也可以跨合约混合调用还可批量执行只读查询。读完本文你将掌握multiCall的完整用法、.get/.simulate/.call三种执行入口的时机差异以及该方法在 Contract 类中的源码级实现。为什么要做多合约调用官方文档给出的核心结论是你可以在单笔交易中执行多个合约调用既可以针对同一合约也可以针对不同的合约。这能够提升效率并降低整体交易成本。在 Fuel 网络上每笔交易都需要支付 Gas 费用并产生链上状态变更。如果 dApp 的业务逻辑需要连续操作多个合约例如「先读计数、再两次自增、再向另一个合约查询值」逐个发起交易会放大费用与延迟将它们打包进一笔交易的multiCall调用可以把多次交互合并为一次提交。同一合约的多次调用Same Contract Multi Calls对同一合约批量调用多个函数使用合约实例上的multiCall方法传入一个由functions调用FunctionInvocationScope数组组成的列表import { Provider, Wallet } from fuels; import { CounterFactory } from ../../../../typegend; const provider new Provider(LOCAL_NETWORK_URL); const deployer Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const counterContractTx await CounterFactory.deploy(deployer); const { contract: counterContract } await counterContractTx.waitForResult(); const { waitForResult } await counterContract .multiCall([ counterContract.functions.get_count(), counterContract.functions.increment_count(2), counterContract.functions.increment_count(4), ]) .call(); const { value: results } await waitForResult(); // results[0] 0 // results[1] 2 // results[2] 6上述示例对应仓库中的 same-contract.ts 片段。它的行为要点multiCall的参数是一个FunctionInvocationScope数组每一项都是通过contract.functions.函数名(...参数)得到的调用作用域所有调用按数组顺序排入队列最终在一笔交易中依序执行调用完成后waitForResult()返回的结果value是一个与调用顺序一一对应的结果数组results[0]是get_count的返回值0results[1]是第一次increment_count(2)后的值2results[2]是第二次increment_count(4)后的值6——可以看到队列中的调用共享同一个合约状态前一次写入会影响后一次的读取。不同合约的多次调用Different Contracts Multi CallsmultiCall同样支持在单笔交易中调用不同的合约。你只需在数组里混入来自多个合约实例的函数调用作用域import { Provider, Wallet } from fuels; import { CounterFactory, EchoValuesFactory } from ../../../../typegend; const provider new Provider(LOCAL_NETWORK_URL); const deployer Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const counterContractTx await CounterFactory.deploy(deployer); const { contract: counterContract } await counterContractTx.waitForResult(); const echoContractTx await EchoValuesFactory.deploy(deployer); const { contract: echoContract } await echoContractTx.waitForResult(); const { waitForResult } await echoContract .multiCall([ echoContract.functions.echo_u8(17), counterContract.functions.get_count(), counterContract.functions.increment_count(5), ]) .call(); const { value: results } await waitForResult(); // results[0] 17 // results[1] BN 0 // results[2] BN 5对应仓库中的 different-contracts.ts。从示例可以看出两个细节调用multiCall的宿主合约这里是echoContract只是「入口」数组内既可以放它的函数调用也可以放counterContract的调用SDK 会在同一笔交易中依次完成对两个不同合约地址的调用返回结果仍按调用顺序对齐results[0]为echo_u8(17)的回显值 17results[1]是计数合约当前值 0results[2]是自增 5 之后的值 5此处以 BN 大数类型返回。为每个调用链式附加 callParams官方文档特别指出你可以对multiCall中的每个合约调用链式追加受支持的方法例如callParams。这意味着批量调用并不牺牲单个调用的参数定制能力——转发资产、设置 Gas 参数等操作可以精确作用于数组中的某一项import { Provider, Wallet } from fuels; import { EchoValuesFactory, ReturnContextFactory } from ../../../../typegend; const provider new Provider(LOCAL_NETWORK_URL); const deployer Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const echoContractTx await EchoValuesFactory.deploy(deployer); const { contract: echoContract } await echoContractTx.waitForResult(); const returnContextTx await ReturnContextFactory.deploy(deployer); const { contract: returnContextContract } await returnContextTx.waitForResult(); const { waitForResult } await echoContract .multiCall([ echoContract.functions.echo_u8(10), returnContextContract.functions.return_context_amount().callParams({ forward: [100, await provider.getBaseAssetId()], }), ]) .call(); const { value: results } await waitForResult(); // results[0] 10 // results[1] BN 100对应仓库中的 different-contracts-chain-methods.ts。示例中第二个调用通过.callParams({ forward: [100, await provider.getBaseAssetId()] })向return_context_amount转发了 100 个基础资产合约将收到的金额原样返回results[1] BN 100。这一模式适合在批量流程中为个别调用注入资产转账或费用参数而不影响其他调用。调用的排队与执行时机官方文档给出了multiCall最关键的使用规则使用multiCall时合约调用会被排队queued只有在你调用.get、.simulate或.call中的其中一个方法后才会真正执行。也就是说multiCall([...])本身只构建调用队列不产生任何链上交互真正的执行由三个终结方法触发语义与 SDK 中其他调用作用域保持一致.call()—— 实际提交交易并等待确认产生链上状态变更.simulate()—— 在本地模拟执行验证交易是否可成功但不提交.get()—— 用于只读场景获取返回值对写入型函数则等价于不落盘的读取。用 multiCall 批量执行只读合约调用当 dApp 需要从多个合约读取数据时multiCall可以在单笔交易中批量执行多次 只读调用对应文档中methods.md#get一节介绍的.get()只读调用模式从而减少发送给网络的请求数量、合并数据获取过程使 dApp 交互更高效import { Provider, Wallet } from fuels; import { CounterFactory, EchoValuesFactory } from ../../../../typegend; const provider new Provider(LOCAL_NETWORK_URL); const deployer Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const counterContractTx await CounterFactory.deploy(deployer); const { contract: counterContract } await counterContractTx.waitForResult(); const echoContractTx await EchoValuesFactory.deploy(deployer); const { contract: echoContract } await echoContractTx.waitForResult(); const { waitForResult } await echoContract .multiCall([ counterContract.functions.get_count(), echoContract.functions.echo_u8(10), echoContract.functions.echo_str(Fuel), ]) .call(); const { value: results } await waitForResult(); // results[0] BN 0 // results[1] 10 // results[2] Fuel对应仓库中的 different-contracts-readonly.ts。这一场景的价值在于跨合约的多路查询被合并为一次网络往返与一次交易执行结果按顺序返回BN 计数值、u8 回显值、字符串回显值。对于仪表盘、聚合数据页等需要并发读取多个合约状态的 dApp 页面这是降低请求频率的推荐做法。源码级实现multiCall 与 MultiCallInvocationScope从源码结构看multiCall的能力由 packages/program 包提供其调用链非常清晰入口方法Contract.multiCall 接收一个FunctionInvocationScope数组并直接构造并返回一个MultiCallInvocationScope实例multiCall(calls: ArrayFunctionInvocationScope) { return new MultiCallInvocationScope(this, calls); }这印证了文档中「调用被排队」的说法——multiCall本身不做任何提交动作只是把传入的各函数作用域登记到批次中。批次作用域MultiCallInvocationScope 继承自BaseInvocationScope构造函数中通过this.addCalls(funcScopes)一次性把整组调用挂入队列并重写了addCall/addCalls以支持继续追加单个或成组的调用constructor(contract: AbstractContract, funcScopes: ArrayFunctionInvocationScope) { super(contract, true); this.addCalls(funcScopes); }由于它继承自通用的BaseInvocationScope因此天然继承了.get、.simulate、.call等终结方法以及callParams等链式参数方法——这正是文档中「排队后由.get/.simulate/.call触发执行」以及「每个调用可单独链式附加callParams」两条规则背后的实现机制。测试佐证multiCall的批量调用行为在 fuel-gauge 集成测试 中被大量使用同一文件内还有 call-test-contract.test.ts、reentrant-contract-calls.test.ts 等用例覆盖了批量调用与返回值顺序、跨合约调用、日志解码等路径可作为验证该 API 实际行为的参考。小结multiCall是 fuels-ts 中「一笔交易、多次合约调用」的标准手段调用同一合约的多个函数contract.multiCall([fn1(), fn2(), ...])跨合约批量调用在数组中混入不同合约实例的functions调用SDK 自动在同一笔交易中依次完成单个调用仍可链式附加callParams等参数定制调用在.get、.simulate、.call触发前始终处于排队状态三者分别对应只读获取、模拟执行与真实提交批量只读查询可显著减少对网络的请求次数。配合 methods.md 的常规调用说明与 inter-contract-calls.md 的合约间调用介绍multiCall构成了 fuels-ts 合约交互章节中提升交易效率的核心工具。【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门