Skip to content

Commit

Permalink
feat: remove ownable functionality (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksuss authored Sep 27, 2024
1 parent 3f6c98e commit 695486c
Show file tree
Hide file tree
Showing 8 changed files with 550 additions and 2,972 deletions.
3,406 changes: 491 additions & 2,915 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ pedantic = "deny"
[dependencies]
anyhow = "1"
hex = "0.4"
near-sdk = "5.2"
near-contract-standards = "5.2"
near-sdk = "5.5"
near-contract-standards = "5.5"
near-plugins = { git = "https://github.com/aleksuss/near-plugins.git", rev = "a1393df" }
semver = { version = "1", features = ["serde"] }
serde = { version = "1", features = ["derive"] }

[dev-dependencies]
near-sdk = { version = "5.2", features = ["unit-testing"] }
near-workspaces = "0.11"
near-sdk = { version = "5.5", features = ["unit-testing"] }
near-workspaces = "0.14"
tokio = { version = "1", features = ["macros"] }

[profile.release]
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

[![CI](https://github.com/aurora-is-near/aurora-controller-factory/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/aurora-is-near/aurora-controller-factory/actions/workflows/rust.yml)

The main purpose of the contract is to provide the possibility to move all ops-related
functions into a separate controller contract. Ops-related functions include: deployment,
upgrading, downgrading, and delegation of execution for some transactions. The controller
The main purpose of the contract is to provide the possibility to move all ops-related
functions into a separate controller contract. Ops-related functions include: deployment,
upgrading, downgrading, and delegation of execution for some transactions. The controller
contract implements role-based access control using the [near-plugins].

### Useful commands
Expand All @@ -20,7 +20,7 @@ contract implements role-based access control using the [near-plugins].
```rust
/// Initializes a new controller contract.
#[init]
fn new(owner_id: AccountId) -> Self;
fn new(dao: Option<AccountId>) -> Self;

/// Attaches new full access key to the controller contract.
#[access_control_any(roles(Role::DAO))]
Expand Down Expand Up @@ -76,7 +76,7 @@ fn upgrade(&self, contract_id: AccountId, hash: Option<String>) -> Promise;

/// Upgrades a contract with account id and provided hash without checking version.
#[access_control_any(roles(Role::DAO))]
fn unrestricted_upgrade(&self, contract_id: AccountId, hash: String) -> Promise;
fn unrestricted_upgrade(&self, contract_id: AccountId, hash: String) -> Promise;

/// Downgrades the contract with account id.
#[access_control_any(roles(Role::DAO))]
Expand Down Expand Up @@ -152,4 +152,5 @@ pub struct DeploymentInfo {
[near-plugins]: https://github.com/aurora-is-near/near-plugins

### LICENSE

**Aurora Controller Factory** is under [CC0 1.0 Universal](LICENSE)
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "1.79.0"
channel = "1.81.0"
components = ["clippy", "rustfmt"]
targets = ["wasm32-unknown-unknown"]
2 changes: 2 additions & 0 deletions src/bin/to_borsh.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// The serialization of the wasm file is needed, because the upgrade transaction
// from near-plugins is waiting for the wasm file to be serialized in `borsh`.
fn main() -> anyhow::Result<()> {
let data =
std::fs::read("target/wasm32-unknown-unknown/release/aurora_controller_factory.wasm")?;
Expand Down
21 changes: 14 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use near_plugins::{
access_control, access_control_any, AccessControlRole, AccessControllable, Ownable, Pausable,
Upgradable,
access_control, access_control_any, AccessControlRole, AccessControllable, Pausable, Upgradable,
};
use near_sdk::borsh::BorshDeserialize;
use near_sdk::collections::LazyOption;
Expand Down Expand Up @@ -59,8 +58,7 @@ pub enum Role {
}

/// Controller contract for deploying and upgrading contracts.
#[derive(Ownable, PanicOnDefault, Pausable, Upgradable)]
#[ownable]
#[derive(PanicOnDefault, Pausable, Upgradable)]
#[access_control(role_type(Role))]
#[upgradable(access_control_roles(
code_stagers(Role::DAO),
Expand Down Expand Up @@ -88,16 +86,25 @@ impl AuroraControllerFactory {
#[must_use]
#[init]
#[allow(clippy::use_self)]
pub fn new(owner_id: AccountId) -> Self {
pub fn new(dao: Option<AccountId>) -> Self {
let mut contract = Self {
releases: IterableMap::new(keys::Prefix::Releases),
blobs: IterableMap::new(keys::Prefix::Blobs),
deployments: IterableMap::new(keys::Prefix::Deployments),
latest: LazyOption::new(keys::Prefix::LatestRelease, None),
};

contract.owner_set(Some(owner_id));
contract.acl_init_super_admin(env::predecessor_account_id());
require!(
contract.acl_init_super_admin(env::current_account_id()),
"Failed to init Super Admin role"
);

// Optionally grant `Role::DAO`.
if let Some(account_id) = dao {
let res = contract.acl_grant_role(Role::DAO.into(), account_id);
require!(Some(true) == res, "Failed to grant DAO role");
}

contract
}

Expand Down
54 changes: 25 additions & 29 deletions src/tests/sdk/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use near_plugins::AccessControllable;
use near_sdk::AccountId;

use crate::types::ReleaseInfo;
Expand All @@ -9,19 +8,18 @@ mod macros;

#[test]
fn test_controller_version() {
set_env!(predecessor_account_id: owner());
let contract = AuroraControllerFactory::new(owner());
set_env!(predecessor_account_id: predecessor_account_id());
let contract = AuroraControllerFactory::new(dao());
assert_eq!(contract.version(), env!("CARGO_PKG_VERSION"));
}

#[test]
fn test_adding_blob() {
set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
input: vec![1; 256],
);
let mut contract = AuroraControllerFactory::new(owner());
assert!(contract.acl_grant_role("DAO".to_owned(), owner()).unwrap());
let mut contract = AuroraControllerFactory::new(dao());

contract.add_release_info(
"2661920f2409dd6c8adeb0c44972959f232b6429afa913845d0fd95e7e768234".to_string(),
Expand All @@ -45,7 +43,7 @@ fn test_adding_blob() {
);

set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
input: vec![2; 256],
);

Expand Down Expand Up @@ -87,23 +85,21 @@ fn test_adding_blob() {
#[should_panic = "release info doesn't exist for the hash"]
fn test_adding_blob_without_adding_hash() {
set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
input: vec![1; 256],
);

let mut contract = AuroraControllerFactory::new(owner());
assert!(contract.acl_grant_role("DAO".to_owned(), owner()).unwrap());
let mut contract = AuroraControllerFactory::new(dao());
contract.add_release_blob();
}

#[test]
fn test_check_latest_release() {
set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
input: vec![1; 256],
);
let mut contract = AuroraControllerFactory::new(owner());
assert!(contract.acl_grant_role("DAO".to_owned(), owner()).unwrap());
let mut contract = AuroraControllerFactory::new(dao());

contract.add_release_info(
"2661920f2409dd6c8adeb0c44972959f232b6429afa913845d0fd95e7e768234".to_string(),
Expand All @@ -123,7 +119,7 @@ fn test_check_latest_release() {
assert_eq!(latest_blob, vec![1; 256]);

set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
input: vec![2; 256],
);

Expand All @@ -148,27 +144,26 @@ fn test_check_latest_release() {
#[test]
#[should_panic = "the latest release hash hasn't been set yet"]
fn test_check_latest_release_hash_without_adding() {
set_env!(predecessor_account_id: owner());
let contract = AuroraControllerFactory::new(owner());
set_env!(predecessor_account_id: predecessor_account_id());
let contract = AuroraControllerFactory::new(dao());
let _ = contract.get_latest_release_hash();
}

#[test]
#[should_panic = "the latest release hash hasn't been set yet"]
fn test_check_latest_release_blob_without_adding() {
set_env!(predecessor_account_id: owner());
let contract = AuroraControllerFactory::new(owner());
set_env!(predecessor_account_id: predecessor_account_id());
let contract = AuroraControllerFactory::new(dao());
let _ = contract.get_latest_release_blob();
}

#[test]
#[should_panic = "version of new latest should be higher than previous"]
fn test_set_latest_with_lower_version() {
set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
);
let mut contract = AuroraControllerFactory::new(owner());
assert!(contract.acl_grant_role("DAO".to_owned(), owner()).unwrap());
let mut contract = AuroraControllerFactory::new(dao());

contract.add_release_info(
"2661920f2409dd6c8adeb0c44972959f232b6429afa913845d0fd95e7e768234".to_string(),
Expand All @@ -194,11 +189,10 @@ fn test_set_latest_with_lower_version() {
#[should_panic = "version of new latest should be higher than previous"]
fn test_add_latest_with_lower_version() {
set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
);

let mut contract = AuroraControllerFactory::new(owner());
assert!(contract.acl_grant_role("DAO".to_owned(), owner()).unwrap());
let mut contract = AuroraControllerFactory::new(dao());

contract.add_release_info(
"f5c22e35d04167e37913e7963ce033b1f3d17a924a4e6fe5fc95af1224051921".to_string(),
Expand All @@ -221,16 +215,18 @@ fn test_add_latest_with_lower_version() {
#[should_panic = "pause method: some_pause_method is not allowed"]
fn test_use_not_allowed_pause_method() {
set_env!(
predecessor_account_id: owner(),
predecessor_account_id: predecessor_account_id(),
);

let mut contract = AuroraControllerFactory::new(owner());
assert!(contract.acl_grant_role("DAO".to_owned(), owner()).unwrap());

let contract = AuroraControllerFactory::new(dao());
contract.delegate_pause(new_engine(), Some("some_pause_method".to_string()));
}

fn owner() -> AccountId {
fn dao() -> Option<AccountId> {
"alice.near".parse().ok()
}

fn predecessor_account_id() -> AccountId {
"alice.near".parse().unwrap()
}

Expand Down
18 changes: 7 additions & 11 deletions src/tests/workspace/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,24 @@ pub const INITIAL_BALANCE: NearToken = NearToken::from_near(200);

pub async fn crate_factory() -> anyhow::Result<(Account, Contract, Worker<Sandbox>)> {
let worker = near_workspaces::sandbox().await?;
let root = worker.root_account().unwrap();
let root = worker.root_account()?;
let factory_owner = root
.create_subaccount(FACTORY_OWNER)
.initial_balance(INITIAL_BALANCE)
.transact()
.await
.unwrap()
.into_result()
.unwrap();
.await?
.into_result()?;

let wasm = std::fs::read(AURORA_FACTORY_CONTRACT_PATH)?;
let contract = factory_owner.deploy(&wasm).await?.result;

let result = factory_owner
.call(factory_owner.id(), "new")
.args_json(json!({"owner_id": factory_owner.id()}))
.args_json(json!({"dao": factory_owner.id()}))
.transact()
.await
.unwrap();
assert!(result.is_success());
.await?;
assert!(result.is_success(), "{result:#?}");

grant_role(&contract, &factory_owner, factory_owner.id(), Role::DAO).await;
grant_role(&contract, &factory_owner, factory_owner.id(), Role::Updater).await;

Ok((factory_owner, contract, worker))
Expand All @@ -54,5 +50,5 @@ pub async fn grant_role(
.transact()
.await
.unwrap();
assert!(result.is_success());
assert!(result.is_success(), "{result:#?}");
}

0 comments on commit 695486c

Please sign in to comment.