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
26 changes: 26 additions & 0 deletions src/admin_controlled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::sdk;

pub type PausedMask = u8;
sept-en marked this conversation as resolved.
Show resolved Hide resolved

pub trait AdminControlled {
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()
}

fn check_not_paused(&self, flag: PausedMask) {
assert!(!self.is_paused(flag));
}
sept-en marked this conversation as resolved.
Show resolved Hide resolved
}
53 changes: 52 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::prelude::*;
Expand All @@ -17,10 +18,15 @@ const GAS_FOR_FINISH_DEPOSIT: Gas = 50_000_000_000_000;
const GAS_FOR_VERIFY_LOG_ENTRY: Gas = 40_000_000_000_000;
const GAS_FOR_TRANSFER_CALL: 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 @@ -49,6 +55,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 @@ -82,14 +89,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_contract();
}
Expand Down Expand Up @@ -139,6 +153,8 @@ impl EthConnectorContract {

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

use crate::prover::Proof;
#[cfg(feature = "log")]
sdk::log("[Deposit tokens]");
Expand Down Expand Up @@ -374,6 +390,8 @@ impl EthConnectorContract {
/// Withdraw from NEAR accounts
/// NOTE: it should be without any log data
pub fn withdraw_near(&mut self) {
self.check_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 @@ -484,6 +502,8 @@ impl EthConnectorContract {
/// We starting early checking for message data to avoid `ft_on_transfer` call panics
/// But we don't check relayer exists. If relayer doesn't exist we simply not mint/burn the amount of the fee
pub fn ft_transfer_call(&mut self) {
//TODO: perhaps need to add pausability functionality here as well?
sept-en marked this conversation as resolved.
Show resolved Hide resolved

sdk::assert_one_yocto();
let args =
TransferCallCallArgs::try_from_slice(&sdk::read_input()).expect(ERR_FAILED_PARSE);
Expand Down Expand Up @@ -551,6 +571,8 @@ impl EthConnectorContract {
/// ft_on_transfer callback function
#[allow(clippy::unnecessary_unwrap)]
pub fn ft_on_transfer(&mut self, engine: &Engine) {
//TODO: perhaps need to add pausability functionality here as well?

sept-en marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(feature = "log")]
sdk::log("Call ft_on_trasfer");
let args = FtOnTransfer::try_from_slice(&sdk::read_input()).expect(ERR_FAILED_PARSE);
Expand Down Expand Up @@ -607,4 +629,33 @@ 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) {
let data = self.get_paused().try_to_vec().unwrap();
sept-en marked this conversation as resolved.
Show resolved Hide resolved
sdk::return_output(&data[..]);
birchmd marked this conversation as resolved.
Show resolved Hide resolved
}

/// Set Eth connector paused flags
pub fn set_paused_flags(&mut self) {
sdk::assert_private_call();

let args =
PauseEthConnectorCallArgs::try_from_slice(&sdk::read_input()).expect(ERR_FAILED_PARSE);
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,
);
}
}
12 changes: 12 additions & 0 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 @@ -434,6 +436,16 @@ mod contract {
EthConnectorContract::get_instance().ft_on_transfer(&engine)
}

#[no_mangle]
pub extern "C" fn get_eth_connector_paused_flags() {
EthConnectorContract::get_instance().get_paused_flags()
sept-en marked this conversation as resolved.
Show resolved Hide resolved
}

#[no_mangle]
pub extern "C" fn set_eth_connector_paused_flags() {
sept-en marked this conversation as resolved.
Show resolved Hide resolved
EthConnectorContract::get_instance().set_paused_flags()
}

#[cfg(feature = "integration-test")]
#[no_mangle]
pub extern "C" fn verify_log_entry() {
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;
use crate::prelude::{String, Vec};
#[cfg(feature = "contract")]
use crate::prover::Proof;
Expand Down Expand Up @@ -287,6 +289,12 @@ pub struct RegisterRelayerCallArgs {
pub address: EthAddress,
}

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

#[cfg(test)]
mod tests {
use super::*;
Expand Down
1 change: 1 addition & 0 deletions src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub enum EthConnectorStorageId {
Contract = 0x0,
FungibleToken = 0x1,
UsedEvent = 0x2,
PausedMask = 0x3,
}

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