composable-move-functions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

composable-move-functions

可组合的Move函数

MCP tool: When available in your environment, also query the Sui documentation MCP server (
https://sui.mcp.kapa.ai
) for up-to-date answers. Use it for verification and for details not covered by these reference files.
MCP工具: 如果你的环境中提供了该工具,也可以查询Sui文档MCP服务器(
https://sui.mcp.kapa.ai
)获取最新答案。可用于验证以及获取这些参考文件未涵盖的细节。

Overview

概述

Sui transactions can chain multiple function calls in a single Programmable Transaction Block (PTB). Functions that transfer objects internally instead of returning them break this composability. This skill covers how to design functions that work well in PTBs.
Sui交易可以在单个可编程交易块(PTB)中链式调用多个函数。那些在内部转移对象而非返回对象的函数会破坏这种可组合性。本技能介绍如何设计能在PTB中良好运行的函数。

No
public entry

禁止使用
public entry

Functions should be either
public
(composable, can be called from other modules and PTBs) or
entry
(transaction endpoint only). Never use
public entry
together.
move
// 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) { }
When to use
entry
:
Only for convenience endpoints that are intentionally non-composable — functions that wrap a composable
public
function and handle transfers to sender.
函数应要么为
public
(可组合,可从其他模块和PTB中调用),要么为
entry
(仅作为交易端点)。切勿同时使用
public entry
move
// 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
函数并处理向发送者转移对象的函数。

Return Objects, Don't Transfer Internally

返回对象,而非在内部转移

Public functions should return values to the caller rather than transferring them to
ctx.sender()
. This makes them composable in PTBs — the caller decides what to do with the result.
move
// 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());
}
公共函数应将值返回给调用者,而非转移到
ctx.sender()
。这样它们在PTB中具备可组合性——由调用者决定如何处理结果。
move
// 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 implication for returned values

返回值对CLI的影响

Functions that return non-
drop
values cannot be invoked via
sui client call
— the CLI has no way to consume the returned value, causing an
UnusedValueWithoutDrop
error. Use
sui client ptb
instead, where you can chain
--assign
and
--transfer-objects
to handle the return value:
bash
sui client ptb \
  --move-call @pkg::module::create_thing --assign thing \
  --transfer-objects "[thing]" @sender
If the function is called frequently from the CLI, consider providing a companion
entry
wrapper that transfers internally (as shown above).
This applies broadly:
  • add_liquidity
    should return LP coins and remainder coins, not transfer them
  • remove_liquidity
    should return both coins, not transfer them
  • swap
    should return the output coin, not transfer it
  • borrow
    should return the borrowed asset, not transfer it
返回非
drop
类型值的函数无法通过
sui client call
调用——CLI无法处理未使用的返回值,会导致
UnusedValueWithoutDrop
错误。应改用
sui client ptb
,你可以通过链式使用
--assign
--transfer-objects
来处理返回值:
bash
sui client ptb \
  --move-call @pkg::module::create_thing --assign thing \
  --transfer-objects "[thing]" @sender
如果该函数经常从CLI调用,可考虑提供一个在内部处理转移的配套
entry
包装函数(如上文所示)。
这一原则广泛适用:
  • add_liquidity
    应返回LP代币和剩余代币,而非直接转移
  • remove_liquidity
    应返回两种代币,而非直接转移
  • swap
    应返回输出代币,而非直接转移
  • borrow
    应返回借入资产,而非直接转移

Parameter Ordering

参数排序

Function parameters follow a strict order:
  1. Objects first — the primary object being acted on
  2. Capabilities second — authorization tokens like
    AdminCap
  3. Primitive values — amounts, flags, addresses
  4. Clock — always at the end (before ctx), exception to objects-first rule
  5. ctx: &mut TxContext
    last
    — ALWAYS the final parameter, after all primitives and all other arguments
move
// 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,
) { }
函数参数遵循严格的顺序:
  1. 对象优先 —— 要操作的主要对象
  2. 能力其次 —— 如
    AdminCap
    这类授权令牌
  3. 原始值 —— 数量、标志、地址
  4. Clock —— 始终放在末尾(ctx之前),是对象优先规则的例外
  5. ctx: &mut TxContext
    最后
    —— 始终是最后一个参数,在所有原始值和其他参数之后
move
// 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 Exception

Clock例外情况

Clock
goes near the end, just before
ctx
, even though it's an object:
move
public fun timed_action(
    app: &mut App,
    cap: &AppCap,
    value: u8,
    clock: &Clock,
    ctx: &mut TxContext,
) { }
Clock
应放在接近末尾的位置,就在
ctx
之前,即使它是一个对象:
move
public fun timed_action(
    app: &mut App,
    cap: &AppCap,
    value: u8,
    clock: &Clock,
    ctx: &mut TxContext,
) { }

Quick Reference

快速参考

PatternRule
Visibility
public
for composable,
entry
for endpoints. Never
public entry
.
ReturnsPublic functions return objects. Don't transfer to sender internally.
Entry wrappersSeparate
entry
function that calls
public
function + transfers.
Param orderObject → Capability → Primitives → Clock → TxContext
模式规则
可见性
public
用于可组合函数,
entry
用于端点。禁止使用
public entry
返回值公共函数返回对象。不要在内部向发送者转移对象。
Entry包装函数单独的
entry
函数调用
public
函数并处理转移。
参数顺序对象 → 能力 → 原始值 → Clock → TxContext