Skip to content

Commit

Permalink
Add ink_env::pay_with_call! helper macro for off-chain emulation of…
Browse files Browse the repository at this point in the history
… sending payments with contract msg calls (#1379)

* first ver.: transfer_in api function implememted but we can't have it in on-chain env

* transfer_in moved to test_api

* doc + example updated

* Update examples/contract-transfer/lib.rs

Co-authored-by: Hernando Castano <[email protected]>

* use stmt moved to macro

* docs and nitty gritties

* moved the macro to the test mod

* spell fix

* next review round suggestions applied

* Use four spaces for macro indentation

Co-authored-by: Hernando Castano <[email protected]>
Co-authored-by: Hernando Castano <[email protected]>
  • Loading branch information
3 people authored Sep 13, 2022
1 parent fb871a0 commit d42bfbf
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 6 deletions.
49 changes: 49 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,8 @@ 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.
pub fn set_value_transferred<T>(value: T::Balance)
where
T: Environment<Balance = u128>, // Just temporary for the MVP!
Expand All @@ -209,6 +211,44 @@ where
})
}

/// Transfers value from the caller account to the contract.
///
/// Please note that the acting accounts should be set with [`set_caller()`] and [`set_callee()`] beforehand.
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 +395,12 @@ pub fn assert_contract_termination<T, F>(
assert_eq!(value_transferred, expected_value_transferred_to_beneficiary);
assert_eq!(beneficiary, expected_beneficiary);
}

/// Prepend contract message call with value transfer. Used for tests in off-chain environment.
#[macro_export]
macro_rules! pay_with_call {
($contract:ident . $message:ident ( $($params:ty)? ) , $amount:expr) => {{
$crate::test::transfer_in::<Environment>($amount);
$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);

// 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

0 comments on commit d42bfbf

Please sign in to comment.