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}