Skip to main content

casper_contract_sdk/contrib/
ownable.rs

1//! This module provides an implementation of the Ownable pattern for smart contracts.
2//!
3//! The Ownable pattern is a common design pattern in smart contracts that allows for
4//! a single owner to control the contract. This module provides a simple implementation
5//! of this pattern, allowing for ownership to be transferred or renounced.
6use borsh::{BorshDeserialize, BorshSerialize};
7use casper_contract_macros::CasperABI;
8
9#[allow(unused_imports)]
10use crate as casper_contract_sdk;
11use crate::{casper::Entity, macros::casper};
12
13/// The state of the Ownable contract, which contains the owner of the contract.
14#[casper(path = crate)]
15pub struct OwnableState {
16    owner: Option<Entity>,
17}
18
19impl Default for OwnableState {
20    fn default() -> Self {
21        Self {
22            owner: Some(crate::casper::get_caller()),
23        }
24    }
25}
26
27/// Represents the possible errors that can occur during ownership operations.
28#[derive(CasperABI, BorshSerialize, BorshDeserialize)]
29#[casper(path = crate)]
30pub enum OwnableError {
31    /// The caller is not authorized to perform the action.
32    NotAuthorized,
33}
34
35/// The Ownable trait provides a simple ownership model for smart contracts.
36/// It allows for a single owner to be set, and provides functions to transfer or renounce
37/// ownership.
38#[casper(path = crate, export = true)]
39pub trait Ownable {
40    #[casper(private)]
41    fn state(&self) -> &OwnableState;
42    #[casper(private)]
43    fn state_mut(&mut self) -> &mut OwnableState;
44
45    /// Checks if the caller is the owner of the contract.
46    ///
47    /// This function is used to restrict access to certain functions to only the owner.
48    #[casper(private)]
49    fn only_owner(&self) -> Result<(), OwnableError> {
50        let caller = crate::casper::get_caller();
51        match self.state().owner {
52            Some(owner) if caller != owner => {
53                return Err(OwnableError::NotAuthorized);
54            }
55            None => {
56                return Err(OwnableError::NotAuthorized);
57            }
58            Some(_owner) => {}
59        }
60        Ok(())
61    }
62
63    /// Transfers ownership of the contract to a new owner.
64    #[casper(revert_on_error)]
65    fn transfer_ownership(&mut self, new_owner: Entity) -> Result<(), OwnableError> {
66        self.only_owner()?;
67        self.state_mut().owner = Some(new_owner);
68        Ok(())
69    }
70
71    /// Returns the current owner of the contract.
72    fn owner(&self) -> Option<Entity> {
73        self.state().owner
74    }
75
76    /// Renounces ownership of the contract, making it no longer owned by any entity.
77    ///
78    /// This function can only be called by the current owner of the contract
79    /// once the contract is deployed. After calling this function, the contract
80    /// will no longer have an owner, and no entity will be able to call
81    /// functions that require ownership.
82    #[casper(revert_on_error)]
83    fn renounce_ownership(&mut self) -> Result<(), OwnableError> {
84        self.only_owner()?;
85        self.state_mut().owner = None;
86        Ok(())
87    }
88}