logo

「Solidity開発者向けSui Move入門編」を読んで(1)

俺のAptosは一向に火を吹かない
profile photo
TaniguchiAkira

初めに

脳の老化が迫り来る昨今、皆様いかがお過ごしでしょうか。
30年前はいろんな情報が勝手に脳に記録されていきました、今はそんなことできません。
無駄に覚えていた今週の歌謡曲TOP10、DA PUMP、SPEED、FIELD OF VIEW、DEENなど、おらはりましたね。(今もいはります、蕎麦に対する知見も凄そうです)
話は変わりますが、コントラクトといえばSolidityと言う常識は遠い過去のものであり、SolanaのRustに始まりSuiのMoveときて、Arbitrumのstylusと言う時代の流れに、皆様はついていけていますか?
大半の人は危機感は感じるものの、日々の多忙な業務に追い込まれ、新しいことに手を出せずにいるのではないでしょうか。
と言うわけで最近公開されたこのブログを読んで、Solidityだけはちょっとわかる私がSui Moveを学びつつ、わからないところを自分なりに調べて見たりして、その過程を共有しようと思います。
長くなりそうなので、いくつかの記事に分割します。
なお、これから「Move」と表現しているものは全て「Sui Move」に置き換えて読んでください。
あと、ここに記載されているコードは実際にコンパイルまで進んでいません。ご了承ください。
A Gentle Introduction to Sui Move, for Solidity developers | yakitori.dev
For when you want your Solidity devs to cry in a new language
A Gentle Introduction to Sui Move, for Solidity developers | yakitori.dev

想定対象読者

  • Solidityはある程度わかる
  • いつまでもSolidityで食べていけないことは理解している
  • というかSolidityっていずれCOBOLみたいな位置付けになるよね、って思ってる
  • FF7で中2病を加速させたアラフォー

詳細

コントラクトの構成の違い

Solidityはコードとデータの保存領域を同じコントラクトで管理している。
それに対してMoveはコードとデータを分離して管理している。
まずここが大きな違い。Solidityだってupgradeableなものはデータとコードが分かれてるじゃないか、って言うヤボなツッコミは一旦置いといてほしい。
Moveのコードの部分を「モジュール」と言い、Solidityのように継承することはできない。
一方、データの部分を「オブジェクト」と言う。
(愚痴)
また、モジュールとオブジェクトは1対Nの関係をもつ。
例えばブログでいうdegital_artモジュールはDegitalArtと言うデータの構造体とcreate_art、update_priceと言う関数で構成されている。
誰かがcreate_art関数を実行するたびにDegitalArtと言うオブジェクトが作成される。
https://yakitori.dev/blog/00-sui-move-for-solidity-devs/
https://yakitori.dev/blog/00-sui-move-for-solidity-devs/

所有権

作成されたDegitalArtオブジェクトには自動で所有権が設定され、他のウォレットを接続して作成されたDegitalArtオブジェクトを指定してupdate_priceを実行しても、エラーになる。
また所有権は移動させることができる。
abap
public fun transfer_art( recipient: address, art: DigitalArt, ctx: &mut TxContext ) { // 所有権の移転、これ以外にも誰でも参照できるようになる。share_objectという関数も用意されている transfer::transfer(art, recipient); }
transferの使用例

型能力

structに「has key」や「has store」などをつけることにより、型に能力を持たせることができる
型能力
詳細
key
UIDを持つことができるようになる。グローバルストレージにそのデータが保存されることを 許可され、他のトランザクションや関数からアクセスできるようになる。
store
所有権を他のユーザに譲渡することができる。また、他のオブジェクト内に保存されることを許可する
copy
コピー可能であることを許可する、keyと併用ができない
drop
削除できることを許可する
abap
// `has store`を持つ構造体 struct Item has key, store { id: u64, name: vector<u8>, } // `Container`は他のオブジェクト(`Item`)を保持するため、`Item`には`has store`が必要 struct Container has key, store { items: vector<Item>, } // 新しいItemを作成する関数 public fun create_item(id: u64, name: vector<u8>): Item { Item { id, name } } // ContainerにItemを追加する関数 public fun add_item(container: &mut Container, item: Item) { vector::push_back(&mut container.items, item); }
has storeの使用例
abap
// `has copy`を持つ構造体 struct Config has copy { value: u64, } // コピーを試みる関数 public fun copy_config() { let original = Config { value: 100 }; let copied = original; // コピーが可能 // `copied`と`original`は同じ値を持つ }
has copyの例
abap
struct TempData has drop { value: u64, } // TempDataを作成して破棄する public fun create_and_drop() { let data = TempData { value: 42 }; // `data`は関数の終了時に自動的に破棄される }
has dropの例

@mysten/sui

ethers.jsのように、suiにもsuiを扱うためのライブラリが存在する。
下記はcreate_artを実行してオブジェクトのIDを取得した後、update_artを実行してデータを更新するスクリプトの例
typescript
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client'; import { Ed25519Keypair, TransactionBlock } from '@mysten/sui/keypairs/ed25519'; // SuiClientのセットアップ const client = new SuiClient({ url: getFullnodeUrl('devnet') }); // Devnet用 // ウォレットのセットアップ(例:エドワード署名のキーペア) const keypair = Ed25519Keypair.fromSecretKey(<シークレットキー>); // シークレットキーを使ってウォレットを作成 // トランザクションブロックの作成とオブジェクトIDの取得 async function createArtAndGetId(artist, title, price) { const tx = new TransactionBlock(); // コントラクトモジュールのパスや関数名、引数を設定 tx.moveCall({ target: "0xYourModuleAddress::digital_art::create_art", // デプロイ済みモジュールのアドレスと関数 arguments: [ tx.pure(artist), // アーティストのアドレス tx.pure(title), // タイトル(vector<u8>) tx.pure(price), // 価格 ] }); // トランザクションの署名と送信 const result = await client.signAndExecuteTransactionBlock({ signer: keypair, transactionBlock: tx }); // 新しく生成されたオブジェクトのIDを取得 const createdObjectId = result.effects.created?.[0]?.reference?.objectId; if (createdObjectId) { console.log('New DigitalArt Object ID:', createdObjectId); return createdObjectId; } else { console.error('Failed to create object or retrieve object ID'); return null; } } // 関数呼び出し const artistAddress = "0xArtistAddress"; // アーティストのアドレス const title = new TextEncoder().encode("Artwork Title"); // タイトルをvector<u8>に変換 const price = 1000; // 価格 createArtAndGetId(artistAddress, title, price) .then((objectId) => { if (objectId) { console.log("Successfully created DigitalArt with ID:", objectId); // ここで objectId を使って他の操作が可能 } }) .catch(err => console.error("Error:", err));
typescript
// Update price using the created object's ID async function updatePrice(artId, newPrice) { const tx = new TransactionBlock(); // コントラクトモジュールのパスや関数名、引数を設定 tx.moveCall({ target: "0xYourModuleAddress::digital_art::update_price", // デプロイ済みモジュールのアドレスと関数 arguments: [ tx.object(artId), // 更新対象のDigitalArtオブジェクトID tx.pure(newPrice), // 新しい価格 ] }); // トランザクションの署名と送信 const result = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx }); console.log('Transaction Result:', result); } // 先ほど取得した objectId を使って価格を更新 updatePrice(objectId, 2000) .then(() => console.log("Price updated successfully!")) .catch(err => console.error("Error updating price:", err));

予告

次回はSolidityでいうonlyOwnerのような、アクセス制御をどうするか書いていく。

参考リンク

A Gentle Introduction to Sui Move, for Solidity developers | yakitori.dev
For when you want your Solidity devs to cry in a new language
A Gentle Introduction to Sui Move, for Solidity developers | yakitori.dev
Related posts
post image
Aptos Japanがないのはなぜなのか
post image
いまだに俺のAptosは一向に火を吹かない
post image
Solidity
Optimism
Arbitrum
L2
Wormhole
Layer0
オレオレインターフェースからERC7802へ
ユニバーサル規格は大事
Powered by Notaku