#near #ownable #multisig

no-std multi-ownable

NEAR plugin for sharing ownership of a contract between multiple accounts

3 releases

0.1.2 Jan 22, 2022
0.1.1 Jan 22, 2022
0.1.0 Jan 22, 2022

#8 in #ownable

MIT license

14KB
157 lines

multi-ownable

A NEAR plugin enables multiple Accounts to share ownership of a contract. Calls are stored in hashed form, so storage requirements are very low.

test

cargo test -- --nocapture

usage

multi-ownable can be addeded to your contract via a macro:

// Arguments:
// 1. name of your contract
// 2. name of the field where the multi ownable state is stored
// 3. enum type for possible multisig calls
// 4. callback function to process completed multisig calls
crate::impl_multi_ownable!(Contract, multi_ownable, MultiOwnableCall, on_call);

Here is a full working example of how to use multi-ownable

// import "impl_multi_ownable" and "MultiOwnableData"
use multi_ownable::{impl_multi_ownable, MultiOwnableData};
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::{env, near_bindgen, require, AccountId, BorshStorageKey, PanicOnDefault};

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
  multi_ownable: MultiOwnableData, // add this to the Contract
  number: u64,
}
#[derive(BorshSerialize, BorshStorageKey)]
enum StorageKey {
  Owners,
  MultiOwnableCalls,
}

#[near_bindgen]
impl Contract {
  #[init]
  pub fn new(owner_id: AccountId) -> Self {
    let mut this = Self {
      number: 0,
      multi_ownable: MultiOwnableData::new(StorageKey::Owners, StorageKey::MultiOwnableCalls),
    };
    // initialize multi_ownable in the "new" func of your Contract
    this.init_multi_ownable(vec![owner_id.clone()], 1);
    this
  }

  pub fn get_number(&self) -> u64 {
    self.number
  }

  // arguments are received as a json string
  fn on_call(&mut self, call_name: MultiOwnableCall, arguments: &str) {
    match call_name {
      MultiOwnableCall::UpdateNumber => self._update_number(arguments),
      MultiOwnableCall::DoSomethingElse => self._do_something_else(arguments),
    }
  }

  #[private]
  fn _update_number(&mut self, args: &str) {
    // first, deserialize your arguments
    let UpdateNumberArgs { number } =
      near_sdk::serde_json::from_str(&args).expect("Invalid SetRewardRateArgs");
    self.number = number;
  }

  #[private]
  fn _do_something_else(&self, _args: &str) {
    // do something else
  }
}

// an argument struct for "update_number" call
#[derive(Serialize, Deserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct UpdateNumberArgs {
  pub number: u64,
}

// create an enum to match possible multisig calls
// make sure to both "rename" and "alias" your fields to be snake_case
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub enum MultiOwnableCall {
  #[serde(rename = "update_number", alias = "update_number")]
  UpdateNumber,
  #[serde(rename = "do_something_else", alias = "do_something_else")]
  DoSomethingElse,
}

crate::impl_multi_ownable!(Contract, multi_ownable, MultiOwnableCall, on_call);

Dependencies

~6MB
~118K SLoC