diff --git a/crates/sui-framework/docs/sui-framework/authenticator_state.md b/crates/sui-framework/docs/sui-framework/authenticator_state.md index 93d44e078b5d6..fe4f48e3a07de 100644 --- a/crates/sui-framework/docs/sui-framework/authenticator_state.md +++ b/crates/sui-framework/docs/sui-framework/authenticator_state.md @@ -308,9 +308,9 @@ Sender is not @0x0 the system address.
fun jwk_equal(a: &JWK, b: &JWK): bool {
     (&a.kty == &b.kty) &&
-       (&a.e == &b.e) &&
-       (&a.n == &b.n) &&
-       (&a.alg == &b.alg)
+           (&a.e == &b.e) &&
+           (&a.n == &b.n) &&
+           (&a.alg == &b.alg)
 }
 
@@ -484,9 +484,7 @@ Can only be called by genesis or change_epoch transactions. Implementation -
fun load_inner_mut(
-    self: &mut AuthenticatorState,
-): &mut AuthenticatorStateInner {
+
fun load_inner_mut(self: &mut AuthenticatorState): &mut AuthenticatorStateInner {
     let version = self.version;
 
     // replace this with a lazy update function when we add a new version of the inner object.
@@ -518,9 +516,7 @@ Can only be called by genesis or change_epoch transactions.
 Implementation
 
 
-
fun load_inner(
-    self: &AuthenticatorState,
-): &AuthenticatorStateInner {
+
fun load_inner(self: &AuthenticatorState): &AuthenticatorStateInner {
     let version = self.version;
 
     // replace this with a lazy update function when we add a new version of the inner object.
@@ -709,7 +705,8 @@ indicate that the JWK has been validated in the current epoch and should not be
     self: &mut AuthenticatorState,
     // any jwk below this epoch is not retained
     min_epoch: u64,
-    ctx: &TxContext) {
+    ctx: &TxContext,
+) {
     // This will only be called by sui_system::advance_epoch
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
 
@@ -793,10 +790,7 @@ JWK state from the chain.
 Implementation
 
 
-
fun get_active_jwks(
-    self: &AuthenticatorState,
-    ctx: &TxContext,
-): vector<ActiveJwk> {
+
fun get_active_jwks(self: &AuthenticatorState, ctx: &TxContext): vector<ActiveJwk> {
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
     self.load_inner().active_jwks
 }
diff --git a/crates/sui-framework/docs/sui-framework/borrow.md b/crates/sui-framework/docs/sui-framework/borrow.md
index 0fe949d035fb0..c9af348f4c10c 100644
--- a/crates/sui-framework/docs/sui-framework/borrow.md
+++ b/crates/sui-framework/docs/sui-framework/borrow.md
@@ -137,7 +137,7 @@ Create a new Referent s
 
public fun new<T: key + store>(value: T, ctx: &mut TxContext): Referent<T> {
     Referent {
         id: tx_context::fresh_object_address(ctx),
-        value: option::some(value)
+        value: option::some(value),
     }
 }
 
@@ -167,10 +167,13 @@ hot potato. let value = self.value.extract(); let id = object::id(&value); - (value, Borrow { - ref: self.id, - obj: id - }) + ( + value, + Borrow { + ref: self.id, + obj: id, + }, + ) }
diff --git a/crates/sui-framework/docs/sui-framework/clock.md b/crates/sui-framework/docs/sui-framework/clock.md index 4093c882c71ad..3919d8837f026 100644 --- a/crates/sui-framework/docs/sui-framework/clock.md +++ b/crates/sui-framework/docs/sui-framework/clock.md @@ -154,11 +154,7 @@ called exactly once, during genesis. Implementation -
fun consensus_commit_prologue(
-    clock: &mut Clock,
-    timestamp_ms: u64,
-    ctx: &TxContext,
-) {
+
fun consensus_commit_prologue(clock: &mut Clock, timestamp_ms: u64, ctx: &TxContext) {
     // Validator will make a special system call with sender set as 0x0.
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
 
diff --git a/crates/sui-framework/docs/sui-framework/display.md b/crates/sui-framework/docs/sui-framework/display.md
index 3d085df973e54..e56a69e0d080f 100644
--- a/crates/sui-framework/docs/sui-framework/display.md
+++ b/crates/sui-framework/docs/sui-framework/display.md
@@ -247,7 +247,10 @@ Create a new Display object with a set of fields.
 
 
 
public fun new_with_fields<T: key>(
-    pub: &Publisher, fields: vector<String>, values: vector<String>, ctx: &mut TxContext
+    pub: &Publisher,
+    fields: vector<String>,
+    values: vector<String>,
+    ctx: &mut TxContext,
 ): Display<T> {
     let len = fields.length();
     assert!(len == values.length(), EVecLengthMismatch);
@@ -283,7 +286,7 @@ Create a new empty Display object and keep it.
 Implementation
 
 
-
entry public fun create_and_keep<T: key>(pub: &Publisher, ctx: &mut TxContext) {
+
public entry fun create_and_keep<T: key>(pub: &Publisher, ctx: &mut TxContext) {
     transfer::public_transfer(new<T>(pub, ctx), ctx.sender())
 }
 
@@ -308,9 +311,7 @@ Manually bump the version and emit an event with the updated version's contents. Implementation -
entry public fun update_version<T: key>(
-    display: &mut Display<T>
-) {
+
public entry fun update_version<T: key>(display: &mut Display<T>) {
     display.version = display.version + 1;
     event::emit(VersionUpdated<T> {
         version: display.version,
@@ -340,7 +341,7 @@ Sets a custom name field with the value.
 Implementation
 
 
-
entry public fun add<T: key>(self: &mut Display<T>, name: String, value: String) {
+
public entry fun add<T: key>(self: &mut Display<T>, name: String, value: String) {
     self.add_internal(name, value)
 }
 
@@ -365,8 +366,10 @@ Sets multiple fields with values. Implementation -
entry public fun add_multiple<T: key>(
-    self: &mut Display<T>, fields: vector<String>, values: vector<String>
+
public entry fun add_multiple<T: key>(
+    self: &mut Display<T>,
+    fields: vector<String>,
+    values: vector<String>,
 ) {
     let len = fields.length();
     assert!(len == values.length(), EVecLengthMismatch);
@@ -400,7 +403,7 @@ TODO (long run): version changes;
 Implementation
 
 
-
entry public fun edit<T: key>(self: &mut Display<T>, name: String, value: String) {
+
public entry fun edit<T: key>(self: &mut Display<T>, name: String, value: String) {
     let (_, _) = self.fields.remove(&name);
     self.add_internal(name, value)
 }
@@ -426,7 +429,7 @@ Remove the key from the Display.
 Implementation
 
 
-
entry public fun remove<T: key>(self: &mut Display<T>, name: String) {
+
public entry fun remove<T: key>(self: &mut Display<T>, name: String) {
     self.fields.remove(&name);
 }
 
@@ -530,7 +533,7 @@ Internal function to create a new let uid = object::new(ctx); event::emit(DisplayCreated<T> { - id: uid.to_inner() + id: uid.to_inner(), }); Display { diff --git a/crates/sui-framework/docs/sui-framework/hex.md b/crates/sui-framework/docs/sui-framework/hex.md index 5a835de9a6314..c7844eb46f877 100644 --- a/crates/sui-framework/docs/sui-framework/hex.md +++ b/crates/sui-framework/docs/sui-framework/hex.md @@ -133,11 +133,11 @@ Aborts if the hex string contains non-valid hex characters (valid characters are
fun decode_byte(hex: u8): u8 {
-    if (/* 0 .. 9 */ 48 <= hex && hex < 58) {
+    if (48 <= hex && hex < 58) {
         hex - 48
-    } else if (/* A .. F */ 65 <= hex && hex < 71) {
+    } else if (65 <= hex && hex < 71) {
         10 + hex - 65
-    } else if (/* a .. f */ 97 <= hex && hex < 103) {
+    } else if (97 <= hex && hex < 103) {
         10 + hex - 97
     } else {
         abort ENotValidHexCharacter
diff --git a/crates/sui-framework/docs/sui-framework/math.md b/crates/sui-framework/docs/sui-framework/math.md
index d138083a64689..be044025e9ba1 100644
--- a/crates/sui-framework/docs/sui-framework/math.md
+++ b/crates/sui-framework/docs/sui-framework/math.md
@@ -162,7 +162,7 @@ DEPRECATED, use std::u128::sqrt instead
 
 
 
public fun sqrt_u128(x: u128): u128 {
-   x.sqrt()
+    x.sqrt()
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/object.md b/crates/sui-framework/docs/sui-framework/object.md index 8e7a390ad700e..020d715c11e82 100644 --- a/crates/sui-framework/docs/sui-framework/object.md +++ b/crates/sui-framework/docs/sui-framework/object.md @@ -330,7 +330,7 @@ This should only be called once from clock(): UID { UID { - id: ID { bytes: SUI_CLOCK_OBJECT_ID } + id: ID { bytes: SUI_CLOCK_OBJECT_ID }, } }
@@ -358,7 +358,7 @@ This should only be called once from authenticator_state(): UID { UID { - id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID } + id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID }, } }
@@ -386,7 +386,7 @@ This should only be called once from randomness_state(): UID { UID { - id: ID { bytes: SUI_RANDOM_ID } + id: ID { bytes: SUI_RANDOM_ID }, } }
@@ -414,7 +414,7 @@ This should only be called once from sui_deny_list_object_id(): UID { UID { - id: ID { bytes: SUI_DENY_LIST_OBJECT_ID } + id: ID { bytes: SUI_DENY_LIST_OBJECT_ID }, } }
@@ -442,7 +442,7 @@ This should only be called once from bridge.
fun bridge(): UID {
     UID {
-        id: ID { bytes: SUI_BRIDGE_ID }
+        id: ID { bytes: SUI_BRIDGE_ID },
     }
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/package.md b/crates/sui-framework/docs/sui-framework/package.md index a2c043014e433..b718af007cc98 100644 --- a/crates/sui-framework/docs/sui-framework/package.md +++ b/crates/sui-framework/docs/sui-framework/package.md @@ -899,11 +899,7 @@ for the upgrade to succeed. Implementation -
public fun authorize_upgrade(
-    cap: &mut UpgradeCap,
-    policy: u8,
-    digest: vector<u8>
-): UpgradeTicket {
+
public fun authorize_upgrade(cap: &mut UpgradeCap, policy: u8, digest: vector<u8>): UpgradeTicket {
     let id_zero = @0x0.to_id();
     assert!(cap.package != id_zero, EAlreadyAuthorized);
     assert!(policy >= cap.policy, ETooPermissive);
@@ -941,10 +937,7 @@ the upgrade.
 Implementation
 
 
-
public fun commit_upgrade(
-    cap: &mut UpgradeCap,
-    receipt: UpgradeReceipt,
-) {
+
public fun commit_upgrade(cap: &mut UpgradeCap, receipt: UpgradeReceipt) {
     let UpgradeReceipt { cap: cap_id, package } = receipt;
 
     assert!(object::id(cap) == cap_id, EWrongUpgradeCap);
diff --git a/crates/sui-framework/docs/sui-framework/pay.md b/crates/sui-framework/docs/sui-framework/pay.md
index 7abd57b9fe2ed..84b2a29a92726 100644
--- a/crates/sui-framework/docs/sui-framework/pay.md
+++ b/crates/sui-framework/docs/sui-framework/pay.md
@@ -80,9 +80,7 @@ and the remaining balance is left is self.
 Implementation
 
 
-
public entry fun split<T>(
-    coin: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext
-) {
+
public entry fun split<T>(coin: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext) {
     keep(coin.split(split_amount, ctx), ctx)
 }
 
@@ -108,9 +106,7 @@ in split_amounts. Remaining balance is left in self. Implementation -
public entry fun split_vec<T>(
-    self: &mut Coin<T>, split_amounts: vector<u64>, ctx: &mut TxContext
-) {
+
public entry fun split_vec<T>(self: &mut Coin<T>, split_amounts: vector<u64>, ctx: &mut TxContext) {
     let (mut i, len) = (0, split_amounts.length());
     while (i < len) {
         split(self, split_amounts[i], ctx);
@@ -141,7 +137,10 @@ Aborts with EVALUE if amount is greater than or equal
 
 
 
public entry fun split_and_transfer<T>(
-    c: &mut Coin<T>, amount: u64, recipient: address, ctx: &mut TxContext
+    c: &mut Coin<T>,
+    amount: u64,
+    recipient: address,
+    ctx: &mut TxContext,
 ) {
     transfer::public_transfer(c.split(amount, ctx), recipient)
 }
@@ -168,9 +167,7 @@ not evenly divisible by n, the remainder is left in selfImplementation
 
 
-
public entry fun divide_and_keep<T>(
-    self: &mut Coin<T>, n: u64, ctx: &mut TxContext
-) {
+
public entry fun divide_and_keep<T>(self: &mut Coin<T>, n: u64, ctx: &mut TxContext) {
     let mut vec: vector<Coin<T>> = self.divide_into_n(n, ctx);
     let (mut i, len) = (0, vec.length());
     while (i < len) {
diff --git a/crates/sui-framework/docs/sui-framework/random.md b/crates/sui-framework/docs/sui-framework/random.md
index 27837f0a1cf5c..a685e78d198b9 100644
--- a/crates/sui-framework/docs/sui-framework/random.md
+++ b/crates/sui-framework/docs/sui-framework/random.md
@@ -300,9 +300,7 @@ Can only be called by genesis or change_epoch transactions.
 Implementation
 
 
-
fun load_inner_mut(
-    self: &mut Random,
-): &mut RandomInner {
+
fun load_inner_mut(self: &mut Random): &mut RandomInner {
     let version = versioned::version(&self.inner);
 
     // Replace this with a lazy update function when we add a new version of the inner object.
@@ -332,9 +330,7 @@ Can only be called by genesis or change_epoch transactions.
 Implementation
 
 
-
fun load_inner(
-    self: &Random,
-): &RandomInner {
+
fun load_inner(self: &Random): &RandomInner {
     let version = versioned::version(&self.inner);
 
     // Replace this with a lazy update function when we add a new version of the inner object.
@@ -387,8 +383,8 @@ transaction.
         // randomness ever being generated in that epoch.
         assert!(
             (epoch > inner.epoch && new_round == 0) ||
-                (new_round == inner.randomness_round + 1),
-            EInvalidRandomnessUpdate
+                    (new_round == inner.randomness_round + 1),
+            EInvalidRandomnessUpdate,
         );
     };
 
@@ -422,7 +418,7 @@ Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes.
     let inner = load_inner(r);
     let seed = hmac_sha3_256(
         &inner.random_bytes,
-        &ctx.fresh_object_address().to_bytes()
+        &ctx.fresh_object_address().to_bytes(),
     );
     RandomGenerator { seed, counter: 0, buffer: vector[] }
 }
diff --git a/crates/sui-framework/docs/sui-framework/tx_context.md b/crates/sui-framework/docs/sui-framework/tx_context.md
index 97e1840b5aed6..380f047c58eeb 100644
--- a/crates/sui-framework/docs/sui-framework/tx_context.md
+++ b/crates/sui-framework/docs/sui-framework/tx_context.md
@@ -167,7 +167,7 @@ Return the epoch start time as a unix timestamp in milliseconds.
 
 
 
public fun epoch_timestamp_ms(self: &TxContext): u64 {
-   self.epoch_timestamp_ms
+    self.epoch_timestamp_ms
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/url.md b/crates/sui-framework/docs/sui-framework/url.md index e0e2204219292..6129f0f7d229c 100644 --- a/crates/sui-framework/docs/sui-framework/url.md +++ b/crates/sui-framework/docs/sui-framework/url.md @@ -113,7 +113,7 @@ Get inner URL Implementation -
public fun inner_url(self: &Url): String{
+
public fun inner_url(self: &Url): String {
     self.url
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/versioned.md b/crates/sui-framework/docs/sui-framework/versioned.md index afc62e3e59a44..6a67a4a33f744 100644 --- a/crates/sui-framework/docs/sui-framework/versioned.md +++ b/crates/sui-framework/docs/sui-framework/versioned.md @@ -241,7 +241,7 @@ and must be used when we upgrade. VersionChangeCap { versioned_id: object::id(self), old_version: self.version, - } + }, ) }
@@ -267,7 +267,12 @@ by calling remove_value_for_upgrade. Implementation -
public fun upgrade<T: store>(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) {
+
public fun upgrade<T: store>(
+    self: &mut Versioned,
+    new_version: u64,
+    new_value: T,
+    cap: VersionChangeCap,
+) {
     let VersionChangeCap { versioned_id, old_version } = cap;
     assert!(versioned_id == object::id(self), EInvalidUpgrade);
     assert!(old_version < new_version, EInvalidUpgrade);
diff --git a/crates/sui-framework/packages/sui-framework/sources/address.move b/crates/sui-framework/packages/sui-framework/sources/address.move
index 129908910df05..51d65d7b98b5a 100644
--- a/crates/sui-framework/packages/sui-framework/sources/address.move
+++ b/crates/sui-framework/packages/sui-framework/sources/address.move
@@ -2,85 +2,85 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #[defines_primitive(address)]
-module sui::address {
-    use sui::hex;
-    use std::ascii;
-    use std::bcs;
-    use std::string;
-
-    /// Allows calling `.to_id()` on an address to get its `ID`.
-    public use fun sui::object::id_from_address as address.to_id;
-
-    /// The length of an address, in bytes
-    const LENGTH: u64 = 32;
-
-    // The largest integer that can be represented with 32 bytes: 2^(8*32) - 1
-    const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
-
-    #[allow(unused_const)]
-    /// Error from `from_bytes` when it is supplied too many or too few bytes.
-    const EAddressParseError: u64 = 0;
-
-    /// Convert `a` into a u256 by interpreting `a` as the bytes of a big-endian integer
-    /// (e.g., `to_u256(0x1) == 1`)
-    public native fun to_u256(a: address): u256;
-
-    /// Convert `n` into an address by encoding it as a big-endian integer (e.g., `from_u256(1) = @0x1`)
-    /// Aborts if `n` > `MAX_ADDRESS`
-    public native fun from_u256(n: u256): address;
-
-    /// Convert `bytes` into an address.
-    /// Aborts with `EAddressParseError` if the length of `bytes` is not 32
-    public native fun from_bytes(bytes: vector): address;
-
-    /// Convert `a` into BCS-encoded bytes.
-    public fun to_bytes(a: address): vector {
-        bcs::to_bytes(&a)
-    }
-
-    /// Convert `a` to a hex-encoded ASCII string
-    public fun to_ascii_string(a: address): ascii::String {
-        hex::encode(to_bytes(a)).to_ascii_string()
-    }
-
-    /// Convert `a` to a hex-encoded string
-    public fun to_string(a: address): string::String {
-        to_ascii_string(a).to_string()
-    }
-
-    /// Converts an ASCII string to an address, taking the numerical value for each character. The
-    /// string must be Base16 encoded, and thus exactly 64 characters long.
-    /// For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F"
-    /// will be converted to the address @0xDEADB33F.
-    /// Aborts with `EAddressParseError` if the length of `s` is not 64,
-    /// or if an invalid character is encountered.
-    public fun from_ascii_bytes(bytes: &vector): address {
-        assert!(bytes.length() == 64, EAddressParseError);
-        let mut hex_bytes = vector[];
-        let mut i = 0;
-        while (i < 64) {
-            let hi = hex_char_value(bytes[i]);
-            let lo = hex_char_value(bytes[i+1]);
-            hex_bytes.push_back((hi << 4) | lo);
-            i = i + 2;
-        };
-        from_bytes(hex_bytes)
-    }
-
-    fun hex_char_value(c: u8): u8 {
-        if (c >= 48 && c <= 57) c - 48 // 0-9
-        else if (c >= 65 && c <= 70) c - 55 // A-F
-        else if (c >= 97 && c <= 102) c - 87 // a-f
-        else abort EAddressParseError
-    }
-
-    /// Length of a Sui address in bytes
-    public fun length(): u64 {
-        LENGTH
-    }
-
-    /// Largest possible address
-    public fun max(): u256 {
-        MAX
-    }
+module sui::address;
+
+use std::ascii;
+use std::bcs;
+use std::string;
+use sui::hex;
+
+/// Allows calling `.to_id()` on an address to get its `ID`.
+public use fun sui::object::id_from_address as address.to_id;
+
+/// The length of an address, in bytes
+const LENGTH: u64 = 32;
+
+// The largest integer that can be represented with 32 bytes: 2^(8*32) - 1
+const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
+
+#[allow(unused_const)]
+/// Error from `from_bytes` when it is supplied too many or too few bytes.
+const EAddressParseError: u64 = 0;
+
+/// Convert `a` into a u256 by interpreting `a` as the bytes of a big-endian integer
+/// (e.g., `to_u256(0x1) == 1`)
+public native fun to_u256(a: address): u256;
+
+/// Convert `n` into an address by encoding it as a big-endian integer (e.g., `from_u256(1) = @0x1`)
+/// Aborts if `n` > `MAX_ADDRESS`
+public native fun from_u256(n: u256): address;
+
+/// Convert `bytes` into an address.
+/// Aborts with `EAddressParseError` if the length of `bytes` is not 32
+public native fun from_bytes(bytes: vector): address;
+
+/// Convert `a` into BCS-encoded bytes.
+public fun to_bytes(a: address): vector {
+    bcs::to_bytes(&a)
+}
+
+/// Convert `a` to a hex-encoded ASCII string
+public fun to_ascii_string(a: address): ascii::String {
+    hex::encode(to_bytes(a)).to_ascii_string()
+}
+
+/// Convert `a` to a hex-encoded string
+public fun to_string(a: address): string::String {
+    to_ascii_string(a).to_string()
+}
+
+/// Converts an ASCII string to an address, taking the numerical value for each character. The
+/// string must be Base16 encoded, and thus exactly 64 characters long.
+/// For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F"
+/// will be converted to the address @0xDEADB33F.
+/// Aborts with `EAddressParseError` if the length of `s` is not 64,
+/// or if an invalid character is encountered.
+public fun from_ascii_bytes(bytes: &vector): address {
+    assert!(bytes.length() == 64, EAddressParseError);
+    let mut hex_bytes = vector[];
+    let mut i = 0;
+    while (i < 64) {
+        let hi = hex_char_value(bytes[i]);
+        let lo = hex_char_value(bytes[i+1]);
+        hex_bytes.push_back((hi << 4) | lo);
+        i = i + 2;
+    };
+    from_bytes(hex_bytes)
+}
+
+fun hex_char_value(c: u8): u8 {
+    if (c >= 48 && c <= 57) c - 48 // 0-9
+    else if (c >= 65 && c <= 70) c - 55 // A-F
+    else if (c >= 97 && c <= 102) c - 87 // a-f
+    else abort EAddressParseError
+}
+
+/// Length of a Sui address in bytes
+public fun length(): u64 {
+    LENGTH
+}
+
+/// Largest possible address
+public fun max(): u256 {
+    MAX
 }
diff --git a/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move b/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move
index beca79feea46c..fb39f865ac071 100644
--- a/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move
+++ b/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move
@@ -7,389 +7,377 @@
 //
 // This module is not currently accessible from user contracts, and is used only to record the JWK
 // state to the chain for auditability + restore from snapshot purposes.
-module sui::authenticator_state {
-    use std::string;
-    use sui::dynamic_field;
-    use std::string::{String, utf8};
-
-    /// Sender is not @0x0 the system address.
-    const ENotSystemAddress: u64 = 0;
-    const EWrongInnerVersion: u64 = 1;
-    const EJwksNotSorted: u64 = 2;
-
-    const CurrentVersion: u64 = 1;
-
-    /// Singleton shared object which stores the global authenticator state.
-    /// The actual state is stored in a dynamic field of type AuthenticatorStateInner to support
-    /// future versions of the authenticator state.
-    public struct AuthenticatorState has key {
-        id: UID,
-        version: u64,
-    }
+module sui::authenticator_state;
 
-    public struct AuthenticatorStateInner has store {
-        version: u64,
+use std::string::{Self, String, utf8};
+use sui::dynamic_field;
 
-        /// List of currently active JWKs.
-        active_jwks: vector,
-    }
+/// Sender is not @0x0 the system address.
+const ENotSystemAddress: u64 = 0;
+const EWrongInnerVersion: u64 = 1;
+const EJwksNotSorted: u64 = 2;
 
-    #[allow(unused_field)]
-    /// Must match the JWK struct in fastcrypto-zkp
-    public struct JWK has store, drop, copy {
-        kty: String,
-        e: String,
-        n: String,
-        alg: String,
-    }
+const CurrentVersion: u64 = 1;
 
-    #[allow(unused_field)]
-    /// Must match the JwkId struct in fastcrypto-zkp
-    public struct JwkId has store, drop, copy {
-        iss: String,
-        kid: String,
-    }
+/// Singleton shared object which stores the global authenticator state.
+/// The actual state is stored in a dynamic field of type AuthenticatorStateInner to support
+/// future versions of the authenticator state.
+public struct AuthenticatorState has key {
+    id: UID,
+    version: u64,
+}
 
-    #[allow(unused_field)]
-    public struct ActiveJwk has store, drop, copy {
-        jwk_id: JwkId,
-        jwk: JWK,
-        epoch: u64,
-    }
+public struct AuthenticatorStateInner has store {
+    version: u64,
+    /// List of currently active JWKs.
+    active_jwks: vector,
+}
 
-    #[test_only]
-    public fun create_active_jwk(iss: String, kid: String, kty: String, epoch: u64): ActiveJwk {
-        ActiveJwk {
-            jwk_id: JwkId {
-                iss: iss,
-                kid: kid,
-            },
-            jwk: JWK {
-                kty: kty,
-                e: utf8(b"AQAB"),
-                n: utf8(b"test"),
-                alg: utf8(b"RS256"),
-            },
-            epoch,
-        }
-    }
+#[allow(unused_field)]
+/// Must match the JWK struct in fastcrypto-zkp
+public struct JWK has store, drop, copy {
+    kty: String,
+    e: String,
+    n: String,
+    alg: String,
+}
 
-    fun active_jwk_equal(a: &ActiveJwk, b: &ActiveJwk): bool {
-        // note: epoch is ignored
-        jwk_equal(&a.jwk, &b.jwk) && jwk_id_equal(&a.jwk_id, &b.jwk_id)
+#[allow(unused_field)]
+/// Must match the JwkId struct in fastcrypto-zkp
+public struct JwkId has store, drop, copy {
+    iss: String,
+    kid: String,
+}
+
+#[allow(unused_field)]
+public struct ActiveJwk has store, drop, copy {
+    jwk_id: JwkId,
+    jwk: JWK,
+    epoch: u64,
+}
+
+#[test_only]
+public fun create_active_jwk(iss: String, kid: String, kty: String, epoch: u64): ActiveJwk {
+    ActiveJwk {
+        jwk_id: JwkId {
+            iss: iss,
+            kid: kid,
+        },
+        jwk: JWK {
+            kty: kty,
+            e: utf8(b"AQAB"),
+            n: utf8(b"test"),
+            alg: utf8(b"RS256"),
+        },
+        epoch,
     }
+}
+
+fun active_jwk_equal(a: &ActiveJwk, b: &ActiveJwk): bool {
+    // note: epoch is ignored
+    jwk_equal(&a.jwk, &b.jwk) && jwk_id_equal(&a.jwk_id, &b.jwk_id)
+}
 
-    fun jwk_equal(a: &JWK, b: &JWK): bool {
-        (&a.kty == &b.kty) &&
+fun jwk_equal(a: &JWK, b: &JWK): bool {
+    (&a.kty == &b.kty) &&
            (&a.e == &b.e) &&
            (&a.n == &b.n) &&
            (&a.alg == &b.alg)
-    }
+}
 
-    fun jwk_id_equal(a: &JwkId, b: &JwkId): bool {
-        (&a.iss == &b.iss) && (&a.kid == &b.kid)
-    }
+fun jwk_id_equal(a: &JwkId, b: &JwkId): bool {
+    (&a.iss == &b.iss) && (&a.kid == &b.kid)
+}
 
-    // Compare the underlying byte arrays lexicographically. Since the strings may be utf8 this
-    // ordering is not necessarily the same as the string ordering, but we just need some
-    // canonical that is cheap to compute.
-    fun string_bytes_lt(a: &String, b: &String): bool {
-        let a_bytes = a.as_bytes();
-        let b_bytes = b.as_bytes();
-
-        if (a_bytes.length() < b_bytes.length()) {
-            true
-        } else if (a_bytes.length() > b_bytes.length()) {
-            false
-        } else {
-            let mut i = 0;
-            while (i < a_bytes.length()) {
-                let a_byte = a_bytes[i];
-                let b_byte = b_bytes[i];
-                if (a_byte < b_byte) {
-                    return true
-                } else if (a_byte > b_byte) {
-                    return false
-                };
-                i = i + 1;
+// Compare the underlying byte arrays lexicographically. Since the strings may be utf8 this
+// ordering is not necessarily the same as the string ordering, but we just need some
+// canonical that is cheap to compute.
+fun string_bytes_lt(a: &String, b: &String): bool {
+    let a_bytes = a.as_bytes();
+    let b_bytes = b.as_bytes();
+
+    if (a_bytes.length() < b_bytes.length()) {
+        true
+    } else if (a_bytes.length() > b_bytes.length()) {
+        false
+    } else {
+        let mut i = 0;
+        while (i < a_bytes.length()) {
+            let a_byte = a_bytes[i];
+            let b_byte = b_bytes[i];
+            if (a_byte < b_byte) {
+                return true
+            } else if (a_byte > b_byte) {
+                return false
             };
-            // all bytes are equal
-            false
-        }
-    }
-
-    fun jwk_lt(a: &ActiveJwk, b: &ActiveJwk): bool {
-        // note: epoch is ignored
-        if (&a.jwk_id.iss != &b.jwk_id.iss) {
-            return string_bytes_lt(&a.jwk_id.iss, &b.jwk_id.iss)
-        };
-        if (&a.jwk_id.kid != &b.jwk_id.kid) {
-            return string_bytes_lt(&a.jwk_id.kid, &b.jwk_id.kid)
-        };
-        if (&a.jwk.kty != &b.jwk.kty) {
-            return string_bytes_lt(&a.jwk.kty, &b.jwk.kty)
-        };
-        if (&a.jwk.e != &b.jwk.e) {
-            return string_bytes_lt(&a.jwk.e, &b.jwk.e)
-        };
-        if (&a.jwk.n != &b.jwk.n) {
-            return string_bytes_lt(&a.jwk.n, &b.jwk.n)
+            i = i + 1;
         };
-        string_bytes_lt(&a.jwk.alg, &b.jwk.alg)
+        // all bytes are equal
+        false
     }
+}
 
-    #[allow(unused_function)]
-    /// Create and share the AuthenticatorState object. This function is call exactly once, when
-    /// the authenticator state object is first created.
-    /// Can only be called by genesis or change_epoch transactions.
-    fun create(ctx: &TxContext) {
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+fun jwk_lt(a: &ActiveJwk, b: &ActiveJwk): bool {
+    // note: epoch is ignored
+    if (&a.jwk_id.iss != &b.jwk_id.iss) {
+        return string_bytes_lt(&a.jwk_id.iss, &b.jwk_id.iss)
+    };
+    if (&a.jwk_id.kid != &b.jwk_id.kid) {
+        return string_bytes_lt(&a.jwk_id.kid, &b.jwk_id.kid)
+    };
+    if (&a.jwk.kty != &b.jwk.kty) {
+        return string_bytes_lt(&a.jwk.kty, &b.jwk.kty)
+    };
+    if (&a.jwk.e != &b.jwk.e) {
+        return string_bytes_lt(&a.jwk.e, &b.jwk.e)
+    };
+    if (&a.jwk.n != &b.jwk.n) {
+        return string_bytes_lt(&a.jwk.n, &b.jwk.n)
+    };
+    string_bytes_lt(&a.jwk.alg, &b.jwk.alg)
+}
 
-        let version = CurrentVersion;
+#[allow(unused_function)]
+/// Create and share the AuthenticatorState object. This function is call exactly once, when
+/// the authenticator state object is first created.
+/// Can only be called by genesis or change_epoch transactions.
+fun create(ctx: &TxContext) {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
 
-        let inner = AuthenticatorStateInner {
-            version,
-            active_jwks: vector[],
-        };
+    let version = CurrentVersion;
 
-        let mut self = AuthenticatorState {
-            id: object::authenticator_state(),
-            version,
-        };
+    let inner = AuthenticatorStateInner {
+        version,
+        active_jwks: vector[],
+    };
 
-        dynamic_field::add(&mut self.id, version, inner);
-        transfer::share_object(self);
-    }
+    let mut self = AuthenticatorState {
+        id: object::authenticator_state(),
+        version,
+    };
 
-    fun load_inner_mut(
-        self: &mut AuthenticatorState,
-    ): &mut AuthenticatorStateInner {
-        let version = self.version;
+    dynamic_field::add(&mut self.id, version, inner);
+    transfer::share_object(self);
+}
 
-        // replace this with a lazy update function when we add a new version of the inner object.
-        assert!(version == CurrentVersion, EWrongInnerVersion);
+fun load_inner_mut(self: &mut AuthenticatorState): &mut AuthenticatorStateInner {
+    let version = self.version;
 
-        let inner: &mut AuthenticatorStateInner = dynamic_field::borrow_mut(&mut self.id, self.version);
+    // replace this with a lazy update function when we add a new version of the inner object.
+    assert!(version == CurrentVersion, EWrongInnerVersion);
 
-        assert!(inner.version == version, EWrongInnerVersion);
-        inner
-    }
+    let inner: &mut AuthenticatorStateInner = dynamic_field::borrow_mut(&mut self.id, self.version);
 
-    fun load_inner(
-        self: &AuthenticatorState,
-    ): &AuthenticatorStateInner {
-        let version = self.version;
+    assert!(inner.version == version, EWrongInnerVersion);
+    inner
+}
 
-        // replace this with a lazy update function when we add a new version of the inner object.
-        assert!(version == CurrentVersion, EWrongInnerVersion);
+fun load_inner(self: &AuthenticatorState): &AuthenticatorStateInner {
+    let version = self.version;
 
-        let inner: &AuthenticatorStateInner = dynamic_field::borrow(&self.id, self.version);
+    // replace this with a lazy update function when we add a new version of the inner object.
+    assert!(version == CurrentVersion, EWrongInnerVersion);
 
-        assert!(inner.version == version, EWrongInnerVersion);
-        inner
-    }
+    let inner: &AuthenticatorStateInner = dynamic_field::borrow(&self.id, self.version);
 
-    fun check_sorted(new_active_jwks: &vector) {
-        let mut i = 0;
-        while (i < new_active_jwks.length() - 1) {
-            let a = &new_active_jwks[i];
-            let b = &new_active_jwks[i + 1];
-            assert!(jwk_lt(a, b), EJwksNotSorted);
-            i = i + 1;
-        };
-    }
+    assert!(inner.version == version, EWrongInnerVersion);
+    inner
+}
 
-    #[allow(unused_function)]
-    /// Record a new set of active_jwks. Called when executing the AuthenticatorStateUpdate system
-    /// transaction. The new input vector must be sorted and must not contain duplicates.
-    /// If a new JWK is already present, but with a previous epoch, then the epoch is updated to
-    /// indicate that the JWK has been validated in the current epoch and should not be expired.
-    fun update_authenticator_state(
-        self: &mut AuthenticatorState,
-        new_active_jwks: vector,
-        ctx: &TxContext,
-    ) {
-        // Validator will make a special system call with sender set as 0x0.
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
-
-        check_sorted(&new_active_jwks);
-        let new_active_jwks = deduplicate(new_active_jwks);
-
-        let inner = self.load_inner_mut();
-
-        let mut res = vector[];
-        let mut i = 0;
-        let mut j = 0;
-        let active_jwks_len = inner.active_jwks.length();
-        let new_active_jwks_len = new_active_jwks.length();
-
-        while (i < active_jwks_len && j < new_active_jwks_len) {
-            let old_jwk = &inner.active_jwks[i];
-            let new_jwk = &new_active_jwks[j];
-
-            // when they are equal, push only one, but use the max epoch of the two
-            if (active_jwk_equal(old_jwk, new_jwk)) {
-                let mut jwk = *old_jwk;
-                jwk.epoch = old_jwk.epoch.max(new_jwk.epoch);
-                res.push_back(jwk);
-                i = i + 1;
-                j = j + 1;
-            } else if (jwk_id_equal(&old_jwk.jwk_id, &new_jwk.jwk_id)) {
-                // if only jwk_id is equal, then the key has changed. Providers should not send
-                // JWKs like this, but if they do, we must ignore the new JWK to avoid having a
-                // liveness / forking issues
-                res.push_back(*old_jwk);
-                i = i + 1;
-                j = j + 1;
-            } else if (jwk_lt(old_jwk, new_jwk)) {
-                res.push_back(*old_jwk);
-                i = i + 1;
-            } else {
-                res.push_back(*new_jwk);
-                j = j + 1;
-            }
-        };
+fun check_sorted(new_active_jwks: &vector) {
+    let mut i = 0;
+    while (i < new_active_jwks.length() - 1) {
+        let a = &new_active_jwks[i];
+        let b = &new_active_jwks[i + 1];
+        assert!(jwk_lt(a, b), EJwksNotSorted);
+        i = i + 1;
+    };
+}
 
-        while (i < active_jwks_len) {
-            res.push_back(inner.active_jwks[i]);
+#[allow(unused_function)]
+/// Record a new set of active_jwks. Called when executing the AuthenticatorStateUpdate system
+/// transaction. The new input vector must be sorted and must not contain duplicates.
+/// If a new JWK is already present, but with a previous epoch, then the epoch is updated to
+/// indicate that the JWK has been validated in the current epoch and should not be expired.
+fun update_authenticator_state(
+    self: &mut AuthenticatorState,
+    new_active_jwks: vector,
+    ctx: &TxContext,
+) {
+    // Validator will make a special system call with sender set as 0x0.
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    check_sorted(&new_active_jwks);
+    let new_active_jwks = deduplicate(new_active_jwks);
+
+    let inner = self.load_inner_mut();
+
+    let mut res = vector[];
+    let mut i = 0;
+    let mut j = 0;
+    let active_jwks_len = inner.active_jwks.length();
+    let new_active_jwks_len = new_active_jwks.length();
+
+    while (i < active_jwks_len && j < new_active_jwks_len) {
+        let old_jwk = &inner.active_jwks[i];
+        let new_jwk = &new_active_jwks[j];
+
+        // when they are equal, push only one, but use the max epoch of the two
+        if (active_jwk_equal(old_jwk, new_jwk)) {
+            let mut jwk = *old_jwk;
+            jwk.epoch = old_jwk.epoch.max(new_jwk.epoch);
+            res.push_back(jwk);
             i = i + 1;
-        };
-        while (j < new_active_jwks_len) {
-            res.push_back(new_active_jwks[j]);
             j = j + 1;
-        };
-
-        inner.active_jwks = res;
-    }
-
-    fun deduplicate(jwks: vector): vector {
-        let mut res = vector[];
-        let mut i = 0;
-        let mut prev: Option = option::none();
-        while (i < jwks.length()) {
-            let jwk = &jwks[i];
-            if (prev.is_none()) {
-                prev.fill(jwk.jwk_id);
-            } else if (jwk_id_equal(prev.borrow(), &jwk.jwk_id)) {
-                // skip duplicate jwks in input
-                i = i + 1;
-                continue
-            } else {
-                *prev.borrow_mut() = jwk.jwk_id;
-            };
-            res.push_back(*jwk);
+        } else if (jwk_id_equal(&old_jwk.jwk_id, &new_jwk.jwk_id)) {
+            // if only jwk_id is equal, then the key has changed. Providers should not send
+            // JWKs like this, but if they do, we must ignore the new JWK to avoid having a
+            // liveness / forking issues
+            res.push_back(*old_jwk);
             i = i + 1;
-        };
-        res
-    }
-
-    #[allow(unused_function)]
-    // Called directly by rust when constructing the ChangeEpoch transaction.
-    fun expire_jwks(
-        self: &mut AuthenticatorState,
-        // any jwk below this epoch is not retained
-        min_epoch: u64,
-        ctx: &TxContext) {
-        // This will only be called by sui_system::advance_epoch
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
-
-        let inner = load_inner_mut(self);
-
-        let len = inner.active_jwks.length();
-
-        // first we count how many jwks from each issuer are above the min_epoch
-        // and store the counts in a vector that parallels the (sorted) active_jwks vector
-        let mut issuer_max_epochs = vector[];
-        let mut i = 0;
-        let mut prev_issuer: Option = option::none();
+            j = j + 1;
+        } else if (jwk_lt(old_jwk, new_jwk)) {
+            res.push_back(*old_jwk);
+            i = i + 1;
+        } else {
+            res.push_back(*new_jwk);
+            j = j + 1;
+        }
+    };
+
+    while (i < active_jwks_len) {
+        res.push_back(inner.active_jwks[i]);
+        i = i + 1;
+    };
+    while (j < new_active_jwks_len) {
+        res.push_back(new_active_jwks[j]);
+        j = j + 1;
+    };
+
+    inner.active_jwks = res;
+}
 
-        while (i < len) {
-            let cur = &inner.active_jwks[i];
-            let cur_iss = &cur.jwk_id.iss;
-            if (prev_issuer.is_none()) {
-                prev_issuer.fill(*cur_iss);
-                issuer_max_epochs.push_back(cur.epoch);
-            } else {
-                if (cur_iss == prev_issuer.borrow()) {
-                    let back = issuer_max_epochs.length() - 1;
-                    let prev_max_epoch = &mut issuer_max_epochs[back];
-                    *prev_max_epoch = (*prev_max_epoch).max(cur.epoch);
-                } else {
-                    *prev_issuer.borrow_mut() = *cur_iss;
-                    issuer_max_epochs.push_back(cur.epoch);
-                }
-            };
+fun deduplicate(jwks: vector): vector {
+    let mut res = vector[];
+    let mut i = 0;
+    let mut prev: Option = option::none();
+    while (i < jwks.length()) {
+        let jwk = &jwks[i];
+        if (prev.is_none()) {
+            prev.fill(jwk.jwk_id);
+        } else if (jwk_id_equal(prev.borrow(), &jwk.jwk_id)) {
+            // skip duplicate jwks in input
             i = i + 1;
+            continue
+        } else {
+            *prev.borrow_mut() = jwk.jwk_id;
         };
+        res.push_back(*jwk);
+        i = i + 1;
+    };
+    res
+}
 
-        // Now, filter out any JWKs that are below the min_epoch, unless that issuer has no
-        // JWKs >= the min_epoch, in which case we keep all of them.
-        let mut new_active_jwks: vector = vector[];
-        let mut prev_issuer: Option = option::none();
-        let mut i = 0;
-        let mut j = 0;
-        while (i < len) {
-            let jwk = &inner.active_jwks[i];
-            let cur_iss = &jwk.jwk_id.iss;
-
-            if (prev_issuer.is_none()) {
-                prev_issuer.fill(*cur_iss);
-            } else if (cur_iss != prev_issuer.borrow()) {
+#[allow(unused_function)]
+// Called directly by rust when constructing the ChangeEpoch transaction.
+fun expire_jwks(
+    self: &mut AuthenticatorState,
+    // any jwk below this epoch is not retained
+    min_epoch: u64,
+    ctx: &TxContext,
+) {
+    // This will only be called by sui_system::advance_epoch
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    let inner = load_inner_mut(self);
+
+    let len = inner.active_jwks.length();
+
+    // first we count how many jwks from each issuer are above the min_epoch
+    // and store the counts in a vector that parallels the (sorted) active_jwks vector
+    let mut issuer_max_epochs = vector[];
+    let mut i = 0;
+    let mut prev_issuer: Option = option::none();
+
+    while (i < len) {
+        let cur = &inner.active_jwks[i];
+        let cur_iss = &cur.jwk_id.iss;
+        if (prev_issuer.is_none()) {
+            prev_issuer.fill(*cur_iss);
+            issuer_max_epochs.push_back(cur.epoch);
+        } else {
+            if (cur_iss == prev_issuer.borrow()) {
+                let back = issuer_max_epochs.length() - 1;
+                let prev_max_epoch = &mut issuer_max_epochs[back];
+                *prev_max_epoch = (*prev_max_epoch).max(cur.epoch);
+            } else {
                 *prev_issuer.borrow_mut() = *cur_iss;
-                j = j + 1;
-            };
+                issuer_max_epochs.push_back(cur.epoch);
+            }
+        };
+        i = i + 1;
+    };
+
+    // Now, filter out any JWKs that are below the min_epoch, unless that issuer has no
+    // JWKs >= the min_epoch, in which case we keep all of them.
+    let mut new_active_jwks: vector = vector[];
+    let mut prev_issuer: Option = option::none();
+    let mut i = 0;
+    let mut j = 0;
+    while (i < len) {
+        let jwk = &inner.active_jwks[i];
+        let cur_iss = &jwk.jwk_id.iss;
+
+        if (prev_issuer.is_none()) {
+            prev_issuer.fill(*cur_iss);
+        } else if (cur_iss != prev_issuer.borrow()) {
+            *prev_issuer.borrow_mut() = *cur_iss;
+            j = j + 1;
+        };
 
-            let max_epoch_for_iss = &issuer_max_epochs[j];
+        let max_epoch_for_iss = &issuer_max_epochs[j];
 
-            // TODO: if the iss for this jwk has *no* jwks that meet the minimum epoch,
-            // then expire nothing.
-            if (*max_epoch_for_iss < min_epoch || jwk.epoch >= min_epoch) {
-                new_active_jwks.push_back(*jwk);
-            };
-            i = i + 1;
+        // TODO: if the iss for this jwk has *no* jwks that meet the minimum epoch,
+        // then expire nothing.
+        if (*max_epoch_for_iss < min_epoch || jwk.epoch >= min_epoch) {
+            new_active_jwks.push_back(*jwk);
         };
-        inner.active_jwks = new_active_jwks;
-    }
+        i = i + 1;
+    };
+    inner.active_jwks = new_active_jwks;
+}
 
-    #[allow(unused_function)]
-    /// Get the current active_jwks. Called when the node starts up in order to load the current
-    /// JWK state from the chain.
-    fun get_active_jwks(
-        self: &AuthenticatorState,
-        ctx: &TxContext,
-    ): vector {
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
-        self.load_inner().active_jwks
-    }
+#[allow(unused_function)]
+/// Get the current active_jwks. Called when the node starts up in order to load the current
+/// JWK state from the chain.
+fun get_active_jwks(self: &AuthenticatorState, ctx: &TxContext): vector {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    self.load_inner().active_jwks
+}
 
-    #[test_only]
-    public fun create_for_testing(ctx: &TxContext) {
-        create(ctx);
-    }
+#[test_only]
+public fun create_for_testing(ctx: &TxContext) {
+    create(ctx);
+}
 
-    #[test_only]
-    public fun update_authenticator_state_for_testing(
-        self: &mut AuthenticatorState,
-        new_active_jwks: vector,
-        ctx: &TxContext,
-    ) {
-        self.update_authenticator_state(new_active_jwks, ctx);
-    }
+#[test_only]
+public fun update_authenticator_state_for_testing(
+    self: &mut AuthenticatorState,
+    new_active_jwks: vector,
+    ctx: &TxContext,
+) {
+    self.update_authenticator_state(new_active_jwks, ctx);
+}
 
-    #[test_only]
-    public fun expire_jwks_for_testing(
-        self: &mut AuthenticatorState,
-        min_epoch: u64,
-        ctx: &TxContext,
-    ) {
-        self.expire_jwks(min_epoch, ctx);
-    }
+#[test_only]
+public fun expire_jwks_for_testing(self: &mut AuthenticatorState, min_epoch: u64, ctx: &TxContext) {
+    self.expire_jwks(min_epoch, ctx);
+}
 
-    #[test_only]
-    public fun get_active_jwks_for_testing(
-        self: &AuthenticatorState,
-        ctx: &TxContext,
-    ): vector {
-        self.get_active_jwks(ctx)
-    }
+#[test_only]
+public fun get_active_jwks_for_testing(
+    self: &AuthenticatorState,
+    ctx: &TxContext,
+): vector {
+    self.get_active_jwks(ctx)
 }
diff --git a/crates/sui-framework/packages/sui-framework/sources/bcs.move b/crates/sui-framework/packages/sui-framework/sources/bcs.move
index 66ecb2b2e6b40..83f69cdc0c554 100644
--- a/crates/sui-framework/packages/sui-framework/sources/bcs.move
+++ b/crates/sui-framework/packages/sui-framework/sources/bcs.move
@@ -32,237 +32,237 @@
 ///     (u8_value, u64_value, leftovers)
 /// }
 /// ```
-module sui::bcs {
-    use sui::address;
-    use std::bcs;
-
-    /// For when bytes length is less than required for deserialization.
-    const EOutOfRange: u64 = 0;
-    /// For when the boolean value different than `0` or `1`.
-    const ENotBool: u64 = 1;
-    /// For when ULEB byte is out of range (or not found).
-    const ELenOutOfRange: u64 = 2;
-
-    /// A helper struct that saves resources on operations. For better
-    /// vector performance, it stores reversed bytes of the BCS and
-    /// enables use of `vector::pop_back`.
-    public struct BCS has store, copy, drop {
-        bytes: vector
-    }
-
-    /// Get BCS serialized bytes for any value.
-    /// Re-exports stdlib `bcs::to_bytes`.
-    public fun to_bytes(value: &T): vector {
-        bcs::to_bytes(value)
-    }
-
-    /// Creates a new instance of BCS wrapper that holds inversed
-    /// bytes for better performance.
-    public fun new(mut bytes: vector): BCS {
-        bytes.reverse();
-        BCS { bytes }
-    }
-
-    /// Unpack the `BCS` struct returning the leftover bytes.
-    /// Useful for passing the data further after partial deserialization.
-    public fun into_remainder_bytes(bcs: BCS): vector {
-        let BCS { mut bytes } = bcs;
-        bytes.reverse();
-        bytes
-    }
-
-    /// Read address from the bcs-serialized bytes.
-    public fun peel_address(bcs: &mut BCS): address {
-        assert!(bcs.bytes.length() >= address::length(), EOutOfRange);
-        let (mut addr_bytes, mut i) = (vector[], 0);
-        while (i < address::length()) {
-            addr_bytes.push_back(bcs.bytes.pop_back());
-            i = i + 1;
-        };
-        address::from_bytes(addr_bytes)
-    }
-
-    /// Read a `bool` value from bcs-serialized bytes.
-    public fun peel_bool(bcs: &mut BCS): bool {
-        let value = bcs.peel_u8();
-        if (value == 0) false
-        else if (value == 1) true
-        else abort ENotBool
-    }
-
-    /// Read `u8` value from bcs-serialized bytes.
-    public fun peel_u8(bcs: &mut BCS): u8 {
-        assert!(bcs.bytes.length() >= 1, EOutOfRange);
-        bcs.bytes.pop_back()
-    }
-
-    macro fun peel_num<$I, $T>($bcs: &mut BCS, $len: u64, $bits: $I): $T {
-        let bcs = $bcs;
-        assert!(bcs.bytes.length() >= $len, EOutOfRange);
-
-        let mut value: $T = 0;
-        let mut i: $I = 0;
-        let bits = $bits;
-        while (i < bits) {
-            let byte = bcs.bytes.pop_back() as $T;
-            value = value + (byte << (i as u8));
-            i = i + 8;
-        };
-
-        value
-    }
-
-    /// Read `u16` value from bcs-serialized bytes.
-    public fun peel_u16(bcs: &mut BCS): u16 {
-        bcs.peel_num!(2, 16u8)
-    }
-
-    /// Read `u32` value from bcs-serialized bytes.
-    public fun peel_u32(bcs: &mut BCS): u32 {
-        bcs.peel_num!(4, 32u8)
-    }
-
-    /// Read `u64` value from bcs-serialized bytes.
-    public fun peel_u64(bcs: &mut BCS): u64 {
-        bcs.peel_num!(8, 64u8)
-    }
-
-    /// Read `u128` value from bcs-serialized bytes.
-    public fun peel_u128(bcs: &mut BCS): u128 {
-        bcs.peel_num!(16, 128u8)
-    }
-
-    /// Read `u256` value from bcs-serialized bytes.
-    public fun peel_u256(bcs: &mut BCS): u256 {
-        bcs.peel_num!(32, 256u16)
-    }
-
-    // === Vector ===
-
-    /// Read ULEB bytes expecting a vector length. Result should
-    /// then be used to perform `peel_*` operation LEN times.
-    ///
-    /// In BCS `vector` length is implemented with ULEB128;
-    /// See more here: https://en.wikipedia.org/wiki/LEB128
-    public fun peel_vec_length(bcs: &mut BCS): u64 {
-        let (mut total, mut shift, mut len) = (0u64, 0, 0);
-        loop {
-            assert!(len <= 4, ELenOutOfRange);
-            let byte = bcs.bytes.pop_back() as u64;
-            len = len + 1;
-            total = total | ((byte & 0x7f) << shift);
-            if ((byte & 0x80) == 0) break;
-            shift = shift + 7;
-        };
-        total
-    }
-
-    /// Peel `vector<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the
-    /// functionality of peeling each value.
-    public macro fun peel_vec<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): vector<$T> {
-        let bcs = $bcs;
-        let len = bcs.peel_vec_length();
-        let mut i = 0;
-        let mut res = vector[];
-        while (i < len) {
-            res.push_back($peel(bcs));
-            i = i + 1;
-        };
-        res
-    }
-
-    /// Peel a vector of `address` from serialized bytes.
-    public fun peel_vec_address(bcs: &mut BCS): vector
{ - bcs.peel_vec!(|bcs| bcs.peel_address()) - } - - /// Peel a vector of `address` from serialized bytes. - public fun peel_vec_bool(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_bool()) - } - - /// Peel a vector of `u8` (eg string) from serialized bytes. - public fun peel_vec_u8(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u8()) - } - - /// Peel a `vector>` (eg vec of string) from serialized bytes. - public fun peel_vec_vec_u8(bcs: &mut BCS): vector> { - bcs.peel_vec!(|bcs| bcs.peel_vec_u8()) - } - - /// Peel a vector of `u16` from serialized bytes. - public fun peel_vec_u16(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u16()) - } - - /// Peel a vector of `u32` from serialized bytes. - public fun peel_vec_u32(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u32()) - } - - /// Peel a vector of `u64` from serialized bytes. - public fun peel_vec_u64(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u64()) - } - - /// Peel a vector of `u128` from serialized bytes. - public fun peel_vec_u128(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u128()) - } - - /// Peel a vector of `u256` from serialized bytes. - public fun peel_vec_u256(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u256()) - } - - // === Option === - - /// Peel `Option<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the - /// functionality of peeling the inner value. - public macro fun peel_option<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): Option<$T> { - let bcs = $bcs; - if (bcs.peel_bool())option::some($peel(bcs)) - else option::none() - } - - /// Peel `Option
` from serialized bytes. - public fun peel_option_address(bcs: &mut BCS): Option
{ - bcs.peel_option!(|bcs| bcs.peel_address()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_bool(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_bool()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u8(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u8()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u16(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u16()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u32(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u32()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u64(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u64()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u128(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u128()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u256(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u256()) - } +module sui::bcs; + +use std::bcs; +use sui::address; + +/// For when bytes length is less than required for deserialization. +const EOutOfRange: u64 = 0; +/// For when the boolean value different than `0` or `1`. +const ENotBool: u64 = 1; +/// For when ULEB byte is out of range (or not found). +const ELenOutOfRange: u64 = 2; + +/// A helper struct that saves resources on operations. For better +/// vector performance, it stores reversed bytes of the BCS and +/// enables use of `vector::pop_back`. +public struct BCS has store, copy, drop { + bytes: vector, +} + +/// Get BCS serialized bytes for any value. +/// Re-exports stdlib `bcs::to_bytes`. +public fun to_bytes(value: &T): vector { + bcs::to_bytes(value) +} + +/// Creates a new instance of BCS wrapper that holds inversed +/// bytes for better performance. +public fun new(mut bytes: vector): BCS { + bytes.reverse(); + BCS { bytes } +} + +/// Unpack the `BCS` struct returning the leftover bytes. +/// Useful for passing the data further after partial deserialization. +public fun into_remainder_bytes(bcs: BCS): vector { + let BCS { mut bytes } = bcs; + bytes.reverse(); + bytes +} + +/// Read address from the bcs-serialized bytes. +public fun peel_address(bcs: &mut BCS): address { + assert!(bcs.bytes.length() >= address::length(), EOutOfRange); + let (mut addr_bytes, mut i) = (vector[], 0); + while (i < address::length()) { + addr_bytes.push_back(bcs.bytes.pop_back()); + i = i + 1; + }; + address::from_bytes(addr_bytes) +} + +/// Read a `bool` value from bcs-serialized bytes. +public fun peel_bool(bcs: &mut BCS): bool { + let value = bcs.peel_u8(); + if (value == 0) false + else if (value == 1) true + else abort ENotBool +} + +/// Read `u8` value from bcs-serialized bytes. +public fun peel_u8(bcs: &mut BCS): u8 { + assert!(bcs.bytes.length() >= 1, EOutOfRange); + bcs.bytes.pop_back() +} + +macro fun peel_num<$I, $T>($bcs: &mut BCS, $len: u64, $bits: $I): $T { + let bcs = $bcs; + assert!(bcs.bytes.length() >= $len, EOutOfRange); + + let mut value: $T = 0; + let mut i: $I = 0; + let bits = $bits; + while (i < bits) { + let byte = bcs.bytes.pop_back() as $T; + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value +} + +/// Read `u16` value from bcs-serialized bytes. +public fun peel_u16(bcs: &mut BCS): u16 { + bcs.peel_num!(2, 16u8) +} + +/// Read `u32` value from bcs-serialized bytes. +public fun peel_u32(bcs: &mut BCS): u32 { + bcs.peel_num!(4, 32u8) +} + +/// Read `u64` value from bcs-serialized bytes. +public fun peel_u64(bcs: &mut BCS): u64 { + bcs.peel_num!(8, 64u8) +} + +/// Read `u128` value from bcs-serialized bytes. +public fun peel_u128(bcs: &mut BCS): u128 { + bcs.peel_num!(16, 128u8) +} + +/// Read `u256` value from bcs-serialized bytes. +public fun peel_u256(bcs: &mut BCS): u256 { + bcs.peel_num!(32, 256u16) +} + +// === Vector === + +/// Read ULEB bytes expecting a vector length. Result should +/// then be used to perform `peel_*` operation LEN times. +/// +/// In BCS `vector` length is implemented with ULEB128; +/// See more here: https://en.wikipedia.org/wiki/LEB128 +public fun peel_vec_length(bcs: &mut BCS): u64 { + let (mut total, mut shift, mut len) = (0u64, 0, 0); + loop { + assert!(len <= 4, ELenOutOfRange); + let byte = bcs.bytes.pop_back() as u64; + len = len + 1; + total = total | ((byte & 0x7f) << shift); + if ((byte & 0x80) == 0) break; + shift = shift + 7; + }; + total +} + +/// Peel `vector<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the +/// functionality of peeling each value. +public macro fun peel_vec<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): vector<$T> { + let bcs = $bcs; + let len = bcs.peel_vec_length(); + let mut i = 0; + let mut res = vector[]; + while (i < len) { + res.push_back($peel(bcs)); + i = i + 1; + }; + res +} + +/// Peel a vector of `address` from serialized bytes. +public fun peel_vec_address(bcs: &mut BCS): vector
{ + bcs.peel_vec!(|bcs| bcs.peel_address()) +} + +/// Peel a vector of `address` from serialized bytes. +public fun peel_vec_bool(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_bool()) +} + +/// Peel a vector of `u8` (eg string) from serialized bytes. +public fun peel_vec_u8(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u8()) +} + +/// Peel a `vector>` (eg vec of string) from serialized bytes. +public fun peel_vec_vec_u8(bcs: &mut BCS): vector> { + bcs.peel_vec!(|bcs| bcs.peel_vec_u8()) +} + +/// Peel a vector of `u16` from serialized bytes. +public fun peel_vec_u16(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u16()) +} + +/// Peel a vector of `u32` from serialized bytes. +public fun peel_vec_u32(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u32()) +} + +/// Peel a vector of `u64` from serialized bytes. +public fun peel_vec_u64(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u64()) +} + +/// Peel a vector of `u128` from serialized bytes. +public fun peel_vec_u128(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u128()) +} + +/// Peel a vector of `u256` from serialized bytes. +public fun peel_vec_u256(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u256()) +} + +// === Option === + +/// Peel `Option<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the +/// functionality of peeling the inner value. +public macro fun peel_option<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): Option<$T> { + let bcs = $bcs; + if (bcs.peel_bool()) option::some($peel(bcs)) + else option::none() +} + +/// Peel `Option
` from serialized bytes. +public fun peel_option_address(bcs: &mut BCS): Option
{ + bcs.peel_option!(|bcs| bcs.peel_address()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_bool(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_bool()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u8(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u8()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u16(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u16()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u32(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u32()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u64(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u64()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u128(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u128()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u256(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u256()) } diff --git a/crates/sui-framework/packages/sui-framework/sources/borrow.move b/crates/sui-framework/packages/sui-framework/sources/borrow.move index 55eb1e1ae5bd3..483a6aab4912a 100644 --- a/crates/sui-framework/packages/sui-framework/sources/borrow.move +++ b/crates/sui-framework/packages/sui-framework/sources/borrow.move @@ -6,113 +6,115 @@ /// With Programmable transactions, it is possible to borrow a value within /// a transaction, use it and put back in the end. Hot-potato `Borrow` makes /// sure the object is returned and was not swapped for another one. -module sui::borrow { +module sui::borrow; - /// The `Borrow` does not match the `Referent`. - const EWrongBorrow: u64 = 0; - /// An attempt to swap the `Referent.value` with another object of the same type. - const EWrongValue: u64 = 1; +/// The `Borrow` does not match the `Referent`. +const EWrongBorrow: u64 = 0; +/// An attempt to swap the `Referent.value` with another object of the same type. +const EWrongValue: u64 = 1; - /// An object wrapping a `T` and providing the borrow API. - public struct Referent has store { - id: address, - value: Option - } +/// An object wrapping a `T` and providing the borrow API. +public struct Referent has store { + id: address, + value: Option, +} - /// A hot potato making sure the object is put back once borrowed. - public struct Borrow { ref: address, obj: ID } +/// A hot potato making sure the object is put back once borrowed. +public struct Borrow { ref: address, obj: ID } - /// Create a new `Referent` struct - public fun new(value: T, ctx: &mut TxContext): Referent { - Referent { - id: tx_context::fresh_object_address(ctx), - value: option::some(value) - } +/// Create a new `Referent` struct +public fun new(value: T, ctx: &mut TxContext): Referent { + Referent { + id: tx_context::fresh_object_address(ctx), + value: option::some(value), } +} - /// Borrow the `T` from the `Referent` receiving the `T` and a `Borrow` - /// hot potato. - public fun borrow(self: &mut Referent): (T, Borrow) { - let value = self.value.extract(); - let id = object::id(&value); +/// Borrow the `T` from the `Referent` receiving the `T` and a `Borrow` +/// hot potato. +public fun borrow(self: &mut Referent): (T, Borrow) { + let value = self.value.extract(); + let id = object::id(&value); - (value, Borrow { + ( + value, + Borrow { ref: self.id, - obj: id - }) - } + obj: id, + }, + ) +} - /// Put an object and the `Borrow` hot potato back. - public fun put_back(self: &mut Referent, value: T, borrow: Borrow) { - let Borrow { ref, obj } = borrow; +/// Put an object and the `Borrow` hot potato back. +public fun put_back(self: &mut Referent, value: T, borrow: Borrow) { + let Borrow { ref, obj } = borrow; - assert!(object::id(&value) == obj, EWrongValue); - assert!(self.id == ref, EWrongBorrow); - self.value.fill(value); - } + assert!(object::id(&value) == obj, EWrongValue); + assert!(self.id == ref, EWrongBorrow); + self.value.fill(value); +} - /// Unpack the `Referent` struct and return the value. - public fun destroy(self: Referent): T { - let Referent { id: _, value } = self; - value.destroy_some() - } +/// Unpack the `Referent` struct and return the value. +public fun destroy(self: Referent): T { + let Referent { id: _, value } = self; + value.destroy_some() +} - #[test_only] - public struct Test has key, store { - id: object::UID - } +#[test_only] +public struct Test has key, store { + id: object::UID, +} - #[test] - fun test_borrow() { - let ctx = &mut sui::tx_context::dummy(); - let mut ref = new(Test { id: object::new(ctx) }, ctx); +#[test] +fun test_borrow() { + let ctx = &mut sui::tx_context::dummy(); + let mut ref = new(Test { id: object::new(ctx) }, ctx); - let (value, borrow) = borrow(&mut ref); - put_back(&mut ref, value, borrow); + let (value, borrow) = borrow(&mut ref); + put_back(&mut ref, value, borrow); - let Test { id } = destroy(ref); - id.delete(); - } + let Test { id } = destroy(ref); + id.delete(); +} - #[test] - #[expected_failure(abort_code = EWrongValue)] - /// The `value` is swapped with another instance of the type `T`. - fun test_object_swap() { - let ctx = &mut sui::tx_context::dummy(); - let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); - let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); +#[test] +#[expected_failure(abort_code = EWrongValue)] +/// The `value` is swapped with another instance of the type `T`. +fun test_object_swap() { + let ctx = &mut sui::tx_context::dummy(); + let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); + let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); - let (v_1, b_1) = borrow(&mut ref_1); - let (v_2, b_2) = borrow(&mut ref_2); + let (v_1, b_1) = borrow(&mut ref_1); + let (v_2, b_2) = borrow(&mut ref_2); - put_back(&mut ref_1, v_2, b_1); - put_back(&mut ref_2, v_1, b_2); + put_back(&mut ref_1, v_2, b_1); + put_back(&mut ref_2, v_1, b_2); - let Test { id } = destroy(ref_1); - id.delete(); + let Test { id } = destroy(ref_1); + id.delete(); - let Test { id } = destroy(ref_2); - id.delete(); - } + let Test { id } = destroy(ref_2); + id.delete(); +} - #[test] - #[expected_failure(abort_code = EWrongBorrow)] - /// The both `borrow` and `value` are swapped with another `Referent`. - fun test_borrow_fail() { - let ctx = &mut sui::tx_context::dummy(); - let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); - let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); +#[test] +#[expected_failure(abort_code = EWrongBorrow)] +/// The both `borrow` and `value` are swapped with another `Referent`. +fun test_borrow_fail() { + let ctx = &mut sui::tx_context::dummy(); + let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); + let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); - let (v_1, b_1) = borrow(&mut ref_1); - let (v_2, b_2) = borrow(&mut ref_2); + let (v_1, b_1) = borrow(&mut ref_1); + let (v_2, b_2) = borrow(&mut ref_2); - put_back(&mut ref_1, v_2, b_2); - put_back(&mut ref_2, v_1, b_1); + put_back(&mut ref_1, v_2, b_2); + put_back(&mut ref_2, v_1, b_1); - let Test { id } = destroy(ref_1); - id.delete(); + let Test { id } = destroy(ref_1); + id.delete(); - let Test { id } = destroy(ref_2); - id.delete(); - } + let Test { id } = destroy(ref_2); + id.delete(); } diff --git a/crates/sui-framework/packages/sui-framework/sources/clock.move b/crates/sui-framework/packages/sui-framework/sources/clock.move index 9cfa08c9c6872..11b72322248a1 100644 --- a/crates/sui-framework/packages/sui-framework/sources/clock.move +++ b/crates/sui-framework/packages/sui-framework/sources/clock.move @@ -3,91 +3,86 @@ /// APIs for accessing time from move calls, via the `Clock`: a unique /// shared object that is created at 0x6 during genesis. -module sui::clock { +module sui::clock; - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; +/// Sender is not @0x0 the system address. +const ENotSystemAddress: u64 = 0; - /// Singleton shared object that exposes time to Move calls. This - /// object is found at address 0x6, and can only be read (accessed - /// via an immutable reference) by entry functions. - /// - /// Entry Functions that attempt to accept `Clock` by mutable - /// reference or value will fail to verify, and honest validators - /// will not sign or execute transactions that use `Clock` as an - /// input parameter, unless it is passed by immutable reference. - public struct Clock has key { - id: UID, - /// The clock's timestamp, which is set automatically by a - /// system transaction every time consensus commits a - /// schedule, or by `sui::clock::increment_for_testing` during - /// testing. - timestamp_ms: u64, - } +/// Singleton shared object that exposes time to Move calls. This +/// object is found at address 0x6, and can only be read (accessed +/// via an immutable reference) by entry functions. +/// +/// Entry Functions that attempt to accept `Clock` by mutable +/// reference or value will fail to verify, and honest validators +/// will not sign or execute transactions that use `Clock` as an +/// input parameter, unless it is passed by immutable reference. +public struct Clock has key { + id: UID, + /// The clock's timestamp, which is set automatically by a + /// system transaction every time consensus commits a + /// schedule, or by `sui::clock::increment_for_testing` during + /// testing. + timestamp_ms: u64, +} - /// The `clock`'s current timestamp as a running total of - /// milliseconds since an arbitrary point in the past. - public fun timestamp_ms(clock: &Clock): u64 { - clock.timestamp_ms - } +/// The `clock`'s current timestamp as a running total of +/// milliseconds since an arbitrary point in the past. +public fun timestamp_ms(clock: &Clock): u64 { + clock.timestamp_ms +} - #[allow(unused_function)] - /// Create and share the singleton Clock -- this function is - /// called exactly once, during genesis. - fun create(ctx: &TxContext) { - assert!(ctx.sender() == @0x0, ENotSystemAddress); +#[allow(unused_function)] +/// Create and share the singleton Clock -- this function is +/// called exactly once, during genesis. +fun create(ctx: &TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); - transfer::share_object(Clock { - id: object::clock(), - // Initialised to zero, but set to a real timestamp by a - // system transaction before it can be witnessed by a move - // call. - timestamp_ms: 0, - }) - } + transfer::share_object(Clock { + id: object::clock(), + // Initialised to zero, but set to a real timestamp by a + // system transaction before it can be witnessed by a move + // call. + timestamp_ms: 0, + }) +} - #[allow(unused_function)] - fun consensus_commit_prologue( - clock: &mut Clock, - timestamp_ms: u64, - ctx: &TxContext, - ) { - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); +#[allow(unused_function)] +fun consensus_commit_prologue(clock: &mut Clock, timestamp_ms: u64, ctx: &TxContext) { + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); - clock.timestamp_ms = timestamp_ms - } + clock.timestamp_ms = timestamp_ms +} - #[test_only] - /// Expose the functionality of `create()` (usually only done during - /// genesis) for tests that want to create a Clock. - public fun create_for_testing(ctx: &mut TxContext): Clock { - Clock { - id: object::new(ctx), - timestamp_ms: 0, - } +#[test_only] +/// Expose the functionality of `create()` (usually only done during +/// genesis) for tests that want to create a Clock. +public fun create_for_testing(ctx: &mut TxContext): Clock { + Clock { + id: object::new(ctx), + timestamp_ms: 0, } +} - #[test_only] - /// For transactional tests (if a Clock is used as a shared object). - public fun share_for_testing(clock: Clock) { - transfer::share_object(clock) - } +#[test_only] +/// For transactional tests (if a Clock is used as a shared object). +public fun share_for_testing(clock: Clock) { + transfer::share_object(clock) +} - #[test_only] - public fun increment_for_testing(clock: &mut Clock, tick: u64) { - clock.timestamp_ms = clock.timestamp_ms + tick; - } +#[test_only] +public fun increment_for_testing(clock: &mut Clock, tick: u64) { + clock.timestamp_ms = clock.timestamp_ms + tick; +} - #[test_only] - public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64) { - assert!(timestamp_ms >= clock.timestamp_ms); - clock.timestamp_ms = timestamp_ms; - } +#[test_only] +public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64) { + assert!(timestamp_ms >= clock.timestamp_ms); + clock.timestamp_ms = timestamp_ms; +} - #[test_only] - public fun destroy_for_testing(clock: Clock) { - let Clock { id, timestamp_ms: _ } = clock; - id.delete(); - } +#[test_only] +public fun destroy_for_testing(clock: Clock) { + let Clock { id, timestamp_ms: _ } = clock; + id.delete(); } diff --git a/crates/sui-framework/packages/sui-framework/sources/display.move b/crates/sui-framework/packages/sui-framework/sources/display.move index ef590aba27b40..b09e4802600d6 100644 --- a/crates/sui-framework/packages/sui-framework/sources/display.move +++ b/crates/sui-framework/packages/sui-framework/sources/display.move @@ -10,218 +10,184 @@ /// substitution and filling-in the pieces using the data from the object T. /// /// More entry functions might be added in the future depending on the use cases. -module sui::display { - use sui::package::Publisher; - use sui::vec_map::{Self, VecMap}; - use sui::event; - use std::string::String; - - /// For when T does not belong to the package `Publisher`. - const ENotOwner: u64 = 0; - - /// For when vectors passed into one of the multiple insert functions - /// don't match in their lengths. - const EVecLengthMismatch: u64 = 1; - - /// The Display object. Defines the way a T instance should be - /// displayed. Display object can only be created and modified with - /// a PublisherCap, making sure that the rules are set by the owner - /// of the type. - /// - /// Each of the display properties should support patterns outside - /// of the system, making it simpler to customize Display based - /// on the property values of an Object. - /// ``` - /// // Example of a display object - /// Display<0x...::capy::Capy> { - /// fields: - /// - /// - /// - /// - /// } - /// ``` - /// - /// Uses only String type due to external-facing nature of the object, - /// the property names have a priority over their types. - public struct Display has key, store { - id: UID, - /// Contains fields for display. Currently supported - /// fields are: name, link, image and description. - fields: VecMap, - /// Version that can only be updated manually by the Publisher. - version: u16 - } - - /// Event: emitted when a new Display object has been created for type T. - /// Type signature of the event corresponds to the type while id serves for - /// the discovery. - /// - /// Since Sui RPC supports querying events by type, finding a Display for the T - /// would be as simple as looking for the first event with `Display`. - public struct DisplayCreated has copy, drop { - id: ID - } - - /// Version of Display got updated - - public struct VersionUpdated has copy, drop { - id: ID, - version: u16, - fields: VecMap, - } +module sui::display; - // === Initializer Methods === +use std::string::String; +use sui::event; +use sui::package::Publisher; +use sui::vec_map::{Self, VecMap}; - /// Create an empty Display object. It can either be shared empty or filled - /// with data right away via cheaper `set_owned` method. - public fun new(pub: &Publisher, ctx: &mut TxContext): Display { - assert!(is_authorized(pub), ENotOwner); - create_internal(ctx) - } - - /// Create a new Display object with a set of fields. - public fun new_with_fields( - pub: &Publisher, fields: vector, values: vector, ctx: &mut TxContext - ): Display { - let len = fields.length(); - assert!(len == values.length(), EVecLengthMismatch); - - let mut i = 0; - let mut display = new(pub, ctx); - while (i < len) { - display.add_internal(fields[i], values[i]); - i = i + 1; - }; - - display - } +/// For when T does not belong to the package `Publisher`. +const ENotOwner: u64 = 0; - // === Entry functions: Create === +/// For when vectors passed into one of the multiple insert functions +/// don't match in their lengths. +const EVecLengthMismatch: u64 = 1; - #[allow(lint(self_transfer))] - /// Create a new empty Display object and keep it. - entry public fun create_and_keep(pub: &Publisher, ctx: &mut TxContext) { - transfer::public_transfer(new(pub, ctx), ctx.sender()) - } +/// The Display object. Defines the way a T instance should be +/// displayed. Display object can only be created and modified with +/// a PublisherCap, making sure that the rules are set by the owner +/// of the type. +/// +/// Each of the display properties should support patterns outside +/// of the system, making it simpler to customize Display based +/// on the property values of an Object. +/// ``` +/// // Example of a display object +/// Display<0x...::capy::Capy> { +/// fields: +/// +/// +/// +/// +/// } +/// ``` +/// +/// Uses only String type due to external-facing nature of the object, +/// the property names have a priority over their types. +public struct Display has key, store { + id: UID, + /// Contains fields for display. Currently supported + /// fields are: name, link, image and description. + fields: VecMap, + /// Version that can only be updated manually by the Publisher. + version: u16, +} - /// Manually bump the version and emit an event with the updated version's contents. - entry public fun update_version( - display: &mut Display - ) { - display.version = display.version + 1; - event::emit(VersionUpdated { - version: display.version, - fields: *&display.fields, - id: display.id.to_inner(), - }) - } +/// Event: emitted when a new Display object has been created for type T. +/// Type signature of the event corresponds to the type while id serves for +/// the discovery. +/// +/// Since Sui RPC supports querying events by type, finding a Display for the T +/// would be as simple as looking for the first event with `Display`. +public struct DisplayCreated has copy, drop { + id: ID, +} - // === Entry functions: Add/Modify fields === +/// Version of Display got updated - +public struct VersionUpdated has copy, drop { + id: ID, + version: u16, + fields: VecMap, +} - /// Sets a custom `name` field with the `value`. - entry public fun add(self: &mut Display, name: String, value: String) { - self.add_internal(name, value) - } +// === Initializer Methods === - /// Sets multiple `fields` with `values`. - entry public fun add_multiple( - self: &mut Display, fields: vector, values: vector - ) { - let len = fields.length(); - assert!(len == values.length(), EVecLengthMismatch); - - let mut i = 0; - while (i < len) { - self.add_internal(fields[i], values[i]); - i = i + 1; - }; - } +/// Create an empty Display object. It can either be shared empty or filled +/// with data right away via cheaper `set_owned` method. +public fun new(pub: &Publisher, ctx: &mut TxContext): Display { + assert!(is_authorized(pub), ENotOwner); + create_internal(ctx) +} - /// Change the value of the field. - /// TODO (long run): version changes; - entry public fun edit(self: &mut Display, name: String, value: String) { - let (_, _) = self.fields.remove(&name); - self.add_internal(name, value) - } +/// Create a new Display object with a set of fields. +public fun new_with_fields( + pub: &Publisher, + fields: vector, + values: vector, + ctx: &mut TxContext, +): Display { + let len = fields.length(); + assert!(len == values.length(), EVecLengthMismatch); + + let mut i = 0; + let mut display = new(pub, ctx); + while (i < len) { + display.add_internal(fields[i], values[i]); + i = i + 1; + }; + + display +} - /// Remove the key from the Display. - entry public fun remove(self: &mut Display, name: String) { - self.fields.remove(&name); - } +// === Entry functions: Create === - // === Access fields === +#[allow(lint(self_transfer))] +/// Create a new empty Display object and keep it. +public entry fun create_and_keep(pub: &Publisher, ctx: &mut TxContext) { + transfer::public_transfer(new(pub, ctx), ctx.sender()) +} - /// Authorization check; can be performed externally to implement protection rules for Display. - public fun is_authorized(pub: &Publisher): bool { - pub.from_package() - } +/// Manually bump the version and emit an event with the updated version's contents. +public entry fun update_version(display: &mut Display) { + display.version = display.version + 1; + event::emit(VersionUpdated { + version: display.version, + fields: *&display.fields, + id: display.id.to_inner(), + }) +} - /// Read the `version` field. - public fun version(d: &Display): u16 { - d.version - } +// === Entry functions: Add/Modify fields === - /// Read the `fields` field. - public fun fields(d: &Display): &VecMap { - &d.fields - } +/// Sets a custom `name` field with the `value`. +public entry fun add(self: &mut Display, name: String, value: String) { + self.add_internal(name, value) +} - // === Private functions === +/// Sets multiple `fields` with `values`. +public entry fun add_multiple( + self: &mut Display, + fields: vector, + values: vector, +) { + let len = fields.length(); + assert!(len == values.length(), EVecLengthMismatch); + + let mut i = 0; + while (i < len) { + self.add_internal(fields[i], values[i]); + i = i + 1; + }; +} - /// Internal function to create a new `Display`. - fun create_internal(ctx: &mut TxContext): Display { - let uid = object::new(ctx); +/// Change the value of the field. +/// TODO (long run): version changes; +public entry fun edit(self: &mut Display, name: String, value: String) { + let (_, _) = self.fields.remove(&name); + self.add_internal(name, value) +} - event::emit(DisplayCreated { - id: uid.to_inner() - }); +/// Remove the key from the Display. +public entry fun remove(self: &mut Display, name: String) { + self.fields.remove(&name); +} - Display { - id: uid, - fields: vec_map::empty(), - version: 0, - } - } +// === Access fields === - /// Private method for inserting fields without security checks. - fun add_internal(display: &mut Display, name: String, value: String) { - display.fields.insert(name, value) - } +/// Authorization check; can be performed externally to implement protection rules for Display. +public fun is_authorized(pub: &Publisher): bool { + pub.from_package() } -#[test_only] -module sui::display_tests { - use sui::test_scenario as test; - use std::string::String; - use sui::package; - use sui::display; - - #[allow(unused_field)] - /// An example object. - /// Purely for visibility. - public struct Capy has key { - id: UID, - name: String - } +/// Read the `version` field. +public fun version(d: &Display): u16 { + d.version +} - /// Test witness type to create a Publisher object. - public struct CAPY has drop {} +/// Read the `fields` field. +public fun fields(d: &Display): &VecMap { + &d.fields +} - #[test] - fun capy_init() { - let mut test = test::begin(@0x2); - let pub = package::test_claim(CAPY {}, test.ctx()); +// === Private functions === - // create a new display object - let mut display = display::new(&pub, test.ctx()); +/// Internal function to create a new `Display`. +fun create_internal(ctx: &mut TxContext): Display { + let uid = object::new(ctx); - display.add(b"name".to_string(), b"Capy {name}".to_string()); - display.add(b"link".to_string(), b"https://capy.art/capy/{id}".to_string()); - display.add(b"image".to_string(), b"https://api.capy.art/capy/{id}/svg".to_string()); - display.add(b"description".to_string(), b"A Lovely Capy".to_string()); + event::emit(DisplayCreated { + id: uid.to_inner(), + }); - pub.burn_publisher(); - transfer::public_transfer(display, @0x2); - test.end(); + Display { + id: uid, + fields: vec_map::empty(), + version: 0, } } + +/// Private method for inserting fields without security checks. +fun add_internal(display: &mut Display, name: String, value: String) { + display.fields.insert(name, value) +} diff --git a/crates/sui-framework/packages/sui-framework/sources/event.move b/crates/sui-framework/packages/sui-framework/sources/event.move index f708ac46285c5..7aea21d5c2108 100644 --- a/crates/sui-framework/packages/sui-framework/sources/event.move +++ b/crates/sui-framework/packages/sui-framework/sources/event.move @@ -26,22 +26,22 @@ /// } /// } /// ``` -module sui::event { - /// Emit a custom Move event, sending the data offchain. - /// - /// Used for creating custom indexes and tracking onchain - /// activity in a way that suits a specific application the most. - /// - /// The type `T` is the main way to index the event, and can contain - /// phantom parameters, eg `emit(MyEvent)`. - public native fun emit(event: T); +module sui::event; - #[test_only] - /// Get the total number of events emitted during execution so far - public native fun num_events(): u32; +/// Emit a custom Move event, sending the data offchain. +/// +/// Used for creating custom indexes and tracking onchain +/// activity in a way that suits a specific application the most. +/// +/// The type `T` is the main way to index the event, and can contain +/// phantom parameters, eg `emit(MyEvent)`. +public native fun emit(event: T); + +#[test_only] +/// Get the total number of events emitted during execution so far +public native fun num_events(): u32; - #[test_only] - /// Get all events of type `T` emitted during execution. - /// Can only be used in testing, - public native fun events_by_type(): vector; -} +#[test_only] +/// Get all events of type `T` emitted during execution. +/// Can only be used in testing, +public native fun events_by_type(): vector; diff --git a/crates/sui-framework/packages/sui-framework/sources/hex.move b/crates/sui-framework/packages/sui-framework/sources/hex.move index 640e4338d9a62..5776d3e912076 100644 --- a/crates/sui-framework/packages/sui-framework/sources/hex.move +++ b/crates/sui-framework/packages/sui-framework/sources/hex.move @@ -2,104 +2,68 @@ // SPDX-License-Identifier: Apache-2.0 /// HEX (Base16) encoding utility. -module sui::hex { +module sui::hex; - const EInvalidHexLength: u64 = 0; - const ENotValidHexCharacter: u64 = 1; +const EInvalidHexLength: u64 = 0; +const ENotValidHexCharacter: u64 = 1; - /// Vector of Base16 values from `00` to `FF` - const HEX: vector> = vector[ - b"00",b"01",b"02",b"03",b"04",b"05",b"06",b"07",b"08",b"09",b"0a",b"0b",b"0c",b"0d",b"0e",b"0f",b"10",b"11",b"12",b"13",b"14",b"15",b"16",b"17",b"18",b"19",b"1a",b"1b",b"1c",b"1d",b"1e",b"1f",b"20",b"21",b"22",b"23",b"24",b"25",b"26",b"27",b"28",b"29",b"2a",b"2b",b"2c",b"2d",b"2e",b"2f",b"30",b"31",b"32",b"33",b"34",b"35",b"36",b"37",b"38",b"39",b"3a",b"3b",b"3c",b"3d",b"3e",b"3f",b"40",b"41",b"42",b"43",b"44",b"45",b"46",b"47",b"48",b"49",b"4a",b"4b",b"4c",b"4d",b"4e",b"4f",b"50",b"51",b"52",b"53",b"54",b"55",b"56",b"57",b"58",b"59",b"5a",b"5b",b"5c",b"5d",b"5e",b"5f",b"60",b"61",b"62",b"63",b"64",b"65",b"66",b"67",b"68",b"69",b"6a",b"6b",b"6c",b"6d",b"6e",b"6f",b"70",b"71",b"72",b"73",b"74",b"75",b"76",b"77",b"78",b"79",b"7a",b"7b",b"7c",b"7d",b"7e",b"7f",b"80",b"81",b"82",b"83",b"84",b"85",b"86",b"87",b"88",b"89",b"8a",b"8b",b"8c",b"8d",b"8e",b"8f",b"90",b"91",b"92",b"93",b"94",b"95",b"96",b"97",b"98",b"99",b"9a",b"9b",b"9c",b"9d",b"9e",b"9f",b"a0",b"a1",b"a2",b"a3",b"a4",b"a5",b"a6",b"a7",b"a8",b"a9",b"aa",b"ab",b"ac",b"ad",b"ae",b"af",b"b0",b"b1",b"b2",b"b3",b"b4",b"b5",b"b6",b"b7",b"b8",b"b9",b"ba",b"bb",b"bc",b"bd",b"be",b"bf",b"c0",b"c1",b"c2",b"c3",b"c4",b"c5",b"c6",b"c7",b"c8",b"c9",b"ca",b"cb",b"cc",b"cd",b"ce",b"cf",b"d0",b"d1",b"d2",b"d3",b"d4",b"d5",b"d6",b"d7",b"d8",b"d9",b"da",b"db",b"dc",b"dd",b"de",b"df",b"e0",b"e1",b"e2",b"e3",b"e4",b"e5",b"e6",b"e7",b"e8",b"e9",b"ea",b"eb",b"ec",b"ed",b"ee",b"ef",b"f0",b"f1",b"f2",b"f3",b"f4",b"f5",b"f6",b"f7",b"f8",b"f9",b"fa",b"fb",b"fc",b"fd",b"fe",b"ff" - ]; +// prettier-ignore +/// Vector of Base16 values from `00` to `FF` +const HEX: vector> = vector[ + b"00", b"01", b"02", b"03", b"04", b"05", b"06", b"07", b"08", b"09", b"0a", b"0b", b"0c", b"0d", b"0e", b"0f", + b"10", b"11", b"12", b"13", b"14", b"15", b"16", b"17", b"18", b"19", b"1a", b"1b", b"1c", b"1d", b"1e", b"1f", + b"20", b"21", b"22", b"23", b"24", b"25", b"26", b"27", b"28", b"29", b"2a", b"2b", b"2c", b"2d", b"2e", b"2f", + b"30", b"31", b"32", b"33", b"34", b"35", b"36", b"37", b"38", b"39", b"3a", b"3b", b"3c", b"3d", b"3e", b"3f", + b"40", b"41", b"42", b"43", b"44", b"45", b"46", b"47", b"48", b"49", b"4a", b"4b", b"4c", b"4d", b"4e", b"4f", + b"50", b"51", b"52", b"53", b"54", b"55", b"56", b"57", b"58", b"59", b"5a", b"5b", b"5c", b"5d", b"5e", b"5f", + b"60", b"61", b"62", b"63", b"64", b"65", b"66", b"67", b"68", b"69", b"6a", b"6b", b"6c", b"6d", b"6e", b"6f", + b"70", b"71", b"72", b"73", b"74", b"75", b"76", b"77", b"78", b"79", b"7a", b"7b", b"7c", b"7d", b"7e", b"7f", + b"80", b"81", b"82", b"83", b"84", b"85", b"86", b"87", b"88", b"89", b"8a", b"8b", b"8c", b"8d", b"8e", b"8f", + b"90", b"91", b"92", b"93", b"94", b"95", b"96", b"97", b"98", b"99", b"9a", b"9b", b"9c", b"9d", b"9e", b"9f", + b"a0", b"a1", b"a2", b"a3", b"a4", b"a5", b"a6", b"a7", b"a8", b"a9", b"aa", b"ab", b"ac", b"ad", b"ae", b"af", + b"b0", b"b1", b"b2", b"b3", b"b4", b"b5", b"b6", b"b7", b"b8", b"b9", b"ba", b"bb", b"bc", b"bd", b"be", b"bf", + b"c0", b"c1", b"c2", b"c3", b"c4", b"c5", b"c6", b"c7", b"c8", b"c9", b"ca", b"cb", b"cc", b"cd", b"ce", b"cf", + b"d0", b"d1", b"d2", b"d3", b"d4", b"d5", b"d6", b"d7", b"d8", b"d9", b"da", b"db", b"dc", b"dd", b"de", b"df", + b"e0", b"e1", b"e2", b"e3", b"e4", b"e5", b"e6", b"e7", b"e8", b"e9", b"ea", b"eb", b"ec", b"ed", b"ee", b"ef", + b"f0", b"f1", b"f2", b"f3", b"f4", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb", b"fc", b"fd", b"fe", b"ff", +]; - /// Encode `bytes` in lowercase hex - public fun encode(bytes: vector): vector { - let (mut i, mut r, l) = (0, vector[], bytes.length()); - let hex_vector = HEX; - while (i < l) { - r.append(hex_vector[bytes[i] as u64]); - i = i + 1; - }; - r - } - - /// Decode hex into `bytes` - /// Takes a hex string (no 0x prefix) (e.g. b"0f3a") - /// Returns vector of `bytes` that represents the hex string (e.g. x"0f3a") - /// Hex string can be case insensitive (e.g. b"0F3A" and b"0f3a" both return x"0f3a") - /// Aborts if the hex string does not have an even number of characters (as each hex character is 2 characters long) - /// Aborts if the hex string contains non-valid hex characters (valid characters are 0 - 9, a - f, A - F) - public fun decode(hex: vector): vector { - let (mut i, mut r, l) = (0, vector[], hex.length()); - assert!(l % 2 == 0, EInvalidHexLength); - while (i < l) { - let decimal = decode_byte(hex[i]) * 16 + decode_byte(hex[i + 1]); - r.push_back(decimal); - i = i + 2; - }; - r - } - - fun decode_byte(hex: u8): u8 { - if (/* 0 .. 9 */ 48 <= hex && hex < 58) { - hex - 48 - } else if (/* A .. F */ 65 <= hex && hex < 71) { - 10 + hex - 65 - } else if (/* a .. f */ 97 <= hex && hex < 103) { - 10 + hex - 97 - } else { - abort ENotValidHexCharacter - } - } - - #[test] - fun test_hex_encode_string_literal() { - assert!(b"30" == encode(b"0")); - assert!(b"61" == encode(b"a")); - assert!(b"666666" == encode(b"fff")); - } - - #[test] - fun test_hex_encode_hex_literal() { - assert!(b"ff" == encode(x"ff")); - assert!(b"fe" == encode(x"fe")); - assert!(b"00" == encode(x"00")); - } - - #[test] - fun test_hex_decode_string_literal() { - assert!(x"ff" == decode(b"ff")); - assert!(x"fe" == decode(b"fe")); - assert!(x"00" == decode(b"00")); - } - - #[test] - fun test_hex_decode_string_literal__lowercase_and_uppercase() { - assert!(x"ff" == decode(b"Ff")); - assert!(x"ff" == decode(b"fF")); - assert!(x"ff" == decode(b"FF")); - } - - #[test] - fun test_hex_decode_string_literal__long_hex() { - assert!(x"036d2416252ae1db8aedad59e14b007bee6ab94a3e77a3549a81137871604456f3" == decode(b"036d2416252ae1Db8aedAd59e14b007bee6aB94a3e77a3549a81137871604456f3")); - } - - #[test] - #[expected_failure(abort_code = EInvalidHexLength)] - fun test_hex_decode__invalid_length() { - decode(b"0"); - } +/// Encode `bytes` in lowercase hex +public fun encode(bytes: vector): vector { + let (mut i, mut r, l) = (0, vector[], bytes.length()); + let hex_vector = HEX; + while (i < l) { + r.append(hex_vector[bytes[i] as u64]); + i = i + 1; + }; + r +} - #[test] - #[expected_failure(abort_code = ENotValidHexCharacter)] - fun test_hex_decode__hex_literal() { - decode(x"ffff"); - } +/// Decode hex into `bytes` +/// Takes a hex string (no 0x prefix) (e.g. b"0f3a") +/// Returns vector of `bytes` that represents the hex string (e.g. x"0f3a") +/// Hex string can be case insensitive (e.g. b"0F3A" and b"0f3a" both return x"0f3a") +/// Aborts if the hex string does not have an even number of characters (as each hex character is 2 characters long) +/// Aborts if the hex string contains non-valid hex characters (valid characters are 0 - 9, a - f, A - F) +public fun decode(hex: vector): vector { + let (mut i, mut r, l) = (0, vector[], hex.length()); + assert!(l % 2 == 0, EInvalidHexLength); + while (i < l) { + let decimal = decode_byte(hex[i]) * 16 + decode_byte(hex[i + 1]); + r.push_back(decimal); + i = i + 2; + }; + r +} - #[test] - #[expected_failure(abort_code = ENotValidHexCharacter)] - fun test_hex_decode__invalid_string_literal() { - decode(b"0g"); +fun decode_byte(hex: u8): u8 { + if (48 <= hex && hex < 58) { + hex - 48 + } else if (65 <= hex && hex < 71) { + 10 + hex - 65 + } else if (97 <= hex && hex < 103) { + 10 + hex - 97 + } else { + abort ENotValidHexCharacter } } diff --git a/crates/sui-framework/packages/sui-framework/sources/math.move b/crates/sui-framework/packages/sui-framework/sources/math.move index f98a7d7c5eb72..2ad382cc8304d 100644 --- a/crates/sui-framework/packages/sui-framework/sources/math.move +++ b/crates/sui-framework/packages/sui-framework/sources/math.move @@ -3,40 +3,39 @@ /// DEPRECATED, use the each integer type's individual module instead, e.g. `std::u64` #[deprecated(note = b"Use the each integer type's individual module instead, e.g. `std::u64`")] -module sui::math { - - /// DEPRECATED, use `std::u64::max` instead - public fun max(x: u64, y: u64): u64 { - x.max(y) - } - - /// DEPRECATED, use `std::u64::min` instead - public fun min(x: u64, y: u64): u64 { - x.min(y) - } - - /// DEPRECATED, use `std::u64::diff` instead - public fun diff(x: u64, y: u64): u64 { - x.diff(y) - } - - /// DEPRECATED, use `std::u64::pow` instead - public fun pow(base: u64, exponent: u8): u64 { - base.pow(exponent) - } - - /// DEPRECATED, use `std::u64::sqrt` instead - public fun sqrt(x: u64): u64 { - x.sqrt() - } - - /// DEPRECATED, use `std::u128::sqrt` instead - public fun sqrt_u128(x: u128): u128 { - x.sqrt() - } - - /// DEPRECATED, use `std::u64::divide_and_round_up` instead - public fun divide_and_round_up(x: u64, y: u64): u64 { - x.divide_and_round_up(y) - } +module sui::math; + +/// DEPRECATED, use `std::u64::max` instead +public fun max(x: u64, y: u64): u64 { + x.max(y) +} + +/// DEPRECATED, use `std::u64::min` instead +public fun min(x: u64, y: u64): u64 { + x.min(y) +} + +/// DEPRECATED, use `std::u64::diff` instead +public fun diff(x: u64, y: u64): u64 { + x.diff(y) +} + +/// DEPRECATED, use `std::u64::pow` instead +public fun pow(base: u64, exponent: u8): u64 { + base.pow(exponent) +} + +/// DEPRECATED, use `std::u64::sqrt` instead +public fun sqrt(x: u64): u64 { + x.sqrt() +} + +/// DEPRECATED, use `std::u128::sqrt` instead +public fun sqrt_u128(x: u128): u128 { + x.sqrt() +} + +/// DEPRECATED, use `std::u64::divide_and_round_up` instead +public fun divide_and_round_up(x: u64, y: u64): u64 { + x.divide_and_round_up(y) } diff --git a/crates/sui-framework/packages/sui-framework/sources/object.move b/crates/sui-framework/packages/sui-framework/sources/object.move index 5b1a388bb2450..8bc0c67c38fc8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/object.move +++ b/crates/sui-framework/packages/sui-framework/sources/object.move @@ -2,233 +2,232 @@ // SPDX-License-Identifier: Apache-2.0 /// Sui object identifiers -module sui::object { - use std::bcs; - use sui::address; +module sui::object; - /// Allows calling `.to_address` on an `ID` to get an `address`. - public use fun id_to_address as ID.to_address; +use std::bcs; +use sui::address; - /// Allows calling `.to_bytes` on an `ID` to get a `vector`. - public use fun id_to_bytes as ID.to_bytes; +/// Allows calling `.to_address` on an `ID` to get an `address`. +public use fun id_to_address as ID.to_address; - /// Allows calling `.as_inner` on a `UID` to get an `&ID`. - public use fun uid_as_inner as UID.as_inner; +/// Allows calling `.to_bytes` on an `ID` to get a `vector`. +public use fun id_to_bytes as ID.to_bytes; - /// Allows calling `.to_inner` on a `UID` to get an `ID`. - public use fun uid_to_inner as UID.to_inner; +/// Allows calling `.as_inner` on a `UID` to get an `&ID`. +public use fun uid_as_inner as UID.as_inner; - /// Allows calling `.to_address` on a `UID` to get an `address`. - public use fun uid_to_address as UID.to_address; +/// Allows calling `.to_inner` on a `UID` to get an `ID`. +public use fun uid_to_inner as UID.to_inner; - /// Allows calling `.to_bytes` on a `UID` to get a `vector`. - public use fun uid_to_bytes as UID.to_bytes; +/// Allows calling `.to_address` on a `UID` to get an `address`. +public use fun uid_to_address as UID.to_address; - /// The hardcoded ID for the singleton Sui System State Object. - const SUI_SYSTEM_STATE_OBJECT_ID: address = @0x5; +/// Allows calling `.to_bytes` on a `UID` to get a `vector`. +public use fun uid_to_bytes as UID.to_bytes; - /// The hardcoded ID for the singleton Clock Object. - const SUI_CLOCK_OBJECT_ID: address = @0x6; +/// The hardcoded ID for the singleton Sui System State Object. +const SUI_SYSTEM_STATE_OBJECT_ID: address = @0x5; - /// The hardcoded ID for the singleton AuthenticatorState Object. - const SUI_AUTHENTICATOR_STATE_ID: address = @0x7; +/// The hardcoded ID for the singleton Clock Object. +const SUI_CLOCK_OBJECT_ID: address = @0x6; - /// The hardcoded ID for the singleton Random Object. - const SUI_RANDOM_ID: address = @0x8; +/// The hardcoded ID for the singleton AuthenticatorState Object. +const SUI_AUTHENTICATOR_STATE_ID: address = @0x7; - /// The hardcoded ID for the singleton DenyList. - const SUI_DENY_LIST_OBJECT_ID: address = @0x403; +/// The hardcoded ID for the singleton Random Object. +const SUI_RANDOM_ID: address = @0x8; - /// The hardcoded ID for the Bridge Object. - const SUI_BRIDGE_ID: address = @0x9; +/// The hardcoded ID for the singleton DenyList. +const SUI_DENY_LIST_OBJECT_ID: address = @0x403; - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; +/// The hardcoded ID for the Bridge Object. +const SUI_BRIDGE_ID: address = @0x9; - /// An object ID. This is used to reference Sui Objects. - /// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or - /// from an object, and ID's can be freely copied and dropped. - /// Here, the values are not globally unique because there can be multiple values of type `ID` - /// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times - /// as you want for a given `obj`, and each `ID` value will be identical. - public struct ID has copy, drop, store { - // We use `address` instead of `vector` here because `address` has a more - // compact serialization. `address` is serialized as a BCS fixed-length sequence, - // which saves us the length prefix we would pay for if this were `vector`. - // See https://github.com/diem/bcs#fixed-and-variable-length-sequences. - bytes: address - } +/// Sender is not @0x0 the system address. +const ENotSystemAddress: u64 = 0; - /// Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct - /// with the `key` ability, must have `id: UID` as its first field. - /// These are globally unique in the sense that no two values of type `UID` are ever equal, in - /// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`. - /// This is a privileged type that can only be derived from a `TxContext`. - /// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`. - public struct UID has store { - id: ID, - } +/// An object ID. This is used to reference Sui Objects. +/// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or +/// from an object, and ID's can be freely copied and dropped. +/// Here, the values are not globally unique because there can be multiple values of type `ID` +/// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times +/// as you want for a given `obj`, and each `ID` value will be identical. +public struct ID has copy, drop, store { + // We use `address` instead of `vector` here because `address` has a more + // compact serialization. `address` is serialized as a BCS fixed-length sequence, + // which saves us the length prefix we would pay for if this were `vector`. + // See https://github.com/diem/bcs#fixed-and-variable-length-sequences. + bytes: address, +} - // === id === +/// Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct +/// with the `key` ability, must have `id: UID` as its first field. +/// These are globally unique in the sense that no two values of type `UID` are ever equal, in +/// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`. +/// This is a privileged type that can only be derived from a `TxContext`. +/// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`. +public struct UID has store { + id: ID, +} - /// Get the raw bytes of a `ID` - public fun id_to_bytes(id: &ID): vector { - bcs::to_bytes(&id.bytes) - } +// === id === - /// Get the inner bytes of `id` as an address. - public fun id_to_address(id: &ID): address { - id.bytes - } +/// Get the raw bytes of a `ID` +public fun id_to_bytes(id: &ID): vector { + bcs::to_bytes(&id.bytes) +} - /// Make an `ID` from raw bytes. - public fun id_from_bytes(bytes: vector): ID { - address::from_bytes(bytes).to_id() - } +/// Get the inner bytes of `id` as an address. +public fun id_to_address(id: &ID): address { + id.bytes +} - /// Make an `ID` from an address. - public fun id_from_address(bytes: address): ID { - ID { bytes } - } +/// Make an `ID` from raw bytes. +public fun id_from_bytes(bytes: vector): ID { + address::from_bytes(bytes).to_id() +} - // === uid === +/// Make an `ID` from an address. +public fun id_from_address(bytes: address): ID { + ID { bytes } +} - #[allow(unused_function)] - /// Create the `UID` for the singleton `SuiSystemState` object. - /// This should only be called once from `sui_system`. - fun sui_system_state(ctx: &TxContext): UID { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - UID { - id: ID { bytes: SUI_SYSTEM_STATE_OBJECT_ID }, - } - } +// === uid === - /// Create the `UID` for the singleton `Clock` object. - /// This should only be called once from `clock`. - public(package) fun clock(): UID { - UID { - id: ID { bytes: SUI_CLOCK_OBJECT_ID } - } +#[allow(unused_function)] +/// Create the `UID` for the singleton `SuiSystemState` object. +/// This should only be called once from `sui_system`. +fun sui_system_state(ctx: &TxContext): UID { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + UID { + id: ID { bytes: SUI_SYSTEM_STATE_OBJECT_ID }, } +} - /// Create the `UID` for the singleton `AuthenticatorState` object. - /// This should only be called once from `authenticator_state`. - public(package) fun authenticator_state(): UID { - UID { - id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID } - } +/// Create the `UID` for the singleton `Clock` object. +/// This should only be called once from `clock`. +public(package) fun clock(): UID { + UID { + id: ID { bytes: SUI_CLOCK_OBJECT_ID }, } +} - /// Create the `UID` for the singleton `Random` object. - /// This should only be called once from `random`. - public(package) fun randomness_state(): UID { - UID { - id: ID { bytes: SUI_RANDOM_ID } - } +/// Create the `UID` for the singleton `AuthenticatorState` object. +/// This should only be called once from `authenticator_state`. +public(package) fun authenticator_state(): UID { + UID { + id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID }, } +} - /// Create the `UID` for the singleton `DenyList` object. - /// This should only be called once from `deny_list`. - public(package) fun sui_deny_list_object_id(): UID { - UID { - id: ID { bytes: SUI_DENY_LIST_OBJECT_ID } - } +/// Create the `UID` for the singleton `Random` object. +/// This should only be called once from `random`. +public(package) fun randomness_state(): UID { + UID { + id: ID { bytes: SUI_RANDOM_ID }, } +} - #[allow(unused_function)] - /// Create the `UID` for the singleton `Bridge` object. - /// This should only be called once from `bridge`. - fun bridge(): UID { - UID { - id: ID { bytes: SUI_BRIDGE_ID } - } +/// Create the `UID` for the singleton `DenyList` object. +/// This should only be called once from `deny_list`. +public(package) fun sui_deny_list_object_id(): UID { + UID { + id: ID { bytes: SUI_DENY_LIST_OBJECT_ID }, } +} - /// Get the inner `ID` of `uid` - public fun uid_as_inner(uid: &UID): &ID { - &uid.id +#[allow(unused_function)] +/// Create the `UID` for the singleton `Bridge` object. +/// This should only be called once from `bridge`. +fun bridge(): UID { + UID { + id: ID { bytes: SUI_BRIDGE_ID }, } +} - /// Get the raw bytes of a `uid`'s inner `ID` - public fun uid_to_inner(uid: &UID): ID { - uid.id - } +/// Get the inner `ID` of `uid` +public fun uid_as_inner(uid: &UID): &ID { + &uid.id +} - /// Get the raw bytes of a `UID` - public fun uid_to_bytes(uid: &UID): vector { - bcs::to_bytes(&uid.id.bytes) - } +/// Get the raw bytes of a `uid`'s inner `ID` +public fun uid_to_inner(uid: &UID): ID { + uid.id +} - /// Get the inner bytes of `id` as an address. - public fun uid_to_address(uid: &UID): address { - uid.id.bytes - } +/// Get the raw bytes of a `UID` +public fun uid_to_bytes(uid: &UID): vector { + bcs::to_bytes(&uid.id.bytes) +} - // === any object === +/// Get the inner bytes of `id` as an address. +public fun uid_to_address(uid: &UID): address { + uid.id.bytes +} - /// Create a new object. Returns the `UID` that must be stored in a Sui object. - /// This is the only way to create `UID`s. - public fun new(ctx: &mut TxContext): UID { - UID { - id: ID { bytes: ctx.fresh_object_address() }, - } - } +// === any object === - /// Delete the object and it's `UID`. This is the only way to eliminate a `UID`. - // This exists to inform Sui of object deletions. When an object - // gets unpacked, the programmer will have to do something with its - // `UID`. The implementation of this function emits a deleted - // system event so Sui knows to process the object deletion - public fun delete(id: UID) { - let UID { id: ID { bytes } } = id; - delete_impl(bytes) +/// Create a new object. Returns the `UID` that must be stored in a Sui object. +/// This is the only way to create `UID`s. +public fun new(ctx: &mut TxContext): UID { + UID { + id: ID { bytes: ctx.fresh_object_address() }, } +} - /// Get the underlying `ID` of `obj` - public fun id(obj: &T): ID { - borrow_uid(obj).id - } +/// Delete the object and it's `UID`. This is the only way to eliminate a `UID`. +// This exists to inform Sui of object deletions. When an object +// gets unpacked, the programmer will have to do something with its +// `UID`. The implementation of this function emits a deleted +// system event so Sui knows to process the object deletion +public fun delete(id: UID) { + let UID { id: ID { bytes } } = id; + delete_impl(bytes) +} - /// Borrow the underlying `ID` of `obj` - public fun borrow_id(obj: &T): &ID { - &borrow_uid(obj).id - } +/// Get the underlying `ID` of `obj` +public fun id(obj: &T): ID { + borrow_uid(obj).id +} - /// Get the raw bytes for the underlying `ID` of `obj` - public fun id_bytes(obj: &T): vector { - bcs::to_bytes(&borrow_uid(obj).id) - } +/// Borrow the underlying `ID` of `obj` +public fun borrow_id(obj: &T): &ID { + &borrow_uid(obj).id +} - /// Get the inner bytes for the underlying `ID` of `obj` - public fun id_address(obj: &T): address { - borrow_uid(obj).id.bytes - } +/// Get the raw bytes for the underlying `ID` of `obj` +public fun id_bytes(obj: &T): vector { + bcs::to_bytes(&borrow_uid(obj).id) +} - /// Get the `UID` for `obj`. - /// Safe because Sui has an extra bytecode verifier pass that forces every struct with - /// the `key` ability to have a distinguished `UID` field. - /// Cannot be made public as the access to `UID` for a given object must be privileged, and - /// restrictable in the object's module. - native fun borrow_uid(obj: &T): &UID; - - /// Generate a new UID specifically used for creating a UID from a hash - public(package) fun new_uid_from_hash(bytes: address): UID { - record_new_uid(bytes); - UID { id: ID { bytes } } - } +/// Get the inner bytes for the underlying `ID` of `obj` +public fun id_address(obj: &T): address { + borrow_uid(obj).id.bytes +} - // === internal functions === +/// Get the `UID` for `obj`. +/// Safe because Sui has an extra bytecode verifier pass that forces every struct with +/// the `key` ability to have a distinguished `UID` field. +/// Cannot be made public as the access to `UID` for a given object must be privileged, and +/// restrictable in the object's module. +native fun borrow_uid(obj: &T): &UID; + +/// Generate a new UID specifically used for creating a UID from a hash +public(package) fun new_uid_from_hash(bytes: address): UID { + record_new_uid(bytes); + UID { id: ID { bytes } } +} - // helper for delete - native fun delete_impl(id: address); +// === internal functions === - // marks newly created UIDs from hash - native fun record_new_uid(id: address); +// helper for delete +native fun delete_impl(id: address); - #[test_only] - /// Return the most recent created object ID. - public fun last_created(ctx: &TxContext): ID { - ID { bytes: ctx.last_created_object_id() } - } +// marks newly created UIDs from hash +native fun record_new_uid(id: address); +#[test_only] +/// Return the most recent created object ID. +public fun last_created(ctx: &TxContext): ID { + ID { bytes: ctx.last_created_object_id() } } diff --git a/crates/sui-framework/packages/sui-framework/sources/package.move b/crates/sui-framework/packages/sui-framework/sources/package.move index 85917a647c9d4..4ef8990662b7c 100644 --- a/crates/sui-framework/packages/sui-framework/sources/package.move +++ b/crates/sui-framework/packages/sui-framework/sources/package.move @@ -4,355 +4,351 @@ /// Functions for operating on Move packages from within Move: /// - Creating proof-of-publish objects from one-time witnesses /// - Administering package upgrades through upgrade policies. -module sui::package { - use std::ascii::String; - use std::type_name; - use sui::types; - - /// Allows calling `.burn` to destroy a `Publisher`. - public use fun burn_publisher as Publisher.burn; - - /// Allows calling `.module_` to access the name of the module a - /// `Publisher` was derived from. - public use fun published_module as Publisher.module_; - - /// Allows calling `.package` to access the address of the package - /// a `Publisher` was derived from. - public use fun published_package as Publisher.package; - - /// Allows calling `.package` to access the package this cap - /// authorizes upgrades for. - public use fun upgrade_package as UpgradeCap.package; - - /// Allows calling `.policy` to access the most permissive kind of - /// upgrade this cap will authorize. - public use fun upgrade_policy as UpgradeCap.policy; - - /// Allows calling `.authorize` to initiate an upgrade. - public use fun authorize_upgrade as UpgradeCap.authorize; - - /// Allows calling `.commit` to finalize an upgrade. - public use fun commit_upgrade as UpgradeCap.commit; - - /// Allows calling `.package` to access the package this ticket - /// authorizes an upgrade for. - public use fun ticket_package as UpgradeTicket.package; - - /// Allows calling `.policy` to access the kind of upgrade this - /// ticket authorizes. - public use fun ticket_policy as UpgradeTicket.policy; - - /// Allows calling `.digest` to access the digest of the bytecode - /// used for this upgrade. - public use fun ticket_digest as UpgradeTicket.digest; - - /// Allows calling `.cap` to fetch the ID of the cap this receipt - /// should be applied to. - public use fun receipt_cap as UpgradeReceipt.cap; - - /// Allows calling `.package` to fetch the ID of the package after - /// upgrade. - public use fun receipt_package as UpgradeReceipt.package; - - /// Tried to create a `Publisher` using a type that isn't a - /// one-time witness. - const ENotOneTimeWitness: u64 = 0; - /// Tried to set a less restrictive policy than currently in place. - const ETooPermissive: u64 = 1; - /// This `UpgradeCap` has already authorized a pending upgrade. - const EAlreadyAuthorized: u64 = 2; - /// This `UpgradeCap` has not authorized an upgrade. - const ENotAuthorized: u64 = 3; - /// Trying to commit an upgrade to the wrong `UpgradeCap`. - const EWrongUpgradeCap: u64 = 4; - - /// Update any part of the package (function implementations, add new - /// functions or types, change dependencies) - const COMPATIBLE: u8 = 0; - /// Add new functions or types, or change dependencies, existing - /// functions can't change. - const ADDITIVE: u8 = 128; - /// Only be able to change dependencies. - const DEP_ONLY: u8 = 192; - - /// This type can only be created in the transaction that - /// generates a module, by consuming its one-time witness, so it - /// can be used to identify the address that published the package - /// a type originated from. - public struct Publisher has key, store { - id: UID, - package: String, - module_name: String, - } +module sui::package; + +use std::ascii::String; +use std::type_name; +use sui::types; + +/// Allows calling `.burn` to destroy a `Publisher`. +public use fun burn_publisher as Publisher.burn; + +/// Allows calling `.module_` to access the name of the module a +/// `Publisher` was derived from. +public use fun published_module as Publisher.module_; + +/// Allows calling `.package` to access the address of the package +/// a `Publisher` was derived from. +public use fun published_package as Publisher.package; + +/// Allows calling `.package` to access the package this cap +/// authorizes upgrades for. +public use fun upgrade_package as UpgradeCap.package; + +/// Allows calling `.policy` to access the most permissive kind of +/// upgrade this cap will authorize. +public use fun upgrade_policy as UpgradeCap.policy; + +/// Allows calling `.authorize` to initiate an upgrade. +public use fun authorize_upgrade as UpgradeCap.authorize; + +/// Allows calling `.commit` to finalize an upgrade. +public use fun commit_upgrade as UpgradeCap.commit; + +/// Allows calling `.package` to access the package this ticket +/// authorizes an upgrade for. +public use fun ticket_package as UpgradeTicket.package; + +/// Allows calling `.policy` to access the kind of upgrade this +/// ticket authorizes. +public use fun ticket_policy as UpgradeTicket.policy; + +/// Allows calling `.digest` to access the digest of the bytecode +/// used for this upgrade. +public use fun ticket_digest as UpgradeTicket.digest; + +/// Allows calling `.cap` to fetch the ID of the cap this receipt +/// should be applied to. +public use fun receipt_cap as UpgradeReceipt.cap; + +/// Allows calling `.package` to fetch the ID of the package after +/// upgrade. +public use fun receipt_package as UpgradeReceipt.package; + +/// Tried to create a `Publisher` using a type that isn't a +/// one-time witness. +const ENotOneTimeWitness: u64 = 0; +/// Tried to set a less restrictive policy than currently in place. +const ETooPermissive: u64 = 1; +/// This `UpgradeCap` has already authorized a pending upgrade. +const EAlreadyAuthorized: u64 = 2; +/// This `UpgradeCap` has not authorized an upgrade. +const ENotAuthorized: u64 = 3; +/// Trying to commit an upgrade to the wrong `UpgradeCap`. +const EWrongUpgradeCap: u64 = 4; + +/// Update any part of the package (function implementations, add new +/// functions or types, change dependencies) +const COMPATIBLE: u8 = 0; +/// Add new functions or types, or change dependencies, existing +/// functions can't change. +const ADDITIVE: u8 = 128; +/// Only be able to change dependencies. +const DEP_ONLY: u8 = 192; + +/// This type can only be created in the transaction that +/// generates a module, by consuming its one-time witness, so it +/// can be used to identify the address that published the package +/// a type originated from. +public struct Publisher has key, store { + id: UID, + package: String, + module_name: String, +} - /// Capability controlling the ability to upgrade a package. - public struct UpgradeCap has key, store { - id: UID, - /// (Mutable) ID of the package that can be upgraded. - package: ID, - /// (Mutable) The number of upgrades that have been applied - /// successively to the original package. Initially 0. - version: u64, - /// What kind of upgrades are allowed. - policy: u8, - } +/// Capability controlling the ability to upgrade a package. +public struct UpgradeCap has key, store { + id: UID, + /// (Mutable) ID of the package that can be upgraded. + package: ID, + /// (Mutable) The number of upgrades that have been applied + /// successively to the original package. Initially 0. + version: u64, + /// What kind of upgrades are allowed. + policy: u8, +} - /// Permission to perform a particular upgrade (for a fixed version of - /// the package, bytecode to upgrade with and transitive dependencies to - /// depend against). - /// - /// An `UpgradeCap` can only issue one ticket at a time, to prevent races - /// between concurrent updates or a change in its upgrade policy after - /// issuing a ticket, so the ticket is a "Hot Potato" to preserve forward - /// progress. - public struct UpgradeTicket { - /// (Immutable) ID of the `UpgradeCap` this originated from. - cap: ID, - /// (Immutable) ID of the package that can be upgraded. - package: ID, - /// (Immutable) The policy regarding what kind of upgrade this ticket - /// permits. - policy: u8, - /// (Immutable) SHA256 digest of the bytecode and transitive - /// dependencies that will be used in the upgrade. - digest: vector, - } +/// Permission to perform a particular upgrade (for a fixed version of +/// the package, bytecode to upgrade with and transitive dependencies to +/// depend against). +/// +/// An `UpgradeCap` can only issue one ticket at a time, to prevent races +/// between concurrent updates or a change in its upgrade policy after +/// issuing a ticket, so the ticket is a "Hot Potato" to preserve forward +/// progress. +public struct UpgradeTicket { + /// (Immutable) ID of the `UpgradeCap` this originated from. + cap: ID, + /// (Immutable) ID of the package that can be upgraded. + package: ID, + /// (Immutable) The policy regarding what kind of upgrade this ticket + /// permits. + policy: u8, + /// (Immutable) SHA256 digest of the bytecode and transitive + /// dependencies that will be used in the upgrade. + digest: vector, +} - /// Issued as a result of a successful upgrade, containing the - /// information to be used to update the `UpgradeCap`. This is a "Hot - /// Potato" to ensure that it is used to update its `UpgradeCap` before - /// the end of the transaction that performed the upgrade. - public struct UpgradeReceipt { - /// (Immutable) ID of the `UpgradeCap` this originated from. - cap: ID, - /// (Immutable) ID of the package after it was upgraded. - package: ID, - } +/// Issued as a result of a successful upgrade, containing the +/// information to be used to update the `UpgradeCap`. This is a "Hot +/// Potato" to ensure that it is used to update its `UpgradeCap` before +/// the end of the transaction that performed the upgrade. +public struct UpgradeReceipt { + /// (Immutable) ID of the `UpgradeCap` this originated from. + cap: ID, + /// (Immutable) ID of the package after it was upgraded. + package: ID, +} - /// Claim a Publisher object. - /// Requires a One-Time-Witness to prove ownership. Due to this - /// constraint there can be only one Publisher object per module - /// but multiple per package (!). - public fun claim(otw: OTW, ctx: &mut TxContext): Publisher { - assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); +/// Claim a Publisher object. +/// Requires a One-Time-Witness to prove ownership. Due to this +/// constraint there can be only one Publisher object per module +/// but multiple per package (!). +public fun claim(otw: OTW, ctx: &mut TxContext): Publisher { + assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); - let tyname = type_name::get_with_original_ids(); + let tyname = type_name::get_with_original_ids(); - Publisher { - id: object::new(ctx), - package: tyname.get_address(), - module_name: tyname.get_module(), - } + Publisher { + id: object::new(ctx), + package: tyname.get_address(), + module_name: tyname.get_module(), } +} - #[allow(lint(self_transfer))] - /// Claim a Publisher object and send it to transaction sender. - /// Since this function can only be called in the module initializer, - /// the sender is the publisher. - public fun claim_and_keep(otw: OTW, ctx: &mut TxContext) { - sui::transfer::public_transfer(claim(otw, ctx), ctx.sender()) - } +#[allow(lint(self_transfer))] +/// Claim a Publisher object and send it to transaction sender. +/// Since this function can only be called in the module initializer, +/// the sender is the publisher. +public fun claim_and_keep(otw: OTW, ctx: &mut TxContext) { + sui::transfer::public_transfer(claim(otw, ctx), ctx.sender()) +} - /// Destroy a Publisher object effectively removing all privileges - /// associated with it. - public fun burn_publisher(self: Publisher) { - let Publisher { id, package: _, module_name: _ } = self; - id.delete(); - } +/// Destroy a Publisher object effectively removing all privileges +/// associated with it. +public fun burn_publisher(self: Publisher) { + let Publisher { id, package: _, module_name: _ } = self; + id.delete(); +} - /// Check whether type belongs to the same package as the publisher object. - public fun from_package(self: &Publisher): bool { - type_name::get_with_original_ids().get_address() == self.package - } +/// Check whether type belongs to the same package as the publisher object. +public fun from_package(self: &Publisher): bool { + type_name::get_with_original_ids().get_address() == self.package +} - /// Check whether a type belongs to the same module as the publisher object. - public fun from_module(self: &Publisher): bool { - let tyname = type_name::get_with_original_ids(); +/// Check whether a type belongs to the same module as the publisher object. +public fun from_module(self: &Publisher): bool { + let tyname = type_name::get_with_original_ids(); - (tyname.get_address() == self.package) && (tyname.get_module() == self.module_name) - } + (tyname.get_address() == self.package) && (tyname.get_module() == self.module_name) +} - /// Read the name of the module. - public fun published_module(self: &Publisher): &String { - &self.module_name - } +/// Read the name of the module. +public fun published_module(self: &Publisher): &String { + &self.module_name +} - /// Read the package address string. - public fun published_package(self: &Publisher): &String { - &self.package - } +/// Read the package address string. +public fun published_package(self: &Publisher): &String { + &self.package +} - /// The ID of the package that this cap authorizes upgrades for. - /// Can be `0x0` if the cap cannot currently authorize an upgrade - /// because there is already a pending upgrade in the transaction. - /// Otherwise guaranteed to be the latest version of any given - /// package. - public fun upgrade_package(cap: &UpgradeCap): ID { - cap.package - } +/// The ID of the package that this cap authorizes upgrades for. +/// Can be `0x0` if the cap cannot currently authorize an upgrade +/// because there is already a pending upgrade in the transaction. +/// Otherwise guaranteed to be the latest version of any given +/// package. +public fun upgrade_package(cap: &UpgradeCap): ID { + cap.package +} - /// The most recent version of the package, increments by one for each - /// successfully applied upgrade. - public fun version(cap: &UpgradeCap): u64 { - cap.version - } +/// The most recent version of the package, increments by one for each +/// successfully applied upgrade. +public fun version(cap: &UpgradeCap): u64 { + cap.version +} - /// The most permissive kind of upgrade currently supported by this - /// `cap`. - public fun upgrade_policy(cap: &UpgradeCap): u8 { - cap.policy - } +/// The most permissive kind of upgrade currently supported by this +/// `cap`. +public fun upgrade_policy(cap: &UpgradeCap): u8 { + cap.policy +} - /// The package that this ticket is authorized to upgrade - public fun ticket_package(ticket: &UpgradeTicket): ID { - ticket.package - } +/// The package that this ticket is authorized to upgrade +public fun ticket_package(ticket: &UpgradeTicket): ID { + ticket.package +} - /// The kind of upgrade that this ticket authorizes. - public fun ticket_policy(ticket: &UpgradeTicket): u8 { - ticket.policy - } +/// The kind of upgrade that this ticket authorizes. +public fun ticket_policy(ticket: &UpgradeTicket): u8 { + ticket.policy +} - /// ID of the `UpgradeCap` that this `receipt` should be used to - /// update. - public fun receipt_cap(receipt: &UpgradeReceipt): ID { - receipt.cap - } +/// ID of the `UpgradeCap` that this `receipt` should be used to +/// update. +public fun receipt_cap(receipt: &UpgradeReceipt): ID { + receipt.cap +} - /// ID of the package that was upgraded to: the latest version of - /// the package, as of the upgrade represented by this `receipt`. - public fun receipt_package(receipt: &UpgradeReceipt): ID { - receipt.package - } +/// ID of the package that was upgraded to: the latest version of +/// the package, as of the upgrade represented by this `receipt`. +public fun receipt_package(receipt: &UpgradeReceipt): ID { + receipt.package +} - /// A hash of the package contents for the new version of the - /// package. This ticket only authorizes an upgrade to a package - /// that matches this digest. A package's contents are identified - /// by two things: - /// - /// - modules: [[u8]] a list of the package's module contents - /// - deps: [[u8; 32]] a list of 32 byte ObjectIDs of the - /// package's transitive dependencies - /// - /// A package's digest is calculated as: - /// - /// sha3_256(sort(modules ++ deps)) - public fun ticket_digest(ticket: &UpgradeTicket): &vector { - &ticket.digest - } +/// A hash of the package contents for the new version of the +/// package. This ticket only authorizes an upgrade to a package +/// that matches this digest. A package's contents are identified +/// by two things: +/// +/// - modules: [[u8]] a list of the package's module contents +/// - deps: [[u8; 32]] a list of 32 byte ObjectIDs of the +/// package's transitive dependencies +/// +/// A package's digest is calculated as: +/// +/// sha3_256(sort(modules ++ deps)) +public fun ticket_digest(ticket: &UpgradeTicket): &vector { + &ticket.digest +} - /// Expose the constants representing various upgrade policies - public fun compatible_policy(): u8 { COMPATIBLE } - public fun additive_policy(): u8 { ADDITIVE } - public fun dep_only_policy(): u8 { DEP_ONLY } +/// Expose the constants representing various upgrade policies +public fun compatible_policy(): u8 { COMPATIBLE } - /// Restrict upgrades through this upgrade `cap` to just add code, or - /// change dependencies. - public entry fun only_additive_upgrades(cap: &mut UpgradeCap) { - cap.restrict(ADDITIVE) - } +public fun additive_policy(): u8 { ADDITIVE } - /// Restrict upgrades through this upgrade `cap` to just change - /// dependencies. - public entry fun only_dep_upgrades(cap: &mut UpgradeCap) { - cap.restrict(DEP_ONLY) - } +public fun dep_only_policy(): u8 { DEP_ONLY } - /// Discard the `UpgradeCap` to make a package immutable. - public entry fun make_immutable(cap: UpgradeCap) { - let UpgradeCap { id, package: _, version: _, policy: _ } = cap; - id.delete(); - } +/// Restrict upgrades through this upgrade `cap` to just add code, or +/// change dependencies. +public entry fun only_additive_upgrades(cap: &mut UpgradeCap) { + cap.restrict(ADDITIVE) +} + +/// Restrict upgrades through this upgrade `cap` to just change +/// dependencies. +public entry fun only_dep_upgrades(cap: &mut UpgradeCap) { + cap.restrict(DEP_ONLY) +} - /// Issue a ticket authorizing an upgrade to a particular new bytecode - /// (identified by its digest). A ticket will only be issued if one has - /// not already been issued, and if the `policy` requested is at least as - /// restrictive as the policy set out by the `cap`. - /// - /// The `digest` supplied and the `policy` will both be checked by - /// validators when running the upgrade. I.e. the bytecode supplied in - /// the upgrade must have a matching digest, and the changes relative to - /// the parent package must be compatible with the policy in the ticket - /// for the upgrade to succeed. - public fun authorize_upgrade( - cap: &mut UpgradeCap, - policy: u8, - digest: vector - ): UpgradeTicket { - let id_zero = @0x0.to_id(); - assert!(cap.package != id_zero, EAlreadyAuthorized); - assert!(policy >= cap.policy, ETooPermissive); - - let package = cap.package; - cap.package = id_zero; - - UpgradeTicket { - cap: object::id(cap), - package, - policy, - digest, - } +/// Discard the `UpgradeCap` to make a package immutable. +public entry fun make_immutable(cap: UpgradeCap) { + let UpgradeCap { id, package: _, version: _, policy: _ } = cap; + id.delete(); +} + +/// Issue a ticket authorizing an upgrade to a particular new bytecode +/// (identified by its digest). A ticket will only be issued if one has +/// not already been issued, and if the `policy` requested is at least as +/// restrictive as the policy set out by the `cap`. +/// +/// The `digest` supplied and the `policy` will both be checked by +/// validators when running the upgrade. I.e. the bytecode supplied in +/// the upgrade must have a matching digest, and the changes relative to +/// the parent package must be compatible with the policy in the ticket +/// for the upgrade to succeed. +public fun authorize_upgrade(cap: &mut UpgradeCap, policy: u8, digest: vector): UpgradeTicket { + let id_zero = @0x0.to_id(); + assert!(cap.package != id_zero, EAlreadyAuthorized); + assert!(policy >= cap.policy, ETooPermissive); + + let package = cap.package; + cap.package = id_zero; + + UpgradeTicket { + cap: object::id(cap), + package, + policy, + digest, } +} - /// Consume an `UpgradeReceipt` to update its `UpgradeCap`, finalizing - /// the upgrade. - public fun commit_upgrade( - cap: &mut UpgradeCap, - receipt: UpgradeReceipt, - ) { - let UpgradeReceipt { cap: cap_id, package } = receipt; +/// Consume an `UpgradeReceipt` to update its `UpgradeCap`, finalizing +/// the upgrade. +public fun commit_upgrade(cap: &mut UpgradeCap, receipt: UpgradeReceipt) { + let UpgradeReceipt { cap: cap_id, package } = receipt; - assert!(object::id(cap) == cap_id, EWrongUpgradeCap); - assert!(cap.package.to_address() == @0x0, ENotAuthorized); + assert!(object::id(cap) == cap_id, EWrongUpgradeCap); + assert!(cap.package.to_address() == @0x0, ENotAuthorized); - cap.package = package; - cap.version = cap.version + 1; - } + cap.package = package; + cap.version = cap.version + 1; +} - #[test_only] - /// Test-only function to claim a Publisher object bypassing OTW check. - public fun test_claim(_: OTW, ctx: &mut TxContext): Publisher { - let tyname = type_name::get_with_original_ids(); +#[test_only] +/// Test-only function to claim a Publisher object bypassing OTW check. +public fun test_claim(_: OTW, ctx: &mut TxContext): Publisher { + let tyname = type_name::get_with_original_ids(); - Publisher { - id: object::new(ctx), - package: tyname.get_address(), - module_name: tyname.get_module(), - } + Publisher { + id: object::new(ctx), + package: tyname.get_address(), + module_name: tyname.get_module(), } +} - #[test_only] - /// Test-only function to simulate publishing a package at address - /// `ID`, to create an `UpgradeCap`. - public fun test_publish(package: ID, ctx: &mut TxContext): UpgradeCap { - UpgradeCap { - id: object::new(ctx), - package, - version: 1, - policy: COMPATIBLE, - } +#[test_only] +/// Test-only function to simulate publishing a package at address +/// `ID`, to create an `UpgradeCap`. +public fun test_publish(package: ID, ctx: &mut TxContext): UpgradeCap { + UpgradeCap { + id: object::new(ctx), + package, + version: 1, + policy: COMPATIBLE, } +} - #[test_only] - /// Test-only function that takes the role of the actual `Upgrade` - /// command, converting the ticket for the pending upgrade to a - /// receipt for a completed upgrade. - public fun test_upgrade(ticket: UpgradeTicket): UpgradeReceipt { - let UpgradeTicket { cap, package, policy: _, digest: _ } = ticket; - - // Generate a fake package ID for the upgraded package by - // hashing the existing package and cap ID. - let mut data = cap.to_bytes(); - data.append(package.to_bytes()); - let package = object::id_from_bytes(sui::hash::blake2b256(&data)); - - UpgradeReceipt { - cap, package - } +#[test_only] +/// Test-only function that takes the role of the actual `Upgrade` +/// command, converting the ticket for the pending upgrade to a +/// receipt for a completed upgrade. +public fun test_upgrade(ticket: UpgradeTicket): UpgradeReceipt { + let UpgradeTicket { cap, package, policy: _, digest: _ } = ticket; + + // Generate a fake package ID for the upgraded package by + // hashing the existing package and cap ID. + let mut data = cap.to_bytes(); + data.append(package.to_bytes()); + let package = object::id_from_bytes(sui::hash::blake2b256(&data)); + + UpgradeReceipt { + cap, + package, } +} - fun restrict(cap: &mut UpgradeCap, policy: u8) { - assert!(cap.policy <= policy, ETooPermissive); - cap.policy = policy; - } +fun restrict(cap: &mut UpgradeCap, policy: u8) { + assert!(cap.policy <= policy, ETooPermissive); + cap.policy = policy; } diff --git a/crates/sui-framework/packages/sui-framework/sources/pay.move b/crates/sui-framework/packages/sui-framework/sources/pay.move index a13bab88c68c6..f161e935bcfb8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/pay.move +++ b/crates/sui-framework/packages/sui-framework/sources/pay.move @@ -2,86 +2,82 @@ // SPDX-License-Identifier: Apache-2.0 /// This module provides handy functionality for wallets and `sui::Coin` management. -module sui::pay { - use sui::coin::Coin; +module sui::pay; - /// For when empty vector is supplied into join function. - const ENoCoins: u64 = 0; +use sui::coin::Coin; - #[allow(lint(self_transfer))] - /// Transfer `c` to the sender of the current transaction - public fun keep(c: Coin, ctx: &TxContext) { - transfer::public_transfer(c, ctx.sender()) - } +/// For when empty vector is supplied into join function. +const ENoCoins: u64 = 0; - /// Split coin `self` to two coins, one with balance `split_amount`, - /// and the remaining balance is left is `self`. - public entry fun split( - coin: &mut Coin, split_amount: u64, ctx: &mut TxContext - ) { - keep(coin.split(split_amount, ctx), ctx) - } +#[allow(lint(self_transfer))] +/// Transfer `c` to the sender of the current transaction +public fun keep(c: Coin, ctx: &TxContext) { + transfer::public_transfer(c, ctx.sender()) +} - /// Split coin `self` into multiple coins, each with balance specified - /// in `split_amounts`. Remaining balance is left in `self`. - public entry fun split_vec( - self: &mut Coin, split_amounts: vector, ctx: &mut TxContext - ) { - let (mut i, len) = (0, split_amounts.length()); - while (i < len) { - split(self, split_amounts[i], ctx); - i = i + 1; - }; - } +/// Split coin `self` to two coins, one with balance `split_amount`, +/// and the remaining balance is left is `self`. +public entry fun split(coin: &mut Coin, split_amount: u64, ctx: &mut TxContext) { + keep(coin.split(split_amount, ctx), ctx) +} - /// Send `amount` units of `c` to `recipient` - /// Aborts with `EVALUE` if `amount` is greater than or equal to `amount` - public entry fun split_and_transfer( - c: &mut Coin, amount: u64, recipient: address, ctx: &mut TxContext - ) { - transfer::public_transfer(c.split(amount, ctx), recipient) - } +/// Split coin `self` into multiple coins, each with balance specified +/// in `split_amounts`. Remaining balance is left in `self`. +public entry fun split_vec(self: &mut Coin, split_amounts: vector, ctx: &mut TxContext) { + let (mut i, len) = (0, split_amounts.length()); + while (i < len) { + split(self, split_amounts[i], ctx); + i = i + 1; + }; +} +/// Send `amount` units of `c` to `recipient` +/// Aborts with `EVALUE` if `amount` is greater than or equal to `amount` +public entry fun split_and_transfer( + c: &mut Coin, + amount: u64, + recipient: address, + ctx: &mut TxContext, +) { + transfer::public_transfer(c.split(amount, ctx), recipient) +} - #[allow(lint(self_transfer))] - /// Divide coin `self` into `n - 1` coins with equal balances. If the balance is - /// not evenly divisible by `n`, the remainder is left in `self`. - public entry fun divide_and_keep( - self: &mut Coin, n: u64, ctx: &mut TxContext - ) { - let mut vec: vector> = self.divide_into_n(n, ctx); - let (mut i, len) = (0, vec.length()); - while (i < len) { - transfer::public_transfer(vec.pop_back(), ctx.sender()); - i = i + 1; - }; - vec.destroy_empty(); - } +#[allow(lint(self_transfer))] +/// Divide coin `self` into `n - 1` coins with equal balances. If the balance is +/// not evenly divisible by `n`, the remainder is left in `self`. +public entry fun divide_and_keep(self: &mut Coin, n: u64, ctx: &mut TxContext) { + let mut vec: vector> = self.divide_into_n(n, ctx); + let (mut i, len) = (0, vec.length()); + while (i < len) { + transfer::public_transfer(vec.pop_back(), ctx.sender()); + i = i + 1; + }; + vec.destroy_empty(); +} - /// Join `coin` into `self`. Re-exports `coin::join` function. - /// Deprecated: you should call `coin.join(other)` directly. - public entry fun join(self: &mut Coin, coin: Coin) { - self.join(coin) - } +/// Join `coin` into `self`. Re-exports `coin::join` function. +/// Deprecated: you should call `coin.join(other)` directly. +public entry fun join(self: &mut Coin, coin: Coin) { + self.join(coin) +} - /// Join everything in `coins` with `self` - public entry fun join_vec(self: &mut Coin, mut coins: vector>) { - let (mut i, len) = (0, coins.length()); - while (i < len) { - let coin = coins.pop_back(); - self.join(coin); - i = i + 1 - }; - // safe because we've drained the vector - coins.destroy_empty() - } +/// Join everything in `coins` with `self` +public entry fun join_vec(self: &mut Coin, mut coins: vector>) { + let (mut i, len) = (0, coins.length()); + while (i < len) { + let coin = coins.pop_back(); + self.join(coin); + i = i + 1 + }; + // safe because we've drained the vector + coins.destroy_empty() +} - /// Join a vector of `Coin` into a single object and transfer it to `receiver`. - public entry fun join_vec_and_transfer(mut coins: vector>, receiver: address) { - assert!(coins.length() > 0, ENoCoins); +/// Join a vector of `Coin` into a single object and transfer it to `receiver`. +public entry fun join_vec_and_transfer(mut coins: vector>, receiver: address) { + assert!(coins.length() > 0, ENoCoins); - let mut self = coins.pop_back(); - join_vec(&mut self, coins); - transfer::public_transfer(self, receiver) - } + let mut self = coins.pop_back(); + join_vec(&mut self, coins); + transfer::public_transfer(self, receiver) } diff --git a/crates/sui-framework/packages/sui-framework/sources/prover.move b/crates/sui-framework/packages/sui-framework/sources/prover.move index e52feb4826479..6c06173ef87a9 100644 --- a/crates/sui-framework/packages/sui-framework/sources/prover.move +++ b/crates/sui-framework/packages/sui-framework/sources/prover.move @@ -1,5 +1,4 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module sui::prover { -} +module sui::prover; diff --git a/crates/sui-framework/packages/sui-framework/sources/random.move b/crates/sui-framework/packages/sui-framework/sources/random.move index 8d7cdf10025d7..0e687c216d80e 100644 --- a/crates/sui-framework/packages/sui-framework/sources/random.move +++ b/crates/sui-framework/packages/sui-framework/sources/random.move @@ -2,325 +2,320 @@ // SPDX-License-Identifier: Apache-2.0 /// This module provides functionality for generating secure randomness. -module sui::random { - use std::bcs; - use sui::hmac::hmac_sha3_256; - use sui::versioned::{Self, Versioned}; - - // Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; - const EWrongInnerVersion: u64 = 1; - const EInvalidRandomnessUpdate: u64 = 2; - const EInvalidRange: u64 = 3; - const EInvalidLength: u64 = 4; - - const CURRENT_VERSION: u64 = 1; - const RAND_OUTPUT_LEN: u16 = 32; - const U16_MAX: u64 = 0xFFFF; - - /// Singleton shared object which stores the global randomness state. - /// The actual state is stored in a versioned inner field. - public struct Random has key { - id: UID, - // The inner object must never be accessed outside this module as it could be used for accessing global - // randomness via deserialization of RandomInner. - inner: Versioned, - } - - public struct RandomInner has store { - version: u64, - epoch: u64, - randomness_round: u64, - random_bytes: vector, - } - - #[allow(unused_function)] - /// Create and share the Random object. This function is called exactly once, when - /// the Random object is first created. - /// Can only be called by genesis or change_epoch transactions. - fun create(ctx: &mut TxContext) { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - let version = CURRENT_VERSION; - - let inner = RandomInner { - version, - epoch: ctx.epoch(), - randomness_round: 0, - random_bytes: vector[], - }; - - let self = Random { - id: object::randomness_state(), - inner: versioned::create(version, inner, ctx), - }; - transfer::share_object(self); - } - - #[test_only] - public fun create_for_testing(ctx: &mut TxContext) { - create(ctx); - } - - fun load_inner_mut( - self: &mut Random, - ): &mut RandomInner { - let version = versioned::version(&self.inner); - - // Replace this with a lazy update function when we add a new version of the inner object. - assert!(version == CURRENT_VERSION, EWrongInnerVersion); - let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner); - assert!(inner.version == version, EWrongInnerVersion); - inner - } - - fun load_inner( - self: &Random, - ): &RandomInner { - let version = versioned::version(&self.inner); - - // Replace this with a lazy update function when we add a new version of the inner object. - assert!(version == CURRENT_VERSION, EWrongInnerVersion); - let inner: &RandomInner = versioned::load_value(&self.inner); - assert!(inner.version == version, EWrongInnerVersion); - inner - } - - #[allow(unused_function)] - /// Record new randomness. Called when executing the RandomnessStateUpdate system - /// transaction. - fun update_randomness_state( - self: &mut Random, - new_round: u64, - new_bytes: vector, - ctx: &TxContext, - ) { - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - // Randomness should only be incremented. - let epoch = ctx.epoch(); - let inner = self.load_inner_mut(); - if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) { - // First update should be for round zero. - assert!(new_round == 0, EInvalidRandomnessUpdate); - } else { - // Subsequent updates should either increase epoch or increment randomness_round. - // Note that epoch may increase by more than 1 if an epoch is completed without - // randomness ever being generated in that epoch. - assert!( - (epoch > inner.epoch && new_round == 0) || +module sui::random; + +use std::bcs; +use sui::hmac::hmac_sha3_256; +use sui::versioned::{Self, Versioned}; + +// Sender is not @0x0 the system address. +const ENotSystemAddress: u64 = 0; +const EWrongInnerVersion: u64 = 1; +const EInvalidRandomnessUpdate: u64 = 2; +const EInvalidRange: u64 = 3; +const EInvalidLength: u64 = 4; + +const CURRENT_VERSION: u64 = 1; +const RAND_OUTPUT_LEN: u16 = 32; +const U16_MAX: u64 = 0xFFFF; + +/// Singleton shared object which stores the global randomness state. +/// The actual state is stored in a versioned inner field. +public struct Random has key { + id: UID, + // The inner object must never be accessed outside this module as it could be used for accessing global + // randomness via deserialization of RandomInner. + inner: Versioned, +} + +public struct RandomInner has store { + version: u64, + epoch: u64, + randomness_round: u64, + random_bytes: vector, +} + +#[allow(unused_function)] +/// Create and share the Random object. This function is called exactly once, when +/// the Random object is first created. +/// Can only be called by genesis or change_epoch transactions. +fun create(ctx: &mut TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + let version = CURRENT_VERSION; + + let inner = RandomInner { + version, + epoch: ctx.epoch(), + randomness_round: 0, + random_bytes: vector[], + }; + + let self = Random { + id: object::randomness_state(), + inner: versioned::create(version, inner, ctx), + }; + transfer::share_object(self); +} + +#[test_only] +public fun create_for_testing(ctx: &mut TxContext) { + create(ctx); +} + +fun load_inner_mut(self: &mut Random): &mut RandomInner { + let version = versioned::version(&self.inner); + + // Replace this with a lazy update function when we add a new version of the inner object. + assert!(version == CURRENT_VERSION, EWrongInnerVersion); + let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner); + assert!(inner.version == version, EWrongInnerVersion); + inner +} + +fun load_inner(self: &Random): &RandomInner { + let version = versioned::version(&self.inner); + + // Replace this with a lazy update function when we add a new version of the inner object. + assert!(version == CURRENT_VERSION, EWrongInnerVersion); + let inner: &RandomInner = versioned::load_value(&self.inner); + assert!(inner.version == version, EWrongInnerVersion); + inner +} + +#[allow(unused_function)] +/// Record new randomness. Called when executing the RandomnessStateUpdate system +/// transaction. +fun update_randomness_state( + self: &mut Random, + new_round: u64, + new_bytes: vector, + ctx: &TxContext, +) { + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + // Randomness should only be incremented. + let epoch = ctx.epoch(); + let inner = self.load_inner_mut(); + if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) { + // First update should be for round zero. + assert!(new_round == 0, EInvalidRandomnessUpdate); + } else { + // Subsequent updates should either increase epoch or increment randomness_round. + // Note that epoch may increase by more than 1 if an epoch is completed without + // randomness ever being generated in that epoch. + assert!( + (epoch > inner.epoch && new_round == 0) || (new_round == inner.randomness_round + 1), - EInvalidRandomnessUpdate - ); - }; - - inner.epoch = ctx.epoch(); - inner.randomness_round = new_round; - inner.random_bytes = new_bytes; - } - - #[test_only] - public fun update_randomness_state_for_testing( - self: &mut Random, - new_round: u64, - new_bytes: vector, - ctx: &TxContext, - ) { - self.update_randomness_state(new_round, new_bytes, ctx); - } - - - /// Unique randomness generator, derived from the global randomness. - public struct RandomGenerator has drop { - seed: vector, - counter: u16, - buffer: vector, - } - - /// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. - public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator { - let inner = load_inner(r); - let seed = hmac_sha3_256( - &inner.random_bytes, - &ctx.fresh_object_address().to_bytes() + EInvalidRandomnessUpdate, ); - RandomGenerator { seed, counter: 0, buffer: vector[] } - } - - // Get the next block of random bytes. - fun derive_next_block(g: &mut RandomGenerator): vector { - g.counter = g.counter + 1; - hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter)) - } - - // Fill the generator's buffer with 32 random bytes. - fun fill_buffer(g: &mut RandomGenerator) { - let next_block = derive_next_block(g); - vector::append(&mut g.buffer, next_block); - } - - /// Generate n random bytes. - public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector { - let mut result = vector[]; - // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer. - let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN; - while (num_of_blocks > 0) { - vector::append(&mut result, derive_next_block(g)); - num_of_blocks = num_of_blocks - 1; - }; - // Fill the generator's buffer if needed. - let num_of_bytes = num_of_bytes as u64; - if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) { - fill_buffer(g); - }; - // Take remaining bytes from the generator's buffer. - while (vector::length(&result) < num_of_bytes) { - vector::push_back(&mut result, vector::pop_back(&mut g.buffer)); - }; - result - } - - // Helper function that extracts the given number of bytes from the random generator and returns it as u256. - // Assumes that the caller has already checked that num_of_bytes is valid. - // TODO: Replace with a macro when we have support for it. - fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 { - if (vector::length(&g.buffer) < num_of_bytes as u64) { - fill_buffer(g); - }; - let mut result: u256 = 0; - let mut i = 0; - while (i < num_of_bytes) { - let byte = vector::pop_back(&mut g.buffer); - result = (result << 8) + (byte as u256); - i = i + 1; - }; - result - } - - /// Generate a u256. - public fun generate_u256(g: &mut RandomGenerator): u256 { - u256_from_bytes(g, 32) - } - - /// Generate a u128. - public fun generate_u128(g: &mut RandomGenerator): u128 { - u256_from_bytes(g, 16) as u128 - } - - /// Generate a u64. - public fun generate_u64(g: &mut RandomGenerator): u64 { - u256_from_bytes(g, 8) as u64 - } - - /// Generate a u32. - public fun generate_u32(g: &mut RandomGenerator): u32 { - u256_from_bytes(g, 4) as u32 - } - - /// Generate a u16. - public fun generate_u16(g: &mut RandomGenerator): u16 { - u256_from_bytes(g, 2) as u16 - } - - /// Generate a u8. - public fun generate_u8(g: &mut RandomGenerator): u8 { - u256_from_bytes(g, 1) as u8 - } - - /// Generate a boolean. - public fun generate_bool(g: &mut RandomGenerator): bool { - (u256_from_bytes(g, 1) & 1) == 1 - } - - // Helper function to generate a random u128 in [min, max] using a random number with num_of_bytes bytes. - // Assumes that the caller verified the inputs, and uses num_of_bytes to control the bias (e.g., 8 bytes larger - // than the actual type used by the caller function to limit the bias by 2^{-64}). - // TODO: Replace with a macro when we have support for it. - fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 { - assert!(min <= max, EInvalidRange); - if (min == max) { - return min - }; - // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking - // the modulo of the random number by the range size. Then add the min to the result to get a number in - // [min, max]. - let range_size = (max - min) as u256 + 1; - let rand = u256_from_bytes(g, num_of_bytes); - min + (rand % range_size as u128) - } - - /// Generate a random u128 in [min, max] (with a bias of 2^{-64}). - public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 { - u128_in_range(g, min, max, 24) - } - - //// Generate a random u64 in [min, max] (with a bias of 2^{-64}). - public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 { - u128_in_range(g, min as u128, max as u128, 16) as u64 - } - - /// Generate a random u32 in [min, max] (with a bias of 2^{-64}). - public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 { - u128_in_range(g, min as u128, max as u128, 12) as u32 - } - - /// Generate a random u16 in [min, max] (with a bias of 2^{-64}). - public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 { - u128_in_range(g, min as u128, max as u128, 10) as u16 - } - - /// Generate a random u8 in [min, max] (with a bias of 2^{-64}). - public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 { - u128_in_range(g, min as u128, max as u128, 9) as u8 - } - - /// Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). - public fun shuffle(g: &mut RandomGenerator, v: &mut vector) { - let n = vector::length(v); - if (n == 0) { - return - }; - assert!(n <= U16_MAX, EInvalidLength); - let n = n as u16; - let mut i: u16 = 0; - let end = n - 1; - while (i < end) { - let j = generate_u16_in_range(g, i, end); - vector::swap(v, i as u64, j as u64); - i = i + 1; - }; - } - - #[test_only] - public fun generator_seed(r: &RandomGenerator): &vector { - &r.seed - } - - #[test_only] - public fun generator_counter(r: &RandomGenerator): u16 { - r.counter - } - - #[test_only] - public fun generator_buffer(r: &RandomGenerator): &vector { - &r.buffer - } - - #[test_only] - /// Random generator from a non-deterministic seed. - /// To be used when non-deterministic randomness is needed in tests (e.g., fuzzing). - public fun new_generator_for_testing(): RandomGenerator { - let seed = generate_rand_seed_for_testing(); - new_generator_from_seed_for_testing(seed) - } - - #[test_only] - /// Random generator from a given seed. - public fun new_generator_from_seed_for_testing(seed: vector): RandomGenerator { - RandomGenerator { seed, counter: 0, buffer: vector[] } - } - - #[test_only] - native fun generate_rand_seed_for_testing(): vector; + }; + + inner.epoch = ctx.epoch(); + inner.randomness_round = new_round; + inner.random_bytes = new_bytes; +} + +#[test_only] +public fun update_randomness_state_for_testing( + self: &mut Random, + new_round: u64, + new_bytes: vector, + ctx: &TxContext, +) { + self.update_randomness_state(new_round, new_bytes, ctx); +} + +/// Unique randomness generator, derived from the global randomness. +public struct RandomGenerator has drop { + seed: vector, + counter: u16, + buffer: vector, +} + +/// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. +public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator { + let inner = load_inner(r); + let seed = hmac_sha3_256( + &inner.random_bytes, + &ctx.fresh_object_address().to_bytes(), + ); + RandomGenerator { seed, counter: 0, buffer: vector[] } +} + +// Get the next block of random bytes. +fun derive_next_block(g: &mut RandomGenerator): vector { + g.counter = g.counter + 1; + hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter)) +} + +// Fill the generator's buffer with 32 random bytes. +fun fill_buffer(g: &mut RandomGenerator) { + let next_block = derive_next_block(g); + vector::append(&mut g.buffer, next_block); +} + +/// Generate n random bytes. +public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector { + let mut result = vector[]; + // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer. + let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN; + while (num_of_blocks > 0) { + vector::append(&mut result, derive_next_block(g)); + num_of_blocks = num_of_blocks - 1; + }; + // Fill the generator's buffer if needed. + let num_of_bytes = num_of_bytes as u64; + if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) { + fill_buffer(g); + }; + // Take remaining bytes from the generator's buffer. + while (vector::length(&result) < num_of_bytes) { + vector::push_back(&mut result, vector::pop_back(&mut g.buffer)); + }; + result +} + +// Helper function that extracts the given number of bytes from the random generator and returns it as u256. +// Assumes that the caller has already checked that num_of_bytes is valid. +// TODO: Replace with a macro when we have support for it. +fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 { + if (vector::length(&g.buffer) < num_of_bytes as u64) { + fill_buffer(g); + }; + let mut result: u256 = 0; + let mut i = 0; + while (i < num_of_bytes) { + let byte = vector::pop_back(&mut g.buffer); + result = (result << 8) + (byte as u256); + i = i + 1; + }; + result +} + +/// Generate a u256. +public fun generate_u256(g: &mut RandomGenerator): u256 { + u256_from_bytes(g, 32) +} + +/// Generate a u128. +public fun generate_u128(g: &mut RandomGenerator): u128 { + u256_from_bytes(g, 16) as u128 +} + +/// Generate a u64. +public fun generate_u64(g: &mut RandomGenerator): u64 { + u256_from_bytes(g, 8) as u64 +} + +/// Generate a u32. +public fun generate_u32(g: &mut RandomGenerator): u32 { + u256_from_bytes(g, 4) as u32 +} + +/// Generate a u16. +public fun generate_u16(g: &mut RandomGenerator): u16 { + u256_from_bytes(g, 2) as u16 +} + +/// Generate a u8. +public fun generate_u8(g: &mut RandomGenerator): u8 { + u256_from_bytes(g, 1) as u8 +} + +/// Generate a boolean. +public fun generate_bool(g: &mut RandomGenerator): bool { + (u256_from_bytes(g, 1) & 1) == 1 +} + +// Helper function to generate a random u128 in [min, max] using a random number with num_of_bytes bytes. +// Assumes that the caller verified the inputs, and uses num_of_bytes to control the bias (e.g., 8 bytes larger +// than the actual type used by the caller function to limit the bias by 2^{-64}). +// TODO: Replace with a macro when we have support for it. +fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 { + assert!(min <= max, EInvalidRange); + if (min == max) { + return min + }; + // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking + // the modulo of the random number by the range size. Then add the min to the result to get a number in + // [min, max]. + let range_size = (max - min) as u256 + 1; + let rand = u256_from_bytes(g, num_of_bytes); + min + (rand % range_size as u128) +} + +/// Generate a random u128 in [min, max] (with a bias of 2^{-64}). +public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 { + u128_in_range(g, min, max, 24) +} + +//// Generate a random u64 in [min, max] (with a bias of 2^{-64}). +public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 { + u128_in_range(g, min as u128, max as u128, 16) as u64 +} + +/// Generate a random u32 in [min, max] (with a bias of 2^{-64}). +public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 { + u128_in_range(g, min as u128, max as u128, 12) as u32 } + +/// Generate a random u16 in [min, max] (with a bias of 2^{-64}). +public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 { + u128_in_range(g, min as u128, max as u128, 10) as u16 +} + +/// Generate a random u8 in [min, max] (with a bias of 2^{-64}). +public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 { + u128_in_range(g, min as u128, max as u128, 9) as u8 +} + +/// Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). +public fun shuffle(g: &mut RandomGenerator, v: &mut vector) { + let n = vector::length(v); + if (n == 0) { + return + }; + assert!(n <= U16_MAX, EInvalidLength); + let n = n as u16; + let mut i: u16 = 0; + let end = n - 1; + while (i < end) { + let j = generate_u16_in_range(g, i, end); + vector::swap(v, i as u64, j as u64); + i = i + 1; + }; +} + +#[test_only] +public fun generator_seed(r: &RandomGenerator): &vector { + &r.seed +} + +#[test_only] +public fun generator_counter(r: &RandomGenerator): u16 { + r.counter +} + +#[test_only] +public fun generator_buffer(r: &RandomGenerator): &vector { + &r.buffer +} + +#[test_only] +/// Random generator from a non-deterministic seed. +/// To be used when non-deterministic randomness is needed in tests (e.g., fuzzing). +public fun new_generator_for_testing(): RandomGenerator { + let seed = generate_rand_seed_for_testing(); + new_generator_from_seed_for_testing(seed) +} + +#[test_only] +/// Random generator from a given seed. +public fun new_generator_from_seed_for_testing(seed: vector): RandomGenerator { + RandomGenerator { seed, counter: 0, buffer: vector[] } +} + +#[test_only] +native fun generate_rand_seed_for_testing(): vector; diff --git a/crates/sui-framework/packages/sui-framework/sources/tx_context.move b/crates/sui-framework/packages/sui-framework/sources/tx_context.move index 56111acecdc51..1fdef9ff83a81 100644 --- a/crates/sui-framework/packages/sui-framework/sources/tx_context.move +++ b/crates/sui-framework/packages/sui-framework/sources/tx_context.move @@ -1,142 +1,141 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module sui::tx_context { - - #[test_only] - /// Number of bytes in an tx hash (which will be the transaction digest) - const TX_HASH_LENGTH: u64 = 32; - - #[test_only] - /// Expected an tx hash of length 32, but found a different length - const EBadTxHashLength: u64 = 0; - - #[test_only] - /// Attempt to get the most recent created object ID when none has been created. - const ENoIDsCreated: u64 = 1; - - /// Information about the transaction currently being executed. - /// This cannot be constructed by a transaction--it is a privileged object created by - /// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`. - public struct TxContext has drop { - /// The address of the user that signed the current transaction - sender: address, - /// Hash of the current transaction - tx_hash: vector, - /// The current epoch number - epoch: u64, - /// Timestamp that the epoch started at - epoch_timestamp_ms: u64, - /// Counter recording the number of fresh id's created while executing - /// this transaction. Always 0 at the start of a transaction - ids_created: u64 - } - - /// Return the address of the user that signed the current - /// transaction - public fun sender(self: &TxContext): address { - self.sender - } - - /// Return the transaction digest (hash of transaction inputs). - /// Please do not use as a source of randomness. - public fun digest(self: &TxContext): &vector { - &self.tx_hash - } - - /// Return the current epoch - public fun epoch(self: &TxContext): u64 { - self.epoch - } - - /// Return the epoch start time as a unix timestamp in milliseconds. - public fun epoch_timestamp_ms(self: &TxContext): u64 { - self.epoch_timestamp_ms - } - - /// Create an `address` that has not been used. As it is an object address, it will never - /// occur as the address for a user. - /// In other words, the generated address is a globally unique object ID. - public fun fresh_object_address(ctx: &mut TxContext): address { - let ids_created = ctx.ids_created; - let id = derive_id(*&ctx.tx_hash, ids_created); - ctx.ids_created = ids_created + 1; - id - } - - #[allow(unused_function)] - /// Return the number of id's created by the current transaction. - /// Hidden for now, but may expose later - fun ids_created(self: &TxContext): u64 { - self.ids_created - } - - /// Native function for deriving an ID via hash(tx_hash || ids_created) - native fun derive_id(tx_hash: vector, ids_created: u64): address; - - // ==== test-only functions ==== - - #[test_only] - /// Create a `TxContext` for testing - public fun new( - sender: address, - tx_hash: vector, - epoch: u64, - epoch_timestamp_ms: u64, - ids_created: u64, - ): TxContext { - assert!(tx_hash.length() == TX_HASH_LENGTH, EBadTxHashLength); - TxContext { sender, tx_hash, epoch, epoch_timestamp_ms, ids_created } - } - - #[test_only] - /// Create a `TxContext` for testing, with a potentially non-zero epoch number. - public fun new_from_hint( - addr: address, - hint: u64, - epoch: u64, - epoch_timestamp_ms: u64, - ids_created: u64, - ): TxContext { - new(addr, dummy_tx_hash_with_hint(hint), epoch, epoch_timestamp_ms, ids_created) - } - - #[test_only] - /// Create a dummy `TxContext` for testing - public fun dummy(): TxContext { - let tx_hash = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"; - new(@0x0, tx_hash, 0, 0, 0) - } - - #[test_only] - /// Utility for creating 256 unique input hashes. - /// These hashes are guaranteed to be unique given a unique `hint: u64` - fun dummy_tx_hash_with_hint(hint: u64): vector { - let mut tx_hash = std::bcs::to_bytes(&hint); - while (tx_hash.length() < TX_HASH_LENGTH) tx_hash.push_back(0); - tx_hash - } - - #[test_only] - public fun get_ids_created(self: &TxContext): u64 { - ids_created(self) - } - - #[test_only] - /// Return the most recent created object ID. - public fun last_created_object_id(self: &TxContext): address { - let ids_created = self.ids_created; - assert!(ids_created > 0, ENoIDsCreated); - derive_id(*&self.tx_hash, ids_created - 1) - } - - #[test_only] - public fun increment_epoch_number(self: &mut TxContext) { - self.epoch = self.epoch + 1 - } - - #[test_only] - public fun increment_epoch_timestamp(self: &mut TxContext, delta_ms: u64) { - self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms - } +module sui::tx_context; + +#[test_only] +/// Number of bytes in an tx hash (which will be the transaction digest) +const TX_HASH_LENGTH: u64 = 32; + +#[test_only] +/// Expected an tx hash of length 32, but found a different length +const EBadTxHashLength: u64 = 0; + +#[test_only] +/// Attempt to get the most recent created object ID when none has been created. +const ENoIDsCreated: u64 = 1; + +/// Information about the transaction currently being executed. +/// This cannot be constructed by a transaction--it is a privileged object created by +/// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`. +public struct TxContext has drop { + /// The address of the user that signed the current transaction + sender: address, + /// Hash of the current transaction + tx_hash: vector, + /// The current epoch number + epoch: u64, + /// Timestamp that the epoch started at + epoch_timestamp_ms: u64, + /// Counter recording the number of fresh id's created while executing + /// this transaction. Always 0 at the start of a transaction + ids_created: u64, +} + +/// Return the address of the user that signed the current +/// transaction +public fun sender(self: &TxContext): address { + self.sender +} + +/// Return the transaction digest (hash of transaction inputs). +/// Please do not use as a source of randomness. +public fun digest(self: &TxContext): &vector { + &self.tx_hash +} + +/// Return the current epoch +public fun epoch(self: &TxContext): u64 { + self.epoch +} + +/// Return the epoch start time as a unix timestamp in milliseconds. +public fun epoch_timestamp_ms(self: &TxContext): u64 { + self.epoch_timestamp_ms +} + +/// Create an `address` that has not been used. As it is an object address, it will never +/// occur as the address for a user. +/// In other words, the generated address is a globally unique object ID. +public fun fresh_object_address(ctx: &mut TxContext): address { + let ids_created = ctx.ids_created; + let id = derive_id(*&ctx.tx_hash, ids_created); + ctx.ids_created = ids_created + 1; + id +} + +#[allow(unused_function)] +/// Return the number of id's created by the current transaction. +/// Hidden for now, but may expose later +fun ids_created(self: &TxContext): u64 { + self.ids_created +} + +/// Native function for deriving an ID via hash(tx_hash || ids_created) +native fun derive_id(tx_hash: vector, ids_created: u64): address; + +// ==== test-only functions ==== + +#[test_only] +/// Create a `TxContext` for testing +public fun new( + sender: address, + tx_hash: vector, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, +): TxContext { + assert!(tx_hash.length() == TX_HASH_LENGTH, EBadTxHashLength); + TxContext { sender, tx_hash, epoch, epoch_timestamp_ms, ids_created } +} + +#[test_only] +/// Create a `TxContext` for testing, with a potentially non-zero epoch number. +public fun new_from_hint( + addr: address, + hint: u64, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, +): TxContext { + new(addr, dummy_tx_hash_with_hint(hint), epoch, epoch_timestamp_ms, ids_created) +} + +#[test_only] +/// Create a dummy `TxContext` for testing +public fun dummy(): TxContext { + let tx_hash = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"; + new(@0x0, tx_hash, 0, 0, 0) +} + +#[test_only] +/// Utility for creating 256 unique input hashes. +/// These hashes are guaranteed to be unique given a unique `hint: u64` +fun dummy_tx_hash_with_hint(hint: u64): vector { + let mut tx_hash = std::bcs::to_bytes(&hint); + while (tx_hash.length() < TX_HASH_LENGTH) tx_hash.push_back(0); + tx_hash +} + +#[test_only] +public fun get_ids_created(self: &TxContext): u64 { + ids_created(self) +} + +#[test_only] +/// Return the most recent created object ID. +public fun last_created_object_id(self: &TxContext): address { + let ids_created = self.ids_created; + assert!(ids_created > 0, ENoIDsCreated); + derive_id(*&self.tx_hash, ids_created - 1) +} + +#[test_only] +public fun increment_epoch_number(self: &mut TxContext) { + self.epoch = self.epoch + 1 +} + +#[test_only] +public fun increment_epoch_timestamp(self: &mut TxContext, delta_ms: u64) { + self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms } diff --git a/crates/sui-framework/packages/sui-framework/sources/types.move b/crates/sui-framework/packages/sui-framework/sources/types.move index 64a68a82434d3..adfb18a734ec2 100644 --- a/crates/sui-framework/packages/sui-framework/sources/types.move +++ b/crates/sui-framework/packages/sui-framework/sources/types.move @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 /// Sui types helpers and utilities -module sui::types { - // === one-time witness === +module sui::types; - /// Tests if the argument type is a one-time witness, that is a type with only one instantiation - /// across the entire code base. - public native fun is_one_time_witness(_: &T): bool; -} +// === one-time witness === + +/// Tests if the argument type is a one-time witness, that is a type with only one instantiation +/// across the entire code base. +public native fun is_one_time_witness(_: &T): bool; diff --git a/crates/sui-framework/packages/sui-framework/sources/url.move b/crates/sui-framework/packages/sui-framework/sources/url.move index e4bfb272bf551..e2eac86c115b4 100644 --- a/crates/sui-framework/packages/sui-framework/sources/url.move +++ b/crates/sui-framework/packages/sui-framework/sources/url.move @@ -2,34 +2,34 @@ // SPDX-License-Identifier: Apache-2.0 /// URL: standard Uniform Resource Locator string -module sui::url { - use std::ascii::String; +module sui::url; - /// Standard Uniform Resource Locator (URL) string. - public struct Url has store, copy, drop { - // TODO: validate URL format - url: String, - } +use std::ascii::String; - /// Create a `Url`, with no validation - public fun new_unsafe(url: String): Url { - Url { url } - } +/// Standard Uniform Resource Locator (URL) string. +public struct Url has store, copy, drop { + // TODO: validate URL format + url: String, +} - /// Create a `Url` with no validation from bytes - /// Note: this will abort if `bytes` is not valid ASCII - public fun new_unsafe_from_bytes(bytes: vector): Url { - let url = bytes.to_ascii_string(); - Url { url } - } +/// Create a `Url`, with no validation +public fun new_unsafe(url: String): Url { + Url { url } +} - /// Get inner URL - public fun inner_url(self: &Url): String{ - self.url - } +/// Create a `Url` with no validation from bytes +/// Note: this will abort if `bytes` is not valid ASCII +public fun new_unsafe_from_bytes(bytes: vector): Url { + let url = bytes.to_ascii_string(); + Url { url } +} + +/// Get inner URL +public fun inner_url(self: &Url): String { + self.url +} - /// Update the inner URL - public fun update(self: &mut Url, url: String) { - self.url = url; - } +/// Update the inner URL +public fun update(self: &mut Url, url: String) { + self.url = url; } diff --git a/crates/sui-framework/packages/sui-framework/sources/versioned.move b/crates/sui-framework/packages/sui-framework/sources/versioned.move index ae916fcdef8b0..3746bbbd56286 100644 --- a/crates/sui-framework/packages/sui-framework/sources/versioned.move +++ b/crates/sui-framework/packages/sui-framework/sources/versioned.move @@ -1,83 +1,88 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module sui::versioned { - use sui::dynamic_field; +module sui::versioned; - /// Failed to upgrade the inner object due to invalid capability or new version. - const EInvalidUpgrade: u64 = 0; +use sui::dynamic_field; - /// A wrapper type that supports versioning of the inner type. - /// The inner type is a dynamic field of the Versioned object, and is keyed using version. - /// User of this type could load the inner object using corresponding type based on the version. - /// You can also upgrade the inner object to a new type version. - /// If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have - /// to use mutable reference even if it's a read-only API. - public struct Versioned has key, store { - id: UID, - version: u64, - } +/// Failed to upgrade the inner object due to invalid capability or new version. +const EInvalidUpgrade: u64 = 0; - /// Represents a hot potato object generated when we take out the dynamic field. - /// This is to make sure that we always put a new value back. - public struct VersionChangeCap { - versioned_id: ID, - old_version: u64, - } +/// A wrapper type that supports versioning of the inner type. +/// The inner type is a dynamic field of the Versioned object, and is keyed using version. +/// User of this type could load the inner object using corresponding type based on the version. +/// You can also upgrade the inner object to a new type version. +/// If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have +/// to use mutable reference even if it's a read-only API. +public struct Versioned has key, store { + id: UID, + version: u64, +} - /// Create a new Versioned object that contains a initial value of type `T` with an initial version. - public fun create(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned { - let mut self = Versioned { - id: object::new(ctx), - version: init_version, - }; - dynamic_field::add(&mut self.id, init_version, init_value); - self - } +/// Represents a hot potato object generated when we take out the dynamic field. +/// This is to make sure that we always put a new value back. +public struct VersionChangeCap { + versioned_id: ID, + old_version: u64, +} - /// Get the current version of the inner type. - public fun version(self: &Versioned): u64 { - self.version - } +/// Create a new Versioned object that contains a initial value of type `T` with an initial version. +public fun create(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned { + let mut self = Versioned { + id: object::new(ctx), + version: init_version, + }; + dynamic_field::add(&mut self.id, init_version, init_value); + self +} - /// Load the inner value based on the current version. Caller specifies an expected type T. - /// If the type mismatch, the load will fail. - public fun load_value(self: &Versioned): &T { - dynamic_field::borrow(&self.id, self.version) - } +/// Get the current version of the inner type. +public fun version(self: &Versioned): u64 { + self.version +} - /// Similar to load_value, but return a mutable reference. - public fun load_value_mut(self: &mut Versioned): &mut T { - dynamic_field::borrow_mut(&mut self.id, self.version) - } +/// Load the inner value based on the current version. Caller specifies an expected type T. +/// If the type mismatch, the load will fail. +public fun load_value(self: &Versioned): &T { + dynamic_field::borrow(&self.id, self.version) +} - /// Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned - /// and must be used when we upgrade. - public fun remove_value_for_upgrade(self: &mut Versioned): (T, VersionChangeCap) { - ( - dynamic_field::remove(&mut self.id, self.version), - VersionChangeCap { - versioned_id: object::id(self), - old_version: self.version, - } - ) - } +/// Similar to load_value, but return a mutable reference. +public fun load_value_mut(self: &mut Versioned): &mut T { + dynamic_field::borrow_mut(&mut self.id, self.version) +} + +/// Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned +/// and must be used when we upgrade. +public fun remove_value_for_upgrade(self: &mut Versioned): (T, VersionChangeCap) { + ( + dynamic_field::remove(&mut self.id, self.version), + VersionChangeCap { + versioned_id: object::id(self), + old_version: self.version, + }, + ) +} - /// Upgrade the inner object with a new version and new value. Must use the capability returned - /// by calling remove_value_for_upgrade. - public fun upgrade(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) { - let VersionChangeCap { versioned_id, old_version } = cap; - assert!(versioned_id == object::id(self), EInvalidUpgrade); - assert!(old_version < new_version, EInvalidUpgrade); - dynamic_field::add(&mut self.id, new_version, new_value); - self.version = new_version; - } +/// Upgrade the inner object with a new version and new value. Must use the capability returned +/// by calling remove_value_for_upgrade. +public fun upgrade( + self: &mut Versioned, + new_version: u64, + new_value: T, + cap: VersionChangeCap, +) { + let VersionChangeCap { versioned_id, old_version } = cap; + assert!(versioned_id == object::id(self), EInvalidUpgrade); + assert!(old_version < new_version, EInvalidUpgrade); + dynamic_field::add(&mut self.id, new_version, new_value); + self.version = new_version; +} - /// Destroy this Versioned container, and return the inner object. - public fun destroy(self: Versioned): T { - let Versioned { mut id, version } = self; - let ret = dynamic_field::remove(&mut id, version); - id.delete(); - ret - } +/// Destroy this Versioned container, and return the inner object. +public fun destroy(self: Versioned): T { + let Versioned { mut id, version } = self; + let ret = dynamic_field::remove(&mut id, version); + id.delete(); + ret } diff --git a/crates/sui-framework/packages/sui-framework/tests/display_tests.move b/crates/sui-framework/packages/sui-framework/tests/display_tests.move new file mode 100644 index 0000000000000..a704ce67e2c42 --- /dev/null +++ b/crates/sui-framework/packages/sui-framework/tests/display_tests.move @@ -0,0 +1,39 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module sui::display_tests { + use sui::test_scenario as test; + use std::string::String; + use sui::package; + use sui::display; + + #[allow(unused_field)] + /// An example object. + /// Purely for visibility. + public struct Capy has key { + id: UID, + name: String + } + + /// Test witness type to create a Publisher object. + public struct CAPY has drop {} + + #[test] + fun capy_init() { + let mut test = test::begin(@0x2); + let pub = package::test_claim(CAPY {}, test.ctx()); + + // create a new display object + let mut display = display::new(&pub, test.ctx()); + + display.add(b"name".to_string(), b"Capy {name}".to_string()); + display.add(b"link".to_string(), b"https://capy.art/capy/{id}".to_string()); + display.add(b"image".to_string(), b"https://api.capy.art/capy/{id}/svg".to_string()); + display.add(b"description".to_string(), b"A Lovely Capy".to_string()); + + pub.burn_publisher(); + transfer::public_transfer(display, @0x2); + test.end(); + } +} diff --git a/crates/sui-framework/packages/sui-framework/tests/hex_tests.move b/crates/sui-framework/packages/sui-framework/tests/hex_tests.move new file mode 100644 index 0000000000000..990bdb46d8b83 --- /dev/null +++ b/crates/sui-framework/packages/sui-framework/tests/hex_tests.move @@ -0,0 +1,62 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module sui::hex_tests { + use sui::hex; + + #[test] + fun test_hex_encode_string_literal() { + assert!(b"30" == hex::encode(b"0")); + assert!(b"61" == hex::encode(b"a")); + assert!(b"666666" == hex::encode(b"fff")); + } + + #[test] + fun test_hex_encode_hex_literal() { + assert!(b"ff" == hex::encode(x"ff")); + assert!(b"fe" == hex::encode(x"fe")); + assert!(b"00" == hex::encode(x"00")); + } + + #[test] + fun test_hex_decode_string_literal() { + assert!(x"ff" == hex::decode(b"ff")); + assert!(x"fe" == hex::decode(b"fe")); + assert!(x"00" == hex::decode(b"00")); + } + + #[test] + fun test_hex_decode_string_literal__lowercase_and_uppercase() { + assert!(x"ff" == hex::decode(b"Ff")); + assert!(x"ff" == hex::decode(b"fF")); + assert!(x"ff" == hex::decode(b"FF")); + } + + #[test] + fun test_hex_decode_string_literal__long_hex() { + assert!( + x"036d2416252ae1db8aedad59e14b007bee6ab94a3e77a3549a81137871604456f3" == hex::decode( + b"036d2416252ae1Db8aedAd59e14b007bee6aB94a3e77a3549a81137871604456f3" + ), + ); + } + + #[test] + #[expected_failure(abort_code = hex::EInvalidHexLength)] + fun test_hex_decode__invalid_length() { + hex::decode(b"0"); + } + + #[test] + #[expected_failure(abort_code = hex::ENotValidHexCharacter)] + fun test_hex_decode__hex_literal() { + hex::decode(x"ffff"); + } + + #[test] + #[expected_failure(abort_code = hex::ENotValidHexCharacter)] + fun test_hex_decode__invalid_string_literal() { + hex::decode(b"0g"); + } +}