sui-publish

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Publishing, Deploying & Local Network

Sui 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.
Source constraint: All information sourced exclusively from docs.sui.io and MystenLabs/sui-stack-hello-world.
MCP工具: 如果您的环境中可用,也可查询Sui文档MCP服务器(
https://sui.mcp.kapa.ai
)获取最新答案。用它来验证信息以及获取这些参考文件未涵盖的细节。
来源限制: 所有信息均独家来自docs.sui.ioMystenLabs/sui-stack-hello-world

Publishing a package

发布包

Canonical hello-world publish flow

标准hello-world发布流程

For the full-stack starter, publish the existing hello-world package only:
bash
cd sui-stack-hello-world/move/hello-world
sui move build
sui client publish
Use the package ID from the publish output to update
sui-stack-hello-world/ui/src/constants.ts
(
TESTNET_HELLO_WORLD_PACKAGE_ID
). Do not publish a separate counter package, and do not create a second project directory.
对于全栈启动项目,仅发布现有的hello-world包:
bash
cd sui-stack-hello-world/move/hello-world
sui move build
sui client publish
使用发布输出中的包ID更新
sui-stack-hello-world/ui/src/constants.ts
中的
TESTNET_HELLO_WORLD_PACKAGE_ID
。请勿单独发布计数器包,也不要创建第二个项目目录。

Pre-publish checklist

发布前检查清单

  1. Verify your active environment:
    sui client active-env
  2. Verify you have SUI tokens:
    sui client balance
  3. Build successfully:
    sui move build
  1. 验证当前激活环境:
    sui client active-env
  2. 验证您拥有SUI代币:
    sui client balance
  3. 成功构建:
    sui move build

Publish

发布

bash
sui client publish
This deploys the package to the active network and returns:
  • A unique package ID (use this for all future interactions)
  • An UpgradeCap object (sent to your address, controls future upgrades)
  • Object IDs for anything created during
    init
    functions
bash
sui client publish
此命令会将包部署到当前激活的网络,并返回:
  • 唯一的包ID(所有后续交互均需使用此ID)
  • UpgradeCap对象(发送至您的地址,用于控制后续升级)
  • init
    函数执行期间创建的所有对象的ID

Test publishing (ephemeral networks)

测试发布(临时网络)

Use
sui client test-publish
to publish a package to an ephemeral environment for testing without persisting state to a real network:
bash
sui client test-publish
This publishes the package, runs
init
functions, and returns the same output as
sui client publish
(package ID, UpgradeCap, created objects), but the deployment is not permanent. Use it to:
  • Verify that
    init
    functions execute correctly before committing to a real publish
  • Test publish + upgrade flows in CI without consuming Testnet/Devnet resources
  • Validate gas costs and object creation before a Mainnet deploy
test-publish
respects
--build-env
for multi-environment packages:
bash
sui client test-publish --build-env testnet
使用
sui client test-publish
将包发布到临时环境进行测试,不会将状态持久化到真实网络:
bash
sui client test-publish
此命令会发布包、执行
init
函数,并返回与
sui client publish
相同的输出(包ID、UpgradeCap、创建的对象),但部署不会永久保留。可用于:
  • 在正式发布前验证
    init
    函数是否正确执行
  • 在CI中测试发布+升级流程,无需消耗Testnet/Devnet资源
  • 在主网部署前验证gas成本和对象创建情况
test-publish
支持为多环境包使用
--build-env
参数:
bash
sui client test-publish --build-env testnet

After publishing

发布后操作

The publish transaction output lists the package ID under the created objects section (alongside the
UpgradeCap
and any objects created by
init
functions). The
published-at
field is also automatically added to your
Published.toml
. To interact with the published package:
bash
undefined
发布交易的输出会在创建的对象部分列出包ID(与
UpgradeCap
init
函数创建的所有对象一起)。
published-at
字段也会自动添加到您的
Published.toml
文件中。要与已发布的包交互:
bash
undefined

Call a function

调用函数

sui client call --package <PACKAGE_ID> --module greeting --function new
sui client call --package <PACKAGE_ID> --module greeting --function new

Query an object

查询对象

sui client object <OBJECT_ID>
undefined
sui client object <OBJECT_ID>
undefined

"Your package is already published" error

"Your package is already published"错误

If you see this error when running
sui client publish
, it means
Published.toml
already has an entry for your active environment. This happens when iterating on a package during development.
  • To publish to a different network, switch environments with
    sui client switch --env <ENV>
    and run
    sui client publish
    again. The toolchain tracks published addresses per environment in
    Published.toml
    automatically — do not delete
    Published.toml
    .
  • To upgrade the existing package on the same network, use
    sui client upgrade
    (see below).
如果运行
sui client publish
时出现此错误,说明
Published.toml
中已存在当前激活环境的条目。这通常发生在开发过程中迭代包时。
  • 发布到其他网络,使用
    sui client switch --env <ENV>
    切换环境,然后再次运行
    sui client publish
    。工具链会自动在
    Published.toml
    中按环境跟踪已发布的地址——请勿删除
    Published.toml
  • 要在同一网络升级现有包,使用
    sui client upgrade
    (详见下文)。

Upgrading a published package

升级已发布的包

Published packages are immutable, but you can upgrade by publishing a new version linked to the original. The
UpgradeCap
object controls upgrade authority. Important: you can restrict the
UpgradeCap
in the same PTB as the
publish
command — for example, publishing and immediately calling
sui::package::only_additive_upgrades
in one atomic transaction. You can also destroy it entirely to make the package permanently immutable (see upgrade policies below).
bash
sui client upgrade --upgrade-capability <CAP_ID>
已发布的包是不可变的,但您可以通过发布与原包关联的新版本来进行升级。
UpgradeCap
对象控制升级权限。重要提示: 您可以在与
publish
命令相同的PTB(可编程交易块)中限制
UpgradeCap
——例如,在一个原子交易中完成发布并立即调用
sui::package::only_additive_upgrades
。您也可以完全销毁它,使包永久不可变(详见下文升级策略)。
bash
sui client upgrade --upgrade-capability <CAP_ID>

Finding your UpgradeCap

查找UpgradeCap

The
UpgradeCap
object ID is needed for every upgrade. There are several ways to find it:
  1. Published.toml (preferred): After publishing, the toolchain records the cap ID in
    Published.toml
    under the
    upgrade-capability
    field for each environment.
  2. Query owned objects: List all
    UpgradeCap
    objects owned by the publish address:
    bash
    sui client objects --type 0x2::package::UpgradeCap
  3. Publish transaction output: The original
    sui client publish
    output includes the
    UpgradeCap
    object ID in the created objects list.
  4. Explorer: Search for your address on SuiVision (
    suivision.xyz
    ) or Suiscan (
    suiscan.xyz
    ) and filter owned objects by type
    0x2::package::UpgradeCap
    .
每次升级都需要
UpgradeCap
对象ID。有几种查找方式:
  1. Published.toml(推荐):发布后,工具链会在
    Published.toml
    中每个环境的
    upgrade-capability
    字段下记录cap ID。
  2. 查询拥有的对象:列出发布地址拥有的所有
    UpgradeCap
    对象:
    bash
    sui client objects --type 0x2::package::UpgradeCap
  3. 发布交易输出:原始
    sui client publish
    的输出会在创建的对象列表中包含
    UpgradeCap
    对象ID。
  4. 浏览器:在SuiVision(
    suivision.xyz
    )或Suiscan(
    suiscan.xyz
    )上搜索您的地址,按类型
    0x2::package::UpgradeCap
    过滤拥有的对象。

Upgrade policies

升级策略

Upgrade policies restrict what can change:
  • Compatible (default): The most permissive policy. See detailed rules below.
  • Additive: New modules can be added, but existing modules cannot change at all.
  • Dependency-only: Only dependency versions can be updated. No code changes.
Restricting the UpgradeCap in the same PTB as publish: You can restrict the
UpgradeCap
in the same programmable transaction block as the
publish
command itself — for example, calling
sui::package::only_additive_upgrades
on the
UpgradeCap
immediately after publishing, all within a single atomic transaction. This is the recommended approach for locking down upgrade policy from the start. Once restricted, you cannot widen the policy.
Other UpgradeCap options:
  • Transfer to a multisig address for shared upgrade governance.
  • Destroy the UpgradeCap to make the package permanently immutable. Call
    sui::package::make_immutable
    , which consumes and destroys the
    UpgradeCap
    object. Once the cap is destroyed, no one can ever upgrade the package again — this is irreversible.
升级策略会限制可修改的内容:
  • 兼容策略(默认):最宽松的策略。详见下文详细规则。
  • 增量策略:可添加新模块,但现有模块完全不可修改。
  • 仅依赖更新策略:仅能更新依赖版本。不允许修改代码。
在发布的同一PTB中限制UpgradeCap: 您可以在发布命令的同一可编程交易块中限制
UpgradeCap
——例如,发布后立即对
UpgradeCap
调用
sui::package::only_additive_upgrades
,所有操作都在一个原子交易中完成。这是从一开始锁定升级策略的推荐方法。一旦限制,就无法放宽策略。
其他UpgradeCap选项:
  • 转移至多签地址,实现共享升级治理。
  • 销毁UpgradeCap,使包永久不可变。调用
    sui::package::make_immutable
    ,该函数会消耗并销毁
    UpgradeCap
    对象。一旦cap被销毁,任何人都无法再升级包——此操作不可逆。

Compatible upgrade rules (detailed)

兼容升级规则(详细)

Under the compatible policy, these changes are allowed:
  • Add new functions (public or private)
  • Add new modules
  • Change function implementations (body)
  • Add new struct types
  • Change private/friend function signatures
These changes break compatibility and will be rejected:
  • Remove or rename an existing module
  • Remove or rename a public function
  • Change a public function's signature (parameters, return types, type parameters)
  • Remove, rename, or reorder struct fields
  • Change the type of a struct field
  • Add or remove struct abilities (
    key
    ,
    store
    ,
    copy
    ,
    drop
    )
  • Remove a struct type entirely
  • Change a struct's type parameters
Before upgrading, review your diff against these rules. The
sui client upgrade
command will reject incompatible changes at build time with a descriptive error.
兼容策略下,以下修改是允许的
  • 添加新函数(公共或私有)
  • 添加新模块
  • 修改函数实现(函数体)
  • 添加新结构体类型
  • 修改私有/友元函数的签名
以下修改会破坏兼容性,将被拒绝:
  • 删除或重命名现有模块
  • 删除或重命名公共函数
  • 修改公共函数的签名(参数、返回类型、类型参数)
  • 删除、重命名或重新排列结构体字段
  • 修改结构体字段的类型
  • 添加或删除结构体能力(
    key
    store
    copy
    drop
  • 完全删除结构体类型
  • 修改结构体的类型参数
升级前,请对照这些规则检查您的代码差异。
sui client upgrade
命令会在构建时拒绝不兼容的修改,并给出描述性错误。

Type anchoring after upgrades

升级后的类型锚定

Struct types are permanently anchored to the original package ID where they were first published. After an upgrade, the new package gets a new ID, but all objects created by the upgraded code still have their type rooted in the original package ID.
This has critical implications:
  • Querying objects by type (e.g.,
    listOwnedObjects
    with a
    type
    filter) must use the original package ID.
  • Calling functions via
    moveCall
    must use the upgraded (latest) package ID.
  • Frontend apps should maintain both IDs:
    ORIGINAL_PACKAGE_ID
    for type queries and
    PACKAGE_ID
    for function calls.
ts
// Original publish → package ID 0x1234...
// After upgrade  → package ID 0x5678...

// Query: use ORIGINAL package ID
client.core.listOwnedObjects({
  owner: addr,
  type: '0x1234...::module::MyObject',  // ✅ original ID
});

// Call: use UPGRADED package ID
tx.moveCall({
  target: '0x5678...::module::my_function',  // ✅ upgraded ID
});
结构体类型会永久锚定到首次发布时的原始包ID。 升级后,新包会获得新ID,但升级代码创建的所有对象的类型仍以原始包ID为根。
这有几个关键影响:
  • 按类型查询对象(例如,使用
    type
    过滤器的
    listOwnedObjects
    )必须使用原始包ID。
  • 通过
    moveCall
    调用函数
    必须使用升级后的(最新)包ID。
  • 前端应用应同时维护两个ID:
    ORIGINAL_PACKAGE_ID
    用于类型查询,
    PACKAGE_ID
    用于函数调用。
ts
// 首次发布 → 包ID 0x1234...
// 升级后 → 包ID 0x5678...

// 查询:使用原始包ID
client.core.listOwnedObjects({
  owner: addr,
  type: '0x1234...::module::MyObject',  // ✅ 原始ID
});

// 调用:使用升级后的包ID
tx.moveCall({
  target: '0x5678...::module::my_function',  // ✅ 升级后的ID
});

Publishing to multiple networks

发布到多个网络

To publish to a different network (for example, from Testnet to Devnet), switch environments and publish again. Each network gives the package a different ID. The
Published.toml
file tracks published addresses per environment.
Before publishing to a new network, ensure you have tokens for that network:
  • Testnet: Free tokens through the web faucet at
    faucet.sui.io
    , Discord (
    !faucet <ADDRESS>
    in
    #testnet-faucet
    ), or the TypeScript SDK (
    requestSuiFromFaucetV2()
    ).
    sui client faucet
    does not work on Testnet.
  • Devnet: Free tokens via
    sui client faucet
    , the web faucet at
    faucet.sui.io
    , Discord (
    !faucet <ADDRESS>
    in
    #devnet-faucet
    ), or the TypeScript SDK.
  • Localnet: Free tokens via
    sui client faucet
    or the local faucet at
    127.0.0.1:5003/gas
    or
    127.0.0.1:9123/gas
    (started with
    sui start --with-faucet --force-regenesis
    ).
  • Mainnet: SUI tokens with real monetary value. Acquire through exchanges or transfers. No faucet available.
要发布到其他网络(例如从Testnet到Devnet),切换环境并再次发布。每个网络会为包分配不同的ID。
Published.toml
文件会按环境跟踪已发布的地址。
发布到新网络前,请确保您拥有该网络的代币:
  • Testnet: 通过网页水龙头
    faucet.sui.io
    、Discord(
    #testnet-faucet
    频道中的
    !faucet <ADDRESS>
    )或TypeScript SDK(
    requestSuiFromFaucetV2()
    )获取免费代币。
    sui client faucet
    在Testnet上无法使用。
  • Devnet: 通过
    sui client faucet
    、网页水龙头
    faucet.sui.io
    、Discord(
    #devnet-faucet
    频道中的
    !faucet <ADDRESS>
    )或TypeScript SDK获取免费代币。
  • Localnet: 通过
    sui client faucet
    或本地水龙头端点
    127.0.0.1:5003/gas
    127.0.0.1:9123/gas
    (使用
    sui start --with-faucet --force-regenesis
    启动)获取免费代币。
  • Mainnet: 具有实际货币价值的SUI代币。通过交易所或转账获取。无可用水龙头。

Serializing for external signing

序列化以进行外部签名

To generate transaction bytes for signing by another party (for example, a multisig):
bash
sui client publish --serialize-output
This outputs base64 transaction bytes instead of executing.
要生成供其他方(例如多签)签名的交易字节:
bash
sui client publish --serialize-output
此命令会输出base64格式的交易字节,而非执行交易。

Local network (localnet)

本地网络(localnet)

Localnet runs a full Sui network on your machine for offline development and rapid iteration. Start it with:
bash
sui start --with-faucet --force-regenesis
The
--force-regenesis
flag resets all on-chain state each time the network starts, giving you a clean environment on every restart. The
--with-faucet
flag starts a local faucet so you can fund addresses.
To connect the CLI to your localnet:
bash
sui client switch --env localnet
Get local tokens via
sui client faucet
or by hitting the local faucet endpoint directly at
127.0.0.1:5003/gas
or
127.0.0.1:9123/gas
.
Localnet is useful for:
  • Offline development without depending on Testnet/Devnet availability
  • Rapid iteration on publish and upgrade flows (reset state with each restart)
  • Testing
    init
    functions and object creation before deploying to a shared network
Localnet会在您的机器上运行完整的Sui网络,用于离线开发和快速迭代。使用以下命令启动:
bash
sui start --with-faucet --force-regenesis
--force-regenesis
标志会在每次启动网络时重置所有链上状态,使您每次重启都能获得干净的环境。
--with-faucet
标志会启动本地水龙头,以便您为地址充值。
要将CLI连接到localnet:
bash
sui client switch --env localnet
通过
sui client faucet
或直接访问本地水龙头端点
127.0.0.1:5003/gas
127.0.0.1:9123/gas
获取本地代币。
Localnet适用于:
  • 离线开发,无需依赖Testnet/Devnet的可用性
  • 快速迭代发布和升级流程(每次重启都会重置状态)
  • 在部署到共享网络前测试
    init
    函数和对象创建

Mainnet launch checklist

主网启动检查清单

Use this checklist when preparing a package for Mainnet publishing. Every item should be verified before executing the publish transaction.
准备将包发布到主网时使用此清单。执行发布交易前,需验证每一项。

1. Tests and coverage

1. 测试与覆盖率

Run the full test suite and confirm all tests pass:
bash
sui move test
For coverage reporting (if your project requires a threshold):
bash
sui move test --coverage
sui move coverage summary
Fix any failing tests before proceeding. Do not publish untested code to Mainnet.
运行完整测试套件并确认所有测试通过:
bash
sui move test
如需生成覆盖率报告(如果项目要求达到阈值):
bash
sui move test --coverage
sui move coverage summary
继续操作前修复所有失败的测试。请勿将未测试的代码发布到主网。

2. Dependencies and addresses

2. 依赖与地址

  • Verify
    Move.toml
    uses
    edition = "2024"
    and has no legacy
    [addresses]
    section or git-based Sui framework dependency.
  • Confirm
    [environments]
    includes a
    mainnet
    entry with the correct chain ID.
  • If using MVR dependencies (
    { r.mvr = "@org/package" }
    ), verify they resolve on Mainnet.
  • Run
    sui move build
    to confirm clean compilation with no warnings.
  • 验证
    Move.toml
    使用
    edition = "2024"
    ,且无遗留的
    [addresses]
    部分或基于git的Sui框架依赖。
  • 确认
    [environments]
    包含带有正确链ID的
    mainnet
    条目。
  • 如果使用MVR依赖(
    { r.mvr = "@org/package" }
    ),验证它们在主网上可解析。
  • 运行
    sui move build
    确认编译无警告。

3. Upgrade policy decision

3. 升级策略决策

Decide your upgrade policy before publishing — you cannot widen it later:
PolicyWhat you can changeWhen to use
Compatible (default)Add functions, add modules, update implementations. Cannot remove functions or change struct layouts.Most packages — gives flexibility for bug fixes while preserving type safety.
AdditiveAdd new modules only. Existing modules are frozen.Packages where you want to extend functionality but guarantee existing code never changes.
Dependency-onlyOnly update dependency versions.Nearly-finalized packages that should only track framework updates.
ImmutableNothing. Package is permanently frozen.Fully audited packages where immutability is a trust guarantee (e.g., token contracts).
To restrict the policy in the same transaction as publish, include a
moveCall
to
sui::package::only_additive_upgrades
,
only_dep_upgrades
, or
make_immutable
on the
UpgradeCap
in your publish PTB.
发布前决定您的升级策略——后续无法放宽:
策略可修改内容使用场景
兼容策略(默认)添加函数、添加模块、更新实现。无法删除函数或修改结构体布局。大多数包——在保留类型安全的同时,为bug修复提供灵活性。
增量策略仅能添加新模块。现有模块被冻结。需要扩展功能但保证现有代码永不修改的包。
仅依赖更新策略仅能更新依赖版本。接近最终版本、仅需跟踪框架更新的包。
不可变策略无任何修改。包永久冻结。经过全面审计、不可变性是信任保障的包(例如代币合约)。
要在发布的同一交易中限制策略,请在发布PTB中添加对
UpgradeCap
调用
sui::package::only_additive_upgrades
only_dep_upgrades
make_immutable
moveCall

4. Gas estimation

4. Gas估算

Mainnet SUI has real monetary value. Estimate gas before publishing:
bash
sui client publish --dry-run
The dry-run output includes
computationCost
,
storageCost
, and
storageRebate
. The total gas required is
computationCost + storageCost - storageRebate
. Ensure your address holds enough SUI to cover this amount plus a margin.
主网SUI具有实际货币价值。发布前估算gas:
bash
sui client publish --dry-run
试运行输出包含
computationCost
storageCost
storageRebate
。所需总gas为
computationCost + storageCost - storageRebate
。确保您的地址持有足够的SUI来覆盖此金额及额外余量。

5. Signer and custody plan

5. 签名者与托管方案

Decide who controls the publish address and the
UpgradeCap
:
  • Single signer: Simplest. One key publishes and holds the
    UpgradeCap
    . Suitable for personal projects or early-stage development.
  • Multisig: For teams or high-value packages. Create a multisig address, publish using
    --serialize-output
    , and have the required signers sign offline. Transfer the
    UpgradeCap
    to the multisig address in the same PTB as publish.
  • Immutable on publish: If no upgrades will ever be needed, destroy the
    UpgradeCap
    in the publish PTB (
    sui::package::make_immutable
    ). This removes custody concerns entirely.
For multisig publishing:
bash
undefined
决定谁控制发布地址和
UpgradeCap
  • 单签名者: 最简单。一个密钥负责发布并持有
    UpgradeCap
    。适用于个人项目或早期开发阶段。
  • 多签: 适用于团队或高价值包。创建多签地址,使用
    --serialize-output
    发布,由所需签名者离线签名。在发布的同一PTB中将
    UpgradeCap
    转移至多签地址。
  • 发布时设为不可变: 如果永远不需要升级,在发布PTB中销毁
    UpgradeCap
    sui::package::make_immutable
    )。这完全消除了托管顾虑。
多签发布步骤:
bash
undefined

Generate unsigned transaction bytes

生成未签名的交易字节

sui client publish --serialize-output
sui client publish --serialize-output

Each signer signs the bytes, then combine and execute

每个签名者对字节签名,然后合并并执行

undefined
undefined

6. Final pre-publish verification

6. 发布前最终验证

Before executing the publish transaction on Mainnet:
  • sui client active-env
    returns
    mainnet
  • sui client balance
    shows sufficient SUI for gas (check dry-run estimate)
  • sui move build
    succeeds with no warnings
  • sui move test
    passes with all tests green
  • Move.toml
    has correct
    edition
    , no legacy format
  • Upgrade policy is decided and restriction call is included in the PTB (if applicable)
  • Signer key or multisig is ready
  • You have verified the package on Testnet first — same code, same tests, same publish flow
在主网上执行发布交易前:
  • sui client active-env
    返回
    mainnet
  • sui client balance
    显示有足够的SUI支付gas(检查试运行估算)
  • sui move build
    成功且无警告
  • sui move test
    所有测试通过
  • Move.toml
    使用正确的
    edition
    ,无遗留格式
  • 已决定升级策略,且PTB中包含限制调用(如适用)
  • 签名密钥或多签已准备就绪
  • 已在Testnet上验证过包——相同代码、相同测试、相同发布流程

Dry runs and transaction debugging

试运行与交易调试

A dry run simulates a transaction without submitting it to the network. Use dry runs to:
  • Estimate gas costs before execution.
  • Verify that a transaction succeeds before asking a user to sign.
  • Debug failing transactions by inspecting the error before spending gas.
Wallets (like Slush) automatically perform dry runs before presenting a transaction for signing. If a dry run fails, the wallet shows an error instead of prompting.
From the TypeScript SDK, use
devInspectTransactionBlock
to dry-run a transaction programmatically. From the CLI, the
--dry-run
flag simulates execution.
When debugging a dry run failure: check that all object IDs are correct, the object versions are current, the sender has sufficient gas, the function arguments match the expected types, and the active environment (
sui client active-env
) matches the network where the package is published.
试运行会模拟交易而不提交到网络。使用试运行可:
  • 执行前估算gas成本。
  • 在请求用户签名前验证交易是否成功。
  • 通过检查错误调试失败的交易,无需消耗gas。
钱包(如Slush)在呈现交易供用户签名前会自动执行试运行。如果试运行失败,钱包会显示错误而非提示签名。
从TypeScript SDK,使用
devInspectTransactionBlock
以编程方式试运行交易。从CLI,使用
--dry-run
标志模拟执行。
调试试运行失败时:检查所有对象ID是否正确、对象版本是否最新、发送方是否有足够gas、函数参数是否匹配预期类型,以及当前激活环境(
sui client active-env
)是否与包发布的网络匹配。

Production monitoring

生产监控

Sui packages are immutable once published, so monitoring is critical — you cannot hotfix a live contract, only publish an upgrade.
Sui包一旦发布就不可变,因此监控至关重要——您无法热修复实时合约,只能发布升级版本。

What to monitor

监控内容

SignalHowWhy
Failed transactions involving your packageSubscribe to transaction effects via gRPC streaming, filter by package IDDetects Move aborts, gas failures, or unexpected reverts in production
Gas spendTrack
gasUsed
from transaction effects
Catch unexpectedly expensive operations or gas drain attacks
Event emissionSubscribe to events by type (
{packageId}::module::EventName
) via gRPC streaming
Core business telemetry — mints, transfers, admin actions, deny list changes
Object creation/deletion ratesQuery or subscribe to object changes filtered by your typesDetect abnormal activity (mass minting, object spam)
Admin/cap usageFilter events for capability-gated actionsDetect unauthorized or unexpected admin operations
Shared object contentionMonitor transaction latency for shared-object transactionsHigh contention degrades UX; may need object sharding
指标实现方式原因
涉及您包的失败交易通过gRPC流订阅交易效果,按包ID过滤检测生产环境中的Move中止、gas失败或意外回滚
Gas消耗跟踪交易效果中的
gasUsed
发现异常昂贵的操作或gas耗尽攻击
事件发射通过gRPC流按类型(
{packageId}::module::EventName
)订阅事件
核心业务遥测——铸造、转账、管理员操作、黑名单变更
对象创建/删除速率查询或订阅按您的类型过滤的对象变更检测异常活动(大规模铸造、对象垃圾信息)
管理员/权限使用过滤权限 gated 操作的事件检测未授权或意外的管理员操作
共享对象竞争监控共享对象交易的延迟高竞争会降低用户体验;可能需要对象分片

Implementation

实现方式

Use gRPC streaming subscriptions for real-time monitoring:
ts
for await (const event of client.subscriptionService.subscribeEvents({
  filter: { MoveEventModule: { package: PACKAGE_ID, module: 'my_module' } },
})) {
  // Forward to your monitoring stack (Grafana, Datadog, PagerDuty, etc.)
}
For historical analysis, run a custom indexer (
sui-indexer-alt
) that writes relevant events and transaction effects to your own database. See the
accessing-data
skill's
indexers.md
.
Emit events for every security-critical action in your Move code — admin changes, configuration updates, deny list modifications, object deletions. Events are the only way offchain systems can observe these actions.
使用gRPC流订阅进行实时监控:
ts
for await (const event of client.subscriptionService.subscribeEvents({
  filter: { MoveEventModule: { package: PACKAGE_ID, module: 'my_module' } },
})) {
  // 转发到您的监控栈(Grafana、Datadog、PagerDuty等)
}
如需历史分析,运行自定义索引器(
sui-indexer-alt
),将相关事件和交易效果写入您自己的数据库。请参阅
accessing-data
技能的
indexers.md
在Move代码中为每个安全关键操作发射事件——管理员变更、配置更新、黑名单修改、对象删除。事件是链下系统观察这些操作的唯一方式。

Rollback and incident response

回滚与事件响应

Sui packages cannot be rolled back. Published bytecode is immutable. There is no
revert
or
rollback
command. Recovery means publishing a forward-fix upgrade.
Sui包无法回滚。 发布的字节码是不可变的。没有
revert
rollback
命令。恢复意味着发布向前修复的升级版本。

If a bad upgrade is published

如果发布了错误的升级版本

  1. Assess scope. Determine which functions are affected. Existing objects created by prior versions are still valid — their types are anchored to the original package ID.
  2. Publish a fix upgrade immediately. Write the corrected code, run tests, dry-run on Testnet, then
    sui client upgrade
    on Mainnet. The new package ID replaces the old one for all future calls.
  3. Update frontends. Point
    PACKAGE_IDS
    to the new (fixed) package ID. Type queries still use
    ORIGINAL_PACKAGE_IDS
    .
  4. Communicate. If the bug affected user-facing behavior, notify users through your app's channels.
  1. 评估范围。 确定哪些函数受到影响。先前版本创建的现有对象仍然有效——它们的类型锚定到原始包ID。
  2. 立即发布修复升级版本。 编写修正后的代码,运行测试,在Testnet上试运行,然后在主网执行
    sui client upgrade
    。新包ID会替换旧包ID用于所有后续调用。
  3. 更新前端。
    PACKAGE_IDS
    指向新的(已修复的)包ID。类型查询仍使用
    ORIGINAL_PACKAGE_IDS
  4. 沟通。 如果bug影响了用户可见的行为,通过您应用的渠道通知用户。

If the UpgradeCap is compromised

如果UpgradeCap泄露

An attacker with the
UpgradeCap
can publish arbitrary code under your package. Mitigation:
  • If you still hold the cap: Immediately restrict it (
    only_dep_upgrades
    or
    make_immutable
    ) to prevent further malicious upgrades.
  • If the attacker holds the cap: You cannot recover upgrade authority. Publish a new package, migrate users, and communicate the migration. This is why multisig custody of the
    UpgradeCap
    matters for production packages.
拥有
UpgradeCap
的攻击者可以在您的包下发布任意代码。缓解措施:
  • 如果您仍持有cap: 立即限制它(
    only_dep_upgrades
    make_immutable
    ),防止进一步的恶意升级。
  • 如果攻击者持有cap: 您无法恢复升级权限。发布新包,迁移用户,并沟通迁移事宜。这就是为什么生产包的
    UpgradeCap
    多签托管至关重要。

If a shared object is corrupted

如果共享对象损坏

A buggy function may write invalid state to a shared object. Since shared objects are mutable by any transaction:
  • If you can upgrade: Publish an upgrade with a repair function that fixes the corrupted state. Gate it behind an
    AdminCap
    .
  • If the package is immutable: The only option is to deploy a new package with a migration function that reads the old object's data (if accessible) and creates corrected objects.
有bug的函数可能会向共享对象写入无效状态。由于共享对象可被任何交易修改:
  • 如果您可以升级: 发布带有修复函数的升级版本,该函数可修复损坏的状态。将其 gated 在
    AdminCap
    后。
  • 如果包是不可变的: 唯一的选择是部署带有迁移函数的新包,该函数读取旧对象的数据(如果可访问)并创建修正后的对象。

Prevention checklist

预防检查清单

  • UpgradeCap
    held by multisig or restricted to
    additive
    /
    dep_only
  • All upgrades tested on Testnet with the same code, same publish flow
  • Admin actions emit events for monitoring
  • Critical shared objects have repair functions gated behind capabilities
  • Frontend can switch package IDs without a redeploy (environment config, not hardcoded)
  • UpgradeCap
    由多签持有或限制为
    additive
    /
    dep_only
    策略
  • 所有升级都在Testnet上使用相同代码、相同发布流程进行测试
  • 管理员操作会发射事件用于监控
  • 关键共享对象有 gated 在权限后的修复函数
  • 前端无需重新部署即可切换包ID(使用环境配置,而非硬编码)