From d0b3394aded47b3dc2e8993f31561ed896abe080 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Sun, 29 Jan 2023 03:59:05 +0100 Subject: [PATCH 1/6] Added internal_ft_transfer_call with message check fix --- Makefile.toml | 1 + eth-connector-tests/src/connector.rs | 48 ++++++++++ eth-connector/src/lib.rs | 133 +++++++++++---------------- 3 files changed, 102 insertions(+), 80 deletions(-) diff --git a/Makefile.toml b/Makefile.toml index 46bc5bf..13e154f 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -174,6 +174,7 @@ category = "Test" command = "${CARGO}" args = [ "test", + "test_ft_transfer_call_user_message", "--features", "${CARGO_FEATURES_TEST}", "--", diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index cbc924c..7b2586f 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -311,6 +311,54 @@ async fn test_ft_transfer_call_without_message() -> anyhow::Result<()> { Ok(()) } +#[tokio::test] +async fn test_ft_transfer_call_user_message() { + let contract = TestContract::new().await.unwrap(); + contract.call_deposit_eth_to_near().await.unwrap(); + + let user_acc = contract.create_sub_account("eth_recipient").await.unwrap(); + let receiver_id = AccountId::try_from(DEPOSITED_RECIPIENT.to_string()).unwrap(); + let balance = contract + .get_eth_on_near_balance(&receiver_id) + .await + .unwrap(); + assert_eq!(balance.0, DEPOSITED_AMOUNT - DEPOSITED_FEE); + + let balance = contract + .get_eth_on_near_balance(contract.contract.id()) + .await + .unwrap(); + assert_eq!(balance.0, DEPOSITED_FEE); + + let transfer_amount: U128 = 50.into(); + let memo: Option = None; + let message = ""; + // Send to Aurora contract with wrong message should failed + let res = user_acc + .call(contract.contract.id(), "ft_transfer_call") + .args_json((contract.contract.id(), transfer_amount, &memo, message)) + .gas(DEFAULT_GAS) + .deposit(ONE_YOCTO) + .transact() + .await + .unwrap(); + println!("{:#?}", res); + assert!(res.is_failure()); + //assert!(contract.check_error_message(res, "ERR_INVALID_ON_TRANSFER_MESSAGE_FORMAT")); + + // Assert balances remain unchanged + let balance = contract + .get_eth_on_near_balance(&receiver_id) + .await + .unwrap(); + assert_eq!(balance.0, DEPOSITED_AMOUNT - DEPOSITED_FEE); + let balance = contract + .get_eth_on_near_balance(contract.contract.id()) + .await + .unwrap(); + assert_eq!(balance.0, DEPOSITED_FEE); +} + #[tokio::test] async fn test_deposit_with_0x_prefix() -> anyhow::Result<()> { let contract = TestContract::new().await?; diff --git a/eth-connector/src/lib.rs b/eth-connector/src/lib.rs index 75d45aa..074c741 100644 --- a/eth-connector/src/lib.rs +++ b/eth-connector/src/lib.rs @@ -95,6 +95,57 @@ impl EthConnectorContract { self.ft.internal_register_account(account); } } + + fn internal_ft_transfer_call( + &mut self, + sender_id: AccountId, + receiver_id: AccountId, + amount: U128, + memo: Option, + msg: String, + ) -> PromiseOrValue { + assert_one_yocto(); + self.register_if_not_exists(&receiver_id); + + let amount: Balance = amount.into(); + crate::log!( + "Transfer call from {} to {} amount {}", + sender_id, + receiver_id, + amount, + ); + + // Verify message data before `ft_on_transfer` call for Engine accounts + // to avoid verification panics. + // It's allowed empty message if `receiver_id != known_engin_accounts`. + if receiver_id == known_engine_accounts { + let _ = FtTransferMessageData::parse_on_transfer_message(&msg).sdk_unwrap(); + } + + // Special case, we do not fail if `sender_id = receiver_id` + // if `predecessor_account_id` call `ft_transfer_call` as receiver itself + // to call `ft_on_transfer`. + if sender_id != receiver_id { + // It's panic if: sender_id == receiver_id + self.ft + .internal_transfer(&sender_id, &receiver_id, amount, memo); + } + + let receiver_gas = env::prepaid_gas() + .0 + .checked_sub(GAS_FOR_FT_TRANSFER_CALL.0) + .unwrap_or_else(|| env::panic_str("Prepaid gas overflow")); + // Initiating receiver's call and the callback + ext_ft_receiver::ext(receiver_id.clone()) + .with_static_gas(receiver_gas.into()) + .ft_on_transfer(sender_id.clone(), amount.into(), msg) + .then( + ext_ft_resolver::ext(env::current_account_id()) + .with_static_gas(GAS_FOR_RESOLVE_TRANSFER) + .ft_resolve_transfer(sender_id, receiver_id, amount.into()), + ) + .into() + } } #[near_bindgen] @@ -162,47 +213,8 @@ impl FungibleTokenCore for EthConnectorContract { memo: Option, msg: String, ) -> PromiseOrValue { - self.register_if_not_exists(&receiver_id); - let sender_id = env::predecessor_account_id(); - let amount: Balance = amount.into(); - crate::log!( - "Transfer call from {} to {} amount {}", - sender_id, - receiver_id, - amount, - ); - - // Verify message data before `ft_on_transfer` call to avoid verification panics - // It's allowed empty message if `receiver_id =! current_account_id` - if sender_id == receiver_id { - let message_data = FtTransferMessageData::parse_on_transfer_message(&msg).sdk_unwrap(); - // Check is transfer amount > fee - if message_data.fee.as_u128() >= amount { - panic_err("insufficient balance for fee"); - } - } - - // Special case for Aurora transfer itself - we shouldn't transfer - if sender_id != receiver_id { - self.ft - .internal_transfer(&sender_id, &receiver_id, amount, memo); - } - - let receiver_gas = env::prepaid_gas() - .0 - .checked_sub(GAS_FOR_FT_TRANSFER_CALL.0) - .unwrap_or_else(|| env::panic_str("Prepaid gas overflow")); - // Initiating receiver's call and the callback - ext_ft_receiver::ext(receiver_id.clone()) - .with_static_gas(receiver_gas.into()) - .ft_on_transfer(sender_id.clone(), amount.into(), msg) - .then( - ext_ft_resolver::ext(env::current_account_id()) - .with_static_gas(GAS_FOR_RESOLVE_TRANSFER) - .ft_resolve_transfer(sender_id, receiver_id, amount.into()), - ) - .into() + self.internal_ft_transfer_call(sender_id, receiver_id, amount, memo, msg) } fn ft_total_supply(&self) -> U128 { @@ -247,46 +259,7 @@ impl EngineFungibleToken for EthConnectorContract { msg: String, ) -> PromiseOrValue { self.assert_access_right().sdk_unwrap(); - self.register_if_not_exists(&receiver_id); - - let amount: Balance = amount.into(); - crate::log!( - "Transfer call from {} to {} amount {}", - sender_id, - receiver_id, - amount, - ); - - // Verify message data before `ft_on_transfer` call to avoid verification panics - // It's allowed empty message if `receiver_id =! current_account_id` - if sender_id == receiver_id { - let message_data = FtTransferMessageData::parse_on_transfer_message(&msg).sdk_unwrap(); - // Check is transfer amount > fee - if message_data.fee.as_u128() >= amount { - panic_err("insufficient balance for fee"); - } - } - - // Special case for Aurora transfer itself - we shouldn't transfer - if sender_id != receiver_id { - self.ft - .internal_transfer(&sender_id, &receiver_id, amount, memo); - } - - let receiver_gas = env::prepaid_gas() - .0 - .checked_sub(GAS_FOR_FT_TRANSFER_CALL.0) - .unwrap_or_else(|| env::panic_str("Prepaid gas overflow")); - // Initiating receiver's call and the callback - ext_ft_receiver::ext(receiver_id.clone()) - .with_static_gas(receiver_gas.into()) - .ft_on_transfer(sender_id.clone(), amount.into(), msg) - .then( - ext_ft_resolver::ext(env::current_account_id()) - .with_static_gas(GAS_FOR_RESOLVE_TRANSFER) - .ft_resolve_transfer(sender_id, receiver_id, amount.into()), - ) - .into() + self.internal_ft_transfer_call(sender_id, receiver_id, amount, memo, msg) } } From 5c4785cb62dfffd5b67f309a0da7824a6639b1e3 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Tue, 31 Jan 2023 02:24:52 +0100 Subject: [PATCH 2/6] Added Engine accounts management, and tests for wrong message ft_on_transfer --- eth-connector-tests/src/connector.rs | 65 +++++++++++++++++++++++----- eth-connector/src/connector.rs | 7 +++ eth-connector/src/lib.rs | 24 +++++++--- 3 files changed, 81 insertions(+), 15 deletions(-) diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index 65e7c9f..d22a19b 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -317,9 +317,9 @@ async fn test_ft_transfer_call_user_message() { contract.call_deposit_eth_to_near().await.unwrap(); let user_acc = contract.create_sub_account("eth_recipient").await.unwrap(); - let receiver_id = AccountId::try_from(DEPOSITED_RECIPIENT.to_string()).unwrap(); + let receiver_id = contract.contract.id(); let balance = contract - .get_eth_on_near_balance(&receiver_id) + .get_eth_on_near_balance(user_acc.id()) .await .unwrap(); assert_eq!(balance.0, DEPOSITED_AMOUNT - DEPOSITED_FEE); @@ -336,27 +336,72 @@ async fn test_ft_transfer_call_user_message() { // Send to Aurora contract with wrong message should failed let res = user_acc .call(contract.contract.id(), "ft_transfer_call") - .args_json((contract.contract.id(), transfer_amount, &memo, message)) + .args_json((&receiver_id, transfer_amount, &memo, message)) .gas(DEFAULT_GAS) .deposit(ONE_YOCTO) .transact() .await .unwrap(); - println!("{:#?}", res); - assert!(res.is_failure()); - //assert!(contract.check_error_message(res, "ERR_INVALID_ON_TRANSFER_MESSAGE_FORMAT")); + //println!("{:#?}", res); + assert!(res.is_success()); - // Assert balances remain unchanged let balance = contract .get_eth_on_near_balance(&receiver_id) .await .unwrap(); - assert_eq!(balance.0, DEPOSITED_AMOUNT - DEPOSITED_FEE); + assert_eq!(balance.0, DEPOSITED_FEE + transfer_amount.0); let balance = contract - .get_eth_on_near_balance(contract.contract.id()) + .get_eth_on_near_balance(user_acc.id()) .await .unwrap(); - assert_eq!(balance.0, DEPOSITED_FEE); + assert_eq!( + balance.0, + DEPOSITED_AMOUNT - DEPOSITED_FEE - transfer_amount.0 + ); + + let res = contract + .contract + .call("set_engine_account") + .args_json((&receiver_id,)) + .gas(DEFAULT_GAS) + .transact() + .await + .unwrap(); + assert!(res.is_success()); + + let res = contract + .contract + .call("get_engine_accounts") + .view() + .await + .unwrap() + .json::>() + .unwrap(); + assert!(res.contains(&receiver_id)); + + let res = user_acc + .call(contract.contract.id(), "ft_transfer_call") + .args_json((&receiver_id, transfer_amount, &memo, message)) + .gas(DEFAULT_GAS) + .deposit(ONE_YOCTO) + .transact() + .await + .unwrap(); + assert!(res.is_failure()); + assert!(contract.check_error_message(res, "ERR_INVALID_ON_TRANSFER_MESSAGE_FORMAT")); + let balance = contract + .get_eth_on_near_balance(&receiver_id) + .await + .unwrap(); + assert_eq!(balance.0, DEPOSITED_FEE + transfer_amount.0); + let balance = contract + .get_eth_on_near_balance(user_acc.id()) + .await + .unwrap(); + assert_eq!( + balance.0, + DEPOSITED_AMOUNT - DEPOSITED_FEE - transfer_amount.0 + ); } #[tokio::test] diff --git a/eth-connector/src/connector.rs b/eth-connector/src/connector.rs index 3663acb..35e90e4 100644 --- a/eth-connector/src/connector.rs +++ b/eth-connector/src/connector.rs @@ -85,3 +85,10 @@ pub trait EngineStorageManagement { fn engine_storage_unregister(&mut self, sender_id: AccountId, force: Option) -> bool; } + +#[ext_contract(ext_known_enine_accounts)] +pub trait KnownEnginAccountsManagement { + fn set_engine_account(&mut self, engine_account: AccountId); + + fn get_engine_accounts(&self) -> Vec; +} diff --git a/eth-connector/src/lib.rs b/eth-connector/src/lib.rs index daa60c4..9ffdc0d 100644 --- a/eth-connector/src/lib.rs +++ b/eth-connector/src/lib.rs @@ -1,7 +1,7 @@ use crate::admin_controlled::{AdminControlled, PausedMask, PAUSE_WITHDRAW, UNPAUSE_ALL}; use crate::connector::{ ConnectorDeposit, ConnectorFundsFinish, ConnectorWithdraw, EngineFungibleToken, - EngineStorageManagement, FungibleTokeStatistic, + EngineStorageManagement, FungibleTokeStatistic, KnownEnginAccountsManagement, }; use crate::connector_impl::{ EthConnector, FinishDepositCallArgs, TransferCallCallArgs, WithdrawResult, @@ -55,6 +55,7 @@ pub struct EthConnectorContract { metadata: LazyOption, used_proofs: LookupMap, accounts_counter: u64, + known_engine_accounts: Vec, } #[derive(BorshSerialize, BorshStorageKey)] @@ -116,9 +117,9 @@ impl EthConnectorContract { ); // Verify message data before `ft_on_transfer` call for Engine accounts - // to avoid verification panics. - // It's allowed empty message if `receiver_id != known_engin_accounts`. - if receiver_id == known_engine_accounts { + // to avoid verification panics inside `ft_on_transfer`. + // Allowed empty message if `receiver_id != known_engin_accounts`. + if self.known_engine_accounts.contains(&receiver_id) { let _ = FtTransferMessageData::parse_on_transfer_message(&msg).sdk_unwrap(); } @@ -126,7 +127,7 @@ impl EthConnectorContract { // if `predecessor_account_id` call `ft_transfer_call` as receiver itself // to call `ft_on_transfer`. if sender_id != receiver_id { - // It's panic if: sender_id == receiver_id + // It's panic if: `sender_id == receiver_id` self.ft .internal_transfer(&sender_id, &receiver_id, amount, memo); } @@ -175,6 +176,7 @@ impl EthConnectorContract { metadata: LazyOption::new(StorageKey::Metadata, Some(&metadata)), used_proofs: LookupMap::new(StorageKey::Proof), accounts_counter: 0, + known_engine_accounts: vec![], }; this.register_if_not_exists(&owner_id); this @@ -263,6 +265,18 @@ impl EngineFungibleToken for EthConnectorContract { } } +/// Management for a known Engine accounts +#[near_bindgen] +impl KnownEnginAccountsManagement for EthConnectorContract { + fn set_engine_account(&mut self, engine_account: AccountId) { + self.known_engine_accounts.push(engine_account); + } + + fn get_engine_accounts(&self) -> Vec { + self.known_engine_accounts.clone() + } +} + /// Implementations used only for EngineStorageManagement impl EthConnectorContract { fn internal_storage_balance_of(&self, account_id: &AccountId) -> Option { From 81330373e6553433a928aebd929557118044b4eb Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Tue, 31 Jan 2023 02:30:12 +0100 Subject: [PATCH 3/6] Fix clippy --- eth-connector-tests/src/connector.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index d22a19b..ddcdc5d 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -345,10 +345,7 @@ async fn test_ft_transfer_call_user_message() { //println!("{:#?}", res); assert!(res.is_success()); - let balance = contract - .get_eth_on_near_balance(&receiver_id) - .await - .unwrap(); + let balance = contract.get_eth_on_near_balance(receiver_id).await.unwrap(); assert_eq!(balance.0, DEPOSITED_FEE + transfer_amount.0); let balance = contract .get_eth_on_near_balance(user_acc.id()) @@ -377,7 +374,7 @@ async fn test_ft_transfer_call_user_message() { .unwrap() .json::>() .unwrap(); - assert!(res.contains(&receiver_id)); + assert!(res.contains(receiver_id)); let res = user_acc .call(contract.contract.id(), "ft_transfer_call") @@ -389,10 +386,7 @@ async fn test_ft_transfer_call_user_message() { .unwrap(); assert!(res.is_failure()); assert!(contract.check_error_message(res, "ERR_INVALID_ON_TRANSFER_MESSAGE_FORMAT")); - let balance = contract - .get_eth_on_near_balance(&receiver_id) - .await - .unwrap(); + let balance = contract.get_eth_on_near_balance(receiver_id).await.unwrap(); assert_eq!(balance.0, DEPOSITED_FEE + transfer_amount.0); let balance = contract .get_eth_on_near_balance(user_acc.id()) From b0375a2275fb8ec38d168ab77c8aa2b977c93b1f Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Sun, 22 Jan 2023 22:26:43 +0100 Subject: [PATCH 4/6] Add access right for set_engine_account and refactor related tests --- Makefile.toml | 1 - eth-connector-tests/src/connector.rs | 78 +++++++++++++++++++++++----- eth-connector-tests/src/utils.rs | 13 +++++ eth-connector/src/connector.rs | 4 +- eth-connector/src/lib.rs | 17 ++++-- 5 files changed, 92 insertions(+), 21 deletions(-) diff --git a/Makefile.toml b/Makefile.toml index 13e154f..46bc5bf 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -174,7 +174,6 @@ category = "Test" command = "${CARGO}" args = [ "test", - "test_ft_transfer_call_user_message", "--features", "${CARGO_FEATURES_TEST}", "--", diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index ddcdc5d..ecc9a70 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -194,6 +194,11 @@ async fn test_deposit_eth_to_near_balance_total_supply() -> anyhow::Result<()> { #[tokio::test] async fn test_deposit_eth_to_aurora_balance_total_supply() -> anyhow::Result<()> { let contract = TestContract::new().await?; + contract + .set_engine_account(&contract.contract.id()) + .await + .unwrap(); + contract.call_deposit_eth_to_aurora().await?; assert!( contract.call_is_used_proof(PROOF_DATA_ETH).await?, @@ -266,7 +271,11 @@ async fn test_ft_transfer_call_without_message() -> anyhow::Result<()> { let transfer_amount: U128 = 50.into(); let memo: Option = None; let message = ""; - // Send to Aurora contract with wrong message should failed + contract + .set_engine_account(contract.contract.id()) + .await + .unwrap(); + // Send to Engine contract with wrong message should failed let res = contract .contract .call("ft_transfer_call") @@ -333,7 +342,7 @@ async fn test_ft_transfer_call_user_message() { let transfer_amount: U128 = 50.into(); let memo: Option = None; let message = ""; - // Send to Aurora contract with wrong message should failed + // Send to non-engine contract with wrong message should failed let res = user_acc .call(contract.contract.id(), "ft_transfer_call") .args_json((&receiver_id, transfer_amount, &memo, message)) @@ -342,7 +351,6 @@ async fn test_ft_transfer_call_user_message() { .transact() .await .unwrap(); - //println!("{:#?}", res); assert!(res.is_success()); let balance = contract.get_eth_on_near_balance(receiver_id).await.unwrap(); @@ -356,15 +364,12 @@ async fn test_ft_transfer_call_user_message() { DEPOSITED_AMOUNT - DEPOSITED_FEE - transfer_amount.0 ); - let res = contract - .contract - .call("set_engine_account") - .args_json((&receiver_id,)) - .gas(DEFAULT_GAS) - .transact() + contract + .set_and_check_access_right(contract.contract.id()) .await .unwrap(); - assert!(res.is_success()); + + contract.set_engine_account(&receiver_id).await.unwrap(); let res = contract .contract @@ -376,6 +381,7 @@ async fn test_ft_transfer_call_user_message() { .unwrap(); assert!(res.contains(receiver_id)); + // Send to engine contract with wrong message should failed let res = user_acc .call(contract.contract.id(), "ft_transfer_call") .args_json((&receiver_id, transfer_amount, &memo, message)) @@ -398,6 +404,47 @@ async fn test_ft_transfer_call_user_message() { ); } +#[tokio::test] +async fn test_set_and_get_engine_account() { + let contract = TestContract::new().await.unwrap(); + contract.call_deposit_eth_to_near().await.unwrap(); + + let user_acc = contract.create_sub_account("eth_recipient").await.unwrap(); + let res = user_acc + .call(contract.contract.id(), "set_engine_account") + .args_json((&contract.contract.id(),)) + .gas(DEFAULT_GAS) + .transact() + .await + .unwrap(); + assert!(res.is_failure()); + assert!(contract.check_error_message(res, "ERR_ACCESS_RIGHT")); + + contract + .set_and_check_access_right(user_acc.id()) + .await + .unwrap(); + + let res = user_acc + .call(contract.contract.id(), "set_engine_account") + .args_json((&contract.contract.id(),)) + .gas(DEFAULT_GAS) + .transact() + .await + .unwrap(); + assert!(res.is_success()); + + let res = contract + .contract + .call("get_engine_accounts") + .view() + .await + .unwrap() + .json::>() + .unwrap(); + assert!(res.contains(contract.contract.id())); +} + #[tokio::test] async fn test_deposit_with_0x_prefix() -> anyhow::Result<()> { let contract = TestContract::new().await?; @@ -564,6 +611,9 @@ async fn test_ft_transfer_call_fee_greater_than_amount() -> anyhow::Result<()> { let relayer_id = "relayer.root"; let message = [relayer_id, hex::encode(msg).as_str()].join(":"); let memo: Option = None; + + // For `ft_transfer_call` we don't check correcness for `fee amount`. + // So transactions should be success, and balances shouldn't changes let res = contract .contract .call("ft_transfer_call") @@ -572,13 +622,11 @@ async fn test_ft_transfer_call_fee_greater_than_amount() -> anyhow::Result<()> { .deposit(ONE_YOCTO) .transact() .await?; - assert!(res.is_failure()); - assert!(contract.check_error_message(res, "insufficient balance for fee")); + assert!(res.is_success()); let receiver_id = AccountId::try_from(DEPOSITED_RECIPIENT.to_string()).unwrap(); let balance = contract.get_eth_on_near_balance(&receiver_id).await?; assert_eq!(balance.0, DEPOSITED_AMOUNT - DEPOSITED_FEE); - assert_eq!(balance.0, DEPOSITED_AMOUNT - DEPOSITED_FEE); let balance = contract .get_eth_on_near_balance(contract.contract.id()) @@ -656,6 +704,10 @@ async fn test_admin_controlled_admin_can_perform_actions_when_paused() -> anyhow // 2nd deposit call when paused, but the admin is calling it - should succeed // NB: We can use `PROOF_DATA_ETH` this will be just a different proof but the same deposit // method which should be paused + contract + .set_engine_account(&contract.contract.id()) + .await + .unwrap(); contract.call_deposit_eth_to_aurora().await?; // Pause withdraw diff --git a/eth-connector-tests/src/utils.rs b/eth-connector-tests/src/utils.rs index 822987e..50fcb73 100644 --- a/eth-connector-tests/src/utils.rs +++ b/eth-connector-tests/src/utils.rs @@ -306,6 +306,19 @@ impl TestContract { } Ok(()) } + + pub async fn set_engine_account(&self, acc: &AccountId) -> anyhow::Result<()> { + let res = self + .contract + .call("set_engine_account") + .args_json((&acc,)) + .gas(DEFAULT_GAS) + .transact() + .await + .unwrap(); + assert!(res.is_success()); + Ok(()) + } } pub fn print_logs(res: ExecutionFinalResult) { diff --git a/eth-connector/src/connector.rs b/eth-connector/src/connector.rs index 35e90e4..8a19164 100644 --- a/eth-connector/src/connector.rs +++ b/eth-connector/src/connector.rs @@ -86,8 +86,8 @@ pub trait EngineStorageManagement { fn engine_storage_unregister(&mut self, sender_id: AccountId, force: Option) -> bool; } -#[ext_contract(ext_known_enine_accounts)] -pub trait KnownEnginAccountsManagement { +#[ext_contract(ext_known_engine_accounts)] +pub trait KnownEngineAccountsManagement { fn set_engine_account(&mut self, engine_account: AccountId); fn get_engine_accounts(&self) -> Vec; diff --git a/eth-connector/src/lib.rs b/eth-connector/src/lib.rs index 9ffdc0d..ca039fe 100644 --- a/eth-connector/src/lib.rs +++ b/eth-connector/src/lib.rs @@ -1,7 +1,7 @@ use crate::admin_controlled::{AdminControlled, PausedMask, PAUSE_WITHDRAW, UNPAUSE_ALL}; use crate::connector::{ ConnectorDeposit, ConnectorFundsFinish, ConnectorWithdraw, EngineFungibleToken, - EngineStorageManagement, FungibleTokeStatistic, KnownEnginAccountsManagement, + EngineStorageManagement, FungibleTokeStatistic, KnownEngineAccountsManagement, }; use crate::connector_impl::{ EthConnector, FinishDepositCallArgs, TransferCallCallArgs, WithdrawResult, @@ -105,7 +105,6 @@ impl EthConnectorContract { memo: Option, msg: String, ) -> PromiseOrValue { - assert_one_yocto(); self.register_if_not_exists(&receiver_id); let amount: Balance = amount.into(); @@ -215,6 +214,7 @@ impl FungibleTokenCore for EthConnectorContract { memo: Option, msg: String, ) -> PromiseOrValue { + assert_one_yocto(); let sender_id = env::predecessor_account_id(); self.internal_ft_transfer_call(sender_id, receiver_id, amount, memo, msg) } @@ -260,6 +260,7 @@ impl EngineFungibleToken for EthConnectorContract { memo: Option, msg: String, ) -> PromiseOrValue { + assert_one_yocto(); self.assert_access_right().sdk_unwrap(); self.internal_ft_transfer_call(sender_id, receiver_id, amount, memo, msg) } @@ -267,8 +268,9 @@ impl EngineFungibleToken for EthConnectorContract { /// Management for a known Engine accounts #[near_bindgen] -impl KnownEnginAccountsManagement for EthConnectorContract { +impl KnownEngineAccountsManagement for EthConnectorContract { fn set_engine_account(&mut self, engine_account: AccountId) { + self.assert_access_right().sdk_unwrap(); self.known_engine_accounts.push(engine_account); } @@ -507,8 +509,13 @@ impl ConnectorFundsFinish for EthConnectorContract { let data: TransferCallCallArgs = TransferCallCallArgs::try_from_slice(&msg) .map_err(|_| crate::errors::ERR_BORSH_DESERIALIZE) .sdk_unwrap(); - let promise = - self.ft_transfer_call(data.receiver_id, data.amount.into(), data.memo, data.msg); + let promise = self.internal_ft_transfer_call( + env::predecessor_account_id(), + data.receiver_id, + data.amount.into(), + data.memo, + data.msg, + ); match promise { PromiseOrValue::Promise(p) => PromiseOrValue::Promise(p), PromiseOrValue::Value(v) => PromiseOrValue::Value(Some(v)), From 2742c92998c39aeac484edd400f64732d9a95007 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Sun, 22 Jan 2023 22:35:13 +0100 Subject: [PATCH 5/6] Fix clippy --- eth-connector-tests/src/connector.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index ecc9a70..905c46c 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -195,7 +195,7 @@ async fn test_deposit_eth_to_near_balance_total_supply() -> anyhow::Result<()> { async fn test_deposit_eth_to_aurora_balance_total_supply() -> anyhow::Result<()> { let contract = TestContract::new().await?; contract - .set_engine_account(&contract.contract.id()) + .set_engine_account(contract.contract.id()) .await .unwrap(); @@ -369,7 +369,7 @@ async fn test_ft_transfer_call_user_message() { .await .unwrap(); - contract.set_engine_account(&receiver_id).await.unwrap(); + contract.set_engine_account(receiver_id).await.unwrap(); let res = contract .contract @@ -705,7 +705,7 @@ async fn test_admin_controlled_admin_can_perform_actions_when_paused() -> anyhow // NB: We can use `PROOF_DATA_ETH` this will be just a different proof but the same deposit // method which should be paused contract - .set_engine_account(&contract.contract.id()) + .set_engine_account(contract.contract.id()) .await .unwrap(); contract.call_deposit_eth_to_aurora().await?; From 532238dd878230aa663c8b0a00d563b7db5d8f72 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 1 Feb 2023 15:13:38 +0100 Subject: [PATCH 6/6] Added method test: manage_engine_accounts --- eth-connector-tests/src/connector.rs | 46 ++++++++++++++++++++++++++++ eth-connector/src/connector.rs | 2 ++ eth-connector/src/lib.rs | 6 ++++ 3 files changed, 54 insertions(+) diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index 905c46c..f45f78e 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -1680,3 +1680,49 @@ async fn test_engine_storage_unregister() { assert!(res.is_failure()); assert!(contract.check_error_message(res, "The account eth_recipient.root is not registered")); } + +#[tokio::test] +async fn test_manage_engine_accounts() { + let contract = TestContract::new().await.unwrap(); + contract + .set_and_check_access_right(contract.contract.id()) + .await + .unwrap(); + + let acc1 = AccountId::try_from("acc1.root".to_string()).unwrap(); + let acc2 = AccountId::try_from("acc2.root".to_string()).unwrap(); + contract.set_engine_account(&acc1).await.unwrap(); + contract.set_engine_account(&acc2).await.unwrap(); + let res = contract + .contract + .call("get_engine_accounts") + .view() + .await + .unwrap() + .json::>() + .unwrap(); + assert_eq!(res.len(), 2); + assert!(res.contains(&acc1)); + assert!(res.contains(&acc2)); + + let res = contract + .contract + .call("remove_engine_account") + .args_json((&acc1,)) + .gas(DEFAULT_GAS) + .transact() + .await + .unwrap(); + assert!(res.is_success()); + let res = contract + .contract + .call("get_engine_accounts") + .view() + .await + .unwrap() + .json::>() + .unwrap(); + assert_eq!(res.len(), 1); + assert!(!res.contains(&acc1)); + assert!(res.contains(&acc2)); +} diff --git a/eth-connector/src/connector.rs b/eth-connector/src/connector.rs index 8a19164..4febcbe 100644 --- a/eth-connector/src/connector.rs +++ b/eth-connector/src/connector.rs @@ -90,5 +90,7 @@ pub trait EngineStorageManagement { pub trait KnownEngineAccountsManagement { fn set_engine_account(&mut self, engine_account: AccountId); + fn remove_engine_account(&mut self, engine_account: AccountId); + fn get_engine_accounts(&self) -> Vec; } diff --git a/eth-connector/src/lib.rs b/eth-connector/src/lib.rs index ca039fe..2112bd9 100644 --- a/eth-connector/src/lib.rs +++ b/eth-connector/src/lib.rs @@ -274,6 +274,12 @@ impl KnownEngineAccountsManagement for EthConnectorContract { self.known_engine_accounts.push(engine_account); } + fn remove_engine_account(&mut self, engine_account: AccountId) { + self.assert_access_right().sdk_unwrap(); + self.known_engine_accounts + .retain(|acc| *acc != engine_account); + } + fn get_engine_accounts(&self) -> Vec { self.known_engine_accounts.clone() }