Skip to content

Commit

Permalink
Merge pull request #12 from aurora-is-near/fix/ft_transfer_call-messa…
Browse files Browse the repository at this point in the history
…ge-check

Fix `ft transfer call` message check
  • Loading branch information
mrLSD authored Jan 24, 2023
2 parents f39c917 + 6ad673e commit d5399c7
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 84 deletions.
193 changes: 189 additions & 4 deletions eth-connector-tests/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?,
Expand Down Expand Up @@ -266,7 +271,11 @@ async fn test_ft_transfer_call_without_message() -> anyhow::Result<()> {
let transfer_amount: U128 = 50.into();
let memo: Option<String> = 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")
Expand Down Expand Up @@ -311,6 +320,131 @@ 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 = contract.contract.id();
let balance = contract
.get_eth_on_near_balance(user_acc.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<String> = None;
let message = "";
// 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))
.gas(DEFAULT_GAS)
.deposit(ONE_YOCTO)
.transact()
.await
.unwrap();
assert!(res.is_success());

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
);

contract
.set_and_check_access_right(contract.contract.id())
.await
.unwrap();

contract.set_engine_account(receiver_id).await.unwrap();

let res = contract
.contract
.call("get_engine_accounts")
.view()
.await
.unwrap()
.json::<Vec<AccountId>>()
.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))
.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]
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::<Vec<AccountId>>()
.unwrap();
assert!(res.contains(contract.contract.id()));
}

#[tokio::test]
async fn test_deposit_with_0x_prefix() -> anyhow::Result<()> {
let contract = TestContract::new().await?;
Expand Down Expand Up @@ -477,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<String> = 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")
Expand All @@ -485,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())
Expand Down Expand Up @@ -569,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
Expand Down Expand Up @@ -1541,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::<Vec<AccountId>>()
.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::<Vec<AccountId>>()
.unwrap();
assert_eq!(res.len(), 1);
assert!(!res.contains(&acc1));
assert!(res.contains(&acc2));
}
13 changes: 13 additions & 0 deletions eth-connector-tests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
9 changes: 9 additions & 0 deletions eth-connector/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,12 @@ pub trait EngineStorageManagement {

fn engine_storage_unregister(&mut self, sender_id: AccountId, force: Option<bool>) -> bool;
}

#[ext_contract(ext_known_engine_accounts)]
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<AccountId>;
}
Loading

0 comments on commit d5399c7

Please sign in to comment.