Icon HelpCircleForumIcon Link

⌘K

Icon HelpCircleForumIcon Link
Src 5 Ownership

Icon LinkSRC-5: Ownership

The following standard intends to enable the use of administrators or owners in Sway contracts.

Icon LinkMotivation

The standard seeks to provide a method for restricting access to particular users within a Sway contract.

Icon LinkPrior Art

The sway-libs Icon Link repository contains a pre-existing Ownership library.

Ownership libraries exist for other ecosystems such as OpenZeppelin's Ownership library Icon Link.

Icon LinkSpecification

Icon LinkState

There SHALL be 3 states for any library implementing an ownership module in the following order:

Icon LinkUninitialized

The Uninitialized state SHALL be set as the initial state if no owner or admin is set. The Uninitialized state MUST be used when an owner or admin MAY be set in the future.

Icon LinkInitialized

The Initialized state SHALL be set as the state if an owner or admin is set with an associated Identity type.

Icon LinkRevoked

The Revoked state SHALL be set when there is no owner or admin and there SHALL NOT be one set in the future.

Example:

pub enum State {
    Uninitialized: (),
    Initialized: Identity,
    Revoked: (),
}

Icon LinkFunctions

The following functions MUST be implemented to follow the SRC-5 standard:

Icon Linkfn owner() -> State

This function SHALL return the current state of ownership for the contract where State is either Uninitialized, Initialized, or Revoked.

Icon LinkErrors

There SHALL be error handling.

Icon LinkNotOwner

This error MUST be emitted when only_owner() reverts.

Icon LinkRationale

In order to provide a universal method of administrative capabilities, SRC-5 will further enable interoperability between applications and provide safeguards for smart contract security.

Icon LinkBackwards Compatibility

The SRC-5 standard is compatible with the sway-libs Icon Link repository pre-existing Ownership library. Considerations should be made to best handle multiple owners or admins.

There are no standards that SRC-5 requires to be compatible with.

Icon LinkSecurity Considerations

The SRC-5 standard should help improve the security of Sway contracts and their interoperability.

Icon LinkExample ABI

abi SRC5 {
    #[storage(read)]
    fn owner() -> State;
}

Icon LinkExample Implementation

Icon LinkUninitialized

Example of the SRC-5 implementation where a contract does not have an owner set at compile time with the intent to set it during runtime.

contract;
 
use standards::src5::{SRC5, State};
 
storage {
    /// The owner in storage.
    owner: State = State::Uninitialized,
}
 
impl SRC5 for Contract {
    /// Returns the owner.
    ///
    /// # Return Values
    ///
    /// * [State] - Represents the state of ownership for this contract.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `1`
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src5::SRC5;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let ownership_abi = abi(contract_id, SRC_5);
    ///
    ///     match ownership_abi.owner() {
    ///         State::Uninitialized => log("The ownership is uninitialized"),
    ///         _ => log("This example will never reach this statement"),
    ///     }
    /// }
    /// ```
    #[storage(read)]
    fn owner() -> State {
        storage.owner.read()
    }
}
 

Icon LinkInitialized

Example of the SRC-5 implementation where a contract has an owner set at compile time.

contract;
 
use standards::src5::{SRC5, State};
 
/// The owner of this contract at deployment.
#[allow(dead_code)]
const INITIAL_OWNER: Identity = Identity::Address(Address::zero());
 
storage {
    /// The owner in storage.
    owner: State = State::Initialized(INITIAL_OWNER),
}
 
impl SRC5 for Contract {
    /// Returns the owner.
    ///
    /// # Return Values
    ///
    /// * [State] - Represents the state of ownership for this contract.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `1`
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src5::SRC5;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let ownership_abi = abi(contract_id, SRC_5);
    ///
    ///     match ownership_abi.owner() {
    ///         State::Initialized(owner) => log("The ownership is initialized"),
    ///         _ => log("This example will never reach this statement"),
    ///     }
    /// }
    /// ```
    #[storage(read)]
    fn owner() -> State {
        storage.owner.read()
    }
}