Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EthConnector: make AdminControlled and pausable #88

Merged
merged 13 commits into from
May 27, 2021
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;
sept-en marked this conversation as resolved.
Show resolved Hide resolved

pub trait AdminControlled {
/// Returns true if the current account is owner
fn is_owner(&self) -> bool {
sept-en marked this conversation as resolved.
Show resolved Hide resolved
sept-en marked this conversation as resolved.
Show resolved Hide resolved
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;
sept-en marked this conversation as resolved.
Show resolved Hide resolved

#[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