Skip to content

Commit e481c7f

Browse files
authored
Merge pull request #192 from mijinummi/security/138-access-controls-sensitive-functions
Security/138 access controls sensitive functions
2 parents 267eda3 + 78923a9 commit e481c7f

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-0
lines changed

contracts/access_control/Cargo.toml

Whitespace-only changes.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
3+
#[ink::contract]
4+
mod access_control {
5+
use ink::storage::Mapping;
6+
7+
#[derive(scale::Encode, scale::Decode, Clone, Debug, PartialEq, Eq)]
8+
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
9+
pub enum Role {
10+
Admin,
11+
Governor,
12+
Emergency,
13+
}
14+
15+
#[ink(storage)]
16+
pub struct AccessControl {
17+
roles: Mapping<AccountId, Role>,
18+
}
19+
20+
impl AccessControl {
21+
#[ink(constructor)]
22+
pub fn new(admin: AccountId) -> Self {
23+
let mut roles = Mapping::default();
24+
roles.insert(admin, &Role::Admin);
25+
Self { roles }
26+
}
27+
28+
#[ink(message)]
29+
pub fn assign_role(&mut self, account: AccountId, role: Role) {
30+
let caller = self.env().caller();
31+
let caller_role = self.roles.get(caller).unwrap_or(Role::Governor);
32+
assert!(caller_role == Role::Admin, "Only Admin can assign roles");
33+
self.roles.insert(account, &role);
34+
}
35+
36+
#[ink(message)]
37+
pub fn get_role(&self, account: AccountId) -> Option<Role> {
38+
self.roles.get(account)
39+
}
40+
41+
pub fn ensure_role(&self, account: AccountId, required: Role) {
42+
let role = self.roles.get(account).expect("No role assigned");
43+
assert!(role == required, "Access denied");
44+
}
45+
}
46+
}

contracts/emergency/Cargo.toml

Whitespace-only changes.

contracts/emergency/src/lib.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
3+
#[ink::contract]
4+
mod emergency {
5+
use ink::storage::Mapping;
6+
7+
#[ink(storage)]
8+
pub struct EmergencyControl {
9+
approvals: Mapping<AccountId, bool>,
10+
required_signatures: u8,
11+
paused: bool,
12+
}
13+
14+
impl EmergencyControl {
15+
#[ink(constructor)]
16+
pub fn new(required_signatures: u8) -> Self {
17+
Self {
18+
approvals: Mapping::default(),
19+
required_signatures,
20+
paused: false,
21+
}
22+
}
23+
24+
#[ink(message)]
25+
pub fn approve_pause(&mut self) {
26+
let caller = self.env().caller();
27+
self.approvals.insert(caller, &true);
28+
}
29+
30+
#[ink(message)]
31+
pub fn execute_pause(&mut self) {
32+
let mut count = 0;
33+
for (account, approved) in self.approvals.iter() {
34+
if approved {
35+
count += 1;
36+
}
37+
}
38+
assert!(count >= self.required_signatures, "Not enough approvals");
39+
self.paused = true;
40+
}
41+
42+
#[ink(message)]
43+
pub fn is_paused(&self) -> bool {
44+
self.paused
45+
}
46+
}
47+
}

contracts/governance/src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
3+
#[ink::contract]
4+
mod governance {
5+
use ink::storage::Mapping;
6+
7+
#[ink(storage)]
8+
pub struct Governance {
9+
pending_actions: Mapping<u32, (AccountId, u64)>, // actionId → (initiator, timestamp)
10+
delay: u64,
11+
}
12+
13+
impl Governance {
14+
#[ink(constructor)]
15+
pub fn new(delay: u64) -> Self {
16+
Self {
17+
pending_actions: Mapping::default(),
18+
delay,
19+
}
20+
}
21+
22+
#[ink(message)]
23+
pub fn propose_action(&mut self, action_id: u32) {
24+
let caller = self.env().caller();
25+
let now = self.env().block_timestamp();
26+
self.pending_actions.insert(action_id, &(caller, now));
27+
}
28+
29+
#[ink(message)]
30+
pub fn execute_action(&mut self, action_id: u32) {
31+
if let Some((initiator, timestamp)) = self.pending_actions.get(action_id) {
32+
let now = self.env().block_timestamp();
33+
assert!(now >= timestamp + self.delay, "Action delay not met");
34+
// Execute governance action here
35+
self.pending_actions.remove(action_id);
36+
}
37+
}
38+
}
39+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[test]
2+
fn test_admin_can_assign_roles() {
3+
let mut ac = AccessControl::new(admin);
4+
ac.assign_role(user, Role::Governor);
5+
assert_eq!(ac.get_role(user), Some(Role::Governor));
6+
}
7+
8+
#[test]
9+
#[should_panic(expected = "Access denied")]
10+
fn test_non_admin_cannot_assign_roles() {
11+
let mut ac = AccessControl::new(admin);
12+
ac.assign_role(user, Role::Governor); // should fail if caller != admin
13+
}

0 commit comments

Comments
 (0)