sui_framework_sdk/
lib.rs

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