1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//! Mocking API for the sandbox.
use super::Session;
use crate::{
    mock::ContractMock,
    runtime::{AccountIdFor, Runtime},
    DEFAULT_GAS_LIMIT,
};

/// Interface for basic mocking operations.
pub trait MockingApi<R: Runtime> {
    /// Deploy `mock` as a standard contract. Returns the address of the deployed contract.
    fn deploy(&mut self, mock: ContractMock) -> AccountIdFor<R::Config>;

    /// Mock part of an existing contract. In particular, allows to override real behavior of
    /// deployed contract's messages.
    fn mock_existing_contract(&mut self, _mock: ContractMock, _address: AccountIdFor<R::Config>);
}

impl<R: Runtime> MockingApi<R> for Session<R>
where
    R::Config: pallet_contracts::Config,
{
    fn deploy(&mut self, mock: ContractMock) -> AccountIdFor<R::Config> {
        // We have to deploy some contract. We use a dummy contract for that. Thanks to that, we
        // ensure that the pallet will treat our mock just as a regular contract, until we actually
        // call it.
        let mock_bytes = wat::parse_str(DUMMY_CONTRACT).expect("Dummy contract should be valid");
        let salt = self
            .mocks
            .lock()
            .expect("Should be able to acquire lock on registry")
            .salt();

        let mock_address = self
            .sandbox()
            .deploy_contract(
                mock_bytes,
                0u32.into(),
                vec![],
                salt,
                R::default_actor(),
                DEFAULT_GAS_LIMIT,
                None,
            )
            .result
            .expect("Deployment of a dummy contract should succeed")
            .account_id;

        self.mocks
            .lock()
            .expect("Should be able to acquire lock on registry")
            .register(mock_address.clone(), mock);

        mock_address
    }

    fn mock_existing_contract(&mut self, _mock: ContractMock, _address: AccountIdFor<R::Config>) {
        todo!("soon")
    }
}

/// A dummy contract that is used to deploy a mock.
///
/// Has a single noop constructor and a single panicking message.
const DUMMY_CONTRACT: &str = r#"
(module
	(import "env" "memory" (memory 1 1))
	(func (export "deploy"))
	(func (export "call") (unreachable))
)"#;