ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Fuel SDK 实战:使用 Predicate 发送与花费链上资产(Send and Spend Funds From Predicates)

Fuel SDK 实战:使用 Predicate 发送与花费链上资产(Send and Spend Funds From Predicates) Fuel SDK 实战使用 Predicate 发送与花费链上资产Send and Spend Funds From Predicates【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-tsPredicate谓词是 Sway 中一类返回布尔值的特殊程序它像一道规则锁一样守护链上资产——只有当交易满足谓词预设条件时资产才允许被转移。本文以 fuels-ts 仓库中 send-and-spend-funds-from-predicates.md 为主线结合仓库内真实 Sway 源码与 TS 测试片段完整演示向谓词地址转账、由谓词条件验证后花费资产、预构建交易、异常与验证失败处理的整条链路。读完本文你将掌握如何用forc build产物实例化谓词、如何为谓词充值并执行转移、如何用createTransfer预取交易 ID以及两类典型失败场景的排查方法。Predicate 如何锁定与解锁资产在 Fuel 网络中资产可以像发送到普通地址一样发送到 Predicate 的地址该地址由谓词字节码与数据计算出的根root派生而来。区别在于要花掉这些资产交易必须附上谓词字节码与数据让链下先执行谓词逻辑返回true才放行返回false则整笔交易被拒绝。这一特性在 Predicates 概览 中有清晰阐述谓词是纯函数、不依赖链上存储只在收到参数后做出布尔决策因此校验可以在上链之前完成既降低网络拥堵也让交易更便宜。当谓词校验成功后资产才可用否则 SDK 会抛出验证错误见下文Predicate 验证失败一节。第一步编写一个受控地址的 Sway Predicate仓库中的示例谓词位于 apps/docs/sway/simple-predicate/src/main.sw完整逻辑如下predicate; fn main(input_address: b256) - bool { let valid_address 0xfc05c23a8f7f66222377170ddcbfea9c543dff0dd2d2ba4d0478a4521423a9d4; input_address valid_address }它的含义非常直接入口函数main接收一个b256类型的参数input_address函数体内硬编码了一个合法地址valid_address只有当input_address与该valid_address完全相等时返回true否则返回false。也就是说只有持有正确地址数据的人才能触发这笔受控资产的转移。第二步编译并收集两大关键产物在项目目录执行forc build编译上述谓词后会得到两个必需工件JSON ABI描述main函数签名与参数类型供 SDK 正确编码谓词数据谓词字节码binary需要附带在交易中供节点/链下执行。此外fuels-ts 的类型生成工具会根据 ABI 自动生成类型安全的谓词类本仓库文档示例中为SimplePredicate这样无需手写 ABI 与字节码的加载逻辑即可实例化。第三步在 SDK 中实例化谓词并传入数据关键点本示例main需要一个名为input_address、类型为B256的参数。该参数正是谓词数据predicate data需要在构造谓词时一并传入。代码见 transferring-assets.tsimport { Provider, Wallet } from fuels; const provider new Provider(LOCAL_NETWORK_URL); const baseAssetId await provider.getBaseAssetId(); const sender Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const receiver Wallet.generate({ provider }); const inputAddress 0xfc05c23a8f7f66222377170ddcbfea9c543dff0dd2d2ba4d0478a4521423a9d4; const predicate new SimplePredicate({ provider, data: [inputAddress], });几个值得注意的实现细节在底层 Predicate 实现 中构造函数接收bytecode、abi、provider以及可选的data与configurableConstantsdata会被编码成predicateData字节供交易携带。谓词地址predicate.address由字节码 谓词数据共同推导数据一旦改变能花费资金的地址也随之改变。因此原文档特别提示若想在实例化之后再修改谓词数据或使用与构造时不同的数据必须重新创建新的Predicate实例。这也正是示例代码把data: [inputAddress]放在构造函数里的原因。从源码结构看谓词数据参与了predicateId/根的计算所以改数据 换一把新锁必须新建实例。关于钱包的创建与资助可以参考仓库的 钱包使用指南 与 谓词实例化完整说明。第四步向谓词地址转入资产有了可用的钱包sender后就可以像给普通地址转账一样向predicate.address转入资产为后续的条件花费储备资金见 transferring-assets.ts#L23-L39// 打算发送给谓词的金额 const amountToPredicate 10_000_000; // 从 sender 钱包向谓词地址转入资产 const fundPredicateTx await sender.transfer( predicate.address, amountToPredicate, baseAssetId, { gasLimit: 1000, } ); // 等待交易上链 await fundPredicateTx.waitForResult();transfer的三个核心参数是接收方地址此处为谓词地址、转账金额、以及资产 ID通过provider.getBaseAssetId()获取的基础资产。第五步让谓词亲自转出资产谓词持有资金后即可用它来验证一笔新的转账交易直接调用predicate.transfer把资金转给目标钱包receiver见 transferring-assets.ts#L46-L59// 从谓词转给接收钱包的金额 const amountToReceiver 200; // 由谓词发起转账此时谓词条件会被求值 const transferFromPredicateTx await predicate.transfer( receiver.address, amountToReceiver, baseAssetId ); await transferFromPredicateTx.waitForResult();同样地transfer接收两个核心参数接收方地址与转账金额。SDK 在提交前会把谓词字节码与数据填充进交易输入对应 predicate.ts 中的输入填充逻辑链下执行谓词main若传入的input_address等于硬编码的valid_address谓词返回true资金成功转到receiver若不等谓词返回falseSDK 抛出PredicateVerificationFailed错误详见下文。实现层面Predicate重写了sendTransaction并在发送前用populateTransactionPredicates把字节码、谓词数据与 witness 写入交易请求且发送时关闭了自动依赖估算estimateTxDependencies: false。transfer/createTransfer则定义在 Account 基类 中供普通钱包与谓词共用同一套转账 API。进阶用createTransfer预构建交易并预取交易 IDpredicate.transfer是一步到位的便捷写法。若需要先搭好交易、确认无误再提交可以使用createTransfer。它返回一个ScriptTransactionRequest随后用sendTransaction提交。预构建的最大好处是在真正提交之前就能获知交易 ID。仓库 pre-stage.ts 演示了这一流程// 预创建一笔从谓词转出的交易 const transactionRequest await predicate.createTransfer( receiver.address, amountToReceiver, baseAssetId, { gasLimit: 1000, } ); // 提交前即可获得交易 ID const chainId await provider.getChainId(); const transactionId transactionRequest.getTransactionId(chainId); // 提交交易并等待结果 const submitTransaction await predicate.sendTransaction(transactionRequest); await submitTransaction.waitForResult();示例后半段还会校验transactionId submitTransaction.id验证预取 ID 与最终上链交易 ID 一致这在需要先行签名、多步编排或离线审计的场景下非常实用。Predicate与Account的其他常用方法如transfer、createTransfer、sendTransaction、simulateTransaction等可进一步参考 Predicate 方法指南。失败场景一试图花费谓词的全部余额直接转出谓词地址上的全部余额会失败因为没有剩余资产去支付交易手续费gas。此时 SDK 会抛出类似如下报错见 failure-not-enough-funds.tsInsufficient funds or too many small value coins. Consider combining UTXOs. For the following asset ID: baseAssetId.这个报错提示了两种排查方向要么为交易预留足够支付手续费的部分资产即不要转出 100% 余额要么合并零碎的 UTXO避免因小额硬币过多而无法凑出可用的资金与手续费组合。示例中该错误通过safeExec来自fuels/test-utils捕获后与期望文案比对以验证错误确实发生。失败场景二Predicate 条件不满足验证失败回顾我们的谓词只有当input_address与硬编码的valid_address相等时才返回true。因此若在实例化时传入一个随机生成的、不同于valid_address的B256地址谓词校验必然失败整笔转账被拒绝。仓库 failure-returns-false.ts 展示了该场景的错误特征const inputAddress getRandomB256(); // 故意用与 valid_address 不同的地址 // ...先给谓词充值再尝试转账... // 捕获到的错误信息以如下片段开头 const errorMessage PredicateVerificationFailed;也就是说SDK 抛出的错误以PredicateVerificationFailed开头。只要在测试或日志中看到这一关键字即可确认是谓词条件未满足返回false导致交易被拒而不是网络或余额问题——这能显著加速排查。小结与延伸阅读围绕发送与花费谓词资产核心链路可概括为四步编写 Sway 谓词main返回布尔值执行forc build得到 ABI 与字节码构造SimplePredicate或任意生成的谓词类把main所需的参数通过data传入用普通钱包向predicate.address转账充值调用predicate.transfer或createTransfersendTransaction两步式由谓词条件放行资产注意留出手续费余额否则会触发资金不足错误。谓词机制的边界条件数据不可变、纯函数、链下校验使其天然适合做时间锁、多签、白名单地址、条件支付等可编程资产锁场景。想深入了解的朋友还可以继续阅读仓库中同一专题下的 Predicate 概览与调试技巧、实例化谓词、部署谓词、可配置常量 以及 自定义交易对应 Sway 源码与 TypeScript 片段则分别位于 docs/sway/simple-predicate/src/main.sw 与 predicates/snippets/cookbook 目录下可直接对照运行验证。【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表