Skip to main content

defuse/contract/
mod.rs

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