mcpField
S
setup-sui-contracts

setup-sui-contracts

github.com/openzeppelin開発21975 回インストール2 日前に更新
リポジトリ

setup-sui-contracts について

OpenZeppelin Contracts for Suiを使ってSui Moveプロジェクトを構築する開発者向けのセットアップスキルです。プロジェクト作成、依存関係の発見と設定、例に基づく統合、ビルドとテストを案内します。

主な機能

  1. 01Moveパッケージの初期化
  2. 02OpenZeppelinパッケージと例の発見
  3. 03MVRおよびGit依存関係の設定
  4. 04エージェント向けガイドとMCP設定の生成
  5. 05必要な環境でのビルドとテスト

活用シーン

  1. 01Sui Moveプロジェクトの開始
  2. 02Move.tomlへのOpenZeppelinパッケージ追加
  3. 03依存関係のバージョン競合の解決
  4. 04コーディングエージェント向けプロジェクトガイドの準備

MCP 対応

OpenZeppelin Sui MCPサーバー(https://mcp.openzeppelin.com/contracts/sui/mcp)の設定方法を説明します。ツールはレシピの検索とパッケージメタデータを提供し、依存関係の設定や例の統合に利用できます。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/openzeppelin/openzeppelin-skills --skill setup-sui-contracts

インストール後、Claude Code で/setup-sui-contractsを入力して読み込まれたか確認します。

詳細

Sui のセットアップ

前提条件

Sui のインストールガイドに従って、Sui CLI をインストールします。CLI には Move ツールチェーンと Move Registry(MVR)リゾルバーが含まれているため、Move を別途インストールする必要はありません。

ライブラリについて調べるときは、まず AI 検索用のエントリーポイントである llms.txt から始めてください。ここにはライブラリのコンテンツ(アーキテクチャドキュメント、contracts/ および math/ のパッケージカタログ、各パッケージの README/例/API リファレンス、監査情報)がまとめられています。パスを推測するのではなく、リンクをたどってください。

OpenZeppelin Contracts for Sui では、トップレベルの README に特定の Sui CLI バージョンが指定されています(これはリポジトリのメタデータであり、llms.txt からはリンクされていません)。そこで必要なバージョンを確認し、ローカルのインストールと照合してください。指定バージョンはテスト済みで、最も安全に一致させられるバージョンです。より新しいパッチ/マイナーバージョンでも通常は動作するため、多少の差異はブロッカーではなく警告として扱ってください。

sui --version

プロジェクトの作成

新しい Move パッケージを初期化します(新規プロジェクトを始める場合のみ)。

sui move new my_project
cd my_project

これにより、Move edition = "2024" を使用した Move.toml、.gitignore、コメントアウトされたスタブモジュール sources/my_project.move および tests/my_project_tests.move が作成されます。スタブは何もしないプレースホルダー(全体が /* … */ で囲まれています)です。独自のモジュールを追加するときに、置き換えるか削除してください。

OpenZeppelin の依存関係

OpenZeppelin パッケージは Move Registry (MVR) に公開されており、Move.toml の [dependencies] に r.mvr 形式で追加します。この形式では、Move パッケージ名を MVR スラッグに対応付けます。

[dependencies]
<move_package_name> = { r.mvr = "@openzeppelin-move/<slug>" }

記憶しているパッケージ一覧を当てにしないでください。ライブラリの進化に伴って内容が変わるためです。利用可能なものは、唯一の信頼できる情報源であるライブラリ自体のメタデータから確認してください。

  1. まずはいつもどおり、AI 向けの情報発見の入口である llms.txt を確認します。
  2. リンク先にあるすべてのパッケージカタログをたどります。存在するカタログを決めるのは llms.txt です。新しいトップレベルカタログが随時追加されるため、固定の一覧を想定せず、そこからカタログ一式を確認してください。各カタログの表には、MVR スラッグ、Move パッケージ名、ドキュメント、主な機能が記載されています。
  3. 各パッケージの README.md を読み、正確な r.mvr のインストール例とモジュール一覧を確認します。スラッグが解決できることは、moveregistry.com で調べるか、確実な方法として下記のビルドを実行して確認します。ビルドでは、すべてのスラッグが MVR に対して解決されます。

カタログのパスは、カタログファイル自身のディレクトリを基準にしています。 <catalog-dir>/README.md にあるカタログでは、各パッケージの Path は <catalog-dir>/ からの相対パスです。そのため、パッケージの raw README は .../main/<catalog-dir>/<path>/README.md にあります。<path> は、リポジトリのルートではなく、そのリンク元カタログのディレクトリを基準に解決してください(単純な .../main/<path>/README.md は 404 になります)。迷った場合は、ツリーを一覧表示してください:gh api 'repos/OpenZeppelin/contracts-sui/git/trees/main?recursive=1'(クォートで囲んでください。一部のシェルでは、クォートされていない ? がグロブとして扱われます)。

Move パッケージ名(use 文で使用)は MVR スラッグと異なります。スラッグ @openzeppelin-move/integer-math は Move パッケージ openzeppelin_math に対応します。プロジェクトで実際に使うパッケージだけを追加してください。

通常、1つのパッケージには複数のモジュールが含まれています。 カタログに記載されているのはパッケージです。必要な構成要素は、多くの場合、パッケージ内にある複数のモジュールのうちの1つです。パッケージが実際に公開しているものを確認するには、パッケージの README にあるモジュール一覧と examples/ を読んでください。1つのパッケージが1つのコンポーネントに相当すると決めつけず、固定のカタログを当てにしないでください。パッケージとモジュールは今後も増えていきます。

OpenZeppelin Sui MCP は、同じメタデータを決定論的なツール呼び出しとして提供します。sui-list-recipes(レシピを検索)、sui-get-recipe(レシピのソースと、インストール行付きの使用パッケージ)、sui-get-package(パッケージのインストール行とドキュメント)を利用できます。MCP が利用可能な場合は、ファイルを手作業でたどる代わりに MCP に問い合わせ、その後、返されたインストール行を Move.toml に追加し、レシピのソースを自分のパッケージに移してください。MCP が返すのはデータであり、ビルド可能なパッケージではありません。それをビルド可能なパッケージにするには、インストール行の追加とソースの移設が必要です。

Move Registry にないパッケージ

すべてのパッケージが Move Registry にあるわけではありません。まったく公開されていないものもあります。パッケージの README.md に r.mvr のインストール例がない場合は、GitHub リリースから依存関係を指定してください。git 依存関係の参照先にはリリースタグを固定し、変動するブランチは決して使わないでください。

[dependencies]
<move_package_name> = { git = "https://github.com/OpenZeppelin/contracts-sui.git", subdir = "<catalog-dir>/<path>", rev = "<release-tag>" }

<catalog-dir>/<path> はリポジトリ内のパッケージディレクトリです(カタログの行に記載されているものと同じ Path です)。rev はブランチではなく、公開済みの GitHub リリースタグに固定してください。下記のダイヤモンド依存関係の競合を避けるため、すべての OpenZeppelin 依存関係で一貫したリビジョンを使ってください。

バージョン競合の解決(ダイヤモンド依存関係)

2つの OZ パッケージが、共有する推移的依存関係の異なるリビジョンを取り込むことがあります。たとえば、あるパッケージが独自の数学パッケージのリビジョンを内包しており、さらにその数学パッケージを直接依存関係として指定している場合などです。この場合、ビルドは中断します。

Package depends on multiple versions of the package with ID 0x…

直接宣言した依存関係に override = true を追加すると、すべての利用者でそのリビジョンが使われるため、競合を解決できます。

[dependencies]
openzeppelin_math = { r.mvr = "@openzeppelin-move/integer-math", override = true }
openzeppelin_fp_math = { r.mvr = "@openzeppelin-move/fixed-point-math" }

実装前にサンプルとドキュメントを確認する

統合コードを書く前に、必ず以下を行ってください。多くのユーザーはカタログの全容を知らず、カタログは時間とともに拡充されるため、ライブラリが提供する機能と、その組み合わせ方を確認しましょう。使用予定の各パッケージについて、次の手順を実施してください。

  1. examples/ を確認します。 各パッケージには、コンパイル可能でCIテスト済みの統合サンプルが含まれています。これらは標準的な組み合わせ方を示すレシピであり、実際の使用パターン(初期化、ケイパビリティ/ウィットネスのフロー、オブジェクトの所有権、テスト)を把握する最も手早い方法です。ゼロから書くよりも、サンプルをコピーして sources/ に合わせて変更してください。

    サンプルとメタデータは main から読み、依存関係はリリースに固定します。 すべてのAIメタデータ(llms.txt、カタログ、パッケージのREADME、STYLEGUIDE.md、examples/)は、最新かつ最も完全な情報が含まれる main ブランチ から読み取ってください(パッケージによっては、タグ付きリリースにはないサンプルが main に含まれていることがあります)。一方、ビルドの 依存関係 は、MVRスラグまたは git rev = "<release-tag>"(上記)のように、特定の リリース に固定して解決されるため、ビルドの再現性が保たれます。この2つは異なる場合があります。main からコピーしたサンプルが、固定したリリースより新しいAPIを参照している場合は、移植時に適合させるか、固定したリリースを更新してください。

    コピーしたサンプルを移植します。 サンプルのモジュールは、ライブラリ自身のアドレスの下で宣言されています(例:module openzeppelin_access::example_reward_treasury;)。これはライブラリ内の説明用であり、そのまま利用側のコードとして使えるものではありません。sources/ にコピーする際は、モジュールを自分のパッケージに合わせて名前を変更してください(module <your_package>::<module>;。<your_package> は Move.toml の [package] 名です)。use openzeppelin_*::… の行は依存関係を参照しているため、そのままにしてください。サンプルでワンタイムウィットネスを定義している場合(モジュール名を大文字にした名前の構造体で、init によって消費されるもの)、その構造体名も新しいモジュール名に合わせて変更してください。変更しないと、init は「Invalid parameter … Expected a one-time witness type」というエラーで失敗します。依存関係のアドレスの下にモジュールを定義することはできないため、コピーしただけでは移植するまでビルドできません。

  2. ドキュメントを読みます。 概念やガイドについては、まずドキュメントサイトを確認します。次に、生成されたAPIリファレンスを確認してください。各カタログの表にある Docs リンクからアクセスできます(適切なバージョンを指しています)。正確なシグネチャ、パラメーター、アボート条件については、.../contracts-sui/<major>.x/api/<catalog_package> というパスを参照してください。<major> は contracts-sui のリリースに対応し、<catalog_package> はMoveパッケージ名ではなく、カタログ上の短い名前です。

  3. コードのドキュメントを読みます。 APIリファレンスはモジュールのドキュメントコメントから生成されるため、インストール済みのソースが信頼できる情報源です。sui move build --doc --build-env testnet を実行すると、同じドキュメントをローカルで生成できます(MVR依存関係がある場合は --build-env が必須です)。このコマンドは、すべてのOZ依存関係のドキュメントも build/<your_package>/docs/dependencies/<move_package_name>/ に出力します。または、インストール済みソースのドキュメントコメントを直接確認してください。

利用可能なサンプルは、llms.txt と各パッケージのREADMEから探し、contracts-sui リポジトリで確認してください。

インポート規約

Moveパッケージ名(Move.toml エントリーの左側)に続けてモジュール名を指定し、use <move_package_name>::<module>; の形式でモジュールをインポートします。その後、パッケージの examples/ とAPIドキュメントに記載された使用パターンに従ってください。

一部の操作は、public use fun による再エクスポートを通じて メソッド構文(value.op(...))で公開されているため、元の関数が型とは別のモジュールにある場合があります。想定していたフリー関数が見つからない場合は、パッケージのソースで public use fun の行を確認し、メソッドとして呼び出してください。

エージェント向けガイダンスの作成

プロジェクトのルートに AGENTS.md を作成し、後からこのプロジェクトを開くエージェントが、OpenZeppelin Contracts for Sui に基づいて構築されていることと、信頼できる情報源の場所を把握できるようにします。contracts-sui の AGENTS.md と同じ方針に従います。つまり、ルールを再掲せず、信頼できる情報源へのリンクだけを記載した、簡潔なポインターファイルにします。また、Claude Code が読み込めるよう、@AGENTS.md だけを記載した CLAUDE.md も追加します(contracts-sui 自体の設定にならいます)。

# AGENTS.md

This is a Sui Move project built on **OpenZeppelin Contracts for Sui**.

## Sources of truth — read these first
- AI discovery entry point: https://raw.githubusercontent.com/OpenZeppelin/contracts-sui/main/llms.txt
  (points to the package catalogs, each package's `examples/`, the generated API reference, and audits)
- Docs: https://docs.openzeppelin.com/contracts-sui
- API reference: https://docs.openzeppelin.com/contracts-sui/<major>.x/api/<catalog_package> (`<major>` matches your contracts-sui release and `<catalog_package>` is the short catalog name; the catalog's `Docs` links carry the correct version)
- Code docs (local): `sui move build --doc --build-env testnet` → `build/<your_package>/docs/` (named after your own package; includes OZ dependencies)

## Conventions
- Before implementing, study each package's `examples/` (compilable, CI-tested composition recipes) and its API docs; prefer audited library components over custom logic.
- Import modules via the Move package name (`use <move_package_name>::<module>;`); a package typically exposes several modules — check its README and `examples/`.
- MVR-backed builds require a build env: `sui move build --build-env testnet`. If two OZ deps pull different revisions of a shared transitive package, add `override = true` to the directly-declared one.
- For fungible-asset custody, consider Sui [Address Balances](https://docs.sui.io/onchain-finance/asset-custody/address-balances/) (SIP-58) over summing `Coin` objects where it fits.
- Code style follows the OpenZeppelin Sui conventions — see Code Quality below.

## Code quality
The library's conventions are the single source of truth for Move style:
- Rules: https://raw.githubusercontent.com/OpenZeppelin/contracts-sui/main/STYLEGUIDE.md
- Design rationale: https://raw.githubusercontent.com/OpenZeppelin/contracts-sui/main/ARCHITECTURE.md
- Review procedure (reads STYLEGUIDE.md, reports/fixes violations): https://raw.githubusercontent.com/OpenZeppelin/contracts-sui/main/.claude/commands/code-quality.md

## MCP
The OpenZeppelin Sui MCP (https://mcp.openzeppelin.com/contracts/sui/mcp) serves recipes and per-package install lines as deterministic tool calls (`sui-list-recipes`, `sui-get-recipe`, `sui-get-package`) — a queryable alternative to reading `llms.txt` + the catalogs by hand. This project ships it pre-wired in `.mcp.json`. It returns data, not a buildable package — wiring the install lines into `Move.toml` and re-homing the source into this package is what turns it into one.

さらに、プロジェクトのルートに事前設定済みの MCP 設定ファイルを追加し、クローン時に手動で設定しなくても、すべてのエージェントが OpenZeppelin on Sui のコンテキストを把握できるようにします。Claude Code は .mcp.json を読み込みます。他のアシスタント(Cursor、Cline)では、それぞれの MCP 設定に同じサーバー URL を指定します。

{
  "mcpServers": {
    "openzeppelin-sui": {
      "type": "http",
      "url": "https://mcp.openzeppelin.com/contracts/sui/mcp"
    }
  }
}

ビルドとテスト

依存関係は MVR 経由で解決されるため、ビルドとテストではビルド環境を指定する必要があります。開発には testnet を使用します(リリースビルドでは mainnet も使用できます)。

sui move build --build-env testnet
sui move test --build-env testnet

--build-env を指定しない場合、CLI は r.mvr の依存関係を解決できず、「local に使用する適切な依存関係を特定できませんでした」というエラーが発生します。新規にスキャフォールディングしたプロジェクトで build と test が成功することが、合格基準です。

プロジェクトに実際のコードが追加されたら、スタイルやデッドコードの問題を早期に検出できるよう、--lint --warnings-are-errors を追加します。

sui move test --build-env testnet --lint --warnings-are-errors
知っておくべきテストパターン

これらのパッケージを基盤にしたコードをテストする際、Sui で繰り返し登場する慣例がいくつかあります。ライブラリ独自の examples/ テストが、公式の参考例です。

  • テストでの One-Time Witness(OTW)。 OTW を受け取るモジュールは init でそれを消費するため、実行時に構築できません。このようなモジュールをユニットテストで実行するには、OTW を構築する #[test_only] の初期化関数を公開します(その構造体は #[test_only] コンテキスト内で構築できます)。

    #[test_only]
    public fun init_for_testing(ctx: &mut TxContext) { init(MY_OTW {}, ctx) }
    
  • Clock。 時刻に依存するモジュールは sui::clock::Clock を受け取ります。テストでは create_for_testing、increment_for_testing、destroy_for_testing を使用します。

  • アサーション。 --warnings-are-errors を有効にすると、リテラルのアボートコード(assert!(cond, 0))は abort_without_constant lint に抵触します。テストでは assert_eq!(std::unit_test から)または引数なしの assert!(cond) を使用します。テスト以外のコードでは、リテラルではなく名前付きエラー定数でアサーションします。

合成に関する制約: Sui の init 関数は Clock(または他の実行時引数)を受け取りません。そのため、コンストラクターが Clock を必要とするコンポーネントは、init 内で完全に構築できません。init でオブジェクトを作成して共有し、その後 Clock を受け取る別のエントリー関数でセットアップを完了します。パッケージの examples/ に、この意図された二段階のパターンが示されています。

コード品質

インテグレーターのコードとライブラリの一貫性を保つため、プロジェクトの Move スタイルを OpenZeppelin 独自の規約に合わせます。依存関係と同様に、ルールを再掲せず、信頼できる情報源を参照します。

  • STYLEGUIDE.md — 成文化されたルール(命名、モジュールとパッケージ、セクションの順序、インポート、構造体、関数、Move 2024 の慣用表現、コレクションとオブジェクトのサイズ、テスト、lint の抑制、ドキュメント)。
  • ARCHITECTURE.md — ルールの根拠となる設計方針(ケイパビリティベースのアクセス、所有オブジェクトと共有オブジェクト、PTB の合成可能性、状態の上限設定、アップグレードの安全性)。
  • .claude/commands/code-quality.md — レビュープロセス。このファイルは STYLEGUIDE.md を読み、各 .move ファイルを照合してから、違反を報告または修正します。手順はプレーンな Markdown で記述されているため、スラッシュコマンド自体は Claude 固有でも、どのエージェントでも実行できます。

後続のエージェントがクローン時に同じ規約に従えるよう、これらを生成する AGENTS.md の Code quality 見出しの下に記載します(上記を参照)。

フォーマット

contracts-sui は、@mysten/prettier-plugin-move Prettier プラグインを使って Move をフォーマットします。連携側のコードも同じレイアウトになるように、この設定に合わせてください。プラグインをインストールし、ライブラリに合わせた .prettierrc を追加します。

npm i -D prettier @mysten/prettier-plugin-move
{
  "tabWidth": 4,
  "printWidth": 100,
  "useModuleLabel": true,
  "autoGroupImports": "module",
  "plugins": ["@mysten/prettier-plugin-move"]
}

次に、リポジトリのルートからフォーマットします(Prettier はプラグインを解決できない場合、.move ファイルを警告なしでスキップするため、devDependencies に含めてください)。

npx prettier --write "**/*.move"

autoGroupImports: "module" は use のグループ化を正規化するため、--write を実行してフォーマットしてください。インポートを手動で調整しても、最初から --check が通ることは期待しないでください。

code-quality.md のレビュープロセスでは、修正を適用した後に同じフォーマット処理を実行します。

コメント