1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! # 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:
//!
//! ```rust
//! // 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`
//!
//! ```rust
//! // 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);
//!
//! ```
pub mod macros;
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::{UnorderedMap, UnorderedSet};
use near_sdk::{AccountId, IntoStorageKey};
pub use sha2;
#[derive(BorshDeserialize, BorshSerialize)]
pub struct MultiOwnableData {
pub owners: UnorderedSet<AccountId>,
pub threshold: u32,
pub calls: UnorderedMap<Vec<u8>, Vec<AccountId>>,
}
impl MultiOwnableData {
pub fn new<S, T>(owners_key: S, calls_key: T) -> Self
where
S: IntoStorageKey,
T: IntoStorageKey,
{
Self {
threshold: 0,
owners: UnorderedSet::new(owners_key),
calls: UnorderedMap::new(calls_key),
}
}
}