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
//! # 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);
//!
//! ```
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),
}
}
}