From db3913f20bcf85ddb1c1119e599b055910609ed7 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 19 Apr 2024 16:07:08 +0300 Subject: [PATCH 1/6] feat: added stardust system package with basic nfts implementation --- crates/sui-framework-snapshot/src/lib.rs | 4 +- crates/sui-framework/build.rs | 34 +- .../docs/move-stdlib/fixed_point32.md | 318 +++++++++++++ .../stardust/expiration_unlock_condition.md | 129 ++++++ crates/sui-framework/docs/stardust/irc27.md | 419 ++++++++++++++++++ crates/sui-framework/docs/stardust/nft.md | 281 ++++++++++++ .../sui-framework/docs/stardust/nft_output.md | 172 +++++++ ...storage_deposit_return_unlock_condition.md | 132 ++++++ .../stardust/timelock_unlock_condition.md | 109 +++++ .../sui-framework/packages/stardust/Move.toml | 12 + .../packages/stardust/sources/nft/irc27.move | 133 ++++++ .../packages/stardust/sources/nft/nft.move | 83 ++++ .../stardust/sources/nft/nft_output.move | 70 +++ .../expiration_unlock_condition.move | 42 ++ ...orage_deposit_return_unlock_condition.move | 41 ++ .../timelock_unlock_condition.move | 26 ++ crates/sui-framework/src/lib.rs | 7 +- crates/sui-move-build/src/lib.rs | 9 +- crates/sui-replay/src/replay.rs | 7 +- crates/sui-types/src/lib.rs | 15 + crates/sui-types/src/sui_serde.rs | 7 +- 21 files changed, 2042 insertions(+), 8 deletions(-) create mode 100644 crates/sui-framework/docs/move-stdlib/fixed_point32.md create mode 100644 crates/sui-framework/docs/stardust/expiration_unlock_condition.md create mode 100644 crates/sui-framework/docs/stardust/irc27.md create mode 100644 crates/sui-framework/docs/stardust/nft.md create mode 100644 crates/sui-framework/docs/stardust/nft_output.md create mode 100644 crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md create mode 100644 crates/sui-framework/docs/stardust/timelock_unlock_condition.md create mode 100644 crates/sui-framework/packages/stardust/Move.toml create mode 100644 crates/sui-framework/packages/stardust/sources/nft/irc27.move create mode 100644 crates/sui-framework/packages/stardust/sources/nft/nft.move create mode 100644 crates/sui-framework/packages/stardust/sources/nft/nft_output.move create mode 100644 crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move create mode 100644 crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move create mode 100644 crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move diff --git a/crates/sui-framework-snapshot/src/lib.rs b/crates/sui-framework-snapshot/src/lib.rs index 808073492e3..0f9fdc3638f 100644 --- a/crates/sui-framework-snapshot/src/lib.rs +++ b/crates/sui-framework-snapshot/src/lib.rs @@ -7,7 +7,8 @@ use std::{fs, io::Read, path::PathBuf}; use sui_framework::SystemPackage; use sui_types::base_types::ObjectID; use sui_types::{ - DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, + DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, + SUI_SYSTEM_PACKAGE_ID, }; pub type SnapshotManifest = BTreeMap; @@ -34,6 +35,7 @@ const SYSTEM_PACKAGE_PUBLISH_ORDER: &[ObjectID] = &[ SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, DEEPBOOK_PACKAGE_ID, + STARDUST_PACKAGE_ID, ]; pub fn load_bytecode_snapshot_manifest() -> SnapshotManifest { diff --git a/crates/sui-framework/build.rs b/crates/sui-framework/build.rs index e47f15227aa..19982ae38fe 100644 --- a/crates/sui-framework/build.rs +++ b/crates/sui-framework/build.rs @@ -24,15 +24,18 @@ fn main() { let deepbook_path = packages_path.join("deepbook"); let sui_system_path = packages_path.join("sui-system"); let sui_framework_path = packages_path.join("sui-framework"); + let stardust_path = packages_path.join("stardust"); let deepbook_path_clone = deepbook_path.clone(); let sui_system_path_clone = sui_system_path.clone(); let sui_framework_path_clone = sui_framework_path.clone(); + let stardust_path_clone = stardust_path.clone(); let move_stdlib_path = packages_path.join("move-stdlib"); build_packages( deepbook_path_clone, sui_system_path_clone, sui_framework_path_clone, + stardust_path_clone, out_dir, ); @@ -69,12 +72,21 @@ fn main() { "cargo:rerun-if-changed={}", move_stdlib_path.join("sources").display() ); + println!( + "cargo:rerun-if-changed={}", + stardust_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + stardust_path.join("sources").display() + ); } fn build_packages( deepbook_path: PathBuf, sui_system_path: PathBuf, sui_framework_path: PathBuf, + stardust_path: PathBuf, out_dir: PathBuf, ) { let config = MoveBuildConfig { @@ -90,11 +102,13 @@ fn build_packages( deepbook_path.clone(), sui_system_path.clone(), sui_framework_path.clone(), + stardust_path.clone(), out_dir.clone(), "deepbook", "sui-system", "sui-framework", "move-stdlib", + "stardust", config, true, ); @@ -111,11 +125,13 @@ fn build_packages( deepbook_path, sui_system_path, sui_framework_path, + stardust_path, out_dir, "deepbook-test", "sui-system-test", "sui-framework-test", "move-stdlib-test", + "stardust-test", config, false, ); @@ -125,11 +141,13 @@ fn build_packages_with_move_config( deepbook_path: PathBuf, sui_system_path: PathBuf, sui_framework_path: PathBuf, + stardust_path: PathBuf, out_dir: PathBuf, deepbook_dir: &str, system_dir: &str, framework_dir: &str, stdlib_dir: &str, + stardust_dir: &str, config: MoveBuildConfig, write_docs: bool, ) { @@ -148,22 +166,31 @@ fn build_packages_with_move_config( .build(sui_system_path) .unwrap(); let deepbook_pkg = BuildConfig { - config, + config: config.clone(), run_bytecode_verifier: true, print_diags_to_stderr: false, } .build(deepbook_path) .unwrap(); + let stardust_pkg = BuildConfig { + config, + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + .build(stardust_path) + .unwrap(); let sui_system = system_pkg.get_sui_system_modules(); let sui_framework = framework_pkg.get_sui_framework_modules(); let deepbook = deepbook_pkg.get_deepbook_modules(); let move_stdlib = framework_pkg.get_stdlib_modules(); + let stardust = stardust_pkg.get_stdlib_modules(); serialize_modules_to_file(sui_system, &out_dir.join(system_dir)).unwrap(); serialize_modules_to_file(sui_framework, &out_dir.join(framework_dir)).unwrap(); serialize_modules_to_file(deepbook, &out_dir.join(deepbook_dir)).unwrap(); serialize_modules_to_file(move_stdlib, &out_dir.join(stdlib_dir)).unwrap(); + serialize_modules_to_file(stardust, &out_dir.join(stardust_dir)).unwrap(); // write out generated docs if write_docs { // Remove the old docs directory -- in case there was a module that was deleted (could @@ -187,6 +214,11 @@ fn build_packages_with_move_config( &framework_pkg.package.compiled_docs.unwrap(), &mut files_to_write, ); + relocate_docs( + stardust_dir, + &stardust_pkg.package.compiled_docs.unwrap(), + &mut files_to_write, + ); for (fname, doc) in files_to_write { let mut dst_path = PathBuf::from(DOCS_DIR); dst_path.push(fname); diff --git a/crates/sui-framework/docs/move-stdlib/fixed_point32.md b/crates/sui-framework/docs/move-stdlib/fixed_point32.md new file mode 100644 index 00000000000..fabffdbc562 --- /dev/null +++ b/crates/sui-framework/docs/move-stdlib/fixed_point32.md @@ -0,0 +1,318 @@ +--- +title: Module `0x1::fixed_point32` +--- + +Defines a fixed-point numeric type with a 32-bit integer part and +a 32-bit fractional part. + + +- [Struct `FixedPoint32`](#0x1_fixed_point32_FixedPoint32) +- [Constants](#@Constants_0) +- [Function `multiply_u64`](#0x1_fixed_point32_multiply_u64) +- [Function `divide_u64`](#0x1_fixed_point32_divide_u64) +- [Function `create_from_rational`](#0x1_fixed_point32_create_from_rational) +- [Function `create_from_raw_value`](#0x1_fixed_point32_create_from_raw_value) +- [Function `get_raw_value`](#0x1_fixed_point32_get_raw_value) +- [Function `is_zero`](#0x1_fixed_point32_is_zero) + + +
+ + + + + +## Struct `FixedPoint32` + +Define a fixed-point numeric type with 32 fractional bits. +This is just a u64 integer but it is wrapped in a struct to +make a unique type. This is a binary representation, so decimal +values may not be exactly representable, but it provides more +than 9 decimal digits of precision both before and after the +decimal point (18 digits total). For comparison, double precision +floating-point has less than 16 decimal digits of precision, so +be careful about using floating-point to convert these values to +decimal. + + +
struct FixedPoint32 has copy, drop, store
+
+ + + +
+Fields + + +
+
+value: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The denominator provided was zero + + +
const EDENOMINATOR: u64 = 65537;
+
+ + + + + +The quotient value would be too large to be held in a u64 + + +
const EDIVISION: u64 = 131074;
+
+ + + + + +A division by zero was encountered + + +
const EDIVISION_BY_ZERO: u64 = 65540;
+
+ + + + + +The multiplied value would be too large to be held in a u64 + + +
const EMULTIPLICATION: u64 = 131075;
+
+ + + + + +The computed ratio when converting to a FixedPoint32 would be unrepresentable + + +
const ERATIO_OUT_OF_RANGE: u64 = 131077;
+
+ + + + + +> TODO: This is a basic constant and should be provided somewhere centrally in the framework. + + +
const MAX_U64: u128 = 18446744073709551615;
+
+ + + + + +## Function `multiply_u64` + +Multiply a u64 integer by a fixed-point number, truncating any +fractional part of the product. This will abort if the product +overflows. + + +
public fun multiply_u64(val: u64, multiplier: fixed_point32::FixedPoint32): u64
+
+ + + +
+Implementation + + +
public fun multiply_u64(val: u64, multiplier: FixedPoint32): u64 {
+    // The product of two 64 bit values has 128 bits, so perform the
+    // multiplication with u128 types and keep the full 128 bit product
+    // to avoid losing accuracy.
+    let unscaled_product = val as u128 * (multiplier.value as u128);
+    // The unscaled product has 32 fractional bits (from the multiplier)
+    // so rescale it by shifting away the low bits.
+    let product = unscaled_product >> 32;
+    // Check whether the value is too large.
+    assert!(product <= MAX_U64, EMULTIPLICATION);
+    product as u64
+}
+
+ + + +
+ + + +## Function `divide_u64` + +Divide a u64 integer by a fixed-point number, truncating any +fractional part of the quotient. This will abort if the divisor +is zero or if the quotient overflows. + + +
public fun divide_u64(val: u64, divisor: fixed_point32::FixedPoint32): u64
+
+ + + +
+Implementation + + +
public fun divide_u64(val: u64, divisor: FixedPoint32): u64 {
+    // Check for division by zero.
+    assert!(divisor.value != 0, EDIVISION_BY_ZERO);
+    // First convert to 128 bits and then shift left to
+    // add 32 fractional zero bits to the dividend.
+    let scaled_value = val as u128 << 32;
+    let quotient = scaled_value / (divisor.value as u128);
+    // Check whether the value is too large.
+    assert!(quotient <= MAX_U64, EDIVISION);
+    // the value may be too large, which will cause the cast to fail
+    // with an arithmetic error.
+    quotient as u64
+}
+
+ + + +
+ + + +## Function `create_from_rational` + +Create a fixed-point value from a rational number specified by its +numerator and denominator. Calling this function should be preferred +for using Self::create_from_raw_value which is also available. +This will abort if the denominator is zero. It will also +abort if the numerator is nonzero and the ratio is not in the range +2^-32 .. 2^32-1. When specifying decimal fractions, be careful about +rounding errors: if you round to display N digits after the decimal +point, you can use a denominator of 10^N to avoid numbers where the +very small imprecision in the binary representation could change the +rounding, e.g., 0.0125 will round down to 0.012 instead of up to 0.013. + + +
public fun create_from_rational(numerator: u64, denominator: u64): fixed_point32::FixedPoint32
+
+ + + +
+Implementation + + +
public fun create_from_rational(numerator: u64, denominator: u64): FixedPoint32 {
+    // If the denominator is zero, this will abort.
+    // Scale the numerator to have 64 fractional bits and the denominator
+    // to have 32 fractional bits, so that the quotient will have 32
+    // fractional bits.
+    let scaled_numerator = numerator as u128 << 64;
+    let scaled_denominator = denominator as u128 << 32;
+    assert!(scaled_denominator != 0, EDENOMINATOR);
+    let quotient = scaled_numerator / scaled_denominator;
+    assert!(quotient != 0 || numerator == 0, ERATIO_OUT_OF_RANGE);
+    // Return the quotient as a fixed-point number. We first need to check whether the cast
+    // can succeed.
+    assert!(quotient <= MAX_U64, ERATIO_OUT_OF_RANGE);
+    FixedPoint32 { value: quotient as u64 }
+}
+
+ + + +
+ + + +## Function `create_from_raw_value` + +Create a fixedpoint value from a raw value. + + +
public fun create_from_raw_value(value: u64): fixed_point32::FixedPoint32
+
+ + + +
+Implementation + + +
public fun create_from_raw_value(value: u64): FixedPoint32 {
+    FixedPoint32 { value }
+}
+
+ + + +
+ + + +## Function `get_raw_value` + +Accessor for the raw u64 value. Other less common operations, such as +adding or subtracting FixedPoint32 values, can be done using the raw +values directly. + + +
public fun get_raw_value(num: fixed_point32::FixedPoint32): u64
+
+ + + +
+Implementation + + +
public fun get_raw_value(num: FixedPoint32): u64 {
+    num.value
+}
+
+ + + +
+ + + +## Function `is_zero` + +Returns true if the ratio is zero. + + +
public fun is_zero(num: fixed_point32::FixedPoint32): bool
+
+ + + +
+Implementation + + +
public fun is_zero(num: FixedPoint32): bool {
+    num.value == 0
+}
+
+ + + +
diff --git a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md b/crates/sui-framework/docs/stardust/expiration_unlock_condition.md new file mode 100644 index 00000000000..22a4176b80a --- /dev/null +++ b/crates/sui-framework/docs/stardust/expiration_unlock_condition.md @@ -0,0 +1,129 @@ +--- +title: Module `0x107a::expiration_unlock_condition` +--- + + + +- [Struct `ExpirationUnlockCondition`](#0x107a_expiration_unlock_condition_ExpirationUnlockCondition) +- [Constants](#@Constants_0) +- [Function `unlock`](#0x107a_expiration_unlock_condition_unlock) +- [Function `can_be_unlocked_by`](#0x107a_expiration_unlock_condition_can_be_unlocked_by) + + +
use 0x2::tx_context;
+
+ + + + + +## Struct `ExpirationUnlockCondition` + +The Stardust expiration unlock condition. + + +
struct ExpirationUnlockCondition has drop, store
+
+ + + +
+Fields + + +
+
+owner: address +
+
+ The address who owns the output before the timestamp has passed. +
+
+return_address: address +
+
+ The address that is allowed to spend the locked funds after the timestamp has passed. +
+
+unix_time: u32 +
+
+ Before this unix time, Address Unlock Condition is allowed to unlock the output, after that only the address defined in Return Address. +
+
+ + +
+ + + +## Constants + + + + +The output can not be unlocked by the sender error. + + +
const EWrongSender: u64 = 0;
+
+ + + + + +## Function `unlock` + +Check the unlock condition. + + +
public fun unlock(condition: &expiration_unlock_condition::ExpirationUnlockCondition, ctx: &mut tx_context::TxContext)
+
+ + + +
+Implementation + + +
public fun unlock(condition: &ExpirationUnlockCondition, ctx: &mut TxContext) {
+    let unlock_address = condition.can_be_unlocked_by(ctx);
+    assert!(unlock_address == ctx.sender(), EWrongSender);
+}
+
+ + + +
+ + + +## Function `can_be_unlocked_by` + +Return the address that can unlock the related output. + + +
public fun can_be_unlocked_by(condition: &expiration_unlock_condition::ExpirationUnlockCondition, ctx: &tx_context::TxContext): address
+
+ + + +
+Implementation + + +
public fun can_be_unlocked_by(condition: &ExpirationUnlockCondition, ctx: &TxContext): address {
+    // Unix time in seconds.
+    let current_time = ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32);
+
+    if (condition.unix_time < current_time) {
+        condition.return_address
+    } else {
+        condition.owner
+    }
+}
+
+ + + +
diff --git a/crates/sui-framework/docs/stardust/irc27.md b/crates/sui-framework/docs/stardust/irc27.md new file mode 100644 index 00000000000..fa914df9b7b --- /dev/null +++ b/crates/sui-framework/docs/stardust/irc27.md @@ -0,0 +1,419 @@ +--- +title: Module `0x107a::irc27` +--- + + + +- [Struct `Irc27Metadata`](#0x107a_irc27_Irc27Metadata) +- [Function `create`](#0x107a_irc27_create) +- [Function `destroy`](#0x107a_irc27_destroy) +- [Function `version`](#0x107a_irc27_version) +- [Function `media_type`](#0x107a_irc27_media_type) +- [Function `uri`](#0x107a_irc27_uri) +- [Function `name`](#0x107a_irc27_name) +- [Function `collection_name`](#0x107a_irc27_collection_name) +- [Function `royalties`](#0x107a_irc27_royalties) +- [Function `issuer_name`](#0x107a_irc27_issuer_name) +- [Function `description`](#0x107a_irc27_description) +- [Function `attributes`](#0x107a_irc27_attributes) + + +
use 0x1::fixed_point32;
+use 0x1::option;
+use 0x1::string;
+use 0x2::table;
+use 0x2::url;
+use 0x2::vec_set;
+
+ + + + + +## Struct `Irc27Metadata` + +The IRC27 NFT metadata standard schema. + + +
struct Irc27Metadata has store
+
+ + + +
+Fields + + +
+
+version: string::String +
+
+ Version of the metadata standard. +
+
+media_type: string::String +
+
+ The media type (MIME) of the asset. + + ## Examples + - Image files: image/jpeg, image/png, image/gif, etc. + - Video files: video/x-msvideo (avi), video/mp4, video/mpeg, etc. + - Audio files: audio/mpeg, audio/wav, etc. + - 3D Assets: model/obj, model/u3d, etc. + - Documents: application/pdf, text/plain, etc. +
+
+uri: url::Url +
+
+ URL pointing to the NFT file location. +
+
+name: string::String +
+
+ The human-readable name of the native token. +
+
+collection_name: option::Option<string::String> +
+
+ The human-readable collection name of the native token. +
+
+royalties: table::Table<address, fixed_point32::FixedPoint32> +
+
+ Royalty payment addresses mapped to the payout percentage. +
+
+issuer_name: option::Option<string::String> +
+
+ The human-readable name of the native token creator. +
+
+description: option::Option<string::String> +
+
+ The human-readable description of the token. +
+
+attributes: vec_set::VecSet<string::String> +
+
+ Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). +
+
+ + +
+ + + +## Function `create` + +Create a new Irc27Metadata object. + + +
public fun create(version: string::String, media_type: string::String, uri: url::Url, name: string::String, collection_name: option::Option<string::String>, royalties: table::Table<address, fixed_point32::FixedPoint32>, issuer_name: option::Option<string::String>, description: option::Option<string::String>, attributes: vec_set::VecSet<string::String>): irc27::Irc27Metadata
+
+ + + +
+Implementation + + +
public fun create(
+    version: String,
+    media_type: String,
+    uri: Url,
+    name: String,
+    collection_name: Option<String>,
+    royalties: Table<address, FixedPoint32>,
+    issuer_name: Option<String>,
+    description: Option<String>,
+    attributes: VecSet<String>,
+): Irc27Metadata {
+    Irc27Metadata {
+        version,
+        media_type,
+        uri,
+        name,
+        collection_name,
+        royalties,
+        issuer_name,
+        description,
+        attributes
+    }
+}
+
+ + + +
+ + + +## Function `destroy` + +Permanently destroy a Irc27Metadata object. + + +
public fun destroy(irc27: irc27::Irc27Metadata)
+
+ + + +
+Implementation + + +
public fun destroy(irc27: Irc27Metadata) {
+    let Irc27Metadata {
+        version: _,
+        media_type: _,
+        uri: _,
+        name: _,
+        collection_name: _,
+        royalties: royalties,
+        issuer_name: _,
+        description: _,
+        attributes: _
+    } = irc27;
+
+    royalties.drop();
+}
+
+ + + +
+ + + +## Function `version` + +Get the metadata's version. + + +
public fun version(irc27: &irc27::Irc27Metadata): &string::String
+
+ + + +
+Implementation + + +
public fun version(irc27: &Irc27Metadata): &String {
+    &irc27.version
+}
+
+ + + +
+ + + +## Function `media_type` + +Get the metadata's media_type. + + +
public fun media_type(irc27: &irc27::Irc27Metadata): &string::String
+
+ + + +
+Implementation + + +
public fun media_type(irc27: &Irc27Metadata): &String {
+    &irc27.media_type
+}
+
+ + + +
+ + + +## Function `uri` + +Get the metadata's uri. + + +
public fun uri(irc27: &irc27::Irc27Metadata): &url::Url
+
+ + + +
+Implementation + + +
public fun uri(irc27: &Irc27Metadata): &Url {
+    &irc27.uri
+}
+
+ + + +
+ + + +## Function `name` + +Get the metadata's name. + + +
public fun name(irc27: &irc27::Irc27Metadata): &string::String
+
+ + + +
+Implementation + + +
public fun name(irc27: &Irc27Metadata): &String {
+    &irc27.name
+}
+
+ + + +
+ + + +## Function `collection_name` + +Get the metadata's collection_name. + + +
public fun collection_name(irc27: &irc27::Irc27Metadata): &option::Option<string::String>
+
+ + + +
+Implementation + + +
public fun collection_name(irc27: &Irc27Metadata): &Option<String> {
+    &irc27.collection_name
+}
+
+ + + +
+ + + +## Function `royalties` + +Get the metadata's royalties. + + +
public fun royalties(irc27: &irc27::Irc27Metadata): &table::Table<address, fixed_point32::FixedPoint32>
+
+ + + +
+Implementation + + +
public fun royalties(irc27: &Irc27Metadata): &Table<address, FixedPoint32> {
+    &irc27.royalties
+}
+
+ + + +
+ + + +## Function `issuer_name` + +Get the metadata's issuer_name. + + +
public fun issuer_name(irc27: &irc27::Irc27Metadata): &option::Option<string::String>
+
+ + + +
+Implementation + + +
public fun issuer_name(irc27: &Irc27Metadata): &Option<String> {
+    &irc27.issuer_name
+}
+
+ + + +
+ + + +## Function `description` + +Get the metadata's description. + + +
public fun description(irc27: &irc27::Irc27Metadata): &option::Option<string::String>
+
+ + + +
+Implementation + + +
public fun description(irc27: &Irc27Metadata): &Option<String> {
+    &irc27.description
+}
+
+ + + +
+ + + +## Function `attributes` + +Get the metadata's attributes. + + +
public fun attributes(irc27: &irc27::Irc27Metadata): &vec_set::VecSet<string::String>
+
+ + + +
+Implementation + + +
public fun attributes(irc27: &Irc27Metadata): &VecSet<String> {
+    &irc27.attributes
+}
+
+ + + +
diff --git a/crates/sui-framework/docs/stardust/nft.md b/crates/sui-framework/docs/stardust/nft.md new file mode 100644 index 00000000000..2dce04936b9 --- /dev/null +++ b/crates/sui-framework/docs/stardust/nft.md @@ -0,0 +1,281 @@ +--- +title: Module `0x107a::nft` +--- + + + +- [Resource `Nft`](#0x107a_nft_Nft) +- [Function `create`](#0x107a_nft_create) +- [Function `destroy`](#0x107a_nft_destroy) +- [Function `sender`](#0x107a_nft_sender) +- [Function `metadata`](#0x107a_nft_metadata) +- [Function `tag`](#0x107a_nft_tag) +- [Function `immutable_issuer`](#0x107a_nft_immutable_issuer) +- [Function `immutable_metadata`](#0x107a_nft_immutable_metadata) + + +
use 0x107a::irc27;
+use 0x1::option;
+use 0x2::object;
+use 0x2::tx_context;
+
+ + + + + +## Resource `Nft` + +The Stardust NFT representation. + + +
struct Nft has store, key
+
+ + + +
+Fields + + +
+
+id: object::UID +
+
+ +
+
+sender: option::Option<address> +
+
+ The sender features. +
+
+metadata: option::Option<vector<u8>> +
+
+ The metadata features. +
+
+tag: option::Option<vector<u8>> +
+
+ The tag features. +
+
+immutable_issuer: option::Option<address> +
+
+ The immutable issuer feature. +
+
+immutable_metadata: irc27::Irc27Metadata +
+
+ The immutable metadata feature. +
+
+ + +
+ + + +## Function `create` + +Create a new Nft object. + + +
public fun create(sender: option::Option<address>, metadata: option::Option<vector<u8>>, tag: option::Option<vector<u8>>, immutable_issuer: option::Option<address>, immutable_metadata: irc27::Irc27Metadata, ctx: &mut tx_context::TxContext): nft::Nft
+
+ + + +
+Implementation + + +
public fun create(
+    sender: Option<address>,
+    metadata: Option<vector<u8>>,
+    tag: Option<vector<u8>>,
+    immutable_issuer: Option<address>,
+    immutable_metadata: Irc27Metadata,
+    ctx: &mut TxContext,
+): Nft {
+    Nft {
+        id: object::new(ctx),
+        sender,
+        metadata,
+        tag,
+        immutable_issuer,
+        immutable_metadata,
+    }
+}
+
+ + + +
+ + + +## Function `destroy` + +Permanently destroy an Nft object. + + +
public fun destroy(output: nft::Nft)
+
+ + + +
+Implementation + + +
public fun destroy(output: Nft) {
+    let Nft {
+        id: id,
+        sender: _,
+        metadata: _,
+        tag: _,
+        immutable_issuer: _,
+        immutable_metadata: immutable_metadata,
+    } = output;
+
+    irc27::destroy(immutable_metadata);
+
+    object::delete(id);
+}
+
+ + + +
+ + + +## Function `sender` + +Get the NFT's sender. + + +
public fun sender(nft: &nft::Nft): &option::Option<address>
+
+ + + +
+Implementation + + +
public fun sender(nft: &Nft): &Option<address> {
+    &nft.sender
+}
+
+ + + +
+ + + +## Function `metadata` + +Get the NFT's metadata. + + +
public fun metadata(nft: &nft::Nft): &option::Option<vector<u8>>
+
+ + + +
+Implementation + + +
public fun metadata(nft: &Nft): &Option<vector<u8>> {
+    &nft.metadata
+}
+
+ + + +
+ + + +## Function `tag` + +Get the NFT's tag. + + +
public fun tag(nft: &nft::Nft): &option::Option<vector<u8>>
+
+ + + +
+Implementation + + +
public fun tag(nft: &Nft): &Option<vector<u8>> {
+    &nft.tag
+}
+
+ + + +
+ + + +## Function `immutable_issuer` + +Get the NFT's immutable_sender. + + +
public fun immutable_issuer(nft: &nft::Nft): &option::Option<address>
+
+ + + +
+Implementation + + +
public fun immutable_issuer(nft: &Nft): &Option<address> {
+    &nft.immutable_issuer
+}
+
+ + + +
+ + + +## Function `immutable_metadata` + +Get the NFT's immutable_metadata. + + +
public fun immutable_metadata(nft: &nft::Nft): &irc27::Irc27Metadata
+
+ + + +
+Implementation + + +
public fun immutable_metadata(nft: &Nft): &Irc27Metadata {
+    &nft.immutable_metadata
+}
+
+ + + +
diff --git a/crates/sui-framework/docs/stardust/nft_output.md b/crates/sui-framework/docs/stardust/nft_output.md new file mode 100644 index 00000000000..16159ea884e --- /dev/null +++ b/crates/sui-framework/docs/stardust/nft_output.md @@ -0,0 +1,172 @@ +--- +title: Module `0x107a::nft_output` +--- + + + +- [Resource `NftOutput`](#0x107a_nft_output_NftOutput) +- [Constants](#@Constants_0) +- [Function `extract_assets`](#0x107a_nft_output_extract_assets) +- [Function `load_nft`](#0x107a_nft_output_load_nft) + + +
use 0x107a::expiration_unlock_condition;
+use 0x107a::nft;
+use 0x107a::storage_deposit_return_unlock_condition;
+use 0x107a::timelock_unlock_condition;
+use 0x1::option;
+use 0x2::balance;
+use 0x2::dynamic_field;
+use 0x2::object;
+use 0x2::sui;
+use 0x2::tx_context;
+
+ + + + + +## Resource `NftOutput` + +The Stardust NFT output representation. + + +
struct NftOutput has key
+
+ + + +
+Fields + + +
+
+id: object::UID +
+
+ +
+
+iota: balance::Balance<sui::SUI> +
+
+ The amount of IOTA tokens held by the output. +
+
+storage_deposit_return: option::Option<storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition> +
+
+ +
+
+timelock: option::Option<timelock_unlock_condition::TimelockUnlockCondition> +
+
+ +
+
+expiration: option::Option<expiration_unlock_condition::ExpirationUnlockCondition> +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The NFT dynamic field name. + + +
const NFT_NAME: vector<u8> = [110, 102, 116];
+
+ + + + + +## Function `extract_assets` + +The function extracts assets from a legacy NFT output. + + +
public fun extract_assets(output: nft_output::NftOutput, ctx: &mut tx_context::TxContext): (balance::Balance<sui::SUI>, nft::Nft)
+
+ + + +
+Implementation + + +
public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance<SUI>, Nft) {
+    // Load the related Nft object.
+    let nft = load_nft(&mut output);
+
+    // Unpuck the output.
+    let NftOutput {
+        id: id,
+        iota: mut iota,
+        storage_deposit_return: mut storage_deposit_return,
+        timelock: mut timelock,
+        expiration: mut expiration
+    } = output;
+
+    // If the output has a timelock, then we need to check if the timelock has expired.
+    if (timelock.is_some()) {
+        timelock.extract().unlock(ctx);
+    };
+
+    // If the output has an expiration, then we need to check who can unlock the output.
+    if (expiration.is_some()) {
+        expiration.extract().unlock(ctx);
+    };
+
+    // If the output has an SDRUC, then we need to return the deposit.
+    if (storage_deposit_return.is_some()) {
+        storage_deposit_return.extract().unlock(&mut iota, ctx);
+    };
+
+    // Destroy the output.
+    object::delete(id);
+
+    return (iota, nft)
+}
+
+ + + +
+ + + +## Function `load_nft` + +Loads the related Nft object. + + +
fun load_nft(output: &mut nft_output::NftOutput): nft::Nft
+
+ + + +
+Implementation + + +
fun load_nft(output: &mut NftOutput): Nft {
+    dynamic_field::remove(&mut output.id, NFT_NAME)
+}
+
+ + + +
diff --git a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md b/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md new file mode 100644 index 00000000000..34cd0826b3a --- /dev/null +++ b/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md @@ -0,0 +1,132 @@ +--- +title: Module `0x107a::storage_deposit_return_unlock_condition` +--- + + + +- [Struct `StorageDepositReturnUnlockCondition`](#0x107a_storage_deposit_return_unlock_condition_StorageDepositReturnUnlockCondition) +- [Function `unlock`](#0x107a_storage_deposit_return_unlock_condition_unlock) +- [Function `return_amount`](#0x107a_storage_deposit_return_unlock_condition_return_amount) +- [Function `return_address`](#0x107a_storage_deposit_return_unlock_condition_return_address) + + +
use 0x2::balance;
+use 0x2::coin;
+use 0x2::sui;
+use 0x2::transfer;
+use 0x2::tx_context;
+
+ + + + + +## Struct `StorageDepositReturnUnlockCondition` + +The Stardust storage deposit return unlock condition. + + +
struct StorageDepositReturnUnlockCondition has drop, store
+
+ + + +
+Fields + + +
+
+return_address: address +
+
+ The address to which the consuming transaction should deposit the amount defined in Return Amount. +
+
+return_amount: u64 +
+
+ The amount of IOTA coins the consuming transaction should deposit to the address defined in Return Address. +
+
+ + +
+ + + +## Function `unlock` + +Check the unlock condition. + + +
public fun unlock(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition, funding: &mut balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext)
+
+ + + +
+Implementation + + +
public fun unlock(condition: &StorageDepositReturnUnlockCondition, funding: &mut Balance<SUI>, ctx: &mut TxContext) {
+    // Aborts if `funding` is not enough.
+    let return_balance = funding.split(condition.return_amount());
+    // Recipient will need to transfer the coin to a normal ed25519 address instead of legacy.
+    public_transfer(from_balance(return_balance, ctx), condition.return_address());
+}
+
+ + + +
+ + + +## Function `return_amount` + +Get the unlock condition's return_amount. + + +
public fun return_amount(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition): u64
+
+ + + +
+Implementation + + +
public fun return_amount(condition: &StorageDepositReturnUnlockCondition): u64 {
+    condition.return_amount
+}
+
+ + + +
+ + + +## Function `return_address` + +Get the unlock condition's return_address. + + +
public fun return_address(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition): address
+
+ + + +
+Implementation + + +
public fun return_address(condition: &StorageDepositReturnUnlockCondition): address {
+    condition.return_address
+}
+
+ + + +
diff --git a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md b/crates/sui-framework/docs/stardust/timelock_unlock_condition.md new file mode 100644 index 00000000000..fc0323cffa8 --- /dev/null +++ b/crates/sui-framework/docs/stardust/timelock_unlock_condition.md @@ -0,0 +1,109 @@ +--- +title: Module `0x107a::timelock_unlock_condition` +--- + + + +- [Struct `TimelockUnlockCondition`](#0x107a_timelock_unlock_condition_TimelockUnlockCondition) +- [Constants](#@Constants_0) +- [Function `unlock`](#0x107a_timelock_unlock_condition_unlock) +- [Function `is_timelocked`](#0x107a_timelock_unlock_condition_is_timelocked) + + +
use 0x2::tx_context;
+
+ + + + + +## Struct `TimelockUnlockCondition` + +The Stardust timelock unlock condition. + + +
struct TimelockUnlockCondition has drop, store
+
+ + + +
+Fields + + +
+
+unix_time: u32 +
+
+ The unix time (seconds since Unix epoch) starting from which the output can be consumed. +
+
+ + +
+ + + +## Constants + + + + +The timelock is not expired error. + + +
const ETimelockNotExpired: u64 = 0;
+
+ + + + + +## Function `unlock` + +Check the unlock condition. + + +
public fun unlock(condition: &timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext)
+
+ + + +
+Implementation + + +
public fun unlock(condition: &TimelockUnlockCondition, ctx: &TxContext) {
+    assert!(!is_timelocked(condition, ctx), ETimelockNotExpired);
+}
+
+ + + +
+ + + +## Function `is_timelocked` + +Check if the output is locked by the Timelock condition. + + +
public fun is_timelocked(condition: &timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext): bool
+
+ + + +
+Implementation + + +
public fun is_timelocked(condition: &TimelockUnlockCondition, ctx: &TxContext): bool {
+    condition.unix_time > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32)
+}
+
+ + + +
diff --git a/crates/sui-framework/packages/stardust/Move.toml b/crates/sui-framework/packages/stardust/Move.toml new file mode 100644 index 00000000000..be146b5d32c --- /dev/null +++ b/crates/sui-framework/packages/stardust/Move.toml @@ -0,0 +1,12 @@ +[package] +name = "Stardust" +version = "0.0.1" +published-at = "0xda5f" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } +Sui = { local = "../sui-framework" } + +[addresses] +stardust = "0x107a" diff --git a/crates/sui-framework/packages/stardust/sources/nft/irc27.move b/crates/sui-framework/packages/stardust/sources/nft/irc27.move new file mode 100644 index 00000000000..0055e72cf33 --- /dev/null +++ b/crates/sui-framework/packages/stardust/sources/nft/irc27.move @@ -0,0 +1,133 @@ +module stardust::irc27 { + + use std::fixed_point32::FixedPoint32; + use std::string::String; + + use sui::table::Table; + use sui::url::Url; + use sui::vec_set::VecSet; + + /// The IRC27 NFT metadata standard schema. + public struct Irc27Metadata has store { + /// Version of the metadata standard. + version: String, + + /// The media type (MIME) of the asset. + /// + /// ## Examples + /// - Image files: `image/jpeg`, `image/png`, `image/gif`, etc. + /// - Video files: `video/x-msvideo` (avi), `video/mp4`, `video/mpeg`, etc. + /// - Audio files: `audio/mpeg`, `audio/wav`, etc. + /// - 3D Assets: `model/obj`, `model/u3d`, etc. + /// - Documents: `application/pdf`, `text/plain`, etc. + media_type: String, + + /// URL pointing to the NFT file location. + uri: Url, + + /// The human-readable name of the native token. + name: String, + + /// The human-readable collection name of the native token. + collection_name: Option, + + /// Royalty payment addresses mapped to the payout percentage. + royalties: Table, + + /// The human-readable name of the native token creator. + issuer_name: Option, + + /// The human-readable description of the token. + description: Option, + + /// Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). + attributes: VecSet, + } + + /// Create a new `Irc27Metadata` object. + public fun create( + version: String, + media_type: String, + uri: Url, + name: String, + collection_name: Option, + royalties: Table, + issuer_name: Option, + description: Option, + attributes: VecSet, + ): Irc27Metadata { + Irc27Metadata { + version, + media_type, + uri, + name, + collection_name, + royalties, + issuer_name, + description, + attributes + } + } + + /// Permanently destroy a `Irc27Metadata` object. + public fun destroy(irc27: Irc27Metadata) { + let Irc27Metadata { + version: _, + media_type: _, + uri: _, + name: _, + collection_name: _, + royalties: royalties, + issuer_name: _, + description: _, + attributes: _ + } = irc27; + + royalties.drop(); + } + + /// Get the metadata's `version`. + public fun version(irc27: &Irc27Metadata): &String { + &irc27.version + } + + /// Get the metadata's `media_type`. + public fun media_type(irc27: &Irc27Metadata): &String { + &irc27.media_type + } + + /// Get the metadata's `uri`. + public fun uri(irc27: &Irc27Metadata): &Url { + &irc27.uri + } + + /// Get the metadata's `name`. + public fun name(irc27: &Irc27Metadata): &String { + &irc27.name + } + + /// Get the metadata's `collection_name`. + public fun collection_name(irc27: &Irc27Metadata): &Option { + &irc27.collection_name + } + + /// Get the metadata's `royalties`. + public fun royalties(irc27: &Irc27Metadata): &Table { + &irc27.royalties + } + + /// Get the metadata's `issuer_name`. + public fun issuer_name(irc27: &Irc27Metadata): &Option { + &irc27.issuer_name + } + + /// Get the metadata's `description`. + public fun description(irc27: &Irc27Metadata): &Option { + &irc27.description + } + + /// Get the metadata's `attributes`. + public fun attributes(irc27: &Irc27Metadata): &VecSet { + &irc27.attributes + } +} diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft.move b/crates/sui-framework/packages/stardust/sources/nft/nft.move new file mode 100644 index 00000000000..6108d82d3aa --- /dev/null +++ b/crates/sui-framework/packages/stardust/sources/nft/nft.move @@ -0,0 +1,83 @@ + +module stardust::nft { + + use stardust::irc27::{Self, Irc27Metadata}; + + /// The Stardust NFT representation. + public struct Nft has key, store { + // The Nft's ID is nested from Stardust + id: UID, + + /// The sender features. + sender: Option
, + /// The metadata features. + metadata: Option>, + /// The tag features. + tag: Option>, + + /// The immutable issuer feature. + immutable_issuer: Option
, + /// The immutable metadata feature. + immutable_metadata: Irc27Metadata, + } + + /// Create a new `Nft` object. + public fun create( + sender: Option
, + metadata: Option>, + tag: Option>, + immutable_issuer: Option
, + immutable_metadata: Irc27Metadata, + ctx: &mut TxContext, + ): Nft { + Nft { + id: object::new(ctx), + sender, + metadata, + tag, + immutable_issuer, + immutable_metadata, + } + } + + /// Permanently destroy an `Nft` object. + public fun destroy(output: Nft) { + let Nft { + id: id, + sender: _, + metadata: _, + tag: _, + immutable_issuer: _, + immutable_metadata: immutable_metadata, + } = output; + + irc27::destroy(immutable_metadata); + + object::delete(id); + } + + /// Get the NFT's `sender`. + public fun sender(nft: &Nft): &Option
{ + &nft.sender + } + + /// Get the NFT's `metadata`. + public fun metadata(nft: &Nft): &Option> { + &nft.metadata + } + + /// Get the NFT's `tag`. + public fun tag(nft: &Nft): &Option> { + &nft.tag + } + + /// Get the NFT's `immutable_sender`. + public fun immutable_issuer(nft: &Nft): &Option
{ + &nft.immutable_issuer + } + + /// Get the NFT's `immutable_metadata`. + public fun immutable_metadata(nft: &Nft): &Irc27Metadata { + &nft.immutable_metadata + } +} diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move new file mode 100644 index 00000000000..d3a40ba4c04 --- /dev/null +++ b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move @@ -0,0 +1,70 @@ +module stardust::nft_output { + + use sui::balance::Balance; + use sui::dynamic_field; + use sui::sui::SUI; + + use stardust::nft::Nft; + + use stardust::expiration_unlock_condition::ExpirationUnlockCondition; + use stardust::storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition; + use stardust::timelock_unlock_condition::TimelockUnlockCondition; + + /// The NFT dynamic field name. + const NFT_NAME: vector = b"nft"; + + /// The Stardust NFT output representation. + public struct NftOutput has key { + id: UID, + + /// The amount of IOTA tokens held by the output. + iota: Balance, + + // The storage deposit return unlock condition. + storage_deposit_return: Option, + // The timelock unlock condition + timelock: Option, + // The expiration unlock condition + expiration: Option, + } + + /// The function extracts assets from a legacy NFT output. + public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance, Nft) { + // Load the related Nft object. + let nft = load_nft(&mut output); + + // Unpuck the output. + let NftOutput { + id: id, + iota: mut iota, + storage_deposit_return: mut storage_deposit_return, + timelock: mut timelock, + expiration: mut expiration + } = output; + + // If the output has a timelock, then we need to check if the timelock has expired. + if (timelock.is_some()) { + timelock.extract().unlock(ctx); + }; + + // If the output has an expiration, then we need to check who can unlock the output. + if (expiration.is_some()) { + expiration.extract().unlock(ctx); + }; + + // If the output has an SDRUC, then we need to return the deposit. + if (storage_deposit_return.is_some()) { + storage_deposit_return.extract().unlock(&mut iota, ctx); + }; + + // Destroy the output. + object::delete(id); + + return (iota, nft) + } + + /// Loads the related `Nft` object. + fun load_nft(output: &mut NftOutput): Nft { + dynamic_field::remove(&mut output.id, NFT_NAME) + } +} diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move new file mode 100644 index 00000000000..ac4f3e0f584 --- /dev/null +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move @@ -0,0 +1,42 @@ +module stardust::expiration_unlock_condition { + + /// The output can not be unlocked by the sender error. + const EWrongSender: u64 = 0; + + /// The Stardust expiration unlock condition. + public struct ExpirationUnlockCondition has store, drop { + /// The address who owns the output before the timestamp has passed. + owner: address, + /// The address that is allowed to spend the locked funds after the timestamp has passed. + return_address: address, + /// Before this unix time, Address Unlock Condition is allowed to unlock the output, after that only the address defined in Return Address. + unix_time: u32, + } + + /// Check the unlock condition. + public fun unlock(condition: &ExpirationUnlockCondition, ctx: &mut TxContext) { + let unlock_address = condition.can_be_unlocked_by(ctx); + assert!(unlock_address == ctx.sender(), EWrongSender); + } + + /// Return the address that can unlock the related output. + public fun can_be_unlocked_by(condition: &ExpirationUnlockCondition, ctx: &TxContext): address { + // Unix time in seconds. + let current_time = ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32); + + if (condition.unix_time < current_time) { + condition.return_address + } else { + condition.owner + } + } + + #[test_only] + public fun create_for_testing(owner: address, return_address: address, unix_time: u32): ExpirationUnlockCondition { + ExpirationUnlockCondition { + owner, + return_address, + unix_time, + } + } +} diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move new file mode 100644 index 00000000000..2d280c12e2a --- /dev/null +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move @@ -0,0 +1,41 @@ +module stardust::storage_deposit_return_unlock_condition { + + use sui::balance::{Balance, split}; + use sui::coin::from_balance; + use sui::sui::SUI; + use sui::transfer::public_transfer; + + /// The Stardust storage deposit return unlock condition. + public struct StorageDepositReturnUnlockCondition has store, drop { + /// The address to which the consuming transaction should deposit the amount defined in Return Amount. + return_address: address, + /// The amount of IOTA coins the consuming transaction should deposit to the address defined in Return Address. + return_amount: u64, + } + + /// Check the unlock condition. + public fun unlock(condition: &StorageDepositReturnUnlockCondition, funding: &mut Balance, ctx: &mut TxContext) { + // Aborts if `funding` is not enough. + let return_balance = funding.split(condition.return_amount()); + // Recipient will need to transfer the coin to a normal ed25519 address instead of legacy. + public_transfer(from_balance(return_balance, ctx), condition.return_address()); + } + + /// Get the unlock condition's `return_amount`. + public fun return_amount(condition: &StorageDepositReturnUnlockCondition): u64 { + condition.return_amount + } + + /// Get the unlock condition's `return_address`. + public fun return_address(condition: &StorageDepositReturnUnlockCondition): address { + condition.return_address + } + + #[test_only] + public fun create_for_testing(return_address: address, return_amount: u64): StorageDepositReturnUnlockCondition { + StorageDepositReturnUnlockCondition { + return_address, + return_amount, + } + } +} diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move new file mode 100644 index 00000000000..bbba10a91e0 --- /dev/null +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move @@ -0,0 +1,26 @@ +module stardust::timelock_unlock_condition { + + /// The timelock is not expired error. + const ETimelockNotExpired: u64 = 0; + + /// The Stardust timelock unlock condition. + public struct TimelockUnlockCondition has store, drop { + /// The unix time (seconds since Unix epoch) starting from which the output can be consumed. + unix_time: u32 + } + + /// Check the unlock condition. + public fun unlock(condition: &TimelockUnlockCondition, ctx: &TxContext) { + assert!(!is_timelocked(condition, ctx), ETimelockNotExpired); + } + + /// Check if the output is locked by the `Timelock` condition. + public fun is_timelocked(condition: &TimelockUnlockCondition, ctx: &TxContext): bool { + condition.unix_time > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32) + } + + #[test_only] + public fun create_for_testing(unix_time: u32): TimelockUnlockCondition { + TimelockUnlockCondition { unix_time } + } +} diff --git a/crates/sui-framework/src/lib.rs b/crates/sui-framework/src/lib.rs index 6a686a04a19..4a5c16c4aed 100644 --- a/crates/sui-framework/src/lib.rs +++ b/crates/sui-framework/src/lib.rs @@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize}; use std::fmt::Formatter; use sui_types::base_types::ObjectRef; use sui_types::storage::ObjectStore; -use sui_types::DEEPBOOK_PACKAGE_ID; use sui_types::{ base_types::ObjectID, digests::TransactionDigest, @@ -19,6 +18,7 @@ use sui_types::{ object::{Object, OBJECT_START_VERSION}, MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, }; +use sui_types::{DEEPBOOK_PACKAGE_ID, STARDUST_PACKAGE_ID}; use tracing::error; /// Represents a system package in the framework, that's built from the source code inside @@ -123,6 +123,11 @@ impl BuiltInFramework { DEEPBOOK_PACKAGE_ID, "deepbook", [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] + ), + ( + STARDUST_PACKAGE_ID, + "stardust", + [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] ) ]) .iter() diff --git a/crates/sui-move-build/src/lib.rs b/crates/sui-move-build/src/lib.rs index 273db6887d7..54f8e321ddd 100644 --- a/crates/sui-move-build/src/lib.rs +++ b/crates/sui-move-build/src/lib.rs @@ -47,7 +47,8 @@ use sui_types::{ error::{SuiError, SuiResult}, is_system_package, move_package::{FnInfo, FnInfoKey, FnInfoMap, MovePackage}, - DEEPBOOK_ADDRESS, MOVE_STDLIB_ADDRESS, SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, + DEEPBOOK_ADDRESS, MOVE_STDLIB_ADDRESS, STARDUST_ADDRESS, SUI_FRAMEWORK_ADDRESS, + SUI_SYSTEM_ADDRESS, }; use sui_verifier::{default_verifier_config, verifier as sui_bytecode_verifier}; @@ -430,6 +431,12 @@ impl CompiledPackage { .filter(|m| *m.self_id().address() == MOVE_STDLIB_ADDRESS) } + /// Get bytecode modules from Stardust that are used by this package + pub fn get_stardust_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == STARDUST_ADDRESS) + } + /// Generate layout schemas for all types declared by this package, as well as /// all struct types passed into `entry` functions declared by modules in this package /// (either directly or by reference). diff --git a/crates/sui-replay/src/replay.rs b/crates/sui-replay/src/replay.rs index b80af00ec77..1892d6b6aae 100644 --- a/crates/sui-replay/src/replay.rs +++ b/crates/sui-replay/src/replay.rs @@ -67,7 +67,7 @@ use sui_types::{ ObjectReadResultKind, SenderSignedData, Transaction, TransactionData, TransactionDataAPI, TransactionKind, VerifiedCertificate, VerifiedTransaction, }, - DEEPBOOK_PACKAGE_ID, + DEEPBOOK_PACKAGE_ID, STARDUST_PACKAGE_ID, }; use tracing::{error, info, trace, warn}; @@ -1050,6 +1050,11 @@ impl LocalExec { if protocol_version < 5 { ids.retain(|id| *id != DEEPBOOK_PACKAGE_ID) } + + if protocol_version < 43 { + ids.retain(|id| *id != STARDUST_PACKAGE_ID) + } + ids } diff --git a/crates/sui-types/src/lib.rs b/crates/sui-types/src/lib.rs index 152438cacc7..54e78b402f7 100644 --- a/crates/sui-types/src/lib.rs +++ b/crates/sui-types/src/lib.rs @@ -105,6 +105,11 @@ pub const SUI_SYSTEM_PACKAGE_ID: ObjectID = ObjectID::from_address(SUI_SYSTEM_AD pub const DEEPBOOK_ADDRESS: AccountAddress = deepbook_addr(); pub const DEEPBOOK_PACKAGE_ID: ObjectID = ObjectID::from_address(DEEPBOOK_ADDRESS); +/// 0x107a-- account address where Stardust modules are stored +/// Same as the ObjectID +pub const STARDUST_ADDRESS: AccountAddress = stardust_addr(); +pub const STARDUST_PACKAGE_ID: ObjectID = ObjectID::from_address(STARDUST_ADDRESS); + /// 0xb-- account address where Bridge modules are stored /// Same as the ObjectID pub const BRIDGE_ADDRESS: AccountAddress = address_from_single_byte(11); @@ -148,6 +153,7 @@ pub fn is_system_package(addr: impl Into) -> bool { | SUI_FRAMEWORK_ADDRESS | SUI_SYSTEM_ADDRESS | DEEPBOOK_ADDRESS + | STARDUST_ADDRESS | BRIDGE_ADDRESS ) } @@ -166,6 +172,14 @@ const fn deepbook_addr() -> AccountAddress { AccountAddress::new(addr) } +/// return 0x0...107a +const fn stardust_addr() -> AccountAddress { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 2] = 0x10; + addr[AccountAddress::LENGTH - 1] = 0x7a; + AccountAddress::new(addr) +} + /// return 0x0...403 const fn deny_list_addr() -> AccountAddress { let mut addr = [0u8; AccountAddress::LENGTH]; @@ -233,6 +247,7 @@ pub fn resolve_address(addr: &str) -> Option { "std" => Some(MOVE_STDLIB_ADDRESS), "sui" => Some(SUI_FRAMEWORK_ADDRESS), "sui_system" => Some(SUI_SYSTEM_ADDRESS), + "stardust" => Some(STARDUST_ADDRESS), "bridge" => Some(BRIDGE_ADDRESS), _ => None, } diff --git a/crates/sui-types/src/sui_serde.rs b/crates/sui-types/src/sui_serde.rs index 714c28e198d..d9fabe64b7e 100644 --- a/crates/sui-types/src/sui_serde.rs +++ b/crates/sui-types/src/sui_serde.rs @@ -23,8 +23,8 @@ use serde_with::{Bytes, DeserializeAs, SerializeAs}; use sui_protocol_config::ProtocolVersion; use crate::{ - parse_sui_struct_tag, parse_sui_type_tag, DEEPBOOK_ADDRESS, SUI_CLOCK_ADDRESS, - SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_STATE_ADDRESS, + parse_sui_struct_tag, parse_sui_type_tag, DEEPBOOK_ADDRESS, STARDUST_ADDRESS, + SUI_CLOCK_ADDRESS, SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_STATE_ADDRESS, }; #[inline] @@ -165,11 +165,12 @@ impl SerializeAs for SuiStructTag { } } -const SUI_ADDRESSES: [AccountAddress; 7] = [ +const SUI_ADDRESSES: [AccountAddress; 8] = [ AccountAddress::ZERO, AccountAddress::ONE, SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, + STARDUST_ADDRESS, DEEPBOOK_ADDRESS, SUI_SYSTEM_STATE_ADDRESS, SUI_CLOCK_ADDRESS, From 5a126d8081a8d8095cb8a71ca6fd0b2718a8b0d5 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 19 Apr 2024 17:11:12 +0300 Subject: [PATCH 2/6] fix: added missed Move.lock file, added license, corrected Stardust package id --- .gitignore | 1 + .../sui-framework/packages/stardust/Move.lock | 27 +++++++++++++++++++ .../sui-framework/packages/stardust/Move.toml | 2 +- .../packages/stardust/sources/nft/irc27.move | 3 +++ .../packages/stardust/sources/nft/nft.move | 2 ++ .../stardust/sources/nft/nft_output.move | 3 +++ .../expiration_unlock_condition.move | 3 +++ ...orage_deposit_return_unlock_condition.move | 3 +++ .../timelock_unlock_condition.move | 3 +++ 9 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 crates/sui-framework/packages/stardust/Move.lock diff --git a/.gitignore b/.gitignore index 951816818cb..ba990eebd53 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ Move.lock !crates/sui-framework/packages/sui-framework/Move.lock !crates/sui-framework/packages/sui-system/Move.lock !crates/sui-framework/packages/deepbook/Move.lock +!crates/sui-framework/packages/stardust/Move.lock .trace .coverage_map.mvcov diff --git a/crates/sui-framework/packages/stardust/Move.lock b/crates/sui-framework/packages/stardust/Move.lock new file mode 100644 index 00000000000..8ec502aab8a --- /dev/null +++ b/crates/sui-framework/packages/stardust/Move.lock @@ -0,0 +1,27 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 1 +manifest_digest = "6C1F0F55CC88971254EA38AAC647E0C39D902AAF2D67AC59A332B50B8EDDE68E" +deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" +dependencies = [ + { name = "MoveStdlib" }, + { name = "Sui" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../move-stdlib" } + +[[move.package]] +name = "Sui" +source = { local = "../sui-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "sui" diff --git a/crates/sui-framework/packages/stardust/Move.toml b/crates/sui-framework/packages/stardust/Move.toml index be146b5d32c..1edd71c2948 100644 --- a/crates/sui-framework/packages/stardust/Move.toml +++ b/crates/sui-framework/packages/stardust/Move.toml @@ -1,7 +1,7 @@ [package] name = "Stardust" version = "0.0.1" -published-at = "0xda5f" +published-at = "0x107a" edition = "2024.beta" [dependencies] diff --git a/crates/sui-framework/packages/stardust/sources/nft/irc27.move b/crates/sui-framework/packages/stardust/sources/nft/irc27.move index 0055e72cf33..e60a1027c5e 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/irc27.move +++ b/crates/sui-framework/packages/stardust/sources/nft/irc27.move @@ -1,3 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + module stardust::irc27 { use std::fixed_point32::FixedPoint32; diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft.move b/crates/sui-framework/packages/stardust/sources/nft/nft.move index 6108d82d3aa..f41d97691d3 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/nft.move +++ b/crates/sui-framework/packages/stardust/sources/nft/nft.move @@ -1,3 +1,5 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 module stardust::nft { diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move index d3a40ba4c04..02f6c61ce59 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move +++ b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move @@ -1,3 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + module stardust::nft_output { use sui::balance::Balance; diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move index ac4f3e0f584..c4b8d16ac30 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move @@ -1,3 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + module stardust::expiration_unlock_condition { /// The output can not be unlocked by the sender error. diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move index 2d280c12e2a..cb15748eddc 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move @@ -1,3 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + module stardust::storage_deposit_return_unlock_condition { use sui::balance::{Balance, split}; diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move index bbba10a91e0..f4850e7cda6 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move @@ -1,3 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + module stardust::timelock_unlock_condition { /// The timelock is not expired error. From 9f519fee32de3378ad9a53af2529ab359dfe9ff2 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 19 Apr 2024 19:22:06 +0300 Subject: [PATCH 3/6] feat: added nft assets extraction test --- .../stardust/expiration_unlock_condition.md | 13 +- crates/sui-framework/docs/stardust/nft.md | 2 +- .../sui-framework/docs/stardust/nft_output.md | 4 + ...storage_deposit_return_unlock_condition.md | 12 +- .../stardust/timelock_unlock_condition.md | 12 +- .../packages/stardust/sources/nft/nft.move | 2 +- .../stardust/sources/nft/nft_output.move | 26 ++++ .../expiration_unlock_condition.move | 11 +- ...orage_deposit_return_unlock_condition.move | 10 +- .../timelock_unlock_condition.move | 10 +- .../packages/stardust/tests/nft_tests.move | 114 ++++++++++++++++++ 11 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 crates/sui-framework/packages/stardust/tests/nft_tests.move diff --git a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md b/crates/sui-framework/docs/stardust/expiration_unlock_condition.md index 22a4176b80a..07f595ce2fc 100644 --- a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md +++ b/crates/sui-framework/docs/stardust/expiration_unlock_condition.md @@ -22,7 +22,7 @@ title: Module `0x107a::expiration_unlock_condition` The Stardust expiration unlock condition. -
struct ExpirationUnlockCondition has drop, store
+
struct ExpirationUnlockCondition has store
 
@@ -77,7 +77,7 @@ The output can not be unlocked by the sender error. Check the unlock condition. -
public fun unlock(condition: &expiration_unlock_condition::ExpirationUnlockCondition, ctx: &mut tx_context::TxContext)
+
public fun unlock(condition: expiration_unlock_condition::ExpirationUnlockCondition, ctx: &mut tx_context::TxContext)
 
@@ -86,9 +86,16 @@ Check the unlock condition. Implementation -
public fun unlock(condition: &ExpirationUnlockCondition, ctx: &mut TxContext) {
+
public fun unlock(condition: ExpirationUnlockCondition, ctx: &mut TxContext) {
     let unlock_address = condition.can_be_unlocked_by(ctx);
+
     assert!(unlock_address == ctx.sender(), EWrongSender);
+
+    let ExpirationUnlockCondition {
+        owner: _,
+        return_address: _,
+        unix_time: _,
+    } = condition;
 }
 
diff --git a/crates/sui-framework/docs/stardust/nft.md b/crates/sui-framework/docs/stardust/nft.md index 2dce04936b9..63043566461 100644 --- a/crates/sui-framework/docs/stardust/nft.md +++ b/crates/sui-framework/docs/stardust/nft.md @@ -43,7 +43,7 @@ The Stardust NFT representation. id: object::UID
- + The Nft's ID is nested from Stardust for the migrated NFTs.
sender: option::Option<address> diff --git a/crates/sui-framework/docs/stardust/nft_output.md b/crates/sui-framework/docs/stardust/nft_output.md index 16159ea884e..cc1e39a6e3a 100644 --- a/crates/sui-framework/docs/stardust/nft_output.md +++ b/crates/sui-framework/docs/stardust/nft_output.md @@ -136,6 +136,10 @@ The function extracts assets from a legacy NFT output. }; // Destroy the output. + option::destroy_none(timelock); + option::destroy_none(expiration); + option::destroy_none(storage_deposit_return); + object::delete(id); return (iota, nft) diff --git a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md b/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md index 34cd0826b3a..2299dd4afd6 100644 --- a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md +++ b/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md @@ -26,7 +26,7 @@ title: Module `0x107a::storage_deposit_return_unlock_condition` The Stardust storage deposit return unlock condition. -
struct StorageDepositReturnUnlockCondition has drop, store
+
struct StorageDepositReturnUnlockCondition has store
 
@@ -60,7 +60,7 @@ The Stardust storage deposit return unlock condition. Check the unlock condition. -
public fun unlock(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition, funding: &mut balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext)
+
public fun unlock(condition: storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition, funding: &mut balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext)
 
@@ -69,11 +69,17 @@ Check the unlock condition. Implementation -
public fun unlock(condition: &StorageDepositReturnUnlockCondition, funding: &mut Balance<SUI>, ctx: &mut TxContext) {
+
public fun unlock(condition: StorageDepositReturnUnlockCondition, funding: &mut Balance<SUI>, ctx: &mut TxContext) {
     // Aborts if `funding` is not enough.
     let return_balance = funding.split(condition.return_amount());
+
     // Recipient will need to transfer the coin to a normal ed25519 address instead of legacy.
     public_transfer(from_balance(return_balance, ctx), condition.return_address());
+
+    let StorageDepositReturnUnlockCondition {
+        return_address: _,
+        return_amount: _,
+    } = condition;
 }
 
diff --git a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md b/crates/sui-framework/docs/stardust/timelock_unlock_condition.md index fc0323cffa8..3eed4a11c18 100644 --- a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md +++ b/crates/sui-framework/docs/stardust/timelock_unlock_condition.md @@ -22,7 +22,7 @@ title: Module `0x107a::timelock_unlock_condition` The Stardust timelock unlock condition. -
struct TimelockUnlockCondition has drop, store
+
struct TimelockUnlockCondition has store
 
@@ -65,7 +65,7 @@ The timelock is not expired error. Check the unlock condition. -
public fun unlock(condition: &timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext)
+
public fun unlock(condition: timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext)
 
@@ -74,8 +74,12 @@ Check the unlock condition. Implementation -
public fun unlock(condition: &TimelockUnlockCondition, ctx: &TxContext) {
-    assert!(!is_timelocked(condition, ctx), ETimelockNotExpired);
+
public fun unlock(condition: TimelockUnlockCondition, ctx: &TxContext) {
+    assert!(!is_timelocked(&condition, ctx), ETimelockNotExpired);
+
+    let TimelockUnlockCondition {
+        unix_time: _,
+    } = condition;
 }
 
diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft.move b/crates/sui-framework/packages/stardust/sources/nft/nft.move index f41d97691d3..02a09be161a 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/nft.move +++ b/crates/sui-framework/packages/stardust/sources/nft/nft.move @@ -7,7 +7,7 @@ module stardust::nft { /// The Stardust NFT representation. public struct Nft has key, store { - // The Nft's ID is nested from Stardust + /// The Nft's ID is nested from Stardust for the migrated NFTs. id: UID, /// The sender features. diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move index 02f6c61ce59..e822234c086 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move +++ b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move @@ -61,6 +61,10 @@ module stardust::nft_output { }; // Destroy the output. + option::destroy_none(timelock); + option::destroy_none(expiration); + option::destroy_none(storage_deposit_return); + object::delete(id); return (iota, nft) @@ -70,4 +74,26 @@ module stardust::nft_output { fun load_nft(output: &mut NftOutput): Nft { dynamic_field::remove(&mut output.id, NFT_NAME) } + + #[test_only] + public fun attach_nft(output: &mut NftOutput, nft: Nft) { + dynamic_field::add(&mut output.id, NFT_NAME, nft) + } + + #[test_only] + public fun create_for_testing( + iota: Balance, + storage_deposit_return: Option, + timelock: Option, + expiration: Option, + ctx: &mut TxContext, + ): NftOutput { + NftOutput { + id: object::new(ctx), + iota, + storage_deposit_return, + timelock, + expiration, + } + } } diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move index c4b8d16ac30..fe0f63edbed 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move @@ -7,7 +7,7 @@ module stardust::expiration_unlock_condition { const EWrongSender: u64 = 0; /// The Stardust expiration unlock condition. - public struct ExpirationUnlockCondition has store, drop { + public struct ExpirationUnlockCondition has store { /// The address who owns the output before the timestamp has passed. owner: address, /// The address that is allowed to spend the locked funds after the timestamp has passed. @@ -17,9 +17,16 @@ module stardust::expiration_unlock_condition { } /// Check the unlock condition. - public fun unlock(condition: &ExpirationUnlockCondition, ctx: &mut TxContext) { + public fun unlock(condition: ExpirationUnlockCondition, ctx: &mut TxContext) { let unlock_address = condition.can_be_unlocked_by(ctx); + assert!(unlock_address == ctx.sender(), EWrongSender); + + let ExpirationUnlockCondition { + owner: _, + return_address: _, + unix_time: _, + } = condition; } /// Return the address that can unlock the related output. diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move index cb15748eddc..99be18ef998 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move @@ -9,7 +9,7 @@ module stardust::storage_deposit_return_unlock_condition { use sui::transfer::public_transfer; /// The Stardust storage deposit return unlock condition. - public struct StorageDepositReturnUnlockCondition has store, drop { + public struct StorageDepositReturnUnlockCondition has store { /// The address to which the consuming transaction should deposit the amount defined in Return Amount. return_address: address, /// The amount of IOTA coins the consuming transaction should deposit to the address defined in Return Address. @@ -17,11 +17,17 @@ module stardust::storage_deposit_return_unlock_condition { } /// Check the unlock condition. - public fun unlock(condition: &StorageDepositReturnUnlockCondition, funding: &mut Balance, ctx: &mut TxContext) { + public fun unlock(condition: StorageDepositReturnUnlockCondition, funding: &mut Balance, ctx: &mut TxContext) { // Aborts if `funding` is not enough. let return_balance = funding.split(condition.return_amount()); + // Recipient will need to transfer the coin to a normal ed25519 address instead of legacy. public_transfer(from_balance(return_balance, ctx), condition.return_address()); + + let StorageDepositReturnUnlockCondition { + return_address: _, + return_amount: _, + } = condition; } /// Get the unlock condition's `return_amount`. diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move index f4850e7cda6..8a6aaab0489 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move @@ -7,14 +7,18 @@ module stardust::timelock_unlock_condition { const ETimelockNotExpired: u64 = 0; /// The Stardust timelock unlock condition. - public struct TimelockUnlockCondition has store, drop { + public struct TimelockUnlockCondition has store { /// The unix time (seconds since Unix epoch) starting from which the output can be consumed. unix_time: u32 } /// Check the unlock condition. - public fun unlock(condition: &TimelockUnlockCondition, ctx: &TxContext) { - assert!(!is_timelocked(condition, ctx), ETimelockNotExpired); + public fun unlock(condition: TimelockUnlockCondition, ctx: &TxContext) { + assert!(!is_timelocked(&condition, ctx), ETimelockNotExpired); + + let TimelockUnlockCondition { + unix_time: _, + } = condition; } /// Check if the output is locked by the `Timelock` condition. diff --git a/crates/sui-framework/packages/stardust/tests/nft_tests.move b/crates/sui-framework/packages/stardust/tests/nft_tests.move new file mode 100644 index 00000000000..e73ae06e5c0 --- /dev/null +++ b/crates/sui-framework/packages/stardust/tests/nft_tests.move @@ -0,0 +1,114 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module stardust::nft_tests { + + use std::ascii; + use std::fixed_point32; + use std::string; + + use sui::balance; + use sui::coin::{Self, Coin}; + use sui::sui::SUI; + use sui::table; + use sui::test_scenario; + use sui::url; + use sui::vec_set; + + use stardust::irc27; + use stardust::nft_output; + use stardust::nft; + + use stardust::expiration_unlock_condition; + use stardust::storage_deposit_return_unlock_condition; + use stardust::timelock_unlock_condition; + + // Demonstration on how to claim the assets from an NFT output with all unlock conditions inside one PTB. + #[test] + fun nft_assets_extraction() { + // Set up a test enviroment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Create an NftOutput object. + let mut nft_output = nft_output::create_for_testing( + balance::create_for_testing(10000), + option::some(storage_deposit_return_unlock_condition::create_for_testing(@0xB, 1000)), + option::some(timelock_unlock_condition::create_for_testing(5)), + option::some(expiration_unlock_condition::create_for_testing(sender, @0xB, 20)), + scenario.ctx(), + ); + + // Create an Nft object. + let mut royalties = table::new(scenario.ctx()); + royalties.add(sender, fixed_point32::create_from_rational(1, 2)); + + let mut attributes = vec_set::empty(); + attributes.insert(string::utf8(b"attribute")); + + let nft = nft::create( + option::some(sender), + option::some(b"metadata"), + option::some(b"tag"), + option::some(sender), + irc27::create( + string::utf8(b"0.0.1"), + string::utf8(b"image/png"), + url::new_unsafe(ascii::string(b"www.best-nft.com/nft.png")), + string::utf8(b"nft"), + option::some(string::utf8(b"collection")), + royalties, + option::some(string::utf8(b"issuer")), + option::some(string::utf8(b"description")), + attributes, + ), + scenario.ctx(), + ); + + // Add the Nft as a dynamic field to the output. + nft_output.attach_nft(nft); + + // Increment epoch timestamp. + scenario.ctx().increment_epoch_timestamp(10000); + + // Extract assets. + let (iota, nft) = nft_output.extract_assets(scenario.ctx()); + + // Check the extracted IOTA balance. + assert!(iota.value() == 9000, 0); + + // Check the extracted NFT. + assert!(nft.sender().contains(&sender), 1); + assert!(nft.metadata().contains(&b"metadata"), 2); + assert!(nft.tag().contains(&b"tag"), 3); + assert!(nft.immutable_issuer().contains(&sender), 4); + + assert!(nft.immutable_metadata().version() == string::utf8(b"0.0.1"), 5); + assert!(nft.immutable_metadata().media_type() == string::utf8(b"image/png"), 6); + assert!(nft.immutable_metadata().uri() == url::new_unsafe(ascii::string(b"www.best-nft.com/nft.png")), 7); + assert!(nft.immutable_metadata().name() == string::utf8(b"nft"), 8); + assert!(nft.immutable_metadata().collection_name().contains(&string::utf8(b"collection")), 9); + assert!(nft.immutable_metadata().royalties().length() == 1, 10); + assert!(nft.immutable_metadata().royalties()[sender] == fixed_point32::create_from_rational(1, 2), 11); + assert!(nft.immutable_metadata().issuer_name().contains(&string::utf8(b"issuer")), 12); + assert!(nft.immutable_metadata().description().contains(&string::utf8(b"description")), 13); + assert!(nft.immutable_metadata().attributes().size() == 1, 14); + assert!(nft.immutable_metadata().attributes().contains(&string::utf8(b"attribute")), 15); + + // Check the storage deposit return. + scenario.next_tx(sender); + + let returned_storage_deposit = scenario.take_from_address>(@0xB); + + assert!(returned_storage_deposit.value() == 1000, 16); + + test_scenario::return_to_address(@0xB, returned_storage_deposit); + + // Transfer the extracted assets. + transfer::public_transfer(coin::from_balance(iota, scenario.ctx()), @0xC); + transfer::public_transfer(nft, @0xC); + + // Cleanup. + scenario.end(); + } +} From db1219e3ad195d05684c35d0bd6541f72c032496 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Mon, 22 Apr 2024 13:19:21 +0300 Subject: [PATCH 4/6] feat: removed the nft part --- .../docs/move-stdlib/fixed_point32.md | 318 ------------- crates/sui-framework/docs/stardust/irc27.md | 419 ------------------ crates/sui-framework/docs/stardust/nft.md | 281 ------------ .../sui-framework/docs/stardust/nft_output.md | 176 -------- .../packages/stardust/sources/nft/irc27.move | 136 ------ .../packages/stardust/sources/nft/nft.move | 85 ---- .../stardust/sources/nft/nft_output.move | 99 ----- .../packages/stardust/tests/nft_tests.move | 114 ----- 8 files changed, 1628 deletions(-) delete mode 100644 crates/sui-framework/docs/move-stdlib/fixed_point32.md delete mode 100644 crates/sui-framework/docs/stardust/irc27.md delete mode 100644 crates/sui-framework/docs/stardust/nft.md delete mode 100644 crates/sui-framework/docs/stardust/nft_output.md delete mode 100644 crates/sui-framework/packages/stardust/sources/nft/irc27.move delete mode 100644 crates/sui-framework/packages/stardust/sources/nft/nft.move delete mode 100644 crates/sui-framework/packages/stardust/sources/nft/nft_output.move delete mode 100644 crates/sui-framework/packages/stardust/tests/nft_tests.move diff --git a/crates/sui-framework/docs/move-stdlib/fixed_point32.md b/crates/sui-framework/docs/move-stdlib/fixed_point32.md deleted file mode 100644 index fabffdbc562..00000000000 --- a/crates/sui-framework/docs/move-stdlib/fixed_point32.md +++ /dev/null @@ -1,318 +0,0 @@ ---- -title: Module `0x1::fixed_point32` ---- - -Defines a fixed-point numeric type with a 32-bit integer part and -a 32-bit fractional part. - - -- [Struct `FixedPoint32`](#0x1_fixed_point32_FixedPoint32) -- [Constants](#@Constants_0) -- [Function `multiply_u64`](#0x1_fixed_point32_multiply_u64) -- [Function `divide_u64`](#0x1_fixed_point32_divide_u64) -- [Function `create_from_rational`](#0x1_fixed_point32_create_from_rational) -- [Function `create_from_raw_value`](#0x1_fixed_point32_create_from_raw_value) -- [Function `get_raw_value`](#0x1_fixed_point32_get_raw_value) -- [Function `is_zero`](#0x1_fixed_point32_is_zero) - - -
- - - - - -## Struct `FixedPoint32` - -Define a fixed-point numeric type with 32 fractional bits. -This is just a u64 integer but it is wrapped in a struct to -make a unique type. This is a binary representation, so decimal -values may not be exactly representable, but it provides more -than 9 decimal digits of precision both before and after the -decimal point (18 digits total). For comparison, double precision -floating-point has less than 16 decimal digits of precision, so -be careful about using floating-point to convert these values to -decimal. - - -
struct FixedPoint32 has copy, drop, store
-
- - - -
-Fields - - -
-
-value: u64 -
-
- -
-
- - -
- - - -## Constants - - - - -The denominator provided was zero - - -
const EDENOMINATOR: u64 = 65537;
-
- - - - - -The quotient value would be too large to be held in a u64 - - -
const EDIVISION: u64 = 131074;
-
- - - - - -A division by zero was encountered - - -
const EDIVISION_BY_ZERO: u64 = 65540;
-
- - - - - -The multiplied value would be too large to be held in a u64 - - -
const EMULTIPLICATION: u64 = 131075;
-
- - - - - -The computed ratio when converting to a FixedPoint32 would be unrepresentable - - -
const ERATIO_OUT_OF_RANGE: u64 = 131077;
-
- - - - - -> TODO: This is a basic constant and should be provided somewhere centrally in the framework. - - -
const MAX_U64: u128 = 18446744073709551615;
-
- - - - - -## Function `multiply_u64` - -Multiply a u64 integer by a fixed-point number, truncating any -fractional part of the product. This will abort if the product -overflows. - - -
public fun multiply_u64(val: u64, multiplier: fixed_point32::FixedPoint32): u64
-
- - - -
-Implementation - - -
public fun multiply_u64(val: u64, multiplier: FixedPoint32): u64 {
-    // The product of two 64 bit values has 128 bits, so perform the
-    // multiplication with u128 types and keep the full 128 bit product
-    // to avoid losing accuracy.
-    let unscaled_product = val as u128 * (multiplier.value as u128);
-    // The unscaled product has 32 fractional bits (from the multiplier)
-    // so rescale it by shifting away the low bits.
-    let product = unscaled_product >> 32;
-    // Check whether the value is too large.
-    assert!(product <= MAX_U64, EMULTIPLICATION);
-    product as u64
-}
-
- - - -
- - - -## Function `divide_u64` - -Divide a u64 integer by a fixed-point number, truncating any -fractional part of the quotient. This will abort if the divisor -is zero or if the quotient overflows. - - -
public fun divide_u64(val: u64, divisor: fixed_point32::FixedPoint32): u64
-
- - - -
-Implementation - - -
public fun divide_u64(val: u64, divisor: FixedPoint32): u64 {
-    // Check for division by zero.
-    assert!(divisor.value != 0, EDIVISION_BY_ZERO);
-    // First convert to 128 bits and then shift left to
-    // add 32 fractional zero bits to the dividend.
-    let scaled_value = val as u128 << 32;
-    let quotient = scaled_value / (divisor.value as u128);
-    // Check whether the value is too large.
-    assert!(quotient <= MAX_U64, EDIVISION);
-    // the value may be too large, which will cause the cast to fail
-    // with an arithmetic error.
-    quotient as u64
-}
-
- - - -
- - - -## Function `create_from_rational` - -Create a fixed-point value from a rational number specified by its -numerator and denominator. Calling this function should be preferred -for using Self::create_from_raw_value which is also available. -This will abort if the denominator is zero. It will also -abort if the numerator is nonzero and the ratio is not in the range -2^-32 .. 2^32-1. When specifying decimal fractions, be careful about -rounding errors: if you round to display N digits after the decimal -point, you can use a denominator of 10^N to avoid numbers where the -very small imprecision in the binary representation could change the -rounding, e.g., 0.0125 will round down to 0.012 instead of up to 0.013. - - -
public fun create_from_rational(numerator: u64, denominator: u64): fixed_point32::FixedPoint32
-
- - - -
-Implementation - - -
public fun create_from_rational(numerator: u64, denominator: u64): FixedPoint32 {
-    // If the denominator is zero, this will abort.
-    // Scale the numerator to have 64 fractional bits and the denominator
-    // to have 32 fractional bits, so that the quotient will have 32
-    // fractional bits.
-    let scaled_numerator = numerator as u128 << 64;
-    let scaled_denominator = denominator as u128 << 32;
-    assert!(scaled_denominator != 0, EDENOMINATOR);
-    let quotient = scaled_numerator / scaled_denominator;
-    assert!(quotient != 0 || numerator == 0, ERATIO_OUT_OF_RANGE);
-    // Return the quotient as a fixed-point number. We first need to check whether the cast
-    // can succeed.
-    assert!(quotient <= MAX_U64, ERATIO_OUT_OF_RANGE);
-    FixedPoint32 { value: quotient as u64 }
-}
-
- - - -
- - - -## Function `create_from_raw_value` - -Create a fixedpoint value from a raw value. - - -
public fun create_from_raw_value(value: u64): fixed_point32::FixedPoint32
-
- - - -
-Implementation - - -
public fun create_from_raw_value(value: u64): FixedPoint32 {
-    FixedPoint32 { value }
-}
-
- - - -
- - - -## Function `get_raw_value` - -Accessor for the raw u64 value. Other less common operations, such as -adding or subtracting FixedPoint32 values, can be done using the raw -values directly. - - -
public fun get_raw_value(num: fixed_point32::FixedPoint32): u64
-
- - - -
-Implementation - - -
public fun get_raw_value(num: FixedPoint32): u64 {
-    num.value
-}
-
- - - -
- - - -## Function `is_zero` - -Returns true if the ratio is zero. - - -
public fun is_zero(num: fixed_point32::FixedPoint32): bool
-
- - - -
-Implementation - - -
public fun is_zero(num: FixedPoint32): bool {
-    num.value == 0
-}
-
- - - -
diff --git a/crates/sui-framework/docs/stardust/irc27.md b/crates/sui-framework/docs/stardust/irc27.md deleted file mode 100644 index fa914df9b7b..00000000000 --- a/crates/sui-framework/docs/stardust/irc27.md +++ /dev/null @@ -1,419 +0,0 @@ ---- -title: Module `0x107a::irc27` ---- - - - -- [Struct `Irc27Metadata`](#0x107a_irc27_Irc27Metadata) -- [Function `create`](#0x107a_irc27_create) -- [Function `destroy`](#0x107a_irc27_destroy) -- [Function `version`](#0x107a_irc27_version) -- [Function `media_type`](#0x107a_irc27_media_type) -- [Function `uri`](#0x107a_irc27_uri) -- [Function `name`](#0x107a_irc27_name) -- [Function `collection_name`](#0x107a_irc27_collection_name) -- [Function `royalties`](#0x107a_irc27_royalties) -- [Function `issuer_name`](#0x107a_irc27_issuer_name) -- [Function `description`](#0x107a_irc27_description) -- [Function `attributes`](#0x107a_irc27_attributes) - - -
use 0x1::fixed_point32;
-use 0x1::option;
-use 0x1::string;
-use 0x2::table;
-use 0x2::url;
-use 0x2::vec_set;
-
- - - - - -## Struct `Irc27Metadata` - -The IRC27 NFT metadata standard schema. - - -
struct Irc27Metadata has store
-
- - - -
-Fields - - -
-
-version: string::String -
-
- Version of the metadata standard. -
-
-media_type: string::String -
-
- The media type (MIME) of the asset. - - ## Examples - - Image files: image/jpeg, image/png, image/gif, etc. - - Video files: video/x-msvideo (avi), video/mp4, video/mpeg, etc. - - Audio files: audio/mpeg, audio/wav, etc. - - 3D Assets: model/obj, model/u3d, etc. - - Documents: application/pdf, text/plain, etc. -
-
-uri: url::Url -
-
- URL pointing to the NFT file location. -
-
-name: string::String -
-
- The human-readable name of the native token. -
-
-collection_name: option::Option<string::String> -
-
- The human-readable collection name of the native token. -
-
-royalties: table::Table<address, fixed_point32::FixedPoint32> -
-
- Royalty payment addresses mapped to the payout percentage. -
-
-issuer_name: option::Option<string::String> -
-
- The human-readable name of the native token creator. -
-
-description: option::Option<string::String> -
-
- The human-readable description of the token. -
-
-attributes: vec_set::VecSet<string::String> -
-
- Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). -
-
- - -
- - - -## Function `create` - -Create a new Irc27Metadata object. - - -
public fun create(version: string::String, media_type: string::String, uri: url::Url, name: string::String, collection_name: option::Option<string::String>, royalties: table::Table<address, fixed_point32::FixedPoint32>, issuer_name: option::Option<string::String>, description: option::Option<string::String>, attributes: vec_set::VecSet<string::String>): irc27::Irc27Metadata
-
- - - -
-Implementation - - -
public fun create(
-    version: String,
-    media_type: String,
-    uri: Url,
-    name: String,
-    collection_name: Option<String>,
-    royalties: Table<address, FixedPoint32>,
-    issuer_name: Option<String>,
-    description: Option<String>,
-    attributes: VecSet<String>,
-): Irc27Metadata {
-    Irc27Metadata {
-        version,
-        media_type,
-        uri,
-        name,
-        collection_name,
-        royalties,
-        issuer_name,
-        description,
-        attributes
-    }
-}
-
- - - -
- - - -## Function `destroy` - -Permanently destroy a Irc27Metadata object. - - -
public fun destroy(irc27: irc27::Irc27Metadata)
-
- - - -
-Implementation - - -
public fun destroy(irc27: Irc27Metadata) {
-    let Irc27Metadata {
-        version: _,
-        media_type: _,
-        uri: _,
-        name: _,
-        collection_name: _,
-        royalties: royalties,
-        issuer_name: _,
-        description: _,
-        attributes: _
-    } = irc27;
-
-    royalties.drop();
-}
-
- - - -
- - - -## Function `version` - -Get the metadata's version. - - -
public fun version(irc27: &irc27::Irc27Metadata): &string::String
-
- - - -
-Implementation - - -
public fun version(irc27: &Irc27Metadata): &String {
-    &irc27.version
-}
-
- - - -
- - - -## Function `media_type` - -Get the metadata's media_type. - - -
public fun media_type(irc27: &irc27::Irc27Metadata): &string::String
-
- - - -
-Implementation - - -
public fun media_type(irc27: &Irc27Metadata): &String {
-    &irc27.media_type
-}
-
- - - -
- - - -## Function `uri` - -Get the metadata's uri. - - -
public fun uri(irc27: &irc27::Irc27Metadata): &url::Url
-
- - - -
-Implementation - - -
public fun uri(irc27: &Irc27Metadata): &Url {
-    &irc27.uri
-}
-
- - - -
- - - -## Function `name` - -Get the metadata's name. - - -
public fun name(irc27: &irc27::Irc27Metadata): &string::String
-
- - - -
-Implementation - - -
public fun name(irc27: &Irc27Metadata): &String {
-    &irc27.name
-}
-
- - - -
- - - -## Function `collection_name` - -Get the metadata's collection_name. - - -
public fun collection_name(irc27: &irc27::Irc27Metadata): &option::Option<string::String>
-
- - - -
-Implementation - - -
public fun collection_name(irc27: &Irc27Metadata): &Option<String> {
-    &irc27.collection_name
-}
-
- - - -
- - - -## Function `royalties` - -Get the metadata's royalties. - - -
public fun royalties(irc27: &irc27::Irc27Metadata): &table::Table<address, fixed_point32::FixedPoint32>
-
- - - -
-Implementation - - -
public fun royalties(irc27: &Irc27Metadata): &Table<address, FixedPoint32> {
-    &irc27.royalties
-}
-
- - - -
- - - -## Function `issuer_name` - -Get the metadata's issuer_name. - - -
public fun issuer_name(irc27: &irc27::Irc27Metadata): &option::Option<string::String>
-
- - - -
-Implementation - - -
public fun issuer_name(irc27: &Irc27Metadata): &Option<String> {
-    &irc27.issuer_name
-}
-
- - - -
- - - -## Function `description` - -Get the metadata's description. - - -
public fun description(irc27: &irc27::Irc27Metadata): &option::Option<string::String>
-
- - - -
-Implementation - - -
public fun description(irc27: &Irc27Metadata): &Option<String> {
-    &irc27.description
-}
-
- - - -
- - - -## Function `attributes` - -Get the metadata's attributes. - - -
public fun attributes(irc27: &irc27::Irc27Metadata): &vec_set::VecSet<string::String>
-
- - - -
-Implementation - - -
public fun attributes(irc27: &Irc27Metadata): &VecSet<String> {
-    &irc27.attributes
-}
-
- - - -
diff --git a/crates/sui-framework/docs/stardust/nft.md b/crates/sui-framework/docs/stardust/nft.md deleted file mode 100644 index 63043566461..00000000000 --- a/crates/sui-framework/docs/stardust/nft.md +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: Module `0x107a::nft` ---- - - - -- [Resource `Nft`](#0x107a_nft_Nft) -- [Function `create`](#0x107a_nft_create) -- [Function `destroy`](#0x107a_nft_destroy) -- [Function `sender`](#0x107a_nft_sender) -- [Function `metadata`](#0x107a_nft_metadata) -- [Function `tag`](#0x107a_nft_tag) -- [Function `immutable_issuer`](#0x107a_nft_immutable_issuer) -- [Function `immutable_metadata`](#0x107a_nft_immutable_metadata) - - -
use 0x107a::irc27;
-use 0x1::option;
-use 0x2::object;
-use 0x2::tx_context;
-
- - - - - -## Resource `Nft` - -The Stardust NFT representation. - - -
struct Nft has store, key
-
- - - -
-Fields - - -
-
-id: object::UID -
-
- The Nft's ID is nested from Stardust for the migrated NFTs. -
-
-sender: option::Option<address> -
-
- The sender features. -
-
-metadata: option::Option<vector<u8>> -
-
- The metadata features. -
-
-tag: option::Option<vector<u8>> -
-
- The tag features. -
-
-immutable_issuer: option::Option<address> -
-
- The immutable issuer feature. -
-
-immutable_metadata: irc27::Irc27Metadata -
-
- The immutable metadata feature. -
-
- - -
- - - -## Function `create` - -Create a new Nft object. - - -
public fun create(sender: option::Option<address>, metadata: option::Option<vector<u8>>, tag: option::Option<vector<u8>>, immutable_issuer: option::Option<address>, immutable_metadata: irc27::Irc27Metadata, ctx: &mut tx_context::TxContext): nft::Nft
-
- - - -
-Implementation - - -
public fun create(
-    sender: Option<address>,
-    metadata: Option<vector<u8>>,
-    tag: Option<vector<u8>>,
-    immutable_issuer: Option<address>,
-    immutable_metadata: Irc27Metadata,
-    ctx: &mut TxContext,
-): Nft {
-    Nft {
-        id: object::new(ctx),
-        sender,
-        metadata,
-        tag,
-        immutable_issuer,
-        immutable_metadata,
-    }
-}
-
- - - -
- - - -## Function `destroy` - -Permanently destroy an Nft object. - - -
public fun destroy(output: nft::Nft)
-
- - - -
-Implementation - - -
public fun destroy(output: Nft) {
-    let Nft {
-        id: id,
-        sender: _,
-        metadata: _,
-        tag: _,
-        immutable_issuer: _,
-        immutable_metadata: immutable_metadata,
-    } = output;
-
-    irc27::destroy(immutable_metadata);
-
-    object::delete(id);
-}
-
- - - -
- - - -## Function `sender` - -Get the NFT's sender. - - -
public fun sender(nft: &nft::Nft): &option::Option<address>
-
- - - -
-Implementation - - -
public fun sender(nft: &Nft): &Option<address> {
-    &nft.sender
-}
-
- - - -
- - - -## Function `metadata` - -Get the NFT's metadata. - - -
public fun metadata(nft: &nft::Nft): &option::Option<vector<u8>>
-
- - - -
-Implementation - - -
public fun metadata(nft: &Nft): &Option<vector<u8>> {
-    &nft.metadata
-}
-
- - - -
- - - -## Function `tag` - -Get the NFT's tag. - - -
public fun tag(nft: &nft::Nft): &option::Option<vector<u8>>
-
- - - -
-Implementation - - -
public fun tag(nft: &Nft): &Option<vector<u8>> {
-    &nft.tag
-}
-
- - - -
- - - -## Function `immutable_issuer` - -Get the NFT's immutable_sender. - - -
public fun immutable_issuer(nft: &nft::Nft): &option::Option<address>
-
- - - -
-Implementation - - -
public fun immutable_issuer(nft: &Nft): &Option<address> {
-    &nft.immutable_issuer
-}
-
- - - -
- - - -## Function `immutable_metadata` - -Get the NFT's immutable_metadata. - - -
public fun immutable_metadata(nft: &nft::Nft): &irc27::Irc27Metadata
-
- - - -
-Implementation - - -
public fun immutable_metadata(nft: &Nft): &Irc27Metadata {
-    &nft.immutable_metadata
-}
-
- - - -
diff --git a/crates/sui-framework/docs/stardust/nft_output.md b/crates/sui-framework/docs/stardust/nft_output.md deleted file mode 100644 index cc1e39a6e3a..00000000000 --- a/crates/sui-framework/docs/stardust/nft_output.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: Module `0x107a::nft_output` ---- - - - -- [Resource `NftOutput`](#0x107a_nft_output_NftOutput) -- [Constants](#@Constants_0) -- [Function `extract_assets`](#0x107a_nft_output_extract_assets) -- [Function `load_nft`](#0x107a_nft_output_load_nft) - - -
use 0x107a::expiration_unlock_condition;
-use 0x107a::nft;
-use 0x107a::storage_deposit_return_unlock_condition;
-use 0x107a::timelock_unlock_condition;
-use 0x1::option;
-use 0x2::balance;
-use 0x2::dynamic_field;
-use 0x2::object;
-use 0x2::sui;
-use 0x2::tx_context;
-
- - - - - -## Resource `NftOutput` - -The Stardust NFT output representation. - - -
struct NftOutput has key
-
- - - -
-Fields - - -
-
-id: object::UID -
-
- -
-
-iota: balance::Balance<sui::SUI> -
-
- The amount of IOTA tokens held by the output. -
-
-storage_deposit_return: option::Option<storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition> -
-
- -
-
-timelock: option::Option<timelock_unlock_condition::TimelockUnlockCondition> -
-
- -
-
-expiration: option::Option<expiration_unlock_condition::ExpirationUnlockCondition> -
-
- -
-
- - -
- - - -## Constants - - - - -The NFT dynamic field name. - - -
const NFT_NAME: vector<u8> = [110, 102, 116];
-
- - - - - -## Function `extract_assets` - -The function extracts assets from a legacy NFT output. - - -
public fun extract_assets(output: nft_output::NftOutput, ctx: &mut tx_context::TxContext): (balance::Balance<sui::SUI>, nft::Nft)
-
- - - -
-Implementation - - -
public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance<SUI>, Nft) {
-    // Load the related Nft object.
-    let nft = load_nft(&mut output);
-
-    // Unpuck the output.
-    let NftOutput {
-        id: id,
-        iota: mut iota,
-        storage_deposit_return: mut storage_deposit_return,
-        timelock: mut timelock,
-        expiration: mut expiration
-    } = output;
-
-    // If the output has a timelock, then we need to check if the timelock has expired.
-    if (timelock.is_some()) {
-        timelock.extract().unlock(ctx);
-    };
-
-    // If the output has an expiration, then we need to check who can unlock the output.
-    if (expiration.is_some()) {
-        expiration.extract().unlock(ctx);
-    };
-
-    // If the output has an SDRUC, then we need to return the deposit.
-    if (storage_deposit_return.is_some()) {
-        storage_deposit_return.extract().unlock(&mut iota, ctx);
-    };
-
-    // Destroy the output.
-    option::destroy_none(timelock);
-    option::destroy_none(expiration);
-    option::destroy_none(storage_deposit_return);
-
-    object::delete(id);
-
-    return (iota, nft)
-}
-
- - - -
- - - -## Function `load_nft` - -Loads the related Nft object. - - -
fun load_nft(output: &mut nft_output::NftOutput): nft::Nft
-
- - - -
-Implementation - - -
fun load_nft(output: &mut NftOutput): Nft {
-    dynamic_field::remove(&mut output.id, NFT_NAME)
-}
-
- - - -
diff --git a/crates/sui-framework/packages/stardust/sources/nft/irc27.move b/crates/sui-framework/packages/stardust/sources/nft/irc27.move deleted file mode 100644 index e60a1027c5e..00000000000 --- a/crates/sui-framework/packages/stardust/sources/nft/irc27.move +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module stardust::irc27 { - - use std::fixed_point32::FixedPoint32; - use std::string::String; - - use sui::table::Table; - use sui::url::Url; - use sui::vec_set::VecSet; - - /// The IRC27 NFT metadata standard schema. - public struct Irc27Metadata has store { - /// Version of the metadata standard. - version: String, - - /// The media type (MIME) of the asset. - /// - /// ## Examples - /// - Image files: `image/jpeg`, `image/png`, `image/gif`, etc. - /// - Video files: `video/x-msvideo` (avi), `video/mp4`, `video/mpeg`, etc. - /// - Audio files: `audio/mpeg`, `audio/wav`, etc. - /// - 3D Assets: `model/obj`, `model/u3d`, etc. - /// - Documents: `application/pdf`, `text/plain`, etc. - media_type: String, - - /// URL pointing to the NFT file location. - uri: Url, - - /// The human-readable name of the native token. - name: String, - - /// The human-readable collection name of the native token. - collection_name: Option, - - /// Royalty payment addresses mapped to the payout percentage. - royalties: Table, - - /// The human-readable name of the native token creator. - issuer_name: Option, - - /// The human-readable description of the token. - description: Option, - - /// Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). - attributes: VecSet, - } - - /// Create a new `Irc27Metadata` object. - public fun create( - version: String, - media_type: String, - uri: Url, - name: String, - collection_name: Option, - royalties: Table, - issuer_name: Option, - description: Option, - attributes: VecSet, - ): Irc27Metadata { - Irc27Metadata { - version, - media_type, - uri, - name, - collection_name, - royalties, - issuer_name, - description, - attributes - } - } - - /// Permanently destroy a `Irc27Metadata` object. - public fun destroy(irc27: Irc27Metadata) { - let Irc27Metadata { - version: _, - media_type: _, - uri: _, - name: _, - collection_name: _, - royalties: royalties, - issuer_name: _, - description: _, - attributes: _ - } = irc27; - - royalties.drop(); - } - - /// Get the metadata's `version`. - public fun version(irc27: &Irc27Metadata): &String { - &irc27.version - } - - /// Get the metadata's `media_type`. - public fun media_type(irc27: &Irc27Metadata): &String { - &irc27.media_type - } - - /// Get the metadata's `uri`. - public fun uri(irc27: &Irc27Metadata): &Url { - &irc27.uri - } - - /// Get the metadata's `name`. - public fun name(irc27: &Irc27Metadata): &String { - &irc27.name - } - - /// Get the metadata's `collection_name`. - public fun collection_name(irc27: &Irc27Metadata): &Option { - &irc27.collection_name - } - - /// Get the metadata's `royalties`. - public fun royalties(irc27: &Irc27Metadata): &Table { - &irc27.royalties - } - - /// Get the metadata's `issuer_name`. - public fun issuer_name(irc27: &Irc27Metadata): &Option { - &irc27.issuer_name - } - - /// Get the metadata's `description`. - public fun description(irc27: &Irc27Metadata): &Option { - &irc27.description - } - - /// Get the metadata's `attributes`. - public fun attributes(irc27: &Irc27Metadata): &VecSet { - &irc27.attributes - } -} diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft.move b/crates/sui-framework/packages/stardust/sources/nft/nft.move deleted file mode 100644 index 02a09be161a..00000000000 --- a/crates/sui-framework/packages/stardust/sources/nft/nft.move +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module stardust::nft { - - use stardust::irc27::{Self, Irc27Metadata}; - - /// The Stardust NFT representation. - public struct Nft has key, store { - /// The Nft's ID is nested from Stardust for the migrated NFTs. - id: UID, - - /// The sender features. - sender: Option
, - /// The metadata features. - metadata: Option>, - /// The tag features. - tag: Option>, - - /// The immutable issuer feature. - immutable_issuer: Option
, - /// The immutable metadata feature. - immutable_metadata: Irc27Metadata, - } - - /// Create a new `Nft` object. - public fun create( - sender: Option
, - metadata: Option>, - tag: Option>, - immutable_issuer: Option
, - immutable_metadata: Irc27Metadata, - ctx: &mut TxContext, - ): Nft { - Nft { - id: object::new(ctx), - sender, - metadata, - tag, - immutable_issuer, - immutable_metadata, - } - } - - /// Permanently destroy an `Nft` object. - public fun destroy(output: Nft) { - let Nft { - id: id, - sender: _, - metadata: _, - tag: _, - immutable_issuer: _, - immutable_metadata: immutable_metadata, - } = output; - - irc27::destroy(immutable_metadata); - - object::delete(id); - } - - /// Get the NFT's `sender`. - public fun sender(nft: &Nft): &Option
{ - &nft.sender - } - - /// Get the NFT's `metadata`. - public fun metadata(nft: &Nft): &Option> { - &nft.metadata - } - - /// Get the NFT's `tag`. - public fun tag(nft: &Nft): &Option> { - &nft.tag - } - - /// Get the NFT's `immutable_sender`. - public fun immutable_issuer(nft: &Nft): &Option
{ - &nft.immutable_issuer - } - - /// Get the NFT's `immutable_metadata`. - public fun immutable_metadata(nft: &Nft): &Irc27Metadata { - &nft.immutable_metadata - } -} diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move b/crates/sui-framework/packages/stardust/sources/nft/nft_output.move deleted file mode 100644 index e822234c086..00000000000 --- a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module stardust::nft_output { - - use sui::balance::Balance; - use sui::dynamic_field; - use sui::sui::SUI; - - use stardust::nft::Nft; - - use stardust::expiration_unlock_condition::ExpirationUnlockCondition; - use stardust::storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition; - use stardust::timelock_unlock_condition::TimelockUnlockCondition; - - /// The NFT dynamic field name. - const NFT_NAME: vector = b"nft"; - - /// The Stardust NFT output representation. - public struct NftOutput has key { - id: UID, - - /// The amount of IOTA tokens held by the output. - iota: Balance, - - // The storage deposit return unlock condition. - storage_deposit_return: Option, - // The timelock unlock condition - timelock: Option, - // The expiration unlock condition - expiration: Option, - } - - /// The function extracts assets from a legacy NFT output. - public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance, Nft) { - // Load the related Nft object. - let nft = load_nft(&mut output); - - // Unpuck the output. - let NftOutput { - id: id, - iota: mut iota, - storage_deposit_return: mut storage_deposit_return, - timelock: mut timelock, - expiration: mut expiration - } = output; - - // If the output has a timelock, then we need to check if the timelock has expired. - if (timelock.is_some()) { - timelock.extract().unlock(ctx); - }; - - // If the output has an expiration, then we need to check who can unlock the output. - if (expiration.is_some()) { - expiration.extract().unlock(ctx); - }; - - // If the output has an SDRUC, then we need to return the deposit. - if (storage_deposit_return.is_some()) { - storage_deposit_return.extract().unlock(&mut iota, ctx); - }; - - // Destroy the output. - option::destroy_none(timelock); - option::destroy_none(expiration); - option::destroy_none(storage_deposit_return); - - object::delete(id); - - return (iota, nft) - } - - /// Loads the related `Nft` object. - fun load_nft(output: &mut NftOutput): Nft { - dynamic_field::remove(&mut output.id, NFT_NAME) - } - - #[test_only] - public fun attach_nft(output: &mut NftOutput, nft: Nft) { - dynamic_field::add(&mut output.id, NFT_NAME, nft) - } - - #[test_only] - public fun create_for_testing( - iota: Balance, - storage_deposit_return: Option, - timelock: Option, - expiration: Option, - ctx: &mut TxContext, - ): NftOutput { - NftOutput { - id: object::new(ctx), - iota, - storage_deposit_return, - timelock, - expiration, - } - } -} diff --git a/crates/sui-framework/packages/stardust/tests/nft_tests.move b/crates/sui-framework/packages/stardust/tests/nft_tests.move deleted file mode 100644 index e73ae06e5c0..00000000000 --- a/crates/sui-framework/packages/stardust/tests/nft_tests.move +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module stardust::nft_tests { - - use std::ascii; - use std::fixed_point32; - use std::string; - - use sui::balance; - use sui::coin::{Self, Coin}; - use sui::sui::SUI; - use sui::table; - use sui::test_scenario; - use sui::url; - use sui::vec_set; - - use stardust::irc27; - use stardust::nft_output; - use stardust::nft; - - use stardust::expiration_unlock_condition; - use stardust::storage_deposit_return_unlock_condition; - use stardust::timelock_unlock_condition; - - // Demonstration on how to claim the assets from an NFT output with all unlock conditions inside one PTB. - #[test] - fun nft_assets_extraction() { - // Set up a test enviroment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Create an NftOutput object. - let mut nft_output = nft_output::create_for_testing( - balance::create_for_testing(10000), - option::some(storage_deposit_return_unlock_condition::create_for_testing(@0xB, 1000)), - option::some(timelock_unlock_condition::create_for_testing(5)), - option::some(expiration_unlock_condition::create_for_testing(sender, @0xB, 20)), - scenario.ctx(), - ); - - // Create an Nft object. - let mut royalties = table::new(scenario.ctx()); - royalties.add(sender, fixed_point32::create_from_rational(1, 2)); - - let mut attributes = vec_set::empty(); - attributes.insert(string::utf8(b"attribute")); - - let nft = nft::create( - option::some(sender), - option::some(b"metadata"), - option::some(b"tag"), - option::some(sender), - irc27::create( - string::utf8(b"0.0.1"), - string::utf8(b"image/png"), - url::new_unsafe(ascii::string(b"www.best-nft.com/nft.png")), - string::utf8(b"nft"), - option::some(string::utf8(b"collection")), - royalties, - option::some(string::utf8(b"issuer")), - option::some(string::utf8(b"description")), - attributes, - ), - scenario.ctx(), - ); - - // Add the Nft as a dynamic field to the output. - nft_output.attach_nft(nft); - - // Increment epoch timestamp. - scenario.ctx().increment_epoch_timestamp(10000); - - // Extract assets. - let (iota, nft) = nft_output.extract_assets(scenario.ctx()); - - // Check the extracted IOTA balance. - assert!(iota.value() == 9000, 0); - - // Check the extracted NFT. - assert!(nft.sender().contains(&sender), 1); - assert!(nft.metadata().contains(&b"metadata"), 2); - assert!(nft.tag().contains(&b"tag"), 3); - assert!(nft.immutable_issuer().contains(&sender), 4); - - assert!(nft.immutable_metadata().version() == string::utf8(b"0.0.1"), 5); - assert!(nft.immutable_metadata().media_type() == string::utf8(b"image/png"), 6); - assert!(nft.immutable_metadata().uri() == url::new_unsafe(ascii::string(b"www.best-nft.com/nft.png")), 7); - assert!(nft.immutable_metadata().name() == string::utf8(b"nft"), 8); - assert!(nft.immutable_metadata().collection_name().contains(&string::utf8(b"collection")), 9); - assert!(nft.immutable_metadata().royalties().length() == 1, 10); - assert!(nft.immutable_metadata().royalties()[sender] == fixed_point32::create_from_rational(1, 2), 11); - assert!(nft.immutable_metadata().issuer_name().contains(&string::utf8(b"issuer")), 12); - assert!(nft.immutable_metadata().description().contains(&string::utf8(b"description")), 13); - assert!(nft.immutable_metadata().attributes().size() == 1, 14); - assert!(nft.immutable_metadata().attributes().contains(&string::utf8(b"attribute")), 15); - - // Check the storage deposit return. - scenario.next_tx(sender); - - let returned_storage_deposit = scenario.take_from_address>(@0xB); - - assert!(returned_storage_deposit.value() == 1000, 16); - - test_scenario::return_to_address(@0xB, returned_storage_deposit); - - // Transfer the extracted assets. - transfer::public_transfer(coin::from_balance(iota, scenario.ctx()), @0xC); - transfer::public_transfer(nft, @0xC); - - // Cleanup. - scenario.end(); - } -} From dfe79f6054b74a9eb39b65758366db45b414c7e2 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Mon, 22 Apr 2024 13:58:55 +0300 Subject: [PATCH 5/6] fix: reverted a part of the Stardust package integration --- crates/sui-framework-snapshot/src/lib.rs | 4 +--- crates/sui-framework-tests/src/unit_tests.rs | 10 ++++++++++ crates/sui-framework/src/lib.rs | 7 +------ crates/sui-replay/src/replay.rs | 6 +----- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/crates/sui-framework-snapshot/src/lib.rs b/crates/sui-framework-snapshot/src/lib.rs index 0f9fdc3638f..808073492e3 100644 --- a/crates/sui-framework-snapshot/src/lib.rs +++ b/crates/sui-framework-snapshot/src/lib.rs @@ -7,8 +7,7 @@ use std::{fs, io::Read, path::PathBuf}; use sui_framework::SystemPackage; use sui_types::base_types::ObjectID; use sui_types::{ - DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID, + DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, }; pub type SnapshotManifest = BTreeMap; @@ -35,7 +34,6 @@ const SYSTEM_PACKAGE_PUBLISH_ORDER: &[ObjectID] = &[ SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, DEEPBOOK_PACKAGE_ID, - STARDUST_PACKAGE_ID, ]; pub fn load_bytecode_snapshot_manifest() -> SnapshotManifest { diff --git a/crates/sui-framework-tests/src/unit_tests.rs b/crates/sui-framework-tests/src/unit_tests.rs index 19ec1e6ef13..6fa480f4c3a 100644 --- a/crates/sui-framework-tests/src/unit_tests.rs +++ b/crates/sui-framework-tests/src/unit_tests.rs @@ -40,6 +40,16 @@ fn run_deepbook_tests() { }); } +#[test] +#[cfg_attr(msim, ignore)] +fn run_stardust_tests() { + check_move_unit_tests({ + let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + buf.extend(["..", "sui-framework", "packages", "stardust"]); + buf + }); +} + #[test] #[cfg_attr(msim, ignore)] fn run_examples_move_unit_tests() { diff --git a/crates/sui-framework/src/lib.rs b/crates/sui-framework/src/lib.rs index 4a5c16c4aed..6a686a04a19 100644 --- a/crates/sui-framework/src/lib.rs +++ b/crates/sui-framework/src/lib.rs @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Formatter; use sui_types::base_types::ObjectRef; use sui_types::storage::ObjectStore; +use sui_types::DEEPBOOK_PACKAGE_ID; use sui_types::{ base_types::ObjectID, digests::TransactionDigest, @@ -18,7 +19,6 @@ use sui_types::{ object::{Object, OBJECT_START_VERSION}, MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, }; -use sui_types::{DEEPBOOK_PACKAGE_ID, STARDUST_PACKAGE_ID}; use tracing::error; /// Represents a system package in the framework, that's built from the source code inside @@ -123,11 +123,6 @@ impl BuiltInFramework { DEEPBOOK_PACKAGE_ID, "deepbook", [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] - ), - ( - STARDUST_PACKAGE_ID, - "stardust", - [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] ) ]) .iter() diff --git a/crates/sui-replay/src/replay.rs b/crates/sui-replay/src/replay.rs index 1892d6b6aae..e0e497a1655 100644 --- a/crates/sui-replay/src/replay.rs +++ b/crates/sui-replay/src/replay.rs @@ -67,7 +67,7 @@ use sui_types::{ ObjectReadResultKind, SenderSignedData, Transaction, TransactionData, TransactionDataAPI, TransactionKind, VerifiedCertificate, VerifiedTransaction, }, - DEEPBOOK_PACKAGE_ID, STARDUST_PACKAGE_ID, + DEEPBOOK_PACKAGE_ID, }; use tracing::{error, info, trace, warn}; @@ -1051,10 +1051,6 @@ impl LocalExec { ids.retain(|id| *id != DEEPBOOK_PACKAGE_ID) } - if protocol_version < 43 { - ids.retain(|id| *id != STARDUST_PACKAGE_ID) - } - ids } From 0c5709a58fa8cb426dacc4996c3f9957eac8b267 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Mon, 22 Apr 2024 19:14:22 +0300 Subject: [PATCH 6/6] fix: added getters to the unlock conditions --- .../stardust/expiration_unlock_condition.md | 84 ++++++++++++++++++- ...storage_deposit_return_unlock_condition.md | 26 +++--- .../stardust/timelock_unlock_condition.md | 28 ++++++- .../expiration_unlock_condition.move | 21 ++++- ...orage_deposit_return_unlock_condition.move | 10 +-- .../timelock_unlock_condition.move | 7 +- 6 files changed, 150 insertions(+), 26 deletions(-) diff --git a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md b/crates/sui-framework/docs/stardust/expiration_unlock_condition.md index 07f595ce2fc..641c2d8f2b6 100644 --- a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md +++ b/crates/sui-framework/docs/stardust/expiration_unlock_condition.md @@ -8,6 +8,9 @@ title: Module `0x107a::expiration_unlock_condition` - [Constants](#@Constants_0) - [Function `unlock`](#0x107a_expiration_unlock_condition_unlock) - [Function `can_be_unlocked_by`](#0x107a_expiration_unlock_condition_can_be_unlocked_by) +- [Function `owner`](#0x107a_expiration_unlock_condition_owner) +- [Function `return_address`](#0x107a_expiration_unlock_condition_return_address) +- [Function `unix_time`](#0x107a_expiration_unlock_condition_unix_time)
use 0x2::tx_context;
@@ -123,14 +126,89 @@ Return the address that can unlock the related output.
     // Unix time in seconds.
     let current_time = ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32);
 
-    if (condition.unix_time < current_time) {
-        condition.return_address
+    if (condition.unix_time() < current_time) {
+        condition.return_address()
     } else {
-        condition.owner
+        condition.owner()
     }
 }
 
+ + + + +## Function `owner` + +Get the unlock condition's owner. + + +
public fun owner(condition: &expiration_unlock_condition::ExpirationUnlockCondition): address
+
+ + + +
+Implementation + + +
public fun owner(condition: &ExpirationUnlockCondition): address {
+    condition.owner
+}
+
+ + + +
+ + + +## Function `return_address` + +Get the unlock condition's return_address. + + +
public fun return_address(condition: &expiration_unlock_condition::ExpirationUnlockCondition): address
+
+ + + +
+Implementation + + +
public fun return_address(condition: &ExpirationUnlockCondition): address {
+    condition.return_address
+}
+
+ + + +
+ + + +## Function `unix_time` + +Get the unlock condition's unix_time. + + +
public fun unix_time(condition: &expiration_unlock_condition::ExpirationUnlockCondition): u32
+
+ + + +
+Implementation + + +
public fun unix_time(condition: &ExpirationUnlockCondition): u32 {
+    condition.unix_time
+}
+
+ + +
diff --git a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md b/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md index 2299dd4afd6..e62df2cdf8d 100644 --- a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md +++ b/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md @@ -6,8 +6,8 @@ title: Module `0x107a::storage_deposit_return_unlock_condition` - [Struct `StorageDepositReturnUnlockCondition`](#0x107a_storage_deposit_return_unlock_condition_StorageDepositReturnUnlockCondition) - [Function `unlock`](#0x107a_storage_deposit_return_unlock_condition_unlock) -- [Function `return_amount`](#0x107a_storage_deposit_return_unlock_condition_return_amount) - [Function `return_address`](#0x107a_storage_deposit_return_unlock_condition_return_address) +- [Function `return_amount`](#0x107a_storage_deposit_return_unlock_condition_return_amount)
use 0x2::balance;
@@ -87,14 +87,14 @@ Check the unlock condition.
 
 
 
-
+
 
-## Function `return_amount`
+## Function `return_address`
 
-Get the unlock condition's return_amount.
+Get the unlock condition's return_address.
 
 
-
public fun return_amount(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition): u64
+
public fun return_address(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition): address
 
@@ -103,8 +103,8 @@ Get the unlock condition's return_amount. Implementation -
public fun return_amount(condition: &StorageDepositReturnUnlockCondition): u64 {
-    condition.return_amount
+
public fun return_address(condition: &StorageDepositReturnUnlockCondition): address {
+    condition.return_address
 }
 
@@ -112,14 +112,14 @@ Get the unlock condition's return_amount. - + -## Function `return_address` +## Function `return_amount` -Get the unlock condition's return_address. +Get the unlock condition's return_amount. -
public fun return_address(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition): address
+
public fun return_amount(condition: &storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition): u64
 
@@ -128,8 +128,8 @@ Get the unlock condition's return_address. Implementation -
public fun return_address(condition: &StorageDepositReturnUnlockCondition): address {
-    condition.return_address
+
public fun return_amount(condition: &StorageDepositReturnUnlockCondition): u64 {
+    condition.return_amount
 }
 
diff --git a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md b/crates/sui-framework/docs/stardust/timelock_unlock_condition.md index 3eed4a11c18..4de6931ac98 100644 --- a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md +++ b/crates/sui-framework/docs/stardust/timelock_unlock_condition.md @@ -8,6 +8,7 @@ title: Module `0x107a::timelock_unlock_condition` - [Constants](#@Constants_0) - [Function `unlock`](#0x107a_timelock_unlock_condition_unlock) - [Function `is_timelocked`](#0x107a_timelock_unlock_condition_is_timelocked) +- [Function `unix_time`](#0x107a_timelock_unlock_condition_unix_time)
use 0x2::tx_context;
@@ -104,7 +105,32 @@ Check if the output is locked by the Timelock condition.
 
 
 
public fun is_timelocked(condition: &TimelockUnlockCondition, ctx: &TxContext): bool {
-    condition.unix_time > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32)
+    condition.unix_time() > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32)
+}
+
+ + + + + + + +## Function `unix_time` + +Get the unlock condition's unix_time. + + +
public fun unix_time(condition: &timelock_unlock_condition::TimelockUnlockCondition): u32
+
+ + + +
+Implementation + + +
public fun unix_time(condition: &TimelockUnlockCondition): u32 {
+    condition.unix_time
 }
 
diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move index fe0f63edbed..d3746fdbe67 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move @@ -34,13 +34,28 @@ module stardust::expiration_unlock_condition { // Unix time in seconds. let current_time = ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32); - if (condition.unix_time < current_time) { - condition.return_address + if (condition.unix_time() < current_time) { + condition.return_address() } else { - condition.owner + condition.owner() } } + /// Get the unlock condition's `owner`. + public fun owner(condition: &ExpirationUnlockCondition): address { + condition.owner + } + + /// Get the unlock condition's `return_address`. + public fun return_address(condition: &ExpirationUnlockCondition): address { + condition.return_address + } + + /// Get the unlock condition's `unix_time`. + public fun unix_time(condition: &ExpirationUnlockCondition): u32 { + condition.unix_time + } + #[test_only] public fun create_for_testing(owner: address, return_address: address, unix_time: u32): ExpirationUnlockCondition { ExpirationUnlockCondition { diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move index 99be18ef998..e21373eb3b8 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move @@ -30,16 +30,16 @@ module stardust::storage_deposit_return_unlock_condition { } = condition; } - /// Get the unlock condition's `return_amount`. - public fun return_amount(condition: &StorageDepositReturnUnlockCondition): u64 { - condition.return_amount - } - /// Get the unlock condition's `return_address`. public fun return_address(condition: &StorageDepositReturnUnlockCondition): address { condition.return_address } + /// Get the unlock condition's `return_amount`. + public fun return_amount(condition: &StorageDepositReturnUnlockCondition): u64 { + condition.return_amount + } + #[test_only] public fun create_for_testing(return_address: address, return_amount: u64): StorageDepositReturnUnlockCondition { StorageDepositReturnUnlockCondition { diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move index 8a6aaab0489..aa1a7bfba9c 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move +++ b/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move @@ -23,7 +23,12 @@ module stardust::timelock_unlock_condition { /// Check if the output is locked by the `Timelock` condition. public fun is_timelocked(condition: &TimelockUnlockCondition, ctx: &TxContext): bool { - condition.unix_time > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32) + condition.unix_time() > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32) + } + + /// Get the unlock condition's `unix_time`. + public fun unix_time(condition: &TimelockUnlockCondition): u32 { + condition.unix_time } #[test_only]