Sui basic - Capability Design Pattern
Tags: sui, beginners, tutorial
Published: 2023-11-23 03:26:51

## Capability Design Pattern

Now we have the basics of a transcript publishing system, we want to add some access control to our smart contract. 

Capability is a commonly used pattern in Move that allows fine-tuned access control using an object-centric model. Let's take a look at how we can define this capability object:

```rust
  // Type that marks the capability to create, update, and delete transcripts
  struct TeacherCap has key {
    id: UID
  }
```

We define a new struct `TeacherCap` that marks the capability to perform privileged actions on transcripts. If we want the capability to be non-transferrable, we simply do not add the `storage` ability to the struct. 

*💡Note: This is also how the equivalent of soulbound tokens (SBT) can be easily implemented in Move. You simply define a struct that has the `key` ability, but not the `store` ability. 

## Passing and Consuming Capability Objects

Next, we need to modify the methods which should be callable by someone with the `TeacherCap` capability object to take in the capability as an extra parameter and consume it immediately. 

For example, for the `create_wrappable_transcript_object` method, we can modify it as the follows:

```rust
    public fun create_wrappable_transcript_object(_: &TeacherCap, history: u8, math: u8, literature: u8, ctx: &mut TxContext) {
        let wrappableTranscript = WrappableTranscript {
            id: object::new(ctx),
            history,
            math,
            literature,
        };
        transfer::transfer(wrappableTranscript, tx_context::sender(ctx))
    }
```

We pass in a reference to `TeacherCap` capability object and consume it immediately with the `_` notation for unused variables and parameters. Note that because we are only passing in a reference to the object, consuming the reference has no effect on the original object. 

*Quiz: What happens if try to pass in `TeacherCap` by value?*

This means only an address that has a `TeacherCap` object can call this method, effectively implementing access control on this method.

We make similar modifications to all other methods in the contract that perform privileged actions on transcripts. 

## Initializer Function

A module's initializer function is called once upon publishing the module. This is useful for initializing the state of the smart contract, and is used often to send out the initial set of capability objects. 

In our example, we can define the `init` method as the following:

```rust
    /// Module initializer is called only once on module publish.
    fun init(ctx: &mut TxContext) {
        transfer::transfer(TeacherCap {
            id: object::new(ctx)
        }, tx_context::sender(ctx))
    }
```

This will create one copy of the `TeacherCap` object and send it to the publisher's address when the module is first published. 

We can see the publish transaction's effects on the [Sui Explorer](https://suiscan.xyz/devnet/home) as below:
![Screenshot 2023-11-16 at 11 39 50](https://github.com/truonggau/sui-tutorial/assets/87189382/8dad4d2b-2d72-40bf-ae9b-d1c36eee1ab1)

The second object created from the above transaction is an instance of the `TeacherCap` object, and sent to the publisher address:
![Screenshot 2023-11-16 at 11 36 24](https://github.com/truonggau/sui-tutorial/assets/87189382/42daee3d-256e-4d24-95cc-85184d236dc7)

*Quiz: What was the first object created?*

## Add Additional Teachers or Admins

In order to give additional addresses admin access, we can simply define a method to create and send additional `TeacherCap` objects as the following:

```rust
    public fun add_additional_teacher(_: &TeacherCap, new_teacher_address: address, ctx: &mut TxContext){
        transfer::transfer(
            TeacherCap {
                id: object::new(ctx)
            },
        new_teacher_address
        )
    }
```

This method re-uses the `TeacherCap` to control access, but if needed, you can also define a new capability struct indicating sudo access. 

*💡Note: You can find some example in [here](https://github.com/truonggau/sui-tutorial/blob/main/basic_example/basic_example/build/basic_example/sources/transcript_3.move).*

## Referent

- Part 4: [object wrapping](https://dev.to/truongnx/sui-basic-object-wrapping-4a7k)

- Part 6: [Event](https://dev.to/truongnx/sui-basic-events-1gh5)