diff --git a/crates/sui/src/sui_move/new.rs b/crates/sui/src/sui_move/new.rs index 41e9017b16e7e..d553d3cc5f30e 100644 --- a/crates/sui/src/sui_move/new.rs +++ b/crates/sui/src/sui_move/new.rs @@ -4,9 +4,12 @@ use clap::Parser; use move_cli::base::new; use std::path::PathBuf; +use sui_types::SUI_FRAMEWORK_ADDRESS; const SUI_PKG_NAME: &str = "Sui"; -const SUI_PKG_PATH: &str = "{ git = \"https://github.com/MystenLabs/sui.git\", subdir = \"crates/sui-framework\", rev = \"main\" }"; + +// Use devnet by default. Probably want to add options to make this configurable later +const SUI_PKG_PATH: &str = "{ git = \"https://github.com/MystenLabs/sui.git\", subdir = \"crates/sui-framework\", rev = \"devnet\" }"; #[derive(Parser)] pub struct New { @@ -21,7 +24,13 @@ impl New { path, "0.0.1", [(SUI_PKG_NAME, SUI_PKG_PATH)], - [(name, "0x0")], + [ + (name, "0x0"), + ( + &SUI_PKG_NAME.to_lowercase(), + &SUI_FRAMEWORK_ADDRESS.to_string(), + ), + ], "", )?; Ok(()) diff --git a/doc/src/build/move/write-package.md b/doc/src/build/move/write-package.md index 9e098d6ccac10..9f38b154eac34 100644 --- a/doc/src/build/move/write-package.md +++ b/doc/src/build/move/write-package.md @@ -2,108 +2,80 @@ title: Write a Sui Move Package --- -## +## -In order to build a Move package and run code defined in -this package, first [install Sui binaries](../install.md#binaries) and -[clone the repository](../install.md#source-code) as this tutorial assumes -you have the Sui repository source code in your current directory. +In order to build a Move package and run code defined in this package, first [install Sui binaries](../install.md#binaries). -Refer to the code example developed for this tutorial in the -[m1.move](https://github.com/MystenLabs/sui/tree/main/sui_programmability/examples/move_tutorial/sources/m1.move) file. +### Creating the package -The directory structure used in this tutorial should at the moment -look as follows (assuming Sui has been cloned to a directory called -"sui"): +First, create an empty Move package: -``` -current_directory -├── sui -``` - -For convenience, make sure the path to Sui binaries -(`~/.cargo/bin`), including the `sui` command used throughout -this tutorial, is part of your system path: - -``` -$ which sui +``` shell +$ sui move new my_first_package ``` -### Creating the directory structure +This creates a skeleton Move project in the `my_first_package` directory. Let's take a look at the package manifest created by this command: -Now proceed to creating a package directory structure in the current -directory, parallel to the `sui` repository. It will contain an -empty manifest file and an empty module source file following the -[Move code organization](../move/index.md#move-code-organization) -described earlier. +```shell +$ cat my_first_package/Move.toml +[package] +name = "my_first_package" +version = "0.0.1" -So from the same directory containing the `sui` repository create a -parallel directory to it by running: +[dependencies] +Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework", rev = "devnet" } -``` shell -$ mkdir -p my_move_package/sources -touch my_move_package/sources/m1.move -touch my_move_package/Move.toml +[addresses] +my_first_package = "0x0" +sui = "0x2" ``` -The directory structure should now be (please note that directories at the same indentation level in the figure below should also be at the same level in the file system): +This file contains: +* Package metadata such as name and version (`[package]` section) +* Other packages that this package depends on (`[dependencies]` section). This package only depends on the Sui Framework, but other third-party dependencies should be added here. +* A list of *named addresses* (`[addresses]` section). These names can be used as convenient aliases for the given addresses in the source code. -``` -current_directory -├── sui -├── my_move_package - ├── Move.toml - ├── sources - ├── m1.move -``` ### Defining the package -Let us assume that our module is part of an implementation of a -fantasy game set in medieval times, where heroes roam the land slaying -beasts with their trusted swords to gain prizes. All of these entities -will be represented by Sui objects; in particular, we want a sword to -be an upgradable asset that can be shared between different players. A -sword asset can be defined similarly to another asset we are already -familiar with from our -[First look at Move source code](../move/index.md#first-look-at-move-source-code). That -is a `Coin` struct type. +Let's start by creating a source file in the package: +``` shell +$ touch my_first_package/sources/my_module.move +``` -Let us put the following module and struct -definitions in the `m1.move` file: +and adding the following code to the `my_module.move` file: -``` rust -module my_first_package::m1 { +```move +module my_first_package::my_module { + // Part 1: imports use sui::object::{Self, UID}; + use sui::transfer; use sui::tx_context::TxContext; + // Part 2: struct definitions struct Sword has key, store { id: UID, magic: u64, strength: u64, } -} -``` -Since we are developing a fantasy game, in addition to the mandatory -`id` field as well as `key` and `store` abilities (same as in the -`Coin` struct), our asset has both `magic` and `strength` fields -describing its respective attribute values. Please note that we need -to import the -[Object package](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/sources/object.move) from -Sui framework to gain access to the `ID` struct type defined -in this package. - -If we want to access sword attributes from a different package, we -need to add accessor functions to our module similar to the `value` -function in the Coin package described in [Move -functions](#move-functions) (please make sure you add these functions, -and all the following code in this tutorial, in the scope of our -package - between curly braces starting and ending the package -definition): - -``` rust + struct Forge has key, store { + id: UID, + swords_created: u64, + } + + // Part 3: module initializer to be executed when this module is published + fun init(ctx: &mut TxContext) { + let admin = Forge { + id: object::new(ctx), + swords_created: 0, + }; + // transfer the forge object to the module/package publisher + transfer::transfer(admin, tx_context::sender(ctx)); + } + + // Part 4: accessors required to read the struct attributes public fun magic(self: &Sword): u64 { self.magic } @@ -111,25 +83,22 @@ definition): public fun strength(self: &Sword): u64 { self.strength } -``` -In order to build a package containing this simple module, we need to -put some required metadata into the `Move.toml` file, including package -name, package version, local dependency path to locate Sui framework -code, and package numeric ID, which must be `0x0` for user-defined modules -to facilitate [package publishing](../cli-client.md#publish-packages). + public fun swords_created(self: &Forge): u64 { + self.swords_created + } + // part 5: public/ entry functions (introduced later in the tutorial) + // part 6: private functions (if any) +} ``` -[package] -name = "MyFirstPackage" -version = "0.0.1" -[dependencies] -Sui = { local = "../sui/crates/sui-framework" } +Let's break down the four different parts of this code: -[addresses] -my_first_package = "0x0" -``` +1. Imports: these allow our module to use types and functions declared in other modules. In this case, we pull in imports from three different modules. + +2. Struct declarations: these define types that can be created/destroyed by this module. Here the `key` *abilities* indicate that these structs are Sui objects that can be transferred between addresses. The `store` ability on the sword allows it to appear in fields of other structs and to be transferred freely. + +3. Module initializer: this is a special function that is invoked exactly once when the module is published. -See the [Move.toml](https://github.com/MystenLabs/sui/blob/main/sui_programmability/examples/move_tutorial/Move.toml) -file used in our [end-to-end tutorial](../../explore/tutorials.md) for an example. +4. Accessor functions--these allow the fields of the fields of module's struct to be read from other modules. diff --git a/sui_programmability/examples/move_tutorial/sources/m1.move b/sui_programmability/examples/move_tutorial/sources/my_module.move similarity index 90% rename from sui_programmability/examples/move_tutorial/sources/m1.move rename to sui_programmability/examples/move_tutorial/sources/my_module.move index 75257ceb255ce..65c6527f1245a 100644 --- a/sui_programmability/examples/move_tutorial/sources/m1.move +++ b/sui_programmability/examples/move_tutorial/sources/my_module.move @@ -1,22 +1,25 @@ // Copyright (c) 2022, Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module my_first_package::m1 { +module my_first_package::my_module { + // Part 1: imports use sui::object::{Self, UID}; + use sui::transfer; use sui::tx_context::TxContext; + // Part 2: struct definitions struct Sword has key, store { id: UID, magic: u64, strength: u64, } - struct Forge has key, store { + struct Forge has key { id: UID, swords_created: u64, } - // module initializer to be executed when this module is published + // Part 3: module initializer to be executed when this module is published fun init(ctx: &mut TxContext) { use sui::transfer; use sui::tx_context; @@ -25,14 +28,10 @@ module my_first_package::m1 { swords_created: 0, }; // transfer the forge object to the module/package publisher - // (presumably the game admin) transfer::transfer(admin, tx_context::sender(ctx)); } - public fun swords_created(self: &Forge): u64 { - self.swords_created - } - + // Part 4: accessors required to read the struct attributes public fun magic(self: &Sword): u64 { self.magic } @@ -41,8 +40,12 @@ module my_first_package::m1 { self.strength } + public fun swords_created(self: &Forge): u64 { + self.swords_created + } + + // Part 5: entry functions to create and transfer swords public entry fun sword_create(forge: &mut Forge, magic: u64, strength: u64, recipient: address, ctx: &mut TxContext) { - use sui::transfer; // create a sword let sword = Sword { id: object::new(ctx), @@ -54,12 +57,7 @@ module my_first_package::m1 { forge.swords_created = forge.swords_created + 1; } - public entry fun sword_transfer(sword: Sword, recipient: address) { - use sui::transfer; - // transfer the sword - transfer::transfer(sword, recipient); - } - + // Part 6: tests #[test] public fun test_module_init() { use sui::test_scenario; @@ -113,7 +111,7 @@ module my_first_package::m1 { // extract the sword owned by the initial owner let sword = test_scenario::take_owned(scenario); // transfer the sword to the final owner - sword_transfer(sword, final_owner); + transfer::transfer(sword, final_owner); }; // fourth transaction executed by the final sword owner test_scenario::next_tx(scenario, &final_owner); @@ -131,7 +129,6 @@ module my_first_package::m1 { #[test] public fun test_sword_create() { - use sui::transfer; use sui::tx_context; // create a dummy TxContext for testing @@ -151,5 +148,4 @@ module my_first_package::m1 { let dummy_address = @0xCAFE; transfer::transfer(sword, dummy_address); } - }