referrerpolicy=no-referrer-when-downgrade

pallet_revive/test_utils/
builder.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use super::{deposit_limit, GAS_LIMIT};
19use crate::{
20	address::AddressMapper, AccountIdOf, BalanceOf, BumpNonce, Code, Config, ContractResult,
21	DepositLimit, ExecReturnValue, InstantiateReturnValue, OriginFor, Pallet, Weight, U256,
22};
23use alloc::{vec, vec::Vec};
24use frame_support::pallet_prelude::DispatchResultWithPostInfo;
25use paste::paste;
26use sp_core::H160;
27
28/// Helper macro to generate a builder for contract API calls.
29macro_rules! builder {
30	// Entry point to generate a builder for the given method.
31	(
32		$method:ident($($field:ident: $type:ty,)*) -> $result:ty;
33        $($extra:item)*
34	) => {
35		paste!{
36			builder!([< $method:camel Builder >], $method($($field: $type,)* ) -> $result; $($extra)*);
37		}
38	};
39	// Generate the builder struct and its methods.
40	(
41		$name:ident,
42		$method:ident($($field:ident: $type:ty,)*) -> $result:ty;
43        $($extra:item)*
44	) => {
45		#[doc = concat!("A builder to construct a ", stringify!($method), " call")]
46		pub struct $name<T: Config> {
47			$($field: $type,)*
48		}
49
50		#[allow(dead_code)]
51		impl<T: Config> $name<T>
52		where
53			BalanceOf<T>: Into<sp_core::U256> + TryFrom<sp_core::U256>,
54			crate::MomentOf<T>: Into<sp_core::U256>,
55			T::Hash: frame_support::traits::IsType<sp_core::H256>,
56		{
57			$(
58				#[doc = concat!("Set the ", stringify!($field))]
59				pub fn $field(mut self, value: $type) -> Self {
60					self.$field = value;
61					self
62				}
63			)*
64
65			#[doc = concat!("Build the ", stringify!($method), " call")]
66			pub fn build(self) -> $result {
67				Pallet::<T>::$method(
68					$(self.$field,)*
69				)
70			}
71
72            $($extra)*
73		}
74	}
75}
76
77pub struct Contract<T: Config> {
78	pub account_id: AccountIdOf<T>,
79	pub addr: H160,
80}
81
82builder!(
83	instantiate_with_code(
84		origin: OriginFor<T>,
85		value: BalanceOf<T>,
86		gas_limit: Weight,
87		storage_deposit_limit: BalanceOf<T>,
88		code: Vec<u8>,
89		data: Vec<u8>,
90		salt: Option<[u8; 32]>,
91	) -> DispatchResultWithPostInfo;
92
93	/// Create an [`InstantiateWithCodeBuilder`] with default values.
94	pub fn instantiate_with_code(origin: OriginFor<T>, code: Vec<u8>) -> Self {
95		Self {
96			origin,
97			value: 0u32.into(),
98			gas_limit: GAS_LIMIT,
99			storage_deposit_limit: deposit_limit::<T>(),
100			code,
101			data: vec![],
102			salt: Some([0; 32]),
103		}
104	}
105);
106
107builder!(
108	instantiate(
109		origin: OriginFor<T>,
110		value: BalanceOf<T>,
111		gas_limit: Weight,
112		storage_deposit_limit: BalanceOf<T>,
113		code_hash: sp_core::H256,
114		data: Vec<u8>,
115		salt: Option<[u8; 32]>,
116	) -> DispatchResultWithPostInfo;
117
118	/// Create an [`InstantiateBuilder`] with default values.
119	pub fn instantiate(origin: OriginFor<T>, code_hash: sp_core::H256) -> Self {
120		Self {
121			origin,
122			value: 0u32.into(),
123			gas_limit: GAS_LIMIT,
124			storage_deposit_limit: deposit_limit::<T>(),
125			code_hash,
126			data: vec![],
127			salt: Some([0; 32]),
128		}
129	}
130);
131
132builder!(
133	bare_instantiate(
134		origin: OriginFor<T>,
135		evm_value: U256,
136		gas_limit: Weight,
137		storage_deposit_limit: DepositLimit<BalanceOf<T>>,
138		code: Code,
139		data: Vec<u8>,
140		salt: Option<[u8; 32]>,
141		bump_nonce: BumpNonce,
142	) -> ContractResult<InstantiateReturnValue, BalanceOf<T>>;
143
144	/// Set the call's evm_value using a native_value amount.
145	pub fn native_value(mut self, value: BalanceOf<T>) -> Self {
146		self.evm_value = Pallet::<T>::convert_native_to_evm(value);
147		self
148	}
149
150	/// Build the instantiate call and unwrap the result.
151	pub fn build_and_unwrap_result(self) -> InstantiateReturnValue {
152		self.build().result.unwrap()
153	}
154
155	/// Build the instantiate call and unwrap the account id.
156	pub fn build_and_unwrap_contract(self) -> Contract<T> {
157		let result = self.build().result.unwrap();
158		assert!(!result.result.did_revert(), "instantiation did revert");
159
160		let addr = result.addr;
161		let account_id = T::AddressMapper::to_account_id(&addr);
162		Contract{ account_id,  addr }
163	}
164
165	/// Create a [`BareInstantiateBuilder`] with default values.
166	pub fn bare_instantiate(origin: OriginFor<T>, code: Code) -> Self {
167		Self {
168			origin,
169			evm_value: Default::default(),
170			gas_limit: GAS_LIMIT,
171			storage_deposit_limit: DepositLimit::Balance(deposit_limit::<T>()),
172			code,
173			data: vec![],
174			salt: Some([0; 32]),
175			bump_nonce: BumpNonce::Yes,
176		}
177	}
178);
179
180builder!(
181	call(
182		origin: OriginFor<T>,
183		dest: H160,
184		value: BalanceOf<T>,
185		gas_limit: Weight,
186		storage_deposit_limit: BalanceOf<T>,
187		data: Vec<u8>,
188	) -> DispatchResultWithPostInfo;
189
190	/// Create a [`CallBuilder`] with default values.
191	pub fn call(origin: OriginFor<T>, dest: H160) -> Self {
192		CallBuilder {
193			origin,
194			dest,
195			value: 0u32.into(),
196			gas_limit: GAS_LIMIT,
197			storage_deposit_limit: deposit_limit::<T>(),
198			data: vec![],
199		}
200	}
201);
202
203builder!(
204	bare_call(
205		origin: OriginFor<T>,
206		dest: H160,
207		evm_value: U256,
208		gas_limit: Weight,
209		storage_deposit_limit: DepositLimit<BalanceOf<T>>,
210		data: Vec<u8>,
211	) -> ContractResult<ExecReturnValue, BalanceOf<T>>;
212
213	/// Set the call's evm_value using a native_value amount.
214	pub fn native_value(mut self, value: BalanceOf<T>) -> Self {
215		self.evm_value = Pallet::<T>::convert_native_to_evm(value);
216		self
217	}
218
219	/// Build the call and unwrap the result.
220	pub fn build_and_unwrap_result(self) -> ExecReturnValue {
221		self.build().result.unwrap()
222	}
223
224	/// Create a [`BareCallBuilder`] with default values.
225	pub fn bare_call(origin: OriginFor<T>, dest: H160) -> Self {
226		Self {
227			origin,
228			dest,
229			evm_value: Default::default(),
230			gas_limit: GAS_LIMIT,
231			storage_deposit_limit: DepositLimit::Balance(deposit_limit::<T>()),
232			data: vec![],
233		}
234	}
235);
236
237builder!(
238	eth_call(
239		origin: OriginFor<T>,
240		dest: H160,
241		value: U256,
242		gas_limit: Weight,
243		storage_deposit_limit: BalanceOf<T>,
244		data: Vec<u8>,
245	) -> DispatchResultWithPostInfo;
246
247	/// Create a [`EthCallBuilder`] with default values.
248	pub fn eth_call(origin: OriginFor<T>, dest: H160) -> Self {
249		Self {
250			origin,
251			dest,
252			value: 0u32.into(),
253			gas_limit: GAS_LIMIT,
254			storage_deposit_limit: deposit_limit::<T>(),
255			data: vec![],
256		}
257	}
258);