The Ownership Library provides a straightforward way to restrict specific calls in a Sway contract to a single owner. Its design follows the SRC-5 standard from Sway Standards and offers a set of functions to initialize, verify, revoke, and transfer ownership.
For implementation details, visit the Sway Libs Docs .
In order to use the Ownership Library, the Ownership Library and the SRC-5 Standard must be added to your Forc.toml file and then imported into your Sway project.
To add the Ownership Library and the SRC-5 Standard as a dependency to your Forc.toml file in your project, use the forc add command.
forc add [email protected]
forc add [email protected]NOTE: Be sure to set the version to the latest release.
To import the Ownership Library and SRC-5 Standard to your Sway Smart Contract, add the following to your Sway file:
use ownership::*;
use src5::*; When integrating the Ownership Library with SRC-5 , ensure that the SRC5 trait from Sway Standards is implemented in your contract, as shown below. The _owner() function from this library is used to fulfill the SRC-5 requirement of exposing the ownership state.
use ownership::_owner;
use src5::{SRC5, State};
impl SRC5 for Contract {
#[storage(read)]
fn owner() -> State {
_owner()
}
} Establishes the initial ownership state by calling initialize_ownership(new_owner). This can only be done once, typically in your contract's constructor.
#[storage(read, write)]
fn my_constructor(new_owner: Identity) {
initialize_ownership(new_owner);
} Please note that the example above does not apply any restrictions on who may call the initialize() function. This leaves the opportunity for a bad actor to front-run your contract and claim ownership for themselves. To ensure the intended Identity is set as the contract owner upon contract deployment, use a configurable where the INITIAL_OWNER is the intended owner of the contract.
configurable {
INITAL_OWNER: Identity = Identity::Address(Address::zero()),
}
impl MyContract for Contract {
#[storage(read, write)]
fn initialize() {
initialize_ownership(INITAL_OWNER);
}
} Protect functions so only the owner can call them by invoking only_owner() at the start of those functions.
#[storage(read)]
fn only_owner_may_call() {
only_owner();
// Only the contract's owner may reach this line.
} To retrieve the current ownership state, call _owner().
#[storage(read)]
fn get_owner_state() {
let owner: State = _owner();
} To transfer ownership from the current owner to a new owner, call transfer_ownership(new_owner).
#[storage(read, write)]
fn transfer_contract_ownership(new_owner: Identity) {
// The caller must be the current owner.
transfer_ownership(new_owner);
} To revoke ownership entirely and disallow the assignment of a new owner, call renounce_ownership().
#[storage(read, write)]
fn renounce_contract_owner() {
// The caller must be the current owner.
renounce_ownership();
// Now no one owns the contract.
}OwnershipRenounced Emitted when ownership is revoked.
previous_owner: Identity of the owner prior to revocation. OwnershipSet Emitted when initial ownership is set.
new_owner: Identity of the newly set owner. OwnershipTransferred Emitted when ownership is transferred from one owner to another.
new_owner: Identity of the new owner. previous_owner: Identity of the prior owner. InitializationError CannotReinitialized: Thrown when attempting to initialize ownership if the owner is already set. AccessError NotOwner: Thrown when a function restricted to the owner is called by a non-owner. Below is a example illustrating how to use this library within a Sway contract:
contract;
use ownership::{_owner, initialize_ownership, only_owner, renounce_ownership, transfer_ownership};
use src5::{SRC5, State};
configurable {
INITAL_OWNER: Identity = Identity::Address(Address::zero()),
}
impl SRC5 for Contract {
#[storage(read)]
fn owner() -> State {
_owner()
}
}
abi MyContract {
#[storage(read, write)]
fn initialize();
#[storage(read)]
fn restricted_action();
#[storage(read, write)]
fn change_owner(new_owner: Identity);
#[storage(read, write)]
fn revoke_ownership();
#[storage(read)]
fn get_current_owner() -> State;
}
impl MyContract for Contract {
#[storage(read, write)]
fn initialize() {
initialize_ownership(INITAL_OWNER);
}
// A function restricted to the owner
#[storage(read)]
fn restricted_action() {
only_owner();
// Protected action
}
// Transfer ownership
#[storage(read, write)]
fn change_owner(new_owner: Identity) {
transfer_ownership(new_owner);
}
// Renounce ownership
#[storage(read, write)]
fn revoke_ownership() {
renounce_ownership();
}
// Get current owner state
#[storage(read)]
fn get_current_owner() -> State {
_owner()
}
}constructor(new_owner) once to set the initial owner. only_owner() to guard any owner-specific functions. _owner(). transfer_ownership(new_owner) or renounce_ownership() for ownership modifications.