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