news 2026/9/6 19:20:55

fuels-ts 实战指南:在部署 Sway 合约时设置 Configurable Constants(可配置常量)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
fuels-ts 实战指南:在部署 Sway 合约时设置 Configurable Constants(可配置常量)

fuels-ts 实战指南:在部署 Sway 合约时设置 Configurable Constants(可配置常量)

【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts

本篇基于 fuels-ts 文档《Configurable Constants》展开,讲解 Fuel SDK 中 Sway 合约"可配置常量"(configurable constants)的完整用法:如何在合约中用configurable块声明带默认值的常量,如何在部署时通过configurableConstants选项按需覆盖其中任意常量,以及配置不完整(例如 Struct 缺字段)时的报错行为。读完本文,你将掌握可配置常量的声明、覆盖与验证全流程,并理解 SDK 在底层"改写字节码"的实现原理。

一、什么是 Configurable Constants

Sway 提供了强大的可配置常量特性:在创建合约时,可以定义一批常量并为每个常量指定默认值;在合约部署之前,你可以重新定义这些常量的值——可以只改其中一部分,也可以全部覆盖。

这一特性为动态的合约环境提供了灵活性:同一份合约代码可以在不同环境下以不同的常量配置部署,实现高定制化,从而编写出更高效、更易适应不同场景的智能合约。

二、在 Sway 合约中声明可配置常量

下面是一个声明了四个可配置常量的示例合约(来自仓库文档配套 Sway 工程 echo-configurables):

contract; enum MyEnum { Checked: (), Pending: (), } struct MyStruct { x: u8, y: u8, state: MyEnum, } configurable { age: u8 = 25, tag: str[4] = __to_str_array("fuel"), grades: [u8; 4] = [3, 4, 3, 2], my_struct: MyStruct = MyStruct { x: 1, y: 2, state: MyEnum::Pending, }, } abi EchoConfigurables { fn echo_configurables() -> (u8, str[4], [u8; 4], MyStruct); } impl EchoConfigurables for Contract { fn echo_configurables() -> (u8, str[4], [u8; 4], MyStruct) { (age, tag, grades, my_struct) } }

该合约中,echo_configurables函数会返回四个可配置常量的当前值,供我们用它来演示通过 SDK 设置常量配置。示例覆盖了多种典型类型:无符号整数(u8)、定长字符串(str[4])、固定长度数组([u8; 4])以及嵌套了枚举的Struct

三、部署时为新值覆盖常量

在合约部署阶段,可以为任意一个或全部可配置常量指定新值。下面的示例(对应 文档代码片段)只覆盖了age一个常量,其余常量保持 Sway 中定义的默认值:

import { Provider, Wallet } from 'fuels'; import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from '../../../env'; import { EchoConfigurablesFactory } from '../../../typegend'; const provider = new Provider(LOCAL_NETWORK_URL); const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const configurableConstants = { age: 10, }; const deploy = await EchoConfigurablesFactory.deploy(wallet, { configurableConstants, }); const { contract } = await deploy.waitForResult(); const { value: [age, tag, grades, myStruct], } = await contract.functions.echo_configurables().get(); // age got updated console.log('age', age); // 10 // while the rest are default values console.log('tag', tag); // 'fuel' console.log('grades', grades); // [3, 4, 3, 2] console.log('myStruct', myStruct); // { x: 1, y: 2, state: 'Pending' }

要点说明:

  • EchoConfigurablesFactory由 fuels-ts 的类型生成(typegen)流程基于合约 ABI 生成,deploy方法接收的第二个参数即 DeployContractOptions;
  • configurableConstants是一个以"常量名"为键的对象,类型签名为{ [name: string]: unknown }只需给出你想覆盖的常量,未提及的常量自动沿用 Sway 源码中的默认值;
  • 调用deploy(wallet, { configurableConstants })后等待交易结果拿到contract实例,再通过contract.functions.echo_configurables().get()验证:age变为 10,而taggradesmyStruct仍为'fuel'[3, 4, 3, 2]{ x: 1, y: 2, state: 'Pending' }

四、Struct 常量必须完整配置,否则部署报错

文档特别强调:为Struct类型常量赋新值时,必须定义该 Struct 的全部属性,否则会抛出错误。仓库文档片段中给出了反例:

const invalidConfigurables = { my_struct: { x: 10, }, }; try { await EchoConfigurablesFactory.deploy(wallet, { configurableConstants: invalidConfigurables, }); } catch (e) { console.log('error', e); // error: Error setting configurable constants on contract: // Invalid struct MyStruct. Field "y" not present. }

只写了x: 10而遗漏了ystate字段,deploy会同步抛出Error setting configurable constants on contract: Invalid struct MyStruct. Field "y" not present.。该错误信息恰好对应 ContractFactory.setConfigurableConstants 中统一的错误包装逻辑(见下文原理分析)。

五、源码级原理:常量值是如何"写进"合约的

从源码结构看,可配置常量的本质是在部署交易发出之前,把编码后的常量值直接覆写到合约字节码的固定偏移位置,即对字节码做"打补丁"。关键调用链如下:

  1. 入口ContractFactory.deploydeployAsCreateTxprepareDeploy。在 prepareDeploy 中,只要deployOptions.configurableConstants存在,就会先调用this.setConfigurableConstants(configurableConstants)之后才创建交易请求。由于合约 ID(contractId)是在字节码改写之后基于bytecode + salt + stateRoot计算的(见 createTransactionRequest 中getContractId(bytecode, options.salt, stateRoot)调用),可以推断:不同configurableConstants配置会产生不同的字节码与不同的合约 ID。

  2. 核心逻辑:setConfigurableConstants 逐条处理用户传入的键值对:

    • 先校验合约 ABI 中确实声明了configurables,否则抛出Contract does not have configurables to be set
    • 再校验每个键都在this.interface.configurables中存在,否则抛出Contract does not have a configurable named: '${key}'
    • 随后通过 Interface.encodeConfigurable 按 ABI 中的configurableType将 JS 值编码为字节序列,并从this.interface.configurables[key].offset取出该常量在字节码中的偏移地址,执行bytes.set(encoded, offset)完成覆写,最后把改写后的字节序列回写到this.bytecode
    • 所有异常都会被捕获并统一包装为INVALID_CONFIGURABLE_CONSTANTS错误,消息前缀即文档示例中看到的Error setting configurable constants on contract: ...,Struct 缺字段时内部抛出Invalid struct MyStruct. Field "y" not present.后同样走这条包装路径。
  3. ABI 侧支撑:Interface 构造函数 在初始化时就把 JSON ABI 中的configurables数组转成以名称为键的映射,每条记录包含常量名、类型与offset,这正是部署时能"定位到字节码哪一段"的依据。

  4. Blob 分片部署同样支持:当合约超过链上contractMaxSize限制时,deploy会自动走 deployAsBlobTx 分片路径;该方法在分块之前同样会调用setConfigurableConstants,因此无论走 Create 交易还是 Blob 分片部署,configurableConstants都能生效。

六、测试验证:SDK 支持的可配置常量类型

仓库集成测试 configurable-contract.test.ts 用ConfigurableContractFactory系统性地验证了各类型常量的默认值断言与覆盖能力,可作为"哪些类型可以安全配置"的权威参考。测试中定义的默认值与覆盖用例涵盖:

类型默认值覆盖值示例
U8/U16/U32/U6410 / 301 / 799 / 10000099 / 499 / 854 / 999999
BOOLtruefalse
B2560x1d6ebd57...随机 256 位值
ENUM'red''blue'(以字符串传枚举变体名)
ARRAY(二维数组)[[253,254],[255,256]][[666,667],[656,657]]
STR_4(定长字符串)'fuel''leuf'
TUPLE[12, false, 'hi'][99, true, 'by']
STRUCT_1{ tag:'000', age:21, scores:[1,3,4] }{ tag:'007', age:30, scores:[10,10,10] }

测试的部署方式值得注意:它并没有手动deploy,而是使用fuels/test-utils提供的launchTestNode,通过contractsConfigs参数把工厂与选项一并交给测试节点:

function setupContract(configurableConstants?: { [name: string]: unknown }) { return launchTestNode({ contractsConfigs: [ { factory: ConfigurableContractFactory, options: { configurableConstants }, }, ], }); }

这说明configurableConstants作为DeployContractOptions的一部分,同样适用于测试节点批量部署场景。该测试文件同时标注了@group node@group browser,即同一套用法在 Node 与浏览器环境下均已验证。此外,仓库中还存在 predicate-configurables.test.ts 等用例,表明该机制不只服务于合约部署。

七、一个真实应用场景:SDK CLI 部署代理合约

fuels-ts 的 CLI 部署命令内部就依赖了configurableConstants。在 deployContracts.ts 中,部署 SR-C14 兼容的代理合约(Proxy Contract)时,SDK 会把目标合约 ID 与部署者地址写入代理合约的两个可配置常量:

const proxyDeployConfig: DeployContractOptions = { ...commonDeployConfig, storageSlots: mergedStorageSlots, configurableConstants: { INITIAL_TARGET: { bits: targetContract.id.toB256() }, INITIAL_OWNER: { Initialized: { Address: { bits: wallet.address.toB256() } } }, }, };

示例体现了两个实践细节:b256类常量需以{ bits: ... }的包装结构传入,枚举型常量则使用{ 变体名: { ... } }的 tagged union 结构——这与AbiCoder的编码规则保持一致。

八、小结与注意事项

  1. 只能覆盖、不能新增configurableConstants的键必须存在于 ABI 声明的configurables中,且合约必须至少声明一个可配置常量,否则 SDK 直接抛错;
  2. Struct 必须完整:覆盖 Struct 常量时缺一不可字段,否则报错Invalid struct Xxx. Field "yyy" not present.
  3. 时机是部署时:从源码实现看,常量覆盖发生在deploy创建交易请求之前,属于"部署时一次性写入字节码"的语义,并非部署后可通过链上调用的存储写入;
  4. 影响合约 ID:常量值被覆写进字节码后才计算 contractId,因此同一份合约代码配不同的configurableConstants,得到的合约 ID 不同;
  5. 全类型支持:u8/u16/u32/u64、bool、b256、enum、数组、定长字符串、元组、struct 等类型均有集成测试覆盖,可放心使用。

【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 19:20:30

生产质量管理异常报告表:从车间设计到闭环复盘的实战指南

简介:生产质量管理异常报告表.doc是一份面向生产企业质量管控场景的Word模板,适合品质管理、车间班组及现场巡检人员使用,用于在生产过程出现异常时快速记录问题、定位原因并推进改进。模板覆盖异常品质特性、管制标准、超出范围及数量、产品…

作者头像 李华
网站建设 2026/9/6 19:15:40

ARIMA+加权马尔可夫链:误差修正提升时间序列预测精度

简介:这是一篇关于组合时间序列预测模型研究的学术论文PDF,面向机器学习、算法研究与设备状态监测领域工程师,旨在解决单一ARIMA模型预测设备状态参数时存在偏差和不稳定的问题。论文提出引入加权马尔可夫链对ARIMA残差序列进行修正&#xff…

作者头像 李华
网站建设 2026/9/6 19:10:18

超越RAG:Agentic RAG架构设计与落地实践指南

简介:《超越RAG:迈向智能体时代的Agentic RAG》PPT课件,围绕大模型检索增强生成的前沿演进展开,适合AI研究者、算法工程师及对RAG技术感兴趣的学习者阅读。内容从传统RAG的检索-生成流程讲起,逐步过渡到Reasoning RAG与…

作者头像 李华