关于 composable-move-functions
composable-move-functions 是面向 Sui Move 开发者的参考技能,指导如何设计可在可编程交易块中组合的函数,重点包括可见性、返回对象和参数顺序。
主要功能
- 01可组合函数的可见性指引
- 02返回对象而非内部转移
- 03入口包装函数模式
- 04命令行处理返回值
- 05统一函数参数顺序
适用场景
- 01设计可在 PTB 中链式调用的函数
- 02区分可组合逻辑与便捷端点
- 03通过 sui client ptb 处理返回对象
- 04统一 Move 函数签名
MCP 相关
条件允许时,建议查询 https://sui.mcp.kapa.ai 上的 Sui 文档 MCP 服务,以验证信息并获取最新答案。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mystenlabs/ skills --skill composable-move-functions安装后在 Claude Code 中输入/composable-move-functions确认已加载。
附带文件evals/code-evals.jsonevals/evals.json
详细介绍
composable-move-functions
MCP 工具: 在你的环境中可用时,也请查询 Sui 文档 MCP 服务(
https://sui.mcp.kapa.ai)以获取最新答案。使用它来核实信息,并了解这些参考文件未涵盖的细节。
概览
Sui 交易可以在单个可编程交易块(PTB)中串联多个函数调用。在内部转移对象而不是返回对象的函数会破坏这种可组合性。本技能介绍如何设计能够在 PTB 中良好协作的函数。
所有模式均摘自 https://move-book.com/guides/code-quality-checklist
不要使用 public entry
函数应该是 public(可组合,可从其他模块和 PTB 调用)或 entry(仅作为交易端点)。绝不要同时使用 public entry。
// WRONG — public entry is redundant and limits composability
public entry fun do_something() { }
// CORRECT — public for composable functions that return values
public fun mint(ctx: &mut TxContext): NFT { }
// CORRECT — entry for intentionally non-composable endpoints
entry fun mint_and_keep(ctx: &mut TxContext) { }
何时使用 entry: 仅用于有意设计为不可组合的便捷端点——这类函数会包装可组合的 public 函数,并处理向发送者的转移。
返回对象,不要在内部转移
公共函数应将值返回给调用方,而不是将其转移到 ctx.sender()。这样函数就能在 PTB 中组合使用——由调用方决定如何处理结果。
// WRONG — couples minting with transfer, can't compose
public fun mint_and_transfer(ctx: &mut TxContext) {
let nft = NFT { id: object::new(ctx) };
transfer::transfer(nft, ctx.sender());
}
// CORRECT — returns the object, caller decides
public fun mint(ctx: &mut TxContext): NFT {
NFT { id: object::new(ctx) }
}
// If you need a convenience entry point, add a separate entry wrapper:
entry fun mint_and_keep(ctx: &mut TxContext) {
let nft = mint(ctx);
transfer::transfer(nft, ctx.sender());
}
返回值对 CLI 的影响
返回非 drop 值的函数无法通过 sui client call 调用——CLI 无法处理返回值,因此会导致 UnusedValueWithoutDrop 错误。请改用 sui client ptb,你可以在其中串联 --assign 和 --transfer-objects 来处理返回值:
sui client ptb \
--move-call @pkg::module::create_thing --assign thing \
--transfer-objects "[thing]" @sender
如果函数经常通过 CLI 调用,可以考虑提供一个配套的 entry 包装函数,在内部进行转移(如上所示)。
这普遍适用:
add_liquidity应返回 LP 币和剩余币,而不是转移它们remove_liquidity应返回两种币,而不是转移它们swap应返回输出币,而不是转移它borrow应返回借入的资产,而不是转移它
参数顺序
函数参数必须严格按照以下顺序排列:
- 对象优先——被操作的主要对象
- 能力对象其次——例如
AdminCap这样的授权令牌 - 基本类型值——数量、标志、地址
- Clock——始终放在末尾(ctx 之前),是对象优先规则的例外
ctx: &mut TxContext最后——始终是最后一个参数,排在所有基本类型值和其他参数之后
// WRONG — cap before object, primitives mixed in
public fun authorize_action(
cap: &AdminCap,
value: u8,
app: &mut App,
ctx: &mut TxContext,
) { }
// CORRECT — object first, cap second, primitives third, ctx last
public fun authorize_action(
app: &mut App,
cap: &AdminCap,
value: u8,
ctx: &mut TxContext,
) { }
Clock 例外
尽管 Clock 是一个对象,但它应放在靠近末尾的位置,也就是 ctx 之前:
public fun timed_action(
app: &mut App,
cap: &AppCap,
value: u8,
clock: &Clock,
ctx: &mut TxContext,
) { }
快速参考
| 模式 | 规则 |
|---|---|
| 可见性 | 可组合函数使用 public,端点使用 entry。绝不要使用 public entry。 |
| 返回值 | 公共函数应返回对象。不要在内部将对象转移给发送者。 |
| Entry 包装函数 | 使用单独的 entry 函数调用 public 函数并进行转移。 |
| 参数顺序 | 对象 → 能力对象 → 基本类型值 → Clock → TxContext |