sui_framework_sdk/
lib.rs

1#![cfg_attr(all(doc, not(doctest)), feature(doc_cfg))]
2
3//! Move types for the core `sui` Sui package located at "0x2" onchain.
4
5pub use af_move_type;
6use af_move_type::{MoveInstance, MoveType};
7pub use af_sui_types::Address;
8use move_stdlib_sdk::type_name::TypeName;
9
10use self::bag::*;
11use self::balance::*;
12// These are used far too often.
13pub use self::dynamic_field::{Field, FieldTypeTag};
14pub use self::object::{ID, UID};
15use self::table::*;
16use self::url::*;
17use self::vec_map::*;
18use self::vec_set::*;
19use self::versioned::*;
20
21af_sui_pkg_sdk::sui_pkg_sdk!(sui @ "0x2" {
22    module bag {
23        struct Bag has key, store {
24            /// the ID of this bag
25            id: UID,
26            /// the number of key-value pairs in the bag
27            size: u64,
28        }
29    }
30
31    module balance {
32        /// A Supply of T. Used for minting and burning.
33        /// Wrapped into a `TreasuryCap` in the `Coin` module.
34        struct Supply<!phantom T> has store {
35            value: u64
36        }
37
38        /// Storable balance - an inner struct of a Coin type.
39        /// Can be used to store coins which don't need the key ability.
40        struct Balance<!phantom T> has store {
41            value: u64
42        }
43    }
44
45    module bcs {
46        /// A helper struct that saves resources on operations. For better
47        /// vector performance, it stores reversed bytes of the BCS and
48        /// enables use of `vector::pop_back`.
49        struct BCS has store, copy, drop {
50            bytes: vector<u8>
51        }
52    }
53
54    module borrow {
55        /// An object wrapping a `T` and providing the borrow API.
56        struct Referent<T: key + store> has store {
57            id: address,
58            value: move_stdlib_sdk::option::Option<T>
59        }
60
61        /// A hot potato making sure the object is put back once borrowed.
62        struct Borrow { #[serde(rename = "ref")] ref_: address, obj: ID }
63    }
64
65    module clock {
66        /// Singleton shared object that exposes time to Move calls.  This
67        /// object is found at address 0x6, and can only be read (accessed
68        /// via an immutable reference) by entry functions.
69        ///
70        /// Entry Functions that attempt to accept `Clock` by mutable
71        /// reference or value will fail to verify, and honest validators
72        /// will not sign or execute transactions that use `Clock` as an
73        /// input parameter, unless it is passed by immutable reference.
74        struct Clock has key {
75            id: UID,
76            /// The clock's timestamp, which is set automatically by a
77            /// system transaction every time consensus commits a
78            /// schedule, or by `sui::clock::increment_for_testing` during
79            /// testing.
80            timestamp_ms: u64,
81        }
82    }
83
84    module coin {
85        /// A coin of type `T` worth `value`. Transferable and storable
86        struct Coin<!phantom T> has key, store {
87            id: UID,
88            balance: Balance<T>
89        }
90
91        /// Each Coin type T created through `create_currency` function will have a
92        /// unique instance of `CoinMetadata<T>` that stores the metadata for this coin type.
93        struct CoinMetadata<!phantom T> has key, store {
94            id: UID,
95            /// Number of decimal places the coin uses.
96            /// A coin with `value ` N and `decimals` D should be shown as N / 10^D
97            /// E.g., a coin with `value` 7002 and decimals 3 should be displayed as 7.002
98            /// This is metadata for display usage only.
99            decimals: u8,
100            /// Name for the token
101            name: String, // from std::string::String
102            /// Symbol for the token
103            symbol: String, // from std::ascii::String
104            /// Description of the token
105            description: String, // from std::string::String
106            /// URL for the token logo
107            icon_url: move_stdlib_sdk::option::Option<Url>
108        }
109
110        /// Similar to CoinMetadata, but created only for regulated coins that use the DenyList.
111        /// This object is always immutable.
112        struct RegulatedCoinMetadata<!phantom T> has key {
113            id: UID,
114            /// The ID of the coin's CoinMetadata object.
115            coin_metadata_object: ID,
116            /// The ID of the coin's DenyCap object.
117            deny_cap_object: ID,
118        }
119
120        /// Capability allowing the bearer to mint and burn
121        /// coins of type `T`. Transferable
122        struct TreasuryCap<!phantom T> has key, store {
123            id: UID,
124            total_supply: Supply<T>
125        }
126
127        /// Capability allowing the bearer to freeze addresses, preventing those addresses from
128        /// interacting with the coin as an input to a transaction.
129        struct DenyCap<!phantom T> has key, store {
130            id: UID,
131        }
132    }
133
134    module deny_list {
135        /// A shared object that stores the addresses that are blocked for a given core type.
136        struct DenyList has key {
137            id: UID,
138            /// The individual deny lists.
139            lists: Bag,
140        }
141
142        /// Stores the addresses that are denied for a given core type.
143        struct PerTypeList has key, store {
144            id: UID,
145            /// Number of object types that have been banned for a given address.
146            /// Used to quickly skip checks for most addresses.
147            denied_count: Table<address, u64>,
148            /// Set of addresses that are banned for a given type.
149            /// For example with `sui::coin::Coin`: If addresses A and B are banned from using
150            /// "0...0123::my_coin::MY_COIN", this will be "0...0123::my_coin::MY_COIN" -> {A, B}.
151            denied_addresses: Table<vector<u8>, VecSet<address>>,
152        }
153    }
154
155    module display {
156        /// The `Display<T>` object. Defines the way a T instance should be
157        /// displayed. Display object can only be created and modified with
158        /// a PublisherCap, making sure that the rules are set by the owner
159        /// of the type.
160        ///
161        /// Each of the display properties should support patterns outside
162        /// of the system, making it simpler to customize Display based
163        /// on the property values of an Object.
164        /// ```move
165        /// // Example of a display object
166        /// Display<0x...::capy::Capy> {
167        ///  fields:
168        ///    <name, "Capy { genes }">
169        ///    <link, "https://capy.art/capy/{ id }">
170        ///    <image, "https://api.capy.art/capy/{ id }/svg">
171        ///    <description, "Lovely Capy, one of many">
172        /// }
173        /// ```
174        ///
175        /// Uses only String type due to external-facing nature of the object,
176        /// the property names have a priority over their types.
177        struct Display<!phantom T: key> has key, store {
178            id: UID,
179            /// Contains fields for display. Currently supported
180            /// fields are: name, link, image and description.
181            fields: VecMap<String, String>,
182            /// Version that can only be updated manually by the Publisher.
183            version: u16
184        }
185
186        /// Event: emitted when a new Display object has been created for type T.
187        /// Type signature of the event corresponds to the type while id serves for
188        /// the discovery.
189        ///
190        /// Since Sui RPC supports querying events by type, finding a Display for the T
191        /// would be as simple as looking for the first event with `Display<T>`.
192        struct DisplayCreated<!phantom T: key> has copy, drop {
193            id: ID
194        }
195
196        /// Version of Display got updated -
197        struct VersionUpdated<!phantom T: key> has copy, drop {
198            id: ID,
199            version: u16,
200            fields: VecMap<String, String>,
201        }
202    }
203
204    module dynamic_field {
205        /// Internal object used for storing the field and value
206        struct Field<Name: copy + drop + store, Value: store> has key {
207            /// Determined by the hash of the object ID, the field name value and it's type,
208            /// i.e. hash(parent.id || name || Name)
209            id: UID,
210            /// The value for the name of this field
211            name: Name,
212            /// The value bound to this field
213            value: Value,
214        }
215    }
216
217    module dynamic_object_field {
218        // Internal object used for storing the field and the name associated with the value
219        // The separate type is necessary to prevent key collision with direct usage of dynamic_field
220        struct Wrapper<Name> has copy, drop, store {
221            name: Name,
222        }
223    }
224
225    module linked_table {
226        struct LinkedTable<K: copy + drop + store, !phantom V: store> has key, store {
227            /// the ID of this table
228            id: UID,
229            /// the number of key-value pairs in the table
230            size: u64,
231            /// the front of the table, i.e. the key of the first entry
232            head: move_stdlib_sdk::option::Option<K>,
233            /// the back of the table, i.e. the key of the last entry
234            tail: move_stdlib_sdk::option::Option<K>,
235        }
236
237        struct Node<K: copy + drop + store, V: store> has store {
238            /// the previous key
239            prev: move_stdlib_sdk::option::Option<K>,
240            /// the next key
241            next: move_stdlib_sdk::option::Option<K>,
242            /// the value being stored
243            value: V
244        }
245    }
246
247    module object_bag {
248        struct ObjectBag has key, store {
249            /// the ID of this bag
250            id: UID,
251            /// the number of key-value pairs in the bag
252            size: u64,
253        }
254    }
255
256    module object_table {
257        struct ObjectTable<!phantom K: copy + drop + store, !phantom V: key + store> has key, store {
258            /// the ID of this table
259            id: UID,
260            /// the number of key-value pairs in the table
261            size: u64,
262        }
263    }
264
265    module package {
266        /// This type can only be created in the transaction that
267        /// generates a module, by consuming its one-time witness, so it
268        /// can be used to identify the address that published the package
269        /// a type originated from.
270        struct Publisher has key, store {
271            id: UID,
272            package: String,
273            module_name: String,
274        }
275
276        /// Capability controlling the ability to upgrade a package.
277        struct UpgradeCap has key, store {
278            id: UID,
279            /// (Mutable) ID of the package that can be upgraded.
280            package: ID,
281            /// (Mutable) The number of upgrades that have been applied
282            /// successively to the original package.  Initially 0.
283            version: u64,
284            /// What kind of upgrades are allowed.
285            policy: u8,
286        }
287
288        /// Permission to perform a particular upgrade (for a fixed version of
289        /// the package, bytecode to upgrade with and transitive dependencies to
290        /// depend against).
291        ///
292        /// An `UpgradeCap` can only issue one ticket at a time, to prevent races
293        /// between concurrent updates or a change in its upgrade policy after
294        /// issuing a ticket, so the ticket is a "Hot Potato" to preserve forward
295        /// progress.
296        struct UpgradeTicket {
297            /// (Immutable) ID of the `UpgradeCap` this originated from.
298            cap: ID,
299            /// (Immutable) ID of the package that can be upgraded.
300            package: ID,
301            /// (Immutable) The policy regarding what kind of upgrade this ticket
302            /// permits.
303            policy: u8,
304            /// (Immutable) SHA256 digest of the bytecode and transitive
305            /// dependencies that will be used in the upgrade.
306            digest: vector<u8>,
307        }
308
309        /// Issued as a result of a successful upgrade, containing the
310        /// information to be used to update the `UpgradeCap`.  This is a "Hot
311        /// Potato" to ensure that it is used to update its `UpgradeCap` before
312        /// the end of the transaction that performed the upgrade.
313        struct UpgradeReceipt {
314            /// (Immutable) ID of the `UpgradeCap` this originated from.
315            cap: ID,
316            /// (Immutable) ID of the package after it was upgraded.
317            package: ID,
318        }
319    }
320
321    module priority_queue {
322        /// Struct representing a priority queue. The `entries` vector represents a max
323        /// heap structure, where entries\[0\] is the root, entries\[1\] and entries\[2\] are the
324        /// left child and right child of the root, etc. More generally, the children of
325        /// entries\[i\] are at at i * 2 + 1 and i * 2 + 2. The max heap should have the invariant
326        /// that the parent node's priority is always higher than its child nodes' priorities.
327        struct PriorityQueue<T: drop> has store, drop {
328            entries: vector<Entry<T>>,
329        }
330
331        struct Entry<T: drop> has store, drop {
332            priority: u64, // higher value means higher priority and will be popped first
333            value: T,
334        }
335    }
336
337    module random {
338        /// Singleton shared object which stores the global randomness state.
339        /// The actual state is stored in a versioned inner field.
340        struct Random has key {
341            id: UID,
342            inner: Versioned,
343        }
344
345        struct RandomInner has store {
346            version: u64,
347
348            epoch: u64,
349            randomness_round: u64,
350            random_bytes: vector<u8>,
351        }
352    }
353
354    module sui {
355        /// Name of the coin
356        struct SUI has drop {}
357    }
358
359    module table {
360        struct Table<!phantom K: copy + drop + store, !phantom V: store> has key, store {
361            /// the ID of this table
362            id: UID,
363            /// the number of key-value pairs in the table
364            size: u64,
365        }
366    }
367
368    module table_vec {
369        struct TableVec<!phantom Element: store> has store {
370            /// The contents of the table vector.
371            contents: Table<u64, Element>,
372        }
373    }
374
375    module token {
376        /// A single `Token` with `Balance` inside. Can only be owned by an address,
377        /// and actions performed on it must be confirmed in a matching `TokenPolicy`.
378        struct Token<!phantom T> has key {
379            id: UID,
380            /// The Balance of the `Token`.
381            balance: Balance<T>,
382        }
383
384        /// A Capability that manages a single `TokenPolicy` specified in the `for`
385        /// field. Created together with `TokenPolicy` in the `new` function.
386        struct TokenPolicyCap<!phantom T> has key, store {
387            id: UID,
388            #[serde(rename = "for")]
389            for_: ID
390        }
391
392        /// `TokenPolicy` represents a set of rules that define what actions can be
393        /// performed on a `Token` and which `Rules` must be satisfied for the
394        /// action to succeed.
395        ///
396        /// - For the sake of availability, `TokenPolicy` is a `key`-only object.
397        /// - Each `TokenPolicy` is managed by a matching `TokenPolicyCap`.
398        /// - For an action to become available, there needs to be a record in the
399        /// `rules` VecMap. To allow an action to be performed freely, there's an
400        /// `allow` function that can be called by the `TokenPolicyCap` owner.
401        struct TokenPolicy<!phantom T> has key {
402            id: UID,
403            /// The balance that is effectively spent by the user on the "spend"
404            /// action. However, actual decrease of the supply can only be done by
405            /// the `TreasuryCap` owner when `flush` is called.
406            ///
407            /// This balance is effectively spent and cannot be accessed by anyone
408            /// but the `TreasuryCap` owner.
409            spent_balance: Balance<T>,
410            /// The set of rules that define what actions can be performed on the
411            /// token. For each "action" there's a set of Rules that must be
412            /// satisfied for the `ActionRequest` to be confirmed.
413            rules: VecMap<String, VecSet<TypeName>>
414        }
415
416        /// A request to perform an "Action" on a token. Stores the information
417        /// about the action to be performed and must be consumed by the `confirm_request`
418        /// or `confirm_request_mut` functions when the Rules are satisfied.
419        struct ActionRequest<!phantom T> {
420            /// Name of the Action to look up in the Policy. Name can be one of the
421            /// default actions: `transfer`, `spend`, `to_coin`, `from_coin` or a
422            /// custom action.
423            name: String,
424            /// Amount is present in all of the txs
425            amount: u64,
426            /// Sender is a permanent field always
427            sender: address,
428            /// Recipient is only available in `transfer` action.
429            recipient: move_stdlib_sdk::option::Option<address>,
430            /// The balance to be "spent" in the `TokenPolicy`, only available
431            /// in the `spend` action.
432            spent_balance: move_stdlib_sdk::option::Option<Balance<T>>,
433            /// Collected approvals (stamps) from completed `Rules`. They're matched
434            /// against `TokenPolicy.rules` to determine if the request can be
435            /// confirmed.
436            approvals: VecSet<TypeName>,
437        }
438
439        /// Dynamic field key for the `TokenPolicy` to store the `Config` for a
440        /// specific action `Rule`. There can be only one configuration per
441        /// `Rule` per `TokenPolicy`.
442        struct RuleKey<!phantom T> has store, copy, drop { is_protected: bool }
443
444        /// An event emitted when a `TokenPolicy` is created and shared. Because
445        /// `TokenPolicy` can only be shared (and potentially frozen in the future),
446        /// we emit this event in the `share_policy` function and mark it as mutable.
447        struct TokenPolicyCreated<!phantom T> has copy, drop {
448            /// ID of the `TokenPolicy` that was created.
449            id: ID,
450            /// Whether the `TokenPolicy` is "shared" (mutable) or "frozen"
451            /// (immutable) - TBD.
452            is_mutable: bool,
453        }
454    }
455
456    module transfer {
457        /// This represents the ability to `receive` an object of type `T`.
458        /// This type is ephemeral per-transaction and cannot be stored on-chain.
459        /// This does not represent the obligation to receive the object that it
460        /// references, but simply the ability to receive the object with object ID
461        /// `id` at version `version` if you can prove mutable access to the parent
462        /// object during the transaction.
463        /// Internals of this struct are opaque outside this module.
464        struct Receiving<!phantom T: key> has drop {
465            id: ID,
466            version: u64,
467        }
468    }
469
470    module tx_context {
471        /// Information about the transaction currently being executed.
472        /// This cannot be constructed by a transaction--it is a privileged object created by
473        /// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`.
474        struct TxContext has drop {
475            /// The address of the user that signed the current transaction
476            sender: address,
477            /// Hash of the current transaction
478            tx_hash: vector<u8>,
479            /// The current epoch number
480            epoch: u64,
481            /// Timestamp that the epoch started at
482            epoch_timestamp_ms: u64,
483            /// Counter recording the number of fresh id's created while executing
484            /// this transaction. Always 0 at the start of a transaction
485            ids_created: u64
486        }
487    }
488
489    module url {
490        /// Standard Uniform Resource Locator (URL) string.
491        struct Url has store, copy, drop {
492            url: String,
493        }
494    }
495
496    module vec_map {
497        /// A map data structure backed by a vector. The map is guaranteed not to contain duplicate keys, but entries
498        /// are *not* sorted by key--entries are included in insertion order.
499        /// All operations are O(N) in the size of the map--the intention of this data structure is only to provide
500        /// the convenience of programming against a map API.
501        /// Large maps should use handwritten parent/child relationships instead.
502        /// Maps that need sorted iteration rather than insertion order iteration should also be handwritten.
503        struct VecMap<K: copy, V> has copy, drop, store {
504            contents: vector<Entry<K, V>>,
505        }
506
507        /// An entry in the map
508        struct Entry<K: copy, V> has copy, drop, store {
509            key: K,
510            value: V,
511        }
512    }
513
514    module vec_set {
515        /// A set data structure backed by a vector. The set is guaranteed not to
516        /// contain duplicate keys. All operations are O(N) in the size of the set
517        /// - the intention of this data structure is only to provide the convenience
518        /// of programming against a set API. Sets that need sorted iteration rather
519        /// than insertion order iteration should be handwritten.
520        struct VecSet<K: copy + drop> has copy, drop, store {
521            contents: vector<K>,
522        }
523    }
524
525    module versioned {
526        /// A wrapper type that supports versioning of the inner type.
527        /// The inner type is a dynamic field of the Versioned object, and is keyed using version.
528        /// User of this type could load the inner object using corresponding type based on the version.
529        /// You can also upgrade the inner object to a new type version.
530        /// If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have
531        /// to use mutable reference even if it's a read-only API.
532        struct Versioned has key, store {
533            id: UID,
534            version: u64,
535        }
536
537        /// Represents a hot potato object generated when we take out the dynamic field.
538        /// This is to make sure that we always put a new value back.
539        struct VersionChangeCap {
540            versioned_id: ID,
541            old_version: u64,
542        }
543    }
544});
545
546/// Custom `ID` and `UID` impls with better [`Display`](std::fmt::Display).
547pub mod object {
548    #![expect(
549        clippy::too_long_first_doc_paragraph,
550        reason = "Docs for the sui-framework have long first paragraphs."
551    )]
552    use super::Address;
553
554    /// An object ID. This is used to reference Sui Objects.
555    /// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or
556    /// from an object, and ID's can be freely copied and dropped.
557    /// Here, the values are not globally unique because there can be multiple values of type `ID`
558    /// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times
559    /// as you want for a given `obj`, and each `ID` value will be identical.
560    #[derive(
561        af_sui_pkg_sdk::MoveStruct,
562        af_sui_pkg_sdk::serde::Deserialize,
563        af_sui_pkg_sdk::serde::Serialize,
564        af_sui_pkg_sdk::Tabled,
565        derive_more::From,
566        Clone,
567        Debug,
568        PartialEq,
569        Eq,
570        Hash,
571    )]
572    #[move_(crate = af_sui_pkg_sdk::af_move_type)]
573    #[serde(crate = "af_sui_pkg_sdk::serde", transparent)]
574    #[tabled(crate = "af_sui_pkg_sdk::tabled")]
575    pub struct ID {
576        pub bytes: Address,
577    }
578
579    impl ID {
580        pub const fn new(object_id: Address) -> Self {
581            Self { bytes: object_id }
582        }
583    }
584
585    impl std::fmt::Display for ID {
586        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
587            write!(f, "{}", self.bytes)
588        }
589    }
590
591    impl From<ID> for Address {
592        fn from(value: ID) -> Self {
593            value.bytes
594        }
595    }
596
597    /// Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct
598    /// with the `key` ability, must have `id: UID` as its first field.
599    /// These are globally unique in the sense that no two values of type `UID` are ever equal, in
600    /// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`.
601    /// This is a privileged type that can only be derived from a `TxContext`.
602    /// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`.
603    #[derive(
604        af_sui_pkg_sdk::MoveStruct,
605        af_sui_pkg_sdk::serde::Deserialize,
606        af_sui_pkg_sdk::serde::Serialize,
607        af_sui_pkg_sdk::Tabled,
608        Clone,
609        Debug,
610        PartialEq,
611        Eq,
612        Hash,
613    )]
614    #[move_(crate = af_sui_pkg_sdk::af_move_type)]
615    #[serde(crate = "af_sui_pkg_sdk::serde")]
616    #[tabled(crate = "af_sui_pkg_sdk::tabled")]
617    pub struct UID {
618        pub id: ID,
619    }
620
621    impl UID {
622        pub const fn new(object_id: Address) -> Self {
623            Self {
624                id: ID::new(object_id),
625            }
626        }
627    }
628
629    impl std::fmt::Display for UID {
630        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631            write!(f, "{}", self.id)
632        }
633    }
634
635    impl From<Address> for UID {
636        fn from(value: Address) -> Self {
637            Self::new(value)
638        }
639    }
640
641    impl From<UID> for Address {
642        fn from(value: UID) -> Self {
643            value.id.bytes
644        }
645    }
646}
647
648// =============================================================================
649// Convenience functions
650// =============================================================================
651
652impl<K: MoveType, V: MoveType> Field<K, V> {
653    /// Unpack an instance of a dynamic field into its name and value instances.
654    pub fn unpack_instance(this: MoveInstance<Self>) -> (MoveInstance<K>, MoveInstance<V>) {
655        #[expect(deprecated)]
656        unpack_field_instance(this)
657    }
658}
659
660#[deprecated = "Use Field::unpack_instance"]
661pub fn unpack_field_instance<K: MoveType, V: MoveType>(
662    field: MoveInstance<Field<K, V>>,
663) -> (MoveInstance<K>, MoveInstance<V>) {
664    let MoveInstance {
665        type_: FieldTypeTag {
666            name: name_type,
667            value: value_type,
668        },
669        value: Field { name, value, .. },
670    } = field;
671    (
672        MoveInstance {
673            type_: name_type,
674            value: name,
675        },
676        MoveInstance {
677            type_: value_type,
678            value,
679        },
680    )
681}