Skip to main content

defuse/contract/
mod.rs

1#[cfg(feature = "abi")]
2mod abi;
3mod accounts;
4mod admin;
5pub mod config;
6mod events;
7mod fees;
8mod garbage_collector;
9mod intents;
10mod prefix;
11mod salts;
12mod state;
13mod tokens;
14mod upgrade;
15mod versioned;
16
17use core::iter;
18
19use borsh::{BorshDeserialize, BorshSerialize};
20use defuse_borsh_utils::As;
21use defuse_core::Result;
22use impl_tools::autoimpl;
23use near_plugins::{AccessControlRole, AccessControllable, Pausable, access_control};
24use near_sdk::{BorshStorageKey, IntoStorageKey, PanicOnDefault, near, require, store::LookupSet};
25use serde::{Deserialize, Serialize};
26use versioned::MaybeVersionedContractStorage;
27
28use crate::{Defuse, contract::events::PostponedMtBurnEvents};
29
30use self::{
31    accounts::Accounts,
32    config::{DefuseConfig, RolesConfig},
33    state::ContractState,
34};
35
36#[cfg_attr(feature = "abi", derive(::schemars::JsonSchema))]
37#[derive(
38    Debug,
39    Clone,
40    Copy,
41    PartialEq,
42    Eq,
43    PartialOrd,
44    Ord,
45    Hash,
46    Serialize,
47    Deserialize,
48    AccessControlRole,
49)]
50pub enum Role {
51    DAO,
52
53    FeesManager,
54    RelayerKeysManager,
55
56    UnrestrictedWithdrawer,
57
58    PauseManager,
59    Upgrader,
60    UnpauseManager,
61
62    UnrestrictedAccountLocker,
63    UnrestrictedAccountUnlocker,
64
65    SaltManager,
66
67    GarbageCollector,
68
69    UnrestrictedAccountManager,
70}
71
72#[access_control(role_type(Role))]
73#[derive(Pausable, PanicOnDefault)]
74#[pausable(
75    pause_roles(Role::DAO, Role::PauseManager),
76    unpause_roles(Role::DAO, Role::UnpauseManager)
77)]
78#[near(
79    contract_state,
80    contract_metadata(
81        standard(standard = "dip4", version = "0.1.0"),
82        standard(standard = "nep245", version = "1.0.0"),
83    )
84)]
85#[autoimpl(Deref using self.storage)]
86#[autoimpl(DerefMut using self.storage)]
87pub struct Contract {
88    #[borsh(
89        deserialize_with = "As::<MaybeVersionedContractStorage>::deserialize",
90        serialize_with = "As::<MaybeVersionedContractStorage>::serialize"
91    )]
92    storage: ContractStorage,
93
94    #[borsh(skip)]
95    runtime: Runtime,
96}
97
98#[autoimpl(Deref using self.state)]
99#[autoimpl(DerefMut using self.state)]
100#[cfg_attr(feature = "abi", derive(::borsh::BorshSchema))]
101#[derive(Debug, BorshSerialize, BorshDeserialize)]
102pub struct ContractStorage {
103    accounts: Accounts,
104
105    state: ContractState,
106
107    relayer_keys: LookupSet<near_sdk::PublicKey>,
108}
109
110#[derive(Debug, Default)]
111pub struct Runtime {
112    pub postponed_burns: PostponedMtBurnEvents,
113}
114
115#[near]
116impl Contract {
117    #[must_use]
118    #[init]
119    #[allow(clippy::use_self)] // Clippy seems to not play well with near-sdk, or there is a bug in clippy - seen in shared security analysis
120    pub fn new(config: DefuseConfig) -> Self {
121        let mut contract = Self {
122            storage: ContractStorage {
123                accounts: Accounts::new(Prefix::Accounts),
124                state: ContractState::new(Prefix::State, config.wnear_id, config.fees),
125                relayer_keys: LookupSet::new(Prefix::RelayerKeys),
126            },
127            runtime: Runtime::default(),
128        };
129        contract.init_acl(config.roles);
130        contract
131    }
132
133    fn init_acl(&mut self, roles: RolesConfig) {
134        let mut acl = self.acl_get_or_init();
135        require!(
136            roles
137                .super_admins
138                .into_iter()
139                .all(|super_admin| acl.add_super_admin_unchecked(&super_admin))
140                && roles
141                    .admins
142                    .into_iter()
143                    .flat_map(|(role, admins)| iter::repeat(role).zip(admins))
144                    .all(|(role, admin)| acl.add_admin_unchecked(role, &admin))
145                && roles
146                    .grantees
147                    .into_iter()
148                    .flat_map(|(role, grantees)| iter::repeat(role).zip(grantees))
149                    .all(|(role, grantee)| acl.grant_role_unchecked(role, &grantee)),
150            "failed to set roles"
151        );
152    }
153}
154
155#[near]
156impl Defuse for Contract {}
157
158#[cfg_attr(feature = "abi", derive(::borsh::BorshSchema))]
159#[derive(BorshSerialize, BorshDeserialize, BorshStorageKey)]
160enum Prefix {
161    Accounts,
162    State,
163    RelayerKeys,
164}
165
166pub trait MigrateStorageWithPrefix<T>: Sized {
167    fn migrate<S>(val: T, prefix: S) -> Self
168    where
169        S: IntoStorageKey;
170}