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

Add ink_env::pay_with_call! helper macro for off-chain emulation of sending payments with contract msg calls #1379

Merged
merged 14 commits into from
Sep 13, 2022
Merged
47 changes: 47 additions & 0 deletions crates/env/src/engine/off_chain/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ where
}

/// Sets the value transferred from the caller to the callee as part of the call.
/// Please note that the acting accounts should be set with [`set_caller()`] and [`set_callee()`] beforehand.
HCastano marked this conversation as resolved.
Show resolved Hide resolved
pub fn set_value_transferred<T>(value: T::Balance)
where
T: Environment<Balance = u128>, // Just temporary for the MVP!
Expand All @@ -209,6 +210,43 @@ where
})
}

/// Transfers value from the caller account to the contract.
HCastano marked this conversation as resolved.
Show resolved Hide resolved
/// Please note that the acting accounts should be set with [`set_caller()`] and [`set_callee()`] beforehand.
HCastano marked this conversation as resolved.
Show resolved Hide resolved
pub fn transfer_in<T>(value: T::Balance)
where
T: Environment<Balance = u128>, // Just temporary for the MVP!
{
<EnvInstance as OnInstance>::on_instance(|instance| {
let caller = instance
.engine
.exec_context
.caller
.as_ref()
.expect("no caller has been set")
.as_bytes()
.to_vec();

let caller_old_balance = instance
.engine
.get_balance(caller.clone())
.unwrap_or_default();

let callee = instance.engine.get_callee();
let contract_old_balance = instance
.engine
.get_balance(callee.clone())
.unwrap_or_default();

instance
.engine
.set_balance(caller, caller_old_balance - value);
instance
.engine
.set_balance(callee, contract_old_balance + value);
instance.engine.set_value_transferred(value);
});
}

/// Returns the amount of storage cells used by the account `account_id`.
///
/// Returns `None` if the `account_id` is non-existent.
Expand Down Expand Up @@ -355,3 +393,12 @@ pub fn assert_contract_termination<T, F>(
assert_eq!(value_transferred, expected_value_transferred_to_beneficiary);
assert_eq!(beneficiary, expected_beneficiary);
}

#[macro_export]
/// Prepend contract message call with value transfer. Used for tests in off-chain environment.
HCastano marked this conversation as resolved.
Show resolved Hide resolved
macro_rules! pay_with_call {
($contract:ident . $message:ident ( $($params:ty)? ) , $amount:expr) => {{
HCastano marked this conversation as resolved.
Show resolved Hide resolved
::ink_env::test::transfer_in::<Environment>($amount);
HCastano marked this conversation as resolved.
Show resolved Hide resolved
HCastano marked this conversation as resolved.
Show resolved Hide resolved
$contract.$message($($params:ty)?)
}}
}
23 changes: 17 additions & 6 deletions examples/contract-transfer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,31 @@ pub mod give_me {

#[ink::test]
fn test_transferred_value() {
use ink_lang::codegen::Env;
// given
let accounts = default_accounts();
let give_me = create_contract(100);
let contract_account = give_me.env().account_id();

// when
// Push the new execution context which sets Eve as caller and
// the `mock_transferred_value` as the value which the contract
// will see as transferred to it.
// Push the new execution context which sets initial balances and
// sets Eve as the caller
set_balance(accounts.eve, 100);
set_balance(contract_account, 0);
set_sender(accounts.eve);
ink_env::test::set_value_transferred::<ink_env::DefaultEnvironment>(10);

// then
// there must be no panic
give_me.was_it_ten();
// we use helper macro to emulate method invocation coming with payment,
// and there must be no panic
ink_env::pay_with_call!(give_me.was_it_ten(), 10);
HCastano marked this conversation as resolved.
Show resolved Hide resolved

// and
// balances should be changed properly
let contract_new_balance = get_balance(contract_account);
let caller_new_balance = get_balance(accounts.eve);

assert_eq!(caller_new_balance, 100 - 10);
assert_eq!(contract_new_balance, 10);
}

#[ink::test]
Expand Down