,
ctx: &TxContext
): T {
assert!(box.owner == ctx.sender());
// Receive `to_receive` from `PostBox`.
let parcel = transfer::public_receive(&mut box.id, to_receive);
parcel
}
/// If user hasn't claimed their `PostBox` yet, create it.
/// Note: this is not a requirement for transferring assets!
/// Parcels can be sent even to unregistered post boxes, see `send` implementation.
public fun register_address(office: &mut PostOffice, ctx: &mut TxContext) {
transfer::share_object(PostBox {
id: derived_object::claim(&mut office.id, ctx.sender()),
owner: ctx.sender()
})
}
// Create a PostOffice on module publish.
fun init(ctx: &mut TxContext) {
transfer::share_object(PostOffice { id: object::new(ctx) });
}
```
## Use Cases
Transferring to objects is a powerful feature that lets objects act as owners of other objects,
and it enables designs that plain address ownership cannot express:
- **Controlled receiving.** Because receiving goes through the parent's module, extra logic can be
attached to it - the `PostOffice` above could, for example, charge a fee for every received
item.
- **Objects as containers.** A parent object collects assets sent to it and can itself be
transferred, carrying its entire "inventory" along - without ever listing the contents in a
transaction.
- **Deferred delivery.** Assets can be sent to an object before its owner is ready to claim them -
a post-box that accumulates items until the user activates their account.
- **Account-like objects.** An object with an ID that receives and releases assets behaves much
like an account, which makes TTO a building block for account-abstraction designs.
Sending _to an object_ is also naturally parallel: transfers to an object ID are plain transfers -
they do not reference the parent in the transaction, and therefore do not contend on it.
## Next Steps
This section concludes the Using Objects chapter: you can now define objects, place them into any
ownership state, manage their identity, and even make objects own other objects. The
[Advanced Programmability](./../programmability) chapter builds on all of it - starting with the
execution environment, and returning to object composition with
[Dynamic Fields](./../programmability/dynamic-fields), the second mechanism behind parent-child
object relationships.
## Further Reading
- [Transfer to Object](https://docs.sui.io/guides/developer/objects/transfers/transfer-to-object) in Sui
Documentation
- [`sui::transfer`][transfer] module documentation
[transfer]: https://docs.sui.io/references/framework/sui/transfer
[key]: ./key-ability.md
[store]: ./store-ability.md
[uid]: ./uid-and-id.md
[internal]: ./internal-constraint.md
[storage-funs]: ./storage-functions.md
---
# Advanced Programmability
In previous chapters we've covered [the basics of Move](./../move-basics) and
[Sui Storage Model](./../storage). Now it's time to dive deeper into the advanced topics of Sui
programmability. This chapter introduces more complex concepts, practices, and features of Move and
Sui that are essential for building more sophisticated applications.
The sections are ordered so that each builds on what came before, but they also form a few mostly
independent threads, and it is fine to follow the one you need right now:
- **The execution environment** - what a program can learn about the transaction it runs in and
the system around it, and how it communicates with the outside world:
[Sui Framework](./sui-framework), [Transaction Context](./transaction-context),
[Module Initializer](./module-initializer), [Epoch and Time](./epoch-and-time),
[Events](./events), and [Binary Canonical Serialization](./bcs).
- **Storage at scale** - from simple vector-based collections to dynamic fields, a primitive that
attaches arbitrary data to objects and lifts static type and size limits:
[Collections](./collections), [Wrapper Type](./wrapper-type-pattern),
[Dynamic Fields](./dynamic-fields), [Dynamic Object Fields](./dynamic-object-fields), and
[Dynamic Collections](./dynamic-collections).
- **Patterns of authority** - Move's answer to access control: from owned objects acting as
permissions to guarantees backed by the system, and features built on top of them:
[Capability](./capability), [Witness](./witness-pattern),
[One Time Witness](./one-time-witness), [Publisher](./publisher), [Display](./display), and
[Hot Potato](./hot-potato-pattern).
- **Assets and funds** - fungible value and the two ways to hold it, as objects and as balances
attached directly to an address: [Balance and Coin](./balance-and-coin) and
[Address Balances](./address-balances).
- **Code evolution** - what happens after the code ships: publishing new versions of a package,
protecting shared state from old versions, and migrating data:
[Package Upgrades](./package-upgrades).
> Many code samples in this chapter are written as [tests](./../move-basics/testing), and use
> test-only helpers from the framework: `tx_context::dummy()` creates a placeholder transaction
> context, and `std::unit_test::destroy` consumes any value at the end of a test. We cover testing
> techniques in detail in the [Testing](./../testing) chapter.
---
# Sui Framework
Sui Framework is a default dependency set in the [Package Manifest](./../concepts/manifest). It
depends on the [Standard Library](./../move-basics/standard-library) and provides the Sui-specific
functionality: storage operations, native types, and the modules the rest of this chapter is built
on.
_For convenience, we grouped the modules in the Sui Framework into multiple categories. But they're
still part of the same framework._
## Core
| Module | Description | Chapter |
| ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------- |
| [sui::address](https://docs.sui.io/references/framework/sui/address) | Adds conversion methods to the [address type](./../move-basics/address) | [Address](./../move-basics/address) |
| [sui::transfer](https://docs.sui.io/references/framework/sui/transfer) | Implements the storage operations for Objects | [Storage Functions](./../storage/storage-functions.md) |
| [sui::tx_context](https://docs.sui.io/references/framework/sui/tx_context) | Contains the `TxContext` struct and methods to read it | [Transaction Context](./transaction-context) |
| [sui::object](https://docs.sui.io/references/framework/sui/object) | Defines the `UID` and `ID` type, required for creating objects | [UID and ID](./../storage/uid-and-id.md) |
| [sui::derived_object](https://docs.sui.io/references/framework/sui/derived_object) | Allows `UID` generation through key derivation | [UID Derivation](./../storage/uid-and-id.md#uid-derivation) |
| [sui::clock](https://docs.sui.io/references/framework/sui/clock) | Defines the `Clock` type and its methods | [Epoch and Time](./epoch-and-time) |
| [sui::dynamic_field](https://docs.sui.io/references/framework/sui/dynamic_field) | Implements methods to add, use and remove dynamic fields | [Dynamic Fields](./dynamic-fields) |
| [sui::dynamic_object_field](https://docs.sui.io/references/framework/sui/dynamic_object_field) | Implements methods to add, use and remove dynamic object fields | [Dynamic Object Fields](./dynamic-object-fields) |
| [sui::event](https://docs.sui.io/references/framework/sui/event) | Allows emitting events for offchain listeners | [Events](./events) |
| [sui::package](https://docs.sui.io/references/framework/sui/package) | Defines the `Publisher` type and package upgrade methods | [Publisher](./publisher) |
| [sui::display](https://docs.sui.io/references/framework/sui/display) | Implements the `Display` object and ways to create and update it | [Display](./display) |
## Collections
| Module | Description | Chapter |
| ------------------------------------------------------------------------------ | ----------------------------------------------------------------- | -------------------------------------------- |
| [sui::vec_set](https://docs.sui.io/references/framework/sui/vec_set) | Implements a set type | [Collections](./collections) |
| [sui::vec_map](https://docs.sui.io/references/framework/sui/vec_map) | Implements a map with vector keys | [Collections](./collections) |
| [sui::table](https://docs.sui.io/references/framework/sui/table) | Implements the `Table` type and methods to interact with it | [Dynamic Collections](./dynamic-collections) |
| [sui::linked_table](https://docs.sui.io/references/framework/sui/linked_table) | Implements the `LinkedTable` type and methods to interact with it | [Dynamic Collections](./dynamic-collections) |
| [sui::bag](https://docs.sui.io/references/framework/sui/bag) | Implements the `Bag` type and methods to interact with it | [Dynamic Collections](./dynamic-collections) |
| [sui::object_table](https://docs.sui.io/references/framework/sui/object_table) | Implements the `ObjectTable` type and methods to interact with it | [Dynamic Collections](./dynamic-collections) |
| [sui::object_bag](https://docs.sui.io/references/framework/sui/object_bag) | Implements the `ObjectBag` type and methods to interact with it | [Dynamic Collections](./dynamic-collections) |
## Coins and Assets
| Module | Description | Chapter |
| ---------------------------------------------------------------------- | ------------------------------------------------------ | ---------------------------------------- |
| [sui::balance](https://docs.sui.io/references/framework/sui/balance) | The `Balance` type - the underlying store of value | [Balance and Coin](./balance-and-coin) |
| [sui::coin](https://docs.sui.io/references/framework/sui/coin) | The `Coin` type - a transferable fungible asset | [Balance and Coin](./balance-and-coin) |
| [sui::sui](https://docs.sui.io/references/framework/sui/sui) | The SUI coin type | [Balance and Coin](./balance-and-coin) |
| [sui::pay](https://docs.sui.io/references/framework/sui/pay) | Helper functions for splitting and merging coins | - |
| [sui::deny_list](https://docs.sui.io/references/framework/sui/deny_list) | Deny list for regulated coin types | - |
| [sui::token](https://docs.sui.io/references/framework/sui/token) | The closed-loop token standard | - |
## Utilities
| Module | Description | Chapter |
| ------------------------------------------------------------------ | ---------------------------------------------------------- | --------------------------------------- |
| [sui::bcs](https://docs.sui.io/references/framework/sui/bcs) | Implements the BCS encoding and decoding functions | [Binary Canonical Serialization](./bcs) |
| [sui::borrow](https://docs.sui.io/references/framework/sui/borrow) | Implements the borrowing mechanic for borrowing by _value_ | [Hot Potato](./hot-potato-pattern) |
| [sui::hex](https://docs.sui.io/references/framework/sui/hex) | Implements the hex encoding and decoding functions | - |
| [sui::random](https://docs.sui.io/references/framework/sui/random) | The `Random` object and secure onchain randomness | [Randomness](./randomness) |
| [sui::types](https://docs.sui.io/references/framework/sui/types) | Provides a way to check if the type is a One-Time-Witness | [One Time Witness](./one-time-witness) |
The framework also contains modules not covered in this book: the commerce primitives
([sui::kiosk](https://docs.sui.io/references/framework/sui/kiosk),
[sui::transfer_policy](https://docs.sui.io/references/framework/sui/transfer_policy)), a set of
cryptographic functions ([sui::hash](https://docs.sui.io/references/framework/sui/hash),
[sui::ed25519](https://docs.sui.io/references/framework/sui/ed25519),
[sui::bls12381](https://docs.sui.io/references/framework/sui/bls12381), and others), and assorted
utilities such as [sui::url](https://docs.sui.io/references/framework/sui/url) and
[sui::versioned](https://docs.sui.io/references/framework/sui/versioned). Refer to the
[framework documentation](https://docs.sui.io/references/framework) for the full list.
## Exported Addresses
Sui Framework exports two named addresses: `sui = 0x2` and `std = 0x1` from the std dependency.
## Implicit Imports
Just like with [Standard Library](./../move-basics/standard-library#implicit-imports), some of the
modules and types are imported implicitly in the Sui Framework. This is the list of modules and
types that are available without explicit `use` import:
- sui::object
- sui::object::ID
- sui::object::UID
- sui::tx_context
- sui::tx_context::TxContext
- sui::transfer
## Source Code
The source code of the Sui Framework is available in the
[Sui repository](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/sui-framework/sources).
---
# Transaction Context
Every transaction is executed in a _transaction context_. The context is a set of predefined
values available to the program during execution, such as the sender address, the current epoch,
or the transaction digest.
The transaction context is available to the program through the `TxContext` struct. The struct is
defined in the [`sui::tx_context`][tx-context-framework] module and contains the following fields:
[tx-context-framework]: https://docs.sui.io/references/framework/sui/tx_context
```move
module sui::tx_context;
/// Information about the transaction currently being executed.
/// This cannot be constructed by a transaction--it is a privileged object created by
/// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`.
public struct TxContext has drop {
/// The address of the user that signed the current transaction
sender: address,
/// Hash of the current transaction
tx_hash: vector,
/// The current epoch number
epoch: u64,
/// Timestamp that the epoch started at
epoch_timestamp_ms: u64,
/// Counter recording the number of fresh id's created while executing
/// this transaction. Always 0 at the start of a transaction
ids_created: u64
}
```
> While the struct still declares its original fields, current versions of the framework no longer
> read most of them directly - the getter functions forward to native functions implemented in the
> Sui execution environment. The fields are kept for compatibility, and `TxContext` is best thought
> of as an opaque handle to the execution environment.
Transaction context cannot be constructed manually or directly modified. It is created by the
system and passed to the function as a reference in a transaction. Any function called in a
[Transaction](./../concepts/what-is-a-transaction) has access to the context and can pass it into
the nested calls.
> `TxContext` has to be the last argument in the function signature.
## Reading the Transaction Context
The `sui::tx_context` module provides a getter for each of the values available in the context.
None of the getters require a mutable reference, since reading the context does not modify it:
- `sender()` - the address that signed the transaction;
- `digest()` - a reference to the 32-byte digest (hash) of the current transaction, unique per
transaction;
- `epoch()` - the current [epoch](./epoch-and-time) number;
- `epoch_timestamp_ms()` - the timestamp of the moment the epoch started, in milliseconds;
- `sponsor()` - the address of the transaction sponsor, or `None` if the transaction was not
sponsored;
- `gas_price()` - the gas price submitted with the current transaction;
- `reference_gas_price()` - the reference gas price of the current epoch.
```move
public fun some_action(ctx: &TxContext) {
let sender = ctx.sender();
let tx_digest = ctx.digest();
let epoch = ctx.epoch();
let epoch_start = ctx.epoch_timestamp_ms();
let sponsor = ctx.sponsor();
let gas_price = ctx.gas_price();
let ref_gas_price = ctx.reference_gas_price();
// ...
}
```
> The transaction digest is a hash of the transaction inputs, and while it is unique per
> transaction, it should never be used as a source of randomness - it is known before the
> transaction is executed, and can be manipulated by the sender.
The `sponsor()` getter is related to _sponsored transactions_ - transactions where a third party,
the sponsor, pays the gas fees on behalf of the user. In a sponsored transaction, `sender()` still
returns the address of the user, so sender-based logic behaves the same whether or not the
transaction is sponsored.
These getters are the complete public interface for reading the context. Other values, such as the
transaction's gas budget, are intentionally not exposed to the program.
## Mutability
Some operations require the context to be passed as a mutable reference - `&mut TxContext`. The
most important of them is the creation of new objects: every object on Sui must have a globally
unique `UID`. Fresh UIDs are derived from the transaction digest and a counter of IDs created so
far in this transaction - the `ids_created` field. Each time a new UID is requested, the counter is
incremented, which guarantees that every derived address is unique. Because the counter has to
change, the operation requires a mutable reference to the context.
We cover object creation in detail in the [UID and ID](./../storage/uid-and-id) section.
## Generating Unique Addresses
The same derivation mechanism can be used directly in your program to generate unique addresses.
The `sui::tx_context` module exposes the `fresh_object_address` function for that, which may be
useful if an application needs a unique identifier - for example, to use as a key in a
[dynamic field](./dynamic-fields) or an offchain index.
```move
module sui::tx_context;
/// Create an `address` that has not been used. As it is an object address, it will never
/// occur as the address for a user.
/// In other words, the generated address is a globally unique object ID.
public fun fresh_object_address(ctx: &mut TxContext): address;
```
## Transaction Context in Tests
Since `TxContext` cannot be constructed in regular code, [tests](./../move-basics/testing) would
not be able to call any function that expects it. For this scenario the framework provides
test-only constructors: the simplest of them is `tx_context::dummy()`, which returns a context
with placeholder values. You will see it in code samples throughout this book:
```move
#[test]
fun test_some_action() {
let ctx = &mut tx_context::dummy();
// pass `ctx` into functions that expect `&mut TxContext`
}
```
For tests that need specific values - a certain sender, epoch, or gas price - the module provides
more test-only constructors, as well as helpers to simulate epoch changes. They are covered in the
[Simulating Transaction Context](./../testing/transaction-context) section. For multi-transaction
scenarios and access to objects in storage, use the `sui::test_scenario` module, described in the
[Test Scenario](./../testing/test-scenario) section.
## Further Reading
- [sui::tx_context][tx-context-framework] module documentation.
---
# Module Initializer
A common use case in many applications is to run certain code just once when the package is
published. Imagine a simple shop module that needs to create the main `Shop` object upon its
publication. In Sui, this is achieved by defining an `init` function within the module. This
function will automatically be called when the module is published.
> The `init` function of every module in the package is called during the publishing process. This
> behavior is limited to the publish command and does not extend to package upgrades - a module
> added in an upgrade will not have its `init` called.
```move
module book::shop;
/// The Capability which grants the Shop owner the right to manage
/// the shop.
public struct ShopOwnerCap has key, store { id: UID }
/// The singular Shop itself, created in the `init` function.
public struct Shop has key {
id: UID,
/* ... */
}
// Called only once, upon module publication. It must be
// private to prevent external invocation.
fun init(ctx: &mut TxContext) {
// Transfers the ShopOwnerCap to the sender (publisher).
transfer::transfer(ShopOwnerCap {
id: object::new(ctx)
}, ctx.sender());
// Shares the Shop object.
transfer::share_object(Shop {
id: object::new(ctx)
});
}
```
In the same package, another module can have its own `init` function, encapsulating distinct logic.
```move
// In the same package as the `shop` module
module book::bank;
public struct Bank has key {
id: UID,
/* ... */
}
fun init(ctx: &mut TxContext) {
transfer::share_object(Bank {
id: object::new(ctx)
});
}
```
## The `init` Rules
The function is called on publish if it is present in the module and follows these rules:
- The function must be named `init`, be private, and have no return values;
- it cannot be declared as `entry` and cannot have type parameters;
- it takes one or two arguments: an optional [One Time Witness](./one-time-witness) and the
[TxContext](./transaction-context), with `TxContext` always being the last argument.
```move
fun init(ctx: &mut TxContext) { /* ... */ }
fun init(otw: OTW, ctx: &mut TxContext) { /* ... */ }
```
These rules are not a convention - they are enforced by the bytecode verifier. A function named
`init` that violates any of them fails verification, and the package cannot be published.
`TxContext` can also be taken as an immutable reference `&TxContext`, but in practice it should
always be `&mut TxContext`: the `init` function cannot access the onchain state, so creating new
objects is the whole point of it - and that requires a mutable reference to the context.
## Trust and Security
While the `init` function can be used to create sensitive objects once, it is important to know
that the same object (e.g. `ShopOwnerCap` from the first example) can still be created in another
function - especially since new functions can be added to the module during an upgrade. The `init`
function is a good place to set up the initial state of the module, but it is not a security
measure on its own.
There are ways to guarantee that the object was created only once, such as the
[One Time Witness](./one-time-witness). And there are ways to limit or disable package upgrades,
described in
[Custom Upgrade Policies](https://docs.sui.io/concepts/sui-move-concepts/packages/custom-policies)
in the Sui Documentation.
## Testing the Initializer
The `init` function is called by the runtime and cannot be invoked in a transaction. However, it
is a regular function in every other sense, so [tests](./../move-basics/testing) placed in the same
module can call it directly:
```move
#[test_only]
use std::unit_test::assert_eq;
#[test]
fun test_init() {
let ctx = &mut tx_context::dummy();
init(ctx);
// Two objects were created: the `ShopOwnerCap` and the `Shop`.
assert_eq!(ctx.ids_created(), 2);
}
```
For an `init` function that takes a [One Time Witness](./one-time-witness), the witness value can
be created in tests with the test-only `sui::test_utils::create_one_time_witness` function. And in
scenario-based tests, described in the [Test Scenario](./../testing/test-scenario) section, the
objects created by `init` can also be inspected after the call.
## Next Steps
As follows from the definition, the `init` function is guaranteed to be called only once when the
module is published. So it is a good place to put the code that initializes the module's objects
and sets up the environment and configuration.
For example, if there's a [Capability](./capability) which is required for certain actions, it
should be created in the `init` function. In the next chapter we will talk about the `Capability`
pattern in more detail.
---
# Pattern: Capability
In programming, a _capability_ is a token that gives the owner the right to perform a specific
action. It is a pattern that is used to control access to resources and operations. A simple example
of a capability is a key to a door. If you have the key, you can open the door. If you don't have
the key, you can't open the door. A more practical example is an Admin Capability which allows the
owner to perform administrative operations, which regular users cannot.
## Capability is an Object
In the [Sui Object Model](./../object/), capabilities are represented as objects. An owner of an
object can pass this object to a function to prove that they have the right to perform a specific
action. Due to strict typing, the function taking a capability as an argument can only be called
with the correct capability.
> There's a convention to name capabilities with the `Cap` suffix, for example, `AdminCap` or
> `KioskOwnerCap`.
```move
module book::capability;
use std::string::String;
/// The capability granting the application admin the right to create new
/// accounts in the system.
public struct AdminCap has key, store { id: UID }
/// The user account in the system.
public struct Account has key, store {
id: UID,
name: String
}
/// Creates a new account in the system. Requires the `AdminCap` capability
/// to be passed as the first argument.
public fun new(_: &AdminCap, name: String, ctx: &mut TxContext): Account {
Account {
id: object::new(ctx),
name,
}
}
/// The `Account` itself acts as a capability too: only its owner can pass
/// a mutable reference to it, and hence only the owner can update the name.
public fun update(account: &mut Account, name: String) {
account.name = name;
}
```
## Using `init` for Admin Capability
A very common practice is to create a single `AdminCap` object on package publish. This way, the
application can have a setup phase where the admin account prepares the state of the application.
```move
module book::admin_cap;
/// The capability granting the admin privileges in the system.
/// Created only once in the `init` function.
public struct AdminCap has key { id: UID }
/// Create the AdminCap object on package publish and transfer it to the
/// package owner.
fun init(ctx: &mut TxContext) {
transfer::transfer(
AdminCap { id: object::new(ctx) },
ctx.sender()
)
}
```
Notice that this `AdminCap` has only the `key` ability, unlike the one in the first example, which
also had `store`. The [abilities](./../move-basics/abilities-introduction) of a capability define
how it can move between accounts: with `key` and `store`, the capability can be freely transferred
with public transfer functions and stored inside other objects; with only `key`, it can be
transferred only by functions defined in its module, so the module can restrict - or completely
forbid - passing the capability on. As described in the
[Storage Functions](./../storage/storage-functions) section, this is the difference between
internal and public transfer.
## Capabilities in the Sui Framework
The capability pattern is not just a convention - the [Sui Framework](./sui-framework) itself is
built around it. Knowing the standard capabilities helps recognize the pattern in real code; here
are the ones you are most likely to encounter:
- `sui::coin::TreasuryCap` - created together with a new currency, grants the right to mint and
burn coins of type `T`. Owning the `TreasuryCap` is owning the supply of the currency; we explore
it in the [Balance and Coin](./balance-and-coin) chapter;
- `sui::package::UpgradeCap` - created when a package is published, authorizes future upgrades of
the package. The owner of the `UpgradeCap` can also restrict future upgrades, or disable them
completely by making the capability immutable;
- `sui::kiosk::KioskOwnerCap` - grants the right to `place`, `take`, and `list` items in a
[Kiosk](https://docs.sui.io/standards/kiosk) - the trading primitive of Sui. While the `Kiosk`
object itself is shared and accessible to everyone, the "owner" operations on it require the
capability;
- `sui::transfer_policy::TransferPolicyCap` - grants the right to manage a `TransferPolicy`:
add and remove trading rules, and withdraw the collected fees.
Two of these capabilities take a type parameter - a technique worth noting. By adding a
[generic](./../move-basics/generics) to the capability, the authority it grants is scoped to a
single type: a `TreasuryCap` controls the supply of `GOLD` and gives no rights over the
`SILVER` currency.
The framework also features a more general form of authority - the `Publisher` object, which proves
authority over all types of a package. It is covered separately in the
[Publisher Authority](./publisher) chapter.
## Address Check vs Capability
Utilizing objects as capabilities is a relatively new concept in blockchain programming. In other
smart-contract languages, authorization is often performed by checking the address of the sender.
This pattern is still viable on Sui, however, the overall recommendation is to use capabilities for
better security, discoverability, and code organization.
Let's look at how the `new` function that creates a user would look if it used the address check:
```move
/// Error code for unauthorized access.
const ENotAuthorized: u64 = 0;
/// The application admin address.
const APPLICATION_ADMIN: address = @0xa11ce;
/// Creates a new user in the system. Requires the sender to be the application
/// admin.
public fun new(ctx: &mut TxContext): User {
assert!(ctx.sender() == APPLICATION_ADMIN, ENotAuthorized);
User { id: object::new(ctx) }
}
```
And now, let's see how the same function looks with the capability:
```move
/// Grants the owner the right to create new users in the system.
public struct AdminCap has key { id: UID }
/// Creates a new user in the system. Requires the `AdminCap` capability to be
/// passed as the first argument.
public fun new(_: &AdminCap, ctx: &mut TxContext): User {
User { id: object::new(ctx) }
}
```
Using capabilities has several advantages over the address check:
- Migration of admin rights is easier with capabilities due to them being objects. In case of
address, if the admin address changes, all the functions that check the address need to be
updated - hence, require a package upgrade.
- Function signatures are more descriptive with capabilities. It is clear that the `new` function
requires the `AdminCap` to be passed as an argument. And this function can't be called without it.
- Object Capabilities don't require extra checks in the function body, and hence, decrease the
chance of a developer mistake.
- An owned Capability also serves in discovery. The owner of the AdminCap can see the object in
their account (via a Wallet or Explorer), and know that they have the admin rights. This is less
transparent with the address check.
However, the address approach has advantages of its own. One case is a _multisig_ address - an
address controlled by multiple parties, where a transaction is only valid if enough of them sign
it. If the admin rights of an application belong to a multisig address, checking the sender may be
simpler than building a transaction that presents a capability object owned by that address.
Another case is an application with a central object - a config or a registry - that is already
passed into every function. Such an object can store the admin address as a regular field, and
checking it requires no extra inputs. The address is plain data, so it can be changed at runtime,
without a package upgrade. The same idea enables _revocation_: an owned capability, once
transferred, cannot be taken back from its owner, but an entry in a central registry - an address
or an ID of a previously issued capability - can be removed by the admin at any moment, instantly
revoking access.
---
# Epoch and Time
Sui has two ways of accessing the current time: the _epoch_ and the `Clock` object. The former
represents operational periods in the system and changes roughly every 24 hours. The latter gives
the current time in milliseconds since the Unix Epoch. Both can be accessed freely in the program.
## Epoch
Epochs are used to separate the system into operational periods. During an epoch the validator set
is fixed; at the epoch boundary, it can change. Epochs play a crucial role in the consensus
algorithm and are used as a unit of measurement in the staking mechanism.
The current epoch can be read from the [transaction context](./transaction-context):
```move
public fun current_epoch(ctx: &TxContext) {
let epoch = ctx.epoch();
// ...
}
```
It is also possible to get the Unix timestamp (in milliseconds) of the epoch start:
```move
public fun current_epoch_start(ctx: &TxContext) {
let epoch_start = ctx.epoch_timestamp_ms();
// ...
}
```
Both values are embedded in the transaction itself, so reading them is free and does not require
access to any object.
Normally, epochs are used in staking and system operations, however, in custom scenarios they can be
used to emulate 24h periods. They are critical if an application relies on the staking logic or
needs to know the current validator set.
## Time
For a more precise time measurement, Sui provides the `Clock` object. It is a system object,
updated by a system transaction on every consensus commit - roughly every quarter of a second -
which stores the current time in milliseconds since the Unix Epoch. The `Clock` object is defined
in the `sui::clock` module and has a
[reserved address](./../appendix/reserved-addresses) `0x6`.
Clock is a shared object, but a transaction attempting to access it mutably will fail. This
limitation allows parallel access to the `Clock` object, which is important for maintaining
performance.
```move
module sui::clock;
/// Singleton shared object that exposes time to Move calls. This
/// object is found at address 0x6, and can only be read (accessed
/// via an immutable reference) by entry functions.
///
/// Entry Functions that attempt to accept `Clock` by mutable
/// reference or value will fail to verify, and honest validators
/// will not sign or execute transactions that use `Clock` as an
/// input parameter, unless it is passed by immutable reference.
public struct Clock has key {
id: UID,
/// The clock's timestamp, which is set automatically by a
/// system transaction every time consensus commits a
/// schedule, or by `sui::clock::increment_for_testing` during
/// testing.
timestamp_ms: u64,
}
```
For regular use, the module exposes a single function - `timestamp_ms`. It returns the current
time in milliseconds since the Unix Epoch.
```move
use sui::clock::Clock;
/// Clock needs to be passed as an immutable reference.
public fun current_time(clock: &Clock) {
let time = clock.timestamp_ms();
// ...
}
```
The `Clock` comes with a few useful guarantees: within a single transaction, `timestamp_ms` always
returns the same value, and across transactions the value never decreases. However, because the
clock is only updated on consensus commits, transactions executed close to each other may see an
identical timestamp.
## Testing
Since the real `Clock` is only updated by the system, the module provides test-only functions to
create a clock, set its value, and destroy it:
```move
#[test_only]
use sui::clock;
#[test_only]
use std::unit_test::assert_eq;
#[test]
fun use_clock_in_test() {
// Get `ctx` and create `Clock` for testing
let ctx = &mut tx_context::dummy();
let mut clock = clock::create_for_testing(ctx);
assert_eq!(clock.timestamp_ms(), 0);
// Add a value to the timestamp stored in `Clock`
clock.increment_for_testing(2_000_000_000);
assert_eq!(clock.timestamp_ms(), 2_000_000_000);
// Set the timestamp, but the time set must be no less than the value stored in `Clock`
clock.set_for_testing(3_000_000_000);
assert_eq!(clock.timestamp_ms(), 3_000_000_000);
// The following setting will fail because the time set must be at least the timestamp stored in `Clock`
// clock.set_for_testing(1_000_000_000);
// assert_eq!(clock.timestamp_ms(), 1_000_000_000);
// If need a shared `Clock` for testing, you can set it through this function
// clock.share_for_testing();
// `Clock` does not have a `drop` capability, so it needs to be destroyed manually at the end of the test
clock.destroy_for_testing();
}
```
## Summary
- The current epoch and its start timestamp are read from the
[transaction context](./transaction-context) - free and available in every transaction; an
epoch lasts roughly 24 hours.
- The `Clock` object at the reserved address `0x6` gives the time in milliseconds, updated on
every consensus commit; it can only be accessed immutably.
- Within a transaction the `Clock` value never changes, and across transactions it never
decreases.
- In tests, use `create_for_testing`, `set_for_testing`, `increment_for_testing`, and
`destroy_for_testing` to control the clock.
## Further Reading
- [sui::clock](https://docs.sui.io/references/framework/sui/clock) module documentation.
---
# Collections
Storing groups of values is one of the most common needs in a program. The
[`vector`](./../move-basics/vector) type, covered in the Move Basics chapter, is the base building
block for it, and the [Sui Framework](./sui-framework) extends it with two collection types that
add structure on top: `VecSet`, which keeps its elements unique, and `VecMap`, which associates
keys with values. In this section we introduce all three in their most common role - as fields of
an object - and show the operations and constraints of each.
## Vector
While the [vector section](./../move-basics/vector) presents the `vector` type as a standalone
value, in a real application it usually lives inside an object. A store that owns a list of books
is a vector in a field:
```move
module book::collections_vector;
use std::string::String;
/// The Book that can be sold by a `BookStore`
public struct Book has key, store {
id: UID,
name: String
}
/// The BookStore that sells `Book`s
public struct BookStore has key, store {
id: UID,
books: vector
}
```
Everything from the vector section applies here unchanged; the collection types below follow the
same pattern - plain struct values that can be placed in a field, passed around, and, unlike
[dynamic fields](./dynamic-fields) introduced later in this chapter, fully described by the type of
the object that holds them.
## VecSet
`VecSet` is a collection that stores _unique_ items. Inserting a value that is already present
aborts, so the set is a natural fit for collections that must not contain duplicates, such as a
list of IDs or addresses.
```move
module book::collections_vec_set;
use sui::vec_set::{Self, VecSet};
public struct App has drop {
/// `VecSet` used in the struct definition
subscribers: VecSet
}
#[test_only]
use std::unit_test::assert_eq;
#[test]
fun vec_set_playground() {
let mut set = vec_set::empty(); // create an empty set
set.insert(1u8); // add items to the set
set.insert(2);
set.insert(3);
assert_eq!(set.contains(&1), true); // check if an item is in the set
assert_eq!(set.length(), 3); // get the number of items in the set
assert_eq!(set.is_empty(), false); // check if the set is empty
set.remove(&2); // remove an item from the set
assert_eq!(set.contains(&2), false);
// the contents can be taken out as a plain vector, e.g. for iteration
let items = set.into_keys();
assert_eq!(items, vector[1, 3]);
}
```
The `contains` function answers membership questions, and the contents can be read back either by
reference, with `keys`, or taken out as a plain `vector` with `into_keys` - for example, to iterate
over them with the [vector macros](./../move-basics/vector#vector-macros).
> The element type of a `VecSet` must have the [`copy`](./../move-basics/copy-ability) and
> [`drop`](./../move-basics/drop-ability) abilities. This is true for primitive types and simple
> data structs, but rules out storing assets in a set.
## VecMap
`VecMap` is a collection of key-value pairs, where each key is unique and maps to a single value.
Reading a value back is the everyday operation of a map, and there are two ways to do it: the index
syntax `map[&key]` borrows a value and aborts if the key is missing, while `try_get` returns an
[`Option`](./../move-basics/option) and never aborts.
```move
module book::collections_vec_map;
use std::string::String;
use sui::vec_map::{Self, VecMap};
public struct Metadata has drop {
name: String,
/// `VecMap` used in the struct definition
attributes: VecMap
}
#[test_only]
use std::unit_test::{assert_eq, assert_ref_eq};
#[test]
fun vec_map_playground() {
let mut map: VecMap = vec_map::empty(); // create an empty map
map.insert(2, "two"); // add a key-value pair to the map
map.insert(3, "three");
assert_eq!(map.contains(&2), true); // check if a key is in the map
assert_eq!(map.length(), 2); // get the number of entries
// index syntax borrows a value by key, aborts if the key is missing
assert_ref_eq!(&map[&2], &"two");
// `try_get` copies the value, returns `none` if the key is missing
assert_eq!(map.try_get(&2), option::some("two"));
assert_eq!(map.try_get(&4), option::none());
// an existing value can be replaced through a mutable reference
*(&mut map[&3]) = "III";
// `remove` returns the key-value pair
let (key, value) = map.remove(&2);
assert_eq!(key, 2);
assert_eq!(value, "two");
}
```
Like `VecSet`, a `VecMap` aborts on an attempt to `insert` a key that is already present - it does
_not_ silently overwrite the old value. Replacing a value requires going through a mutable
reference, as the example above shows, or removing the old entry first. Keys of a `VecMap` must
have the [`copy`](./../move-basics/copy-ability) ability, while the value can be any type.
## Limitations
Vector-based collections are strictly typed: a `VecSet` holds addresses and nothing else,
which is exactly what you want most of the time, but makes them unsuitable for heterogeneous data.
They are also plain values stored inside the object, so they count toward the object size limit of
256KB, described in the [Building Against Limits](./../guides/building-against-limits) guide.
In practice, a different limit matters sooner: every operation - `insert`, `contains`, `get` -
scans the underlying vector element by element, so the cost of each access grows with the size of
the collection. Vector-based collections shine when the number of elements is small and bounded -
tens or hundreds of entries. For large or unbounded collections, the Sui Framework provides
`Table`, `Bag`, and other object-backed types, which we cover in the
[Dynamic Collections](./dynamic-collections) section later in this chapter.
Lastly, vector-based collections do not support equality comparison the way one might expect.
`VecSet` and `VecMap` keep their contents in insertion order, and the `==` operator compares the
underlying vectors element by element. As a result, two sets that contain the same elements, but
received them in a different order, are _not_ equal.
> This behavior is caught by the linter and will emit a warning: _Comparing collections of type
> 'sui::vec_set::VecSet' may yield unexpected result_
```move
let mut set1 = vec_set::empty();
set1.insert(1u8);
set1.insert(2);
let mut set2 = vec_set::empty();
set2.insert(2);
set2.insert(1);
assert_eq!(set1, set2); // aborts!
```
In the example above, both sets contain the same elements - `1` and `2` - but they were inserted in
a different order. Since the comparison is order-sensitive, `set1 == set2` evaluates to `false`, and
the assertion aborts. Do not rely on `==` to compare vector-based collections, unless you can
guarantee that the elements were inserted in the same order.
## Summary
- Vector is a native type that allows storing a list of items; inside an object it appears as a
regular field.
- VecSet is built on top of vector and stores unique items; inserting a duplicate aborts.
- VecMap stores key-value pairs with unique keys; inserting an existing key aborts, and values are
read with the index syntax or `try_get`.
- Vector-based collections are strictly typed, scan their contents linearly on every operation, and
are best suited for small, bounded sets and lists; larger collections call for
[dynamic collections](./dynamic-collections).
## Next Steps
In the next section we will cover the [Wrapper Type Pattern](./wrapper-type-pattern) - a design
pattern often used with collection types to extend or restrict their behavior.
## Further Reading
- [sui::vec_set][vec-set-framework] module documentation.
- [sui::vec_map][vec-map-framework] module documentation.
[vec-set-framework]: https://docs.sui.io/references/framework/sui/vec_set
[vec-map-framework]: https://docs.sui.io/references/framework/sui/vec_map
---
# Pattern: Wrapper Type
Sometimes, there's a need to create a new type that behaves similarly to an existing type but with
certain modifications or restrictions. For example, you might want to create a
[collection type](./collections) that behaves like a vector but doesn’t allow modifying the elements
after they’ve been inserted. The wrapper type pattern is an effective way to achieve this.
## Definition
The wrapper type pattern is a design pattern in which you create a new type that wraps an existing
type. The wrapper type is distinct from the original but can be converted to and from it.
Often, it is implemented as a [positional struct](./../move-basics/struct.md#positional-structs)
with a single field.
```move
module book::wrapper_type_pattern;
/// Very simple stack implementation using the wrapper type pattern. Does not allow
/// accessing the elements unless they are popped.
public struct Stack(vector) has copy, store, drop;
/// Create a new instance by wrapping the value.
public fun new(value: vector): Stack {
Stack(value)
}
/// Push an element to the stack.
public fun push_back(v: &mut Stack, el: T) {
v.0.push_back(el);
}
/// Pop an element from the stack. Unlike `vector`, this function won't
/// fail if the stack is empty and will return `None` instead.
public fun pop_back(v: &mut Stack): Option {
if (v.0.length() == 0) option::none()
else option::some(v.0.pop_back())
}
/// Get the size of the stack.
public fun size(v: &Stack): u64 {
v.0.length()
}
```
## Common Practices
In cases where the goal is to extend the behavior of an existing type, it is common to provide
accessors for the wrapped type. This approach allows users to access the underlying type directly
when needed. For example, in the following code, we provide the `inner()`, `inner_mut()`, and
`into_inner()` methods for the Stack type.
```move
/// Allows reading the contents of the `Stack`.
public fun inner(v: &Stack): &vector { &v.0 }
/// Allows mutable access to the contents of the `Stack`.
public fun inner_mut(v: &mut Stack): &mut vector { &mut v.0 }
/// Unpacks the `Stack` into the underlying `vector`.
public fun into_inner(v: Stack): vector {
let Stack(inner) = v;
inner
}
```
## Advantages
The wrapper type pattern offers several benefits:
- Custom Functions: It allows you to define custom functions for an existing type.
- Robust Function Signatures: It constrains function signatures to the new type, thereby making the
code more robust.
- Improved Readability: It often increases the readability of the code by providing a more
descriptive type name.
## Disadvantages
The wrapper type pattern is powerful in two scenarios - when you want to limit the behavior of an
existing type while providing a custom interface to the same data structure, and when you want to
extend the behavior of an existing type. However, it does have some limitations:
- Verbosity: It can be verbose to implement, especially if you want to expose all the methods of the
wrapped type.
- Sparse Implementation: The implementation can be quite minimal, as it often just forwards calls to
the wrapped type.
## Next Steps
The wrapper type pattern is very useful, particularly when used in conjunction with collection
types, as demonstrated in the previous section. In the next section, we will cover
[Dynamic Fields](./dynamic-fields) - an important primitive that enables
[Dynamic Collections](./dynamic-collections), a way to store large collections of data in a more
flexible, albeit more expensive, way.
---
# Dynamic Fields
The Sui Object Model allows attaching extra data to objects at runtime as _dynamic fields_. The
behavior is similar to how a `Map` works in other programming languages. However, unlike a `Map`,
which in Move would be strictly typed (we have covered it in the [Collections](./collections)
section), dynamic fields allow attaching values of any type. A similar approach from the world of
frontend development would be a JavaScript Object type which allows storing any type of data
dynamically.
> There's no limit to the number of dynamic fields that can be attached to an object. Thus, dynamic
> fields can be used to store large amounts of data that don't fit into the object size limit.
Dynamic fields allow for a wide range of applications, from splitting data into smaller parts to
avoid the [object size limit](./../guides/building-against-limits) to attaching objects as a part
of application logic.
## Definition
Dynamic fields are defined in the `sui::dynamic_field` module of the
[Sui Framework](./sui-framework). They are attached to an object's `UID` via a _name_, and can be
accessed using that name. There can be only one field with a given name attached to an object.
```move
module sui::dynamic_field;
/// Internal object used for storing the field and value
public struct Field has key {
/// Determined by the hash of the object ID, the field name
/// value and its type, i.e. hash(parent.id || name || Name)
id: UID,
/// The value for the name of this field
name: Name,
/// The value bound to this field
value: Value,
}
```
As the definition shows, dynamic fields are stored in an internal `Field` object, which has the
`UID` generated in a deterministic way based on the object ID, the field name, and the field type.
The `Field` object contains the field name and the value bound to it. The constraints on the `Name`
and `Value` type parameters define the abilities that the key and value must have.
_See [full documentation for sui::dynamic_field][dynamic-field-framework] module._
## Usage
The methods available for dynamic fields are straightforward: a field can be added with `add`,
removed with `remove`, and read with `borrow` and `borrow_mut`. Additionally, the `exists_` method
can be used to check if a field exists (for stricter checks with type, there is an
`exists_with_type` method), and `remove_if_exists` removes a field if it is present, returning an
[`Option`](./../move-basics/option) with the value.
```move
module book::dynamic_fields;
// a very common alias for `dynamic_field` is `df` since the
// module name is quite long
use sui::dynamic_field as df;
use std::string::String;
/// The object that we will attach dynamic fields to.
public struct Character has key {
id: UID
}
// List of different accessories that can be attached to a character.
// They must have the `store` ability.
public struct Hat has key, store { id: UID, color: u32 }
public struct Mustache has key, store { id: UID }
#[test]
fun test_character_and_accessories() {
let ctx = &mut tx_context::dummy();
let mut character = Character { id: object::new(ctx) };
// Attach a hat to the character's UID
df::add(
&mut character.id,
b"hat_key",
Hat { id: object::new(ctx), color: 0xFF0000 }
);
// Similarly, attach a mustache to the character's UID
df::add(
&mut character.id,
b"mustache_key",
Mustache { id: object::new(ctx) }
);
// Check that the hat and mustache are attached to the character
assert!(df::exists_(&character.id, b"hat_key"));
assert!(df::exists_(&character.id, b"mustache_key"));
// Modify the color of the hat
let hat: &mut Hat = df::borrow_mut(&mut character.id, b"hat_key");
hat.color = 0x00FF00;
// Remove the hat and mustache from the character
let hat: Hat = df::remove(&mut character.id, b"hat_key");
let mustache: Mustache = df::remove(&mut character.id, b"mustache_key");
// Check that the hat and mustache are no longer attached to the character
assert!(!df::exists_(&character.id, b"hat_key"));
assert!(!df::exists_(&character.id, b"mustache_key"));
std::unit_test::destroy(character);
std::unit_test::destroy(mustache);
std::unit_test::destroy(hat);
}
```
In the example above, we define a `Character` object and two different types of accessories that
could never be put together in a vector. However, dynamic fields allow us to store them together in
a single object. Both objects are attached to the `Character` via a `vector` (a byte string
literal), and can be accessed using their respective names.
As you can see, when we attached the accessories to the Character, we passed them _by value_. In
other words, both values were moved to a new scope, and their ownership was transferred to the
`Character` object. If we changed the ownership of `Character` object, the accessories would have
been moved with it.
And the last important property of dynamic fields we should highlight is that they are _accessed
through their parent_. This means that the `Hat` and `Mustache` objects are not directly accessible
and follow the same rules as the parent object.
## Foreign Types as Dynamic Fields
Dynamic fields allow objects to carry data of any type, including those defined in other modules.
This is possible due to their generic nature and relatively weak constraints on the type parameters.
Let's illustrate this by attaching a few different values to a `Character` object.
```move
let mut character = Character { id: object::new(ctx) };
// Attach a `String` via a `vector` name
let string_value: String = "Hello, World!";
df::add(&mut character.id, b"string_key", string_value);
// Attach a `u64` via a `u32` name
df::add(&mut character.id, 1000u32, 1_000_000_000u64);
// Attach a `bool` via a `bool` name
df::add(&mut character.id, true, false);
```
In this example we showed how different types can be used for both _name_ and the _value_ of a
dynamic field. The `String` is attached via a `vector` name, the `u64` is attached via a `u32`
name, and the `bool` is attached via a `bool` name. Anything is possible with dynamic fields!
## Custom Type as a Field Name
In the examples above, we used primitive types as field names since they have the required set of
abilities. But dynamic fields get even more interesting when we use custom types as field names.
This allows for a more structured way of storing data, and also allows for protecting the field
names from being accessed by other modules.
```move
/// A custom type with fields in it.
public struct AccessoryKey has copy, drop, store { name: String }
/// An empty key, can be attached only once.
public struct MetadataKey has copy, drop, store {}
```
Two field names that we defined above are `AccessoryKey` and `MetadataKey`. The `AccessoryKey` has a
`String` field in it, hence it can be used multiple times with different `name` values. The
`MetadataKey` is an empty key, and can be attached only once.
```move
let mut character = Character { id: object::new(ctx) };
// Attaching via an `AccessoryKey { name: "hat" }`
df::add(
&mut character.id,
AccessoryKey { name: "hat" },
Hat { id: object::new(ctx), color: 0xFF0000 }
);
// Attaching via an `AccessoryKey { name: "mustache" }`
df::add(
&mut character.id,
AccessoryKey { name: "mustache" },
Mustache { id: object::new(ctx) }
);
// Attaching via a `MetadataKey`
df::add(&mut character.id, MetadataKey {}, 42u64);
```
As you can see, custom types work as field names as long as they can be _constructed_ by the
module - in other words, if they are _internal_ to the module and defined in it. This limitation on
struct packing can open up new ways in the design of the application.
This approach is used in the [Object Capability](./object-capability) pattern, where an application
can authorize a foreign object to perform operations in it while not exposing the capabilities to
other modules.
## Exposing UID
Mutable access to `UID` is a security risk. Exposing `UID` of your type as a mutable reference can
lead to unwanted modifications or removal of the object's dynamic fields. Additionally, it affects
[Transfer to Object](./../storage/transfer-to-object) and
[Dynamic Object Fields](./dynamic-object-fields). Make sure to understand the implications before
exposing the `UID` as a mutable reference.
Because dynamic fields are attached to `UID`s, their usage in other modules depends on whether the
`UID` can be accessed. By default struct visibility protects the `id` field and won't let other
modules access it directly. However, if there's a public accessor method that returns a reference to
`UID`, dynamic fields can be read in other modules.
```move
/// Exposes the UID of the character, so that other modules can read
/// dynamic fields.
public fun uid(c: &Character): &UID {
&c.id
}
```
In the example above, we show how to expose the `UID` of a `Character` object. This solution may
work for some applications, however, it is important to remember that exposed `UID` allows reading
_any_ dynamic field attached to the object.
If you need to expose the `UID` only within the package, use a restrictive visibility, like
`public(package)`, or even better - use more specific accessor methods that would allow only reading
specific fields.
```move
/// Only allow modules in the same package to access the UID.
public(package) fun uid_package(c: &Character): &UID {
&c.id
}
/// Allow borrowing dynamic fields from the character.
public fun borrow(
c: &Character,
n: Name
): &Value {
df::borrow(&c.id, n)
}
```
## Orphaned Dynamic Fields
> To prevent orphaned dynamic fields, please use [Dynamic Collection Types](./dynamic-collections)
> such as `Bag` as they track the dynamic fields and won't allow unpacking if there are attached
> fields.
The `object::delete()` function, which is used to delete a UID, does not track the dynamic fields,
and cannot prevent dynamic fields from becoming orphaned. Once the parent UID is deleted, the
dynamic fields are not automatically deleted, and they become orphaned. This means that the dynamic
fields are still stored in the blockchain, but they will never become accessible again.
```move
let hat = Hat { id: object::new(ctx), color: 0xFF0000 };
let mut character = Character { id: object::new(ctx) };
// Attach a `Hat` via a `vector` name
df::add(&mut character.id, b"hat_key", hat);
// ! DO NOT do this in your code
// ! Danger - deleting the parent object
let Character { id } = character;
id.delete();
// ...`Hat` is now stuck in a limbo, it will never be accessible again
```
Orphaned objects are not subject to the storage rebate, and the storage fees will remain unclaimed.
One way to avoid orphaned dynamic fields during unpacking of an object is to return the `UID` and
store it somewhere temporarily until the dynamic fields are removed and handled properly.
## Dynamic Fields vs Fields
Dynamic Fields are more expensive than regular fields, as they require additional storage and costs
for accessing them. Their flexibility comes at a price, and it is important to understand the
implications when making a decision between using dynamic fields and regular fields.
## Limits
Dynamic Fields are not subject to the [object size limit](./../guides/building-against-limits), and
can be used to store large amounts of data. However, they are still subject to the
[dynamic fields created limit](./../guides/building-against-limits), which is set to 1000 fields per
transaction.
## Applications
Dynamic fields can play a crucial role in applications of any complexity. They open up a variety of
different use cases, from storing heterogeneous data to attaching objects as part of the application
logic. They allow for certain [upgradeability practices](./../guides/upgradeability-practices) based
on the ability to define them _later_ and change the type of the field.
## Summary
- Dynamic fields attach values to an object's `UID` under a _name_; both the name and the value
can be of almost any type, including types defined in other modules.
- Attached values are owned by the parent object and can only be accessed through it.
- Custom types used as field names can only be constructed by the defining module, which protects
the fields from external access.
- Deleting the parent `UID` does not remove its dynamic fields - the fields left behind become
inaccessible _orphans_.
## Next Steps
In the next section we will cover [Dynamic Object Fields](./dynamic-object-fields) and explain how
they differ from dynamic fields, and what are the implications of using them.
## Further Reading
- [sui::dynamic_field][dynamic-field-framework] module documentation.
[dynamic-field-framework]: https://docs.sui.io/references/framework/sui/dynamic_field
---
# Dynamic Object Fields
> This section expands on [Dynamic Fields](./dynamic-fields). Please read it first to understand
> the basics of dynamic fields.
Another variation of dynamic fields is _dynamic object fields_, which have certain differences from
regular dynamic fields. In this section, we will cover the specifics of dynamic object fields and
explain how they differ from regular dynamic fields.
> The general recommendation is to avoid using dynamic object fields in favor of (just) dynamic fields,
> especially if there's no need for direct discovery through the ID. The extra costs of dynamic
> object fields may not be justified by the benefits they provide.
## Definition
Dynamic Object Fields are defined in the `sui::dynamic_object_field` module in the
[Sui Framework](./sui-framework). They are similar to dynamic fields in many ways, but unlike them,
dynamic object fields have an extra constraint on the `Value` type. The `Value` must have a
combination of `key` and `store`, not just `store` as in the case of dynamic fields.
The module definition is smaller than that of dynamic fields - only the field _name_ gets a
wrapper type, while the value is stored as-is:
```move
module sui::dynamic_object_field;
/// Internal object used for storing the field and the name associated with the
/// value. The separate type is necessary to prevent key collision with direct
/// usage of dynamic_field
public struct Wrapper has copy, drop, store {
name: Name,
}
```
Unlike the `Field` type in the [Dynamic Fields](./dynamic-fields#definition) section, the `Wrapper` type
only stores the name of the field. The value is the object itself, and is _not wrapped_.
_See [full documentation for sui::dynamic_object_field][dynamic-object-field-framework] module._
The constraints on the `Value` type become visible in the methods available for dynamic object
fields. Here's the signature for the `add` function:
```move
/// Adds a dynamic object field to the object `object: &mut UID` at field
/// specified by `name: Name`. Aborts with `EFieldAlreadyExists` if the object
/// already has that field with that name.
public fun add(
// we use &mut UID in several spots for access control
object: &mut UID,
name: Name,
value: Value,
) { /* implementation omitted */ }
```
The rest of the methods are identical to the ones in the
[Dynamic Fields](./dynamic-fields#usage) section, and carry the same constraint on the `Value`
type. Let's list them for reference:
- `add` - adds a dynamic object field to the object
- `remove` - removes a dynamic object field from the object
- `borrow` - borrows a dynamic object field from the object
- `borrow_mut` - borrows a mutable reference to a dynamic object field from the object
- `exists_` - checks if a dynamic object field exists
- `exists_with_type` - checks if a dynamic object field exists with a specific type
Additionally, there is an `id` method which returns the `ID` of the `Value` object without
specifying its type.
## Usage and Differences with Dynamic Fields
The main difference between dynamic fields and dynamic object fields is that the latter allows
storing _only objects_ as values. This means that you can't store primitive types like `u64` or
`bool`. In exchange for this restriction, the attached object is _not wrapped_ into a separate
object: it keeps its ID and stays visible to offchain tooling.
> This is the property to weigh when choosing between the two: a value attached as a regular
> dynamic field is wrapped into a `Field` object and disappears from ID-based queries, while a
> value attached as a dynamic object field remains discoverable by its ID in wallets and explorers.
```move
module book::dynamic_object_field;
use std::string::String;
// there are two common aliases for the long module name: `dof` and
// `ofield`. Both are commonly used and met in different projects.
use sui::dynamic_object_field as dof;
use sui::dynamic_field as df;
/// The `Character` that we will use for the example
public struct Character has key { id: UID }
/// Metadata that doesn't have the `key` ability
public struct Metadata has store, drop { name: String }
/// Accessory that has the `key` and `store` abilities.
public struct Accessory has key, store { id: UID }
#[test]
fun equip_accessory() {
let ctx = &mut tx_context::dummy();
let mut character = Character { id: object::new(ctx) };
// Create an accessory and attach it to the character
let hat = Accessory { id: object::new(ctx) };
// Add the hat to the character. Just like with `dynamic_fields`
dof::add(&mut character.id, b"hat_key", hat);
// However for non-key structs we can only use `dynamic_field`
df::add(&mut character.id, b"metadata_key", Metadata {
name: "John"
});
// Borrow the hat from the character
let hat_id = dof::id(&character.id, b"hat_key").extract(); // Option
let hat_ref: &Accessory = dof::borrow(&character.id, b"hat_key");
let hat_mut: &mut Accessory = dof::borrow_mut(&mut character.id, b"hat_key");
let hat: Accessory = dof::remove(&mut character.id, b"hat_key");
// Clean up, Metadata is an orphan now.
std::unit_test::destroy(hat);
std::unit_test::destroy(character);
}
```
In the example above, the `Accessory` has both `key` and `store`, so it can be attached as a
dynamic object field. The `Metadata`, however, only has `store`, so it can only be attached as a
regular dynamic field. Both kinds of fields coexist on the same `UID` - even under similar names -
because the internal `Wrapper` type prevents key collisions between the two modules. Lastly, the
example demonstrates the `id` function, which returns the `ID` of the attached object without
requiring its type - something only possible because the object keeps its identity.
## Pricing Differences
Dynamic object fields are a little more expensive than dynamic fields. Because of their internal
structure, a single dynamic object field is stored as two objects: an internal field storing the
name, and the value object itself. As a result, the cost of adding and accessing dynamic object
fields (loading 2 objects compared to 1 for dynamic fields) is higher.
## Summary
- Dynamic object fields require the value to be an object (`key` + `store`) and, unlike regular
dynamic fields, keep the attached object discoverable by its ID in wallets and explorers.
- The methods mirror those of dynamic fields, with an extra `id` function that returns the `ID` of
the attached object without specifying its type.
- Dynamic object fields are more expensive than dynamic fields, so prefer the latter unless
ID-based discovery is required.
## Next Steps
Both dynamic fields and dynamic object fields are powerful features which allow for innovative
solutions in applications. However, they are relatively low-level and require careful handling to
avoid orphaned fields. In the next section, we will introduce a higher-level abstraction -
[Dynamic Collections](./dynamic-collections) - which can help with managing dynamic fields and
objects more effectively.
## Further Reading
- [sui::dynamic_object_field][dynamic-object-field-framework] module documentation.
[dynamic-object-field-framework]: https://docs.sui.io/references/framework/sui/dynamic_object_field
---
# Dynamic Collections
The [Sui Framework](./sui-framework) offers a variety of collection types that build on the
[dynamic fields](./dynamic-fields) and [dynamic object fields](./dynamic-object-fields) concepts.
These collections are designed to be a safer and more understandable way to store and manage dynamic
fields and objects.
For each collection type we will specify the primitive they use, and the specific features they
offer.
> Unlike dynamic (object) fields which operate on UID, collection types have their own type and
> allow calling [associated functions](./../move-basics/struct-methods).
## Common Concepts
All five collections follow the same shape: a struct with the `key` and `store` abilities, holding
its own `UID` and a `size` counter. The entries are attached to that `UID` as dynamic fields. This
is why creating a collection requires a mutable reference to the
[transaction context](./transaction-context) - a fresh `UID` has to be derived from it - and why a
collection is typically stored as a field of another object, as the examples below show.
All of the collection types share the same set of core methods:
- `new` - creates a new, empty collection
- `add` - adds a field to the collection ([LinkedTable](#linkedtable) uses `push_front` and
`push_back` instead)
- `remove` - removes a field from the collection and returns the value
- `borrow` - borrows a field from the collection
- `borrow_mut` - borrows a mutable reference to a field from the collection
- `contains` - checks if a field exists in the collection
- `length` - returns the number of fields in the collection
- `is_empty` - checks if the `length` is 0
- `destroy_empty` - destroys the collection, aborting if it still contains fields
The last method is what makes collections safer than raw dynamic fields: because collections track
their size, they cannot be destroyed while non-empty, which rules out
[orphaned fields](./dynamic-fields#orphaned-dynamic-fields). The flip side of this protection is
that a collection whose values cannot be dropped has to be emptied entry by entry before it can be
destroyed - and since the number of dynamic fields accessed per transaction is
[limited](./../guides/building-against-limits), dismantling a large collection may take more than
one transaction.
Another property, inherited from dynamic fields, is that the keys are not discoverable onchain:
to access an entry, the code has to know its key. Offchain tooling can still list all entries, as
they are stored as dynamic fields on the collection's `UID`. The only collection that can be
iterated onchain is [LinkedTable](#linkedtable).
All collection types support index syntax for `borrow` and `borrow_mut` methods. If you see square
brackets in the examples, they are translated into `borrow` and `borrow_mut` calls.
```move
let hat: &Hat = &bag[b"key"];
let hat_mut: &mut Hat = &mut bag[b"key"];
// is equivalent to
let hat: &Hat = bag.borrow(b"key");
let hat_mut: &mut Hat = bag.borrow_mut(b"key");
```
In the examples we won't focus on these functions, but rather on the differences between the
collection types.
## Bag
Bag, as the name suggests, acts as a "bag" of heterogeneous values. It is a simple, non-generic
type built on [dynamic fields](./dynamic-fields), and it can store any data. Bag is the right
choice when a single container has to hold values of different types - for example, a game
character carrying items of various kinds, or a user profile storing unrelated settings side by
side.
```move
module sui::bag;
public struct Bag has key, store {
/// the ID of this bag
id: UID,
/// the number of key-value pairs in the bag
size: u64,
}
```
_See [full documentation for sui::bag][bag-framework] module._
Since Bag stores values of any type, it offers one extra method:
- `contains_with_type` - checks if a field exists with a specific type
Used as a struct field:
```move
/// Imported from the `sui::bag` module.
use sui::bag::{Self, Bag};
/// An example of a `Bag` as a struct field.
public struct Carrier has key {
id: UID,
bag: Bag
}
```
Using the Bag:
```move
let mut bag = bag::new(ctx);
// bag has the `length` function to get the number of elements
assert_eq!(bag.length(), 0);
// the type of the value is defined at insertion; here it is a `String`
let value: String = "my_value";
bag.add(b"my_key", value);
// length has changed to 1
assert_eq!(bag.length(), 1);
// in order: `borrow`, `borrow_mut` and `remove`
// the value type must be specified
let field_ref: &String = &bag[b"my_key"];
let field_mut: &mut String = &mut bag[b"my_key"];
let field: String = bag.remove(b"my_key");
// length is back to 0 - we can unpack
bag.destroy_empty();
```
## ObjectBag
Defined in the `sui::object_bag` module. Identical to [Bag](#bag), but uses
[dynamic object fields](./dynamic-object-fields) internally. Can only store objects as values, and
in exchange keeps them discoverable by their IDs in offchain tooling. Use it for the same
heterogeneous scenarios as Bag when the stored values are assets that should remain visible in
wallets and explorers - such as an inventory of NFTs of different types.
Like dynamic object fields, ObjectBag offers the `value_id` function, which returns the `ID` of a
stored object without specifying its type.
_See [full documentation for sui::object_bag][object-bag-framework] module._
## Table
Table is a typed dynamic collection that has a fixed type for keys and values. It is built on
[dynamic fields](./dynamic-fields) and defined in the `sui::table` module. Table is the go-to
collection for large uniform registries: user records, balances, or configuration entries keyed by
an address or a name - like the `UserRegistry` in the example below.
```move
module sui::table;
public struct Table has key, store {
/// the ID of this table
id: UID,
/// the number of key-value pairs in the table
size: u64,
}
```
_See [full documentation for sui::table][table-framework] module._
Since the type of the values is fixed, Table offers one extra method:
- `drop` - destroys the table even if it is not empty; only available when the value type has the
[drop](./../move-basics/drop-ability) ability
Used as a struct field:
```move
/// Imported from the `sui::table` module.
use sui::table::{Self, Table};
/// Some record type with `store`
public struct Record has store { /* ... */ }
/// An example of a `Table` as a struct field.
public struct UserRegistry has key {
id: UID,
table: Table
}
```
Using the Table:
```move
// Table requires explicit type parameters for the key and value
// ...but does it only once in initialization.
let mut table = table::new(ctx);
// table has the `length` function to get the number of elements
assert_eq!(table.length(), 0);
table.add(@0xa11ce, "my_value");
table.add(@0xb0b, "another_value");
// length has changed to 2
assert_eq!(table.length(), 2);
// in order: `borrow`, `borrow_mut` and `remove`
let value_ref = &table[@0xa11ce];
let value_mut = &mut table[@0xa11ce];
// removing both values
let _value = table.remove(@0xa11ce);
let _another_value = table.remove(@0xb0b);
// length is back to 0 - we can unpack
table.destroy_empty();
```
## ObjectTable
Defined in the `sui::object_table` module. Identical to [Table](#table), but uses
[dynamic object fields](./dynamic-object-fields) internally. Can only store objects as values, and
in exchange keeps them discoverable by their IDs in offchain tooling. Use it when a registry
stores whole objects of the same type - for example, user profile objects keyed by the owner's
address - and each of them should stay individually discoverable.
Like dynamic object fields, ObjectTable offers the `value_id` function, which returns the `ID` of
a stored object without specifying its type.
_See [full documentation for sui::object_table][object-table-framework] module._
Storing objects requires the value type to have the `key` and `store` abilities:
```move
/// Imported from the `sui::object_table` module.
use sui::object_table::{Self, ObjectTable};
/// A profile is an object - it has the `key` and `store` abilities.
public struct Profile has key, store {
id: UID,
name: String,
}
/// An example of an `ObjectTable` as a struct field.
public struct ProfileRegistry has key {
id: UID,
profiles: ObjectTable
}
```
Using the ObjectTable:
```move
let mut profiles = object_table::new(ctx);
// the interface is the same as the regular `Table`
profiles.add(@0xa11ce, Profile {
id: object::new(ctx),
name: "Alice",
});
// the stored object keeps its `ID` and can be looked up without its type
let profile_id = profiles.value_id(@0xa11ce); // Option
// objects cannot be dropped - remove the entry before destroying the table
let profile = profiles.remove(@0xa11ce);
profiles.destroy_empty();
```
## LinkedTable
Defined in the `sui::linked_table` module. Built on [dynamic fields](./dynamic-fields), similar to
[Table](#table), but the entries are linked together, allowing insertion at either end, ordered
removal, and onchain iteration. This makes it the choice
for anything that must be enumerated or processed in order onchain: queues and waitlists,
leaderboards, or registries whose entries have to be listed - like the `AdminRegistry` in the
example below.
```move
module sui::linked_table;
public struct LinkedTable has key, store {
/// the ID of this table
id: UID,
/// the number of key-value pairs in the table
size: u64,
/// the front of the table, i.e. the key of the first entry
head: Option,
/// the back of the table, i.e. the key of the last entry
tail: Option,
}
```
_See [full documentation for sui::linked_table][linked-table-framework] module._
Since the entries in LinkedTable are linked together, adding an entry requires stating where it
goes, so instead of `add` it has:
- `push_front` - inserts a key-value pair at the front of the table
- `push_back` - inserts a key-value pair at the back of the table
- `pop_front` - removes the front of the table, returns the key and value
- `pop_back` - removes the back of the table, returns the key and value
Additionally, the `front`, `back`, `prev`, and `next` methods return the keys of neighboring
entries, making it possible to iterate over the table onchain. Like [Table](#table), LinkedTable
offers the `drop` method for value types with the [drop](./../move-basics/drop-ability) ability.
Used as a struct field:
```move
/// Imported from the `sui::linked_table` module.
use sui::linked_table::{Self, LinkedTable};
/// Some record type with `store`
public struct Permissions has store { /* ... */ }
/// An example of a `LinkedTable` as a struct field.
public struct AdminRegistry has key {
id: UID,
linked_table: LinkedTable
}
```
Using the LinkedTable:
```move
// LinkedTable requires explicit type parameters for the key and value
// ...but does it only once in initialization.
let mut linked_table = linked_table::new(ctx);
// linked_table has the `length` function to get the number of elements
assert_eq!(linked_table.length(), 0);
linked_table.push_front(@0xa0a, "first_value");
linked_table.push_back(@0xb1b, "second_value");
linked_table.push_back(@0xc2c, "third_value");
// length has changed to 3
assert_eq!(linked_table.length(), 3);
// in order: `borrow`, `borrow_mut` and `remove`
let first_value_ref = &linked_table[@0xa0a];
let second_value_mut = &mut linked_table[@0xb1b];
// remove by key, from the beginning or from the end
let _second_value = linked_table.remove(@0xb1b);
let (_first_addr, _first_value) = linked_table.pop_front();
let (_third_addr, _third_value) = linked_table.pop_back();
// length is back to 0 - we can unpack
linked_table.destroy_empty();
```
## Pricing
Collections inherit the pricing of the primitives they are built on. Creating a collection adds an
object with a `UID` to storage; each entry is priced as a
[dynamic field](./dynamic-fields#dynamic-fields-vs-fields), or - in the Object-variants - as a
[dynamic object field](./dynamic-object-fields#pricing-differences), with its higher, two-object
cost per entry.
## Choosing a Collection Type
A short decision guide:
- The key and value types are fixed and known - use [Table](#table); if the values vary in type,
use [Bag](#bag);
- The values are objects that should stay visible to wallets and explorers - take the
[ObjectTable](#objecttable) / [ObjectBag](#objectbag) variant;
- The collection has to be iterated onchain or preserve insertion order - use
[LinkedTable](#linkedtable), the only one of the five that links its entries;
- The collection is small, bounded, and needs to be embedded or compared as a plain value - the
vector-based [collections](./collections) from the earlier section may be a better fit than a
dynamic one.
> One more thing to keep in mind: the entries of a dynamic collection live outside of the struct
> itself. Serializing a `Table` (for example, with [BCS](./bcs)) or comparing two tables only
> takes the `id` and `size` fields into account - never the contents.
## Summary
- [Bag](#bag) - a simple collection that can store any type of data; fits containers of
heterogeneous values, such as inventories.
- [ObjectBag](#objectbag) - same as Bag, but can only store objects; fits heterogeneous assets
that should stay visible in wallets and explorers.
- [Table](#table) - a typed dynamic collection that has a fixed type for keys and values; fits
large uniform registries.
- [ObjectTable](#objecttable) - same as Table, but can only store objects; fits registries of
same-type objects that should stay individually discoverable.
- [LinkedTable](#linkedtable) - similar to Table but the entries are linked together; fits queues
and anything iterated onchain.
## Next Steps
This section concludes the tour of dynamic fields and the collections built on top of them. In the
next section we will move on to design patterns, starting with the
[Witness](./witness-pattern) pattern.
## Further Reading
- [sui::table][table-framework] module documentation.
- [sui::object_table][object-table-framework] module documentation.
- [sui::linked_table][linked-table-framework] module documentation.
- [sui::bag][bag-framework] module documentation.
- [sui::object_bag][object-bag-framework] module documentation.
[table-framework]: https://docs.sui.io/references/framework/sui/table
[object-table-framework]: https://docs.sui.io/references/framework/sui/object_table
[linked-table-framework]: https://docs.sui.io/references/framework/sui/linked_table
[bag-framework]: https://docs.sui.io/references/framework/sui/bag
[object-bag-framework]: https://docs.sui.io/references/framework/sui/object_bag
---
# Pattern: Witness
Witness is a pattern of proving a fact by constructing evidence of it. In the context of
programming, a witness is a way to prove a certain property of a system by providing a value that
can only be constructed if the property holds.
## Witness in Move
In the [Struct](./../move-basics/struct) section we have shown that a struct can only be created -
or _packed_ - by the module defining it. Hence, in Move, a module proves ownership of the type by
constructing it. This is one of the most important patterns in Move, and it is widely used for
generic type instantiation and authorization.
Practically speaking, for the witness to be used, there has to be a function that expects a witness
as an argument. In the example below it is the `new` function that expects a witness of the `T`
type to create an `Instance`.
> The witness is usually discarded rather than stored, which is why such functions often require
> the witness type to have the [drop](./../move-basics/drop-ability) ability.
```move
module book::witness;
/// A struct that can only be created with a witness of `T`.
public struct Instance has drop {}
/// Create a new `Instance` with the provided witness. The witness is
/// discarded after use.
public fun new(_witness: T): Instance {
Instance {}
}
```
The only way to construct an `Instance` is to call the `new` function with an instance of the
type `T`. This is a basic example of the witness pattern in Move. A module providing a witness often
has a matching implementation, like the module `book::witness_source` below:
```move
module book::witness_source;
use book::witness::{Self, Instance};
/// A struct used as a witness - canonically, an empty struct with `drop`.
public struct W has drop {}
/// Create a new instance of `Instance`.
public fun new_instance(): Instance {
witness::new(W {})
}
```
The instance of the struct `W` is passed into the `new_instance` function to create an
`Instance`, thereby proving that the module `book::witness_source` owns the type `W`.
## Instantiating a Generic Type
Witness allows generic types to be instantiated with a concrete type. This is useful for inheriting
associated behaviors from the type with an option to extend them, if the module provides the ability
to do so.
```move
module sui::balance;
/// A Supply of T. Used for minting and burning.
/// Wrapped into a `TreasuryCap` in the `Coin` module.
public struct Supply has store {
value: u64,
}
/// Create a new supply for type T.
public fun create_supply(_: T): Supply {
Supply { value: 0 }
}
/// Get the `Supply` value.
public fun supply_value(supply: &Supply): u64 {
supply.value
}
```
In the example above, which is borrowed from the [`balance` module][balance-framework] of the
[Sui Framework](./sui-framework), the `Supply` is a generic struct that can be constructed only by
supplying a witness of the type `T`. The witness is taken by value and _discarded_ - hence the `T`
must have the [drop](./../move-basics/drop-ability) ability.
[balance-framework]: https://docs.sui.io/references/framework/sui/balance
The instantiated `Supply` can then be used to mint new `Balance`'s, where `T` is the type of
the supply.
```move
module sui::balance;
const EOverflow: u64 = 1;
/// Storable balance - an inner struct of a Coin type.
/// Can be used to store coins which don't need the key ability.
public struct Balance has store {
value: u64,
}
/// Increase supply by `value` and create a new `Balance` with this value.
public fun increase_supply(self: &mut Supply, value: u64): Balance {
assert!(value <= (std::u64::max_value!() - self.value), EOverflow);
self.value = self.value + value;
Balance { value }
}
```
This is how new currencies are typically created on Sui: the `TreasuryCap` - the
[capability](./capability) described earlier in this chapter - is a wrapper around the `Supply`,
instantiated with a witness.
## Authorization with Witness
Instantiating a type is not the only use for a witness: any function can require one, making the
call available only to the module that defines `T`. The module below implements a generic
`RegulatedCoin`, in which the privileged operations - `mint`, `burn`, and `transfer` - require a
witness, while the shared functionality - `join` - is available to everyone:
```move
/// A custom RegulatedCoin type with implementable functions.
public struct RegulatedCoin has key {
id: UID,
value: u64
}
/// Protected function - requires a Witness.
/// Mints a new `RegulatedCoin` with the value.
public fun mint(_: T, value: u64, ctx: &mut TxContext): RegulatedCoin {
RegulatedCoin { id: object::new(ctx), value }
}
/// Protected function - requires a Witness.
/// Burns the `RegulatedCoin` and returns the value.
public fun burn(_: T, coin: RegulatedCoin): u64 {
let RegulatedCoin { id, value } = coin;
id.delete();
value
}
/// Protected function - requires a Witness.
public fun transfer(_: T, coin: RegulatedCoin