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}