-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Type of change <!--Delete points that do not apply--> - New feature ## Changes The following changes have been made: - Introduces the admin library which has the following functionality: - `add_admin()` - `revoke_admin()` - `is_admin()` - `only_admin()` - `only_owner_or_admin()` - This library allows for multiple administrators rather than a single user. ## Notes - This library is built atop the ownership library where the owner is the only user who may add administrators.
- Loading branch information
Showing
23 changed files
with
799 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
[workspace] | ||
members = [ | ||
"admin", | ||
"fixed_point", | ||
"merkle_proof", | ||
"ownership", | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[project] | ||
authors = ["Fuel Labs <[email protected]>"] | ||
entry = "admin.sw" | ||
license = "Apache-2.0" | ||
name = "admin" | ||
|
||
[dependencies] | ||
ownership = { path = "../ownership" } | ||
src_5 = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.2.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<p align="center"> | ||
<picture> | ||
<source media="(prefers-color-scheme: dark)" srcset=".docs/admin-logo-dark-theme.png"> | ||
<img alt="SwayApps logo" width="400px" src=".docs/admin-logo-light-theme.png"> | ||
</picture> | ||
</p> | ||
|
||
# Overview | ||
|
||
The Admin library provides a way to block users without an "adimistrative status" from calling functions within a contract. Admin is often used when needing administrative calls on a contract that involve multiple users or a whitelist. | ||
|
||
This library extends the [Ownership Library](../ownership/). The Ownership library must be imported and used to enable the Admin library. Only the contract's owner may add and remove administrative users. | ||
|
||
For more information please see the [specification](./SPECIFICATION.md). | ||
|
||
# Using the Library | ||
|
||
## Getting Started | ||
|
||
In order to use the Admin 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). | ||
|
||
You may import the Admin library's functionalities like so: | ||
|
||
```sway | ||
use admin::*; | ||
``` | ||
|
||
Once imported, the Admin library's functions will be available. To use them, the contract's owner must add a user as an admin with the `add_admin()` function. There is no limit to the number of admins a contract may have. | ||
|
||
```sway | ||
#[storage(read, write)] | ||
fn add_a_admin(new_admin: Identity) { | ||
// Can only be called by the Ownership Library's Owner | ||
add_admin(new_admin); | ||
} | ||
``` | ||
|
||
## Basic Functionality | ||
|
||
To restrict a function to only an admin, call the `only_admin()` function. | ||
|
||
```sway | ||
only_admin(); | ||
// Only an admin may reach this line. | ||
``` | ||
|
||
> **NOTE:** Admins and the contract's owner are independent of one another. `only_admin()` will revert if called by the contract's owner. | ||
To restrict a function to only an admin or the contract's owner, call the `only_owner_or_admin()` function. | ||
|
||
```sway | ||
only_owner_or_admin(); | ||
// Only an admin may reach this line. | ||
``` | ||
|
||
To check the administrative privledges of a user, call the `is_admin()` function. | ||
|
||
```sway | ||
#[storage(read)] | ||
fn check_if_admin(admin: Identity) { | ||
let status = is_admin(admin); | ||
assert(status); | ||
} | ||
``` | ||
|
||
## Integrating the Admin Library into the Ownership Library | ||
|
||
To implement the Ownership library with the Admin library, be sure to set a contract owner for your contract. The following demonstrates the integration of the Ownership library with the Admin library. | ||
|
||
```sway | ||
use ownership::initialize_ownership; | ||
use admin::add_admin; | ||
#[storage(read, write)] | ||
fn my_constructor(new_owner: Identity) { | ||
initialize_ownership(new_owner); | ||
} | ||
#[storage(read, write)] | ||
fn add_a_admin(new_admin: Identity) { | ||
// Can only be called by contract's owner set in the constructor above. | ||
add_admin(new_admin); | ||
} | ||
``` | ||
|
||
For more information please see the [specification](./SPECIFICATION.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Overview | ||
|
||
This document provides an overview of the Admin library. | ||
|
||
It outlines the use cases, i.e. specification, and describes how to implement the library. | ||
|
||
## Use Cases | ||
|
||
The Admin library can be used anytime a function should be restricted to **multiple** users. | ||
|
||
## Public Functions | ||
|
||
### `only_admin()` | ||
|
||
This function will ensure that the current caller is an admin. | ||
|
||
### `only_owner_or_admin()` | ||
|
||
This function will ensure that the current caller is an admin or the contract's owner. | ||
|
||
### `is_admin()` | ||
|
||
Returns whether a user is an admin. | ||
|
||
### `add_admin()` | ||
|
||
Only callable by the current owner, this function will add a new admin. | ||
|
||
### `revoke_admin()` | ||
|
||
Only callable by the current owner, this function will remove an admin. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
library; | ||
|
||
mod errors; | ||
|
||
use errors::AdminError; | ||
use ownership::{_owner, only_owner}; | ||
use src_5::State; | ||
use std::{auth::msg_sender, storage::storage_api::clear,}; | ||
|
||
// Sets a new administrator. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `new_admin`: [Identity] - The `Identity` which is to recieve administrator status. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * When the caller is not the contract owner. | ||
/// | ||
/// # Number of Storage Accesses | ||
/// | ||
/// * Reads: `1` | ||
/// * Writes: `1` | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```sway | ||
/// use admin::{add_admin, is_admin}; | ||
/// | ||
/// fn foo(new_admin: Identity) { | ||
/// add_admin(new_admin); | ||
/// assert(is_admin(new_admin)); | ||
/// } | ||
/// ``` | ||
#[storage(read, write)] | ||
pub fn add_admin(new_admin: Identity) { | ||
only_owner(); | ||
let admin_value = match new_admin { | ||
Identity::Address(addr) => addr.value, | ||
Identity::ContractId(contr) => contr.value, | ||
}; | ||
let admin_key = StorageKey::<Identity>::new(admin_value, 0, admin_value); | ||
admin_key.write(new_admin); | ||
} | ||
|
||
// Removes an administrator. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `old_admin`: [Identity] - The `Identity` which the administrator status is to be removed. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * When the caller is not the contract owner. | ||
/// | ||
/// # Number of Storage Accesses | ||
/// | ||
/// * Reads: `1` | ||
/// * Writes: `1` | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```sway | ||
/// use admin::{revoke_admin, is_admin}; | ||
/// | ||
/// fn foo(old_admin: Identity) { | ||
/// revoke_admin(old_admin); | ||
/// assert(!is_admin(old_admin)); | ||
/// } | ||
/// ``` | ||
#[storage(read, write)] | ||
pub fn revoke_admin(old_admin: Identity) { | ||
only_owner(); | ||
let admin_value = match old_admin { | ||
Identity::Address(addr) => addr.value, | ||
Identity::ContractId(contr) => contr.value, | ||
}; | ||
let admin_key = StorageKey::<Identity>::new(admin_value, 0, admin_value); | ||
// TODO: Update to use StorageKey::clear() on next release | ||
// https://github.com/FuelLabs/sway/pull/5284 | ||
let _ = clear::<Identity>(admin_key.slot, admin_key.offset); | ||
} | ||
|
||
// Returns whether `admin` is an administrator. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `admin`: [Identity] - The `Identity` of which to check the administrator status. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [bool] - `true` if the `admin` is an administrator, otherwise `false`. | ||
/// | ||
/// # Number of Storage Accesses | ||
/// | ||
/// * Reads: `1` | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```sway | ||
/// use admin::{is_admin}; | ||
/// | ||
/// fn foo(admin: Identity) { | ||
/// assert(is_admin(admin)); | ||
/// } | ||
/// ``` | ||
#[storage(read)] | ||
pub fn is_admin(admin: Identity) -> bool { | ||
let admin_value = match admin { | ||
Identity::Address(addr) => addr.value, | ||
Identity::ContractId(contr) => contr.value, | ||
}; | ||
let admin_key = StorageKey::<Identity>::new(admin_value, 0, admin_value); | ||
match admin_key.try_read() { | ||
Some(identity) => { | ||
admin == identity | ||
}, | ||
None => { | ||
false | ||
}, | ||
} | ||
} | ||
|
||
// Ensures that the sender is an administrator. | ||
/// | ||
/// # Additional Information | ||
/// | ||
/// NOTE: Owner and administrator are independent of one another. If an Owner calls this function, it will revert. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * When the caller is not an administrator. | ||
/// | ||
/// # Number of Storage Accesses | ||
/// | ||
/// * Reads: `1` | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```sway | ||
/// use admin::{only_admin}; | ||
/// | ||
/// fn foo() { | ||
/// only_admin(); | ||
/// // Only reachable by an administrator | ||
/// } | ||
/// ``` | ||
#[storage(read)] | ||
pub fn only_admin() { | ||
require(is_admin(msg_sender().unwrap()), AdminError::NotAdmin); | ||
} | ||
|
||
// Ensures that the sender is an owner or administrator. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * When the caller is not an owner or administrator. | ||
/// | ||
/// # Number of Storage Accesses | ||
/// | ||
/// * Reads: `2` | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```sway | ||
/// use admin::{only_owner_or_admin}; | ||
/// | ||
/// fn foo() { | ||
/// only_owner_or_admin(); | ||
/// // Only reachable by an owner or administrator | ||
/// } | ||
/// ``` | ||
#[storage(read)] | ||
pub fn only_owner_or_admin() { | ||
let sender = msg_sender().unwrap(); | ||
require( | ||
_owner() == State::Initialized(sender) || is_admin(sender), | ||
AdminError::NotAdmin, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
library; | ||
|
||
/// Error log for when access is denied. | ||
pub enum AdminError { | ||
/// Emiited when the caller is not an admin. | ||
NotAdmin: (), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[project] | ||
authors = ["Fuel Labs <[email protected]>"] | ||
entry = "main.sw" | ||
license = "Apache-2.0" | ||
name = "admin_test" | ||
|
||
[dependencies] | ||
admin = { path = "../../../libs/admin" } | ||
ownership = { path = "../../../libs/ownership" } | ||
src_5 = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.2.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
mod tests; |
Oops, something went wrong.