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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (C) Use Ink (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// Creates an instance of a message builder for an `#[ink::trait_definition]`.
///
/// This is done by creating a wrapper around the trait defined with the
/// [`ink::trait_definition`](crate::trait_definition) macro.
///
/// The macro returns an instance of the generated message builder type which implements
/// the trait, allowing the user to create and invoke messages on the trait.
///
/// This is similar to the call builder syntax accessible via the [`crate::contract_ref!`]
/// macro, except that it is decoupled from the callee account id, as well as the
/// underlying execution environment. This allows it to be used in execution contexts
/// other than cross-contract calls.
///
/// # Usage
///
/// The macro expects two arguments:
/// - The first argument is the path to the trait, e.g. `Erc20` or `erc20::Erc20`.
/// - The second argument is the type of the [`ink_env::Environment`].
///
/// If the second argument is not specified, the macro uses the
/// [`ink_env::DefaultEnvironment`].
///
/// ```rust
/// use ink::message_builder;
/// use ink_env::{
/// call::{
/// ExecutionInput,
/// Executor,
/// },
/// DefaultEnvironment,
/// };
/// use ink_primitives::{
/// AccountId,
/// MessageResult,
/// };
/// use scale::{
/// Decode,
/// Encode,
/// };
///
/// #[ink::trait_definition]
/// pub trait Erc20 {
/// /// Returns the total supply of the ERC-20 smart contract.
/// #[ink(message)]
/// fn total_supply(&self) -> u128;
///
/// /// Transfers balance from the caller to the given address.
/// #[ink(message)]
/// fn transfer(&mut self, amount: u128, to: AccountId) -> bool;
/// }
///
/// #[derive(Clone)]
/// pub struct CustomEnv;
///
/// impl ink_env::Environment for CustomEnv {
/// const MAX_EVENT_TOPICS: usize = 3;
/// type AccountId = [u8; 32];
/// type Balance = u64;
/// type Hash = [u8; 32];
/// type Timestamp = u64;
/// type BlockNumber = u64;
/// type ChainExtension = ();
/// }
///
/// /// To demonstrate implementing an execution environment agnostic executor
/// pub struct ExampleExecutor<E> {
/// marker: core::marker::PhantomData<E>,
/// }
///
/// impl<E> ExampleExecutor<E> {
/// pub fn new() -> Self {
/// Self {
/// marker: core::marker::PhantomData,
/// }
/// }
/// }
///
/// impl<E> Executor<E> for ExampleExecutor<E>
/// where
/// E: ink_env::Environment,
/// {
/// type Error = ();
/// fn exec<Args, Output>(
/// &self,
/// input: &ExecutionInput<Args>,
/// ) -> Result<MessageResult<Output>, Self::Error>
/// where
/// Args: Encode,
/// Output: Decode,
/// {
/// println!("Executing contract with input: {:?}", Encode::encode(input));
/// unimplemented!("Decode contract execution output")
/// }
/// }
///
/// fn default(to: AccountId) {
/// let executor = ExampleExecutor::<DefaultEnvironment>::new();
/// let mut contract = message_builder!(Erc20);
/// let total_supply = contract.total_supply().exec(&executor).unwrap().unwrap();
/// contract.transfer(total_supply, to).exec(&executor).unwrap();
/// }
///
/// fn custom(to: AccountId) {
/// let executor = ExampleExecutor::<CustomEnv>::new();
/// let mut contract = message_builder!(Erc20, CustomEnv);
/// let total_supply = contract.total_supply().exec(&executor).unwrap().unwrap();
/// contract.transfer(total_supply, to).exec(&executor).unwrap();
/// }
///
/// fn generic<E>(to: AccountId)
/// where
/// E: ink_env::Environment,
/// {
/// let executor = ExampleExecutor::<E>::new();
/// let mut contract = message_builder!(Erc20, E);
/// let total_supply = contract.total_supply().exec(&executor).unwrap().unwrap();
/// contract.transfer(total_supply, to).exec(&executor).unwrap();
/// }
/// ```