Skip to content

Commit

Permalink
Refactor Ownership Library for better UX (#204)
Browse files Browse the repository at this point in the history
## Type of change

<!--Delete points that do not apply-->

- Improvement (refactoring, restructuring repository, cleaning tech
debt, ...)

## Changes

The following changes have been made:

- Swaps the need for declaring ownership in storage for a pre-defined
`StorageKey` to store storage. This results in the following
improvements in developer UX as the use of the library was previously
very verbose.

Before:
```sway
storage {
     owner: Ownership = Ownership::initialized(Identity::Address(Address::from(ZERO_B256))),
}

fn foo() {
     let owner = storage.owner.owner();
     storage.owner.only_owner();
     storage.owner.renounce_ownership();
}
```
After:
```sway
fn foo() {
     let owner = _owner();
     only_owner();
     renounce_ownership();
}
```

The downside to this approach is the inability to set the owner during
compile time and a constructor must be implemented.
  • Loading branch information
bitzoic authored Nov 21, 2023
1 parent 3b5d557 commit c1813e1
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 317 deletions.
59 changes: 31 additions & 28 deletions libs/ownership/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,64 @@

# Overview

The Ownership library provides a way to block users other than a single "owner" or "admin" from calling functions. Ownership is often used when needing administrative calls on a contract.
The Ownership library provides a way to block users other than a single "owner" from calling functions. Ownership is often used when needing administrative calls on a contract.

For more information please see the [specification](./SPECIFICATION.md).

# Using the Library

## Getting Started

In order to use the Ownership library it must be added to the Forc.toml file and then imported into your Sway project. To add Sway-libs as a dependency to the Forc.toml file in your project please see the [README.md](../../README.md).
In order to use the Ownership library it must be added to the `Forc.toml` file and then imported into your Sway project. To add Sway-libs as a dependency to the `Forc.toml` file in your project please see the [README.md](../../README.md).

> **NOTE** Until [Issue #5025](https://github.com/FuelLabs/sway/issues/5025) is resolved, in order to use the Ownership Library you must also add the [SRC-5](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_5) standard as a dependencies.
You may import the Ownership library's functionalities like so:

```rust
use ownership::Ownership;
```sway
use ownership::*;
```

Once imported, the `Ownership` struct should be added to the storage block of your contract. There are two approaches when declaring ownership in storage.

1. Initalize the owner on contract deployment by calling the `initialized()` function.

```rust
storage {
owner: Ownership = Ownership::initialized(Identity::Address(Address::from(0x0000000000000000000000000000000000000000000000000000000000000000))),
}
```

2. Leave the owner uninitialized and call the `set_ownership()` function in your own constructor.

```rust
storage {
owner: Ownership = Ownership::uninitialized(),
}
Once imported, the Ownership library's functions will be available. To use them initialize the owner for your contract by calling the `initialize_ownership()` function in your own constructor method.

```sway
#[storage(read, write)]
fn my_constructor(new_owner: Identity) {
storage.owner.set_ownership(new_owner);
initialize_ownership(new_owner);
}
```

> **Note** If this approach is taken, `set_ownership()` **MUST** be called to have a contract owner.
## Basic Functionality

To restrict a function to only the owner, call the `only_owner()` function.

```rust
storage.owner.only_owner();
```sway
only_owner();
// Only the contract's owner may reach this line.
```

To return the owner from storage, call the `owner()` function.
To return the ownership state from storage, call the `_owner()` function.

```rust
let owner: Option<Identity> = storage.owner.owner();
```sway
let owner: State = _owner();
```

## Integrating the Ownership Library into the SRC-5 Standard

To implement the SRC-5 standard with the Ownership library, be sure to add the [SRC-5](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_5) abi to your contract. The following demonstrates the integration of the Ownership library with the SRC-5 standard.

```sway
use ownership::_owner;
use src_5::{State, SRC5};
impl SRC5 for Contract {
#[storage(read)]
fn owner() -> State {
_owner()
}
}
```

> **NOTE** A constructor method must be implemented to initialize the owner.
For more information please see the [specification](./SPECIFICATION.md).
16 changes: 2 additions & 14 deletions libs/ownership/SPECIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,20 @@ The Ownership library can be used anytime a function should be restricted to a s

This function will ensure that the current caller is the owner.

### `owner()`
### `_owner()`

Returns the owner stored in storage.

### `renounce_ownership()`

Only callable by the current owner, this function will remove the owner.

### `set_ownership()`
### `initialize_ownership()`

This function will store a new owner if one has not been set.

### `transfer_ownership()`

Only callable by the current owner, this function will transfer ownership to another user.

### `uninitialized()`

Creates a new ownership in the `Uninitialized` state.

### `initialized()`

Creates a new ownership in the `Initialized` state.

### `revoked()`

Creates a new ownership in the `Revoked` state.

> **Note** Once the ownership has been revoked it cannot be set or transferred again.
4 changes: 1 addition & 3 deletions libs/ownership/src/errors.sw
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
library;

/// Error log for when access is denied.
pub enum AccessError {
pub enum InitializationError {
/// Emiited when an owner has already been set.
CannotReinitialized: (),
/// Emitted when the caller is not the owner of the contract.
NotOwner: (),
}
Loading

0 comments on commit c1813e1

Please sign in to comment.