Skip to content

Commit

Permalink
EthConnector: make AdminControlled and pausable (#88)
Browse files Browse the repository at this point in the history
* EthConnector: make AdminControlled and pausable.

* EthConnector: add AdminControlled&pausability tests.

* Stylystic fixes.

* AdminControlled: add panic message when paused.

* AdminControlled: minor refactoring.

* AdminControlled: add errors. Naming improvements.

* AdminControlled: doc improvements.

* Test fixes.

* Fix fmt

* AdminControlled: make IO in main contract module.

* AdminControlled:explicitly check panic msg in tests.
  • Loading branch information
sept-en committed May 27, 2021
1 parent edc8e1d commit 92f877d
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 19 deletions.
28 changes: 28 additions & 0 deletions src/admin_controlled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::sdk;

pub type PausedMask = u8;

pub trait AdminControlled {
/// Returns true if the current account is owner
fn is_owner(&self) -> bool {
sdk::current_account_id() == sdk::predecessor_account_id()
}

/// Return the current mask representing all paused events.
fn get_paused(&self) -> PausedMask;

/// Update mask with all paused events.
/// Implementor is responsible for guaranteeing that this function can only be
/// called by owner of the contract.
fn set_paused(&mut self, paused: PausedMask);

/// Return if the contract is paused for the current flag and user
fn is_paused(&self, flag: PausedMask) -> bool {
(self.get_paused() & flag) != 0 && !self.is_owner()
}

/// Asserts the passed paused flag is not set. Panics with "ERR_PAUSED" if the flag is set.
fn assert_not_paused(&self, flag: PausedMask) {
assert!(!self.is_paused(flag), "ERR_PAUSED");
}
}
44 changes: 43 additions & 1 deletion src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::parameters::*;
use crate::sdk;
use crate::types::*;

use crate::admin_controlled::{AdminControlled, PausedMask};
use crate::deposit_event::*;
use crate::engine::Engine;
use crate::json::parse_json;
Expand All @@ -18,10 +19,15 @@ const GAS_FOR_FINISH_DEPOSIT: Gas = 50_000_000_000_000;
// Note: Is 40Tgas always enough?
const GAS_FOR_VERIFY_LOG_ENTRY: Gas = 40_000_000_000_000;

const UNPAUSE_ALL: PausedMask = 0;
const PAUSE_DEPOSIT: PausedMask = 1 << 0;
const PAUSE_WITHDRAW: PausedMask = 1 << 1;

#[derive(BorshSerialize, BorshDeserialize)]
pub struct EthConnectorContract {
contract: EthConnector,
ft: FungibleToken,
paused_mask: PausedMask,
}

/// eth-connector specific data
Expand Down Expand Up @@ -51,6 +57,7 @@ impl EthConnectorContract {
Self {
contract: Self::get_contract_data(&EthConnectorStorageId::Contract),
ft: Self::get_contract_data(&EthConnectorStorageId::FungibleToken),
paused_mask: Self::get_contract_data(&EthConnectorStorageId::PausedMask),
}
}

Expand Down Expand Up @@ -84,14 +91,21 @@ impl EthConnectorContract {
prover_account: args.prover_account,
eth_custodian_address: validate_eth_address(args.eth_custodian_address),
};
// Save th-connector specific data
// Save eth-connector specific data
sdk::save_contract(
&Self::get_contract_key(&EthConnectorStorageId::Contract),
&contract_data,
);

let paused_mask = UNPAUSE_ALL;
sdk::save_contract(
&Self::get_contract_key(&EthConnectorStorageId::PausedMask),
&paused_mask,
);
Self {
contract: contract_data,
ft,
paused_mask,
}
.save_ft_contract();
}
Expand Down Expand Up @@ -153,6 +167,8 @@ impl EthConnectorContract {

/// Deposit all types of tokens
pub fn deposit(&self) {
self.assert_not_paused(PAUSE_DEPOSIT);

use crate::prover::Proof;
#[cfg(feature = "log")]
sdk::log("[Deposit tokens]");
Expand Down Expand Up @@ -381,6 +397,8 @@ impl EthConnectorContract {
/// Withdraw from NEAR accounts
/// NOTE: it should be without any log data
pub fn withdraw_near(&mut self) {
self.assert_not_paused(PAUSE_WITHDRAW);

sdk::assert_one_yocto();
let args = WithdrawCallArgs::try_from_slice(&sdk::read_input()).expect(ERR_FAILED_PARSE);
let res = WithdrawResult {
Expand Down Expand Up @@ -612,4 +630,28 @@ impl EthConnectorContract {
fn check_used_event(&self, key: &str) -> bool {
sdk::storage_has_key(&self.used_event_key(key))
}

/// Get Eth connector paused flags
pub fn get_paused_flags(&self) -> PausedMask {
self.get_paused()
}

/// Set Eth connector paused flags
pub fn set_paused_flags(&mut self, args: PauseEthConnectorCallArgs) {
self.set_paused(args.paused_mask);
}
}

impl AdminControlled for EthConnectorContract {
fn get_paused(&self) -> PausedMask {
self.paused_mask
}

fn set_paused(&mut self, paused_mask: PausedMask) {
self.paused_mask = paused_mask;
sdk::save_contract(
&Self::get_contract_key(&EthConnectorStorageId::PausedMask),
&self.paused_mask,
);
}
}
22 changes: 20 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub mod storage;
pub mod transaction;
pub mod types;

#[cfg(feature = "contract")]
mod admin_controlled;
#[cfg(feature = "contract")]
mod connector;
#[cfg(feature = "contract")]
Expand Down Expand Up @@ -50,8 +52,8 @@ mod contract {
#[cfg(feature = "evm_bully")]
use crate::parameters::{BeginBlockArgs, BeginChainArgs};
use crate::parameters::{
ExpectUtf8, FunctionCallArgs, GetStorageAtArgs, NewCallArgs, TransferCallCallArgs,
ViewCallArgs,
ExpectUtf8, FunctionCallArgs, GetStorageAtArgs, NewCallArgs, PauseEthConnectorCallArgs,
TransferCallCallArgs, ViewCallArgs,
};
use crate::prelude::{Address, TryInto, H256, U256};
use crate::sdk;
Expand Down Expand Up @@ -447,6 +449,22 @@ mod contract {
EthConnectorContract::get_instance().ft_on_transfer(&engine)
}

#[no_mangle]
pub extern "C" fn get_paused_flags() {
let paused_flags = EthConnectorContract::get_instance().get_paused_flags();
let data = paused_flags.try_to_vec().expect(ERR_FAILED_PARSE);
sdk::return_output(&data[..]);
}

#[no_mangle]
pub extern "C" fn set_paused_flags() {
sdk::assert_private_call();

let args =
PauseEthConnectorCallArgs::try_from_slice(&sdk::read_input()).expect(ERR_FAILED_PARSE);
EthConnectorContract::get_instance().set_paused_flags(args);
}

#[no_mangle]
pub extern "C" fn get_accounts_counter() {
EthConnectorContract::get_instance().get_accounts_counter()
Expand Down
8 changes: 8 additions & 0 deletions src/parameters.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use borsh::{BorshDeserialize, BorshSerialize};

#[cfg(feature = "contract")]
use crate::admin_controlled::PausedMask;
#[cfg(feature = "contract")]
use crate::json;
#[cfg(feature = "contract")]
Expand Down Expand Up @@ -375,6 +377,12 @@ pub struct RegisterRelayerCallArgs {
pub address: EthAddress,
}

#[cfg(feature = "contract")]
#[derive(BorshSerialize, BorshDeserialize)]
pub struct PauseEthConnectorCallArgs {
pub paused_mask: PausedMask,
}

#[cfg(feature = "contract")]
pub trait ExpectUtf8<T> {
fn expect_utf8(self, message: &[u8]) -> T;
Expand Down
3 changes: 2 additions & 1 deletion src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ pub enum EthConnectorStorageId {
Contract = 0x0,
FungibleToken = 0x1,
UsedEvent = 0x2,
StatisticsAuroraAccountsCounter = 0x3,
PausedMask = 0x3,
StatisticsAuroraAccountsCounter = 0x4,
}

/// We can't use const generic over Enum, but we can do it over integral type
Expand Down
Loading

0 comments on commit 92f877d

Please sign in to comment.