ink_env/api.rs
1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The public raw interface towards the host engine.
16
17use ink_primitives::{
18 Address,
19 H256,
20 U256,
21 abi::AbiEncodeWith,
22 sol::SolResultEncode,
23};
24use ink_storage_traits::Storable;
25use pallet_revive_uapi::ReturnFlags;
26
27use crate::{
28 DecodeDispatch,
29 DispatchError,
30 Result,
31 backend::{
32 EnvBackend,
33 TypedEnvBackend,
34 },
35 call::{
36 Call,
37 CallParams,
38 ConstructorReturnType,
39 CreateParams,
40 DelegateCall,
41 FromAddr,
42 LimitParamsV2,
43 utils::DecodeMessageResult,
44 },
45 engine::{
46 EnvInstance,
47 OnInstance,
48 },
49 event::{
50 Event,
51 TopicEncoder,
52 },
53 hash::{
54 CryptoHash,
55 HashOutput,
56 },
57 types::{
58 Environment,
59 Gas,
60 },
61};
62
63/// Returns the address of the caller of the executed contract.
64///
65/// # Errors
66///
67/// If the returned caller cannot be properly decoded.
68pub fn caller() -> Address {
69 <EnvInstance as OnInstance>::on_instance(TypedEnvBackend::caller)
70}
71
72/// Returns the transferred value for the contract execution.
73///
74/// # Errors
75///
76/// If the returned value cannot be properly decoded.
77pub fn transferred_value() -> U256 {
78 <EnvInstance as OnInstance>::on_instance(|instance| {
79 TypedEnvBackend::transferred_value(instance)
80 })
81}
82
83/// Returns the price for the specified amount of gas.
84///
85/// # Errors
86///
87/// If the returned value cannot be properly decoded.
88pub fn weight_to_fee<E>(gas: Gas) -> E::Balance
89where
90 E: Environment,
91{
92 <EnvInstance as OnInstance>::on_instance(|instance| {
93 TypedEnvBackend::weight_to_fee::<E>(instance, gas)
94 })
95}
96
97/// Returns the current block timestamp.
98///
99/// # Errors
100///
101/// If the returned value cannot be properly decoded.
102pub fn block_timestamp<E>() -> E::Timestamp
103where
104 E: Environment,
105{
106 <EnvInstance as OnInstance>::on_instance(|instance| {
107 TypedEnvBackend::block_timestamp::<E>(instance)
108 })
109}
110
111/// Returns the account ID of the executed contract.
112///
113/// # Note
114///
115/// This method was formerly known as `address`.
116///
117/// # Errors
118///
119/// If the returned value cannot be properly decoded.
120pub fn account_id<E>() -> E::AccountId
121where
122 E: Environment,
123{
124 <EnvInstance as OnInstance>::on_instance(|instance| {
125 TypedEnvBackend::account_id::<E>(instance)
126 })
127}
128
129/// Returns the address of the executed contract.
130///
131/// # Errors
132///
133/// If the returned value cannot be properly decoded.
134pub fn address() -> Address {
135 <EnvInstance as OnInstance>::on_instance(|instance| {
136 TypedEnvBackend::address(instance)
137 })
138}
139
140/// Returns the balance of the executed contract.
141///
142/// # Errors
143///
144/// If the returned value cannot be properly decoded.
145pub fn balance() -> U256 {
146 <EnvInstance as OnInstance>::on_instance(|instance| {
147 TypedEnvBackend::balance(instance)
148 })
149}
150
151/// Returns the current block number.
152///
153/// # Errors
154///
155/// If the returned value cannot be properly decoded.
156pub fn block_number<E>() -> E::BlockNumber
157where
158 E: Environment,
159{
160 <EnvInstance as OnInstance>::on_instance(|instance| {
161 TypedEnvBackend::block_number::<E>(instance)
162 })
163}
164
165/// Returns the minimum balance that is required for creating an account
166/// (i.e. the chain's existential deposit).
167///
168/// # Errors
169///
170/// If the returned value cannot be properly decoded.
171pub fn minimum_balance() -> U256 {
172 <EnvInstance as OnInstance>::on_instance(|instance| {
173 TypedEnvBackend::minimum_balance(instance)
174 })
175}
176
177/// Emits an event with the given event data.
178pub fn emit_event<Evt, Abi>(event: &Evt)
179where
180 Evt: Event<Abi>,
181 Abi: TopicEncoder,
182{
183 <EnvInstance as OnInstance>::on_instance(|instance| {
184 TypedEnvBackend::emit_event::<Evt, Abi>(instance, event)
185 })
186}
187
188/// Writes the value to the contract storage under the given storage key and returns the
189/// size of pre-existing value if any.
190///
191/// # Panics
192///
193/// - If the encode length of value exceeds the configured maximum value length of a
194/// storage entry.
195pub fn set_contract_storage<K, V>(key: &K, value: &V) -> Option<u32>
196where
197 K: scale::Encode,
198 V: Storable,
199{
200 <EnvInstance as OnInstance>::on_instance(|instance| {
201 EnvBackend::set_contract_storage::<K, V>(instance, key, value)
202 })
203}
204
205/// Returns the value stored under the given storage key in the contract's storage if any.
206///
207/// # Errors
208///
209/// - If the decoding of the typed value failed (`KeyNotFound`)
210pub fn get_contract_storage<K, R>(key: &K) -> Result<Option<R>>
211where
212 K: scale::Encode,
213 R: Storable,
214{
215 <EnvInstance as OnInstance>::on_instance(|instance| {
216 EnvBackend::get_contract_storage::<K, R>(instance, key)
217 })
218}
219
220/// Removes the `value` at `key`, returning the previous `value` at `key` from storage.
221///
222/// # Errors
223///
224/// - If the decoding of the typed value failed (`KeyNotFound`)
225pub fn take_contract_storage<K, R>(key: &K) -> Result<Option<R>>
226where
227 K: scale::Encode,
228 R: Storable,
229{
230 <EnvInstance as OnInstance>::on_instance(|instance| {
231 EnvBackend::take_contract_storage::<K, R>(instance, key)
232 })
233}
234
235/// Checks whether there is a value stored under the given storage key in the contract's
236/// storage.
237///
238/// If a value is stored under the specified key, the size of the value is returned.
239pub fn contains_contract_storage<K>(key: &K) -> Option<u32>
240where
241 K: scale::Encode,
242{
243 <EnvInstance as OnInstance>::on_instance(|instance| {
244 EnvBackend::contains_contract_storage::<K>(instance, key)
245 })
246}
247
248/// Clears the contract's storage entry under the given storage key.
249///
250/// If a value was stored under the specified storage key, the size of the value is
251/// returned.
252pub fn clear_contract_storage<K>(key: &K) -> Option<u32>
253where
254 K: scale::Encode,
255{
256 <EnvInstance as OnInstance>::on_instance(|instance| {
257 EnvBackend::clear_contract_storage::<K>(instance, key)
258 })
259}
260
261/// Invokes a contract message and returns its result.
262///
263/// # Note
264///
265/// **This will call into the latest version of the host function which allows setting new
266/// weight and storage limit parameters.**
267///
268/// This is a low level way to evaluate another smart contract.
269/// Prefer to use the ink! guided and type safe approach to using this.
270///
271/// # Errors
272///
273/// - If the called account does not exist.
274/// - If the called account is not a contract.
275/// - If arguments passed to the called contract message are invalid.
276/// - If the called contract execution has trapped.
277/// - If the called contract ran out of gas, proof size, or storage deposit upon
278/// execution.
279/// - If the returned value failed to decode properly.
280pub fn invoke_contract<E, Args, R, Abi>(
281 params: &CallParams<E, Call, Args, R, Abi>,
282) -> Result<ink_primitives::MessageResult<R>>
283where
284 E: Environment,
285 Args: AbiEncodeWith<Abi>,
286 R: DecodeMessageResult<Abi>,
287{
288 <EnvInstance as OnInstance>::on_instance(|instance| {
289 TypedEnvBackend::invoke_contract::<E, Args, R, Abi>(instance, params)
290 })
291}
292
293/// Invokes a contract message via delegate call and returns its result.
294///
295/// # Note
296///
297/// This is a low level way to evaluate another smart contract via delegate call.
298/// Prefer to use the ink! guided and type safe approach to using this.
299///
300/// # Errors
301///
302/// - If the specified code hash does not exist.
303/// - If arguments passed to the called code message are invalid.
304/// - If the called code execution has trapped.
305pub fn invoke_contract_delegate<E, Args, R, Abi>(
306 params: &CallParams<E, DelegateCall, Args, R, Abi>,
307) -> Result<ink_primitives::MessageResult<R>>
308where
309 E: Environment,
310 Args: AbiEncodeWith<Abi>,
311 R: DecodeMessageResult<Abi>,
312{
313 <EnvInstance as OnInstance>::on_instance(|instance| {
314 TypedEnvBackend::invoke_contract_delegate::<E, Args, R, Abi>(instance, params)
315 })
316}
317
318/// Instantiates another contract.
319///
320/// # Note
321///
322/// This is a low level way to instantiate another smart contract, calling the latest
323/// `instantiate_v2` host function. // todo
324///
325/// Prefer to use methods on a `ContractRef` or the
326/// [`CreateBuilder`](`crate::call::CreateBuilder`)
327/// through [`build_create`](`crate::call::build_create`) instead.
328///
329/// # Errors
330///
331/// - If the code hash is invalid.
332/// - If the arguments passed to the instantiation process are invalid.
333/// - If the instantiation process traps.
334/// - If the instantiation process runs out of gas.
335/// - If given insufficient endowment.
336/// - If the returned account ID failed to decode properly.
337pub fn instantiate_contract<E, ContractRef, Args, R, Abi>(
338 params: &CreateParams<E, ContractRef, LimitParamsV2, Args, R, Abi>,
339) -> Result<
340 ink_primitives::ConstructorResult<
341 <R as ConstructorReturnType<ContractRef, Abi>>::Output,
342 >,
343>
344where
345 E: Environment,
346 ContractRef: FromAddr + crate::ContractReverseReference,
347 <ContractRef as crate::ContractReverseReference>::Type:
348 crate::reflect::ContractConstructorDecoder,
349 Args: AbiEncodeWith<Abi>,
350 R: ConstructorReturnType<ContractRef, Abi>,
351{
352 <EnvInstance as OnInstance>::on_instance(|instance| {
353 TypedEnvBackend::instantiate_contract::<E, ContractRef, Args, R, Abi>(
354 instance, params,
355 )
356 })
357}
358
359/// Terminates the existence of the currently executed smart contract.
360///
361/// This removes the calling account and transfers all remaining balance
362/// to the given beneficiary.
363///
364/// # Note
365///
366/// This function never returns. Either the termination was successful and the
367/// execution of the destroyed contract is halted. Or it failed during the termination
368/// which is considered fatal and results in a trap and rollback.
369#[cfg(feature = "unstable-hostfn")]
370pub fn terminate_contract(beneficiary: Address) -> ! {
371 <EnvInstance as OnInstance>::on_instance(|instance| {
372 TypedEnvBackend::terminate_contract(instance, beneficiary)
373 })
374}
375
376/// Transfers value from the contract to the destination account ID.
377///
378/// # Note
379///
380/// This is more efficient and simpler than the alternative to make a no-op
381/// contract call or invoke a runtime function that performs the
382/// transaction.
383///
384/// # Errors
385///
386/// - If the contract does not have sufficient free funds.
387/// - If the transfer had brought the sender's total balance below the minimum balance.
388/// You need to use `terminate_contract` in case this is your intention.
389pub fn transfer<E>(destination: Address, value: U256) -> Result<()>
390where
391 E: Environment,
392{
393 <EnvInstance as OnInstance>::on_instance(|instance| {
394 TypedEnvBackend::transfer::<E>(instance, destination, value)
395 })
396}
397
398/// Returns the execution input to the executed contract and decodes it as `T`.
399///
400/// # Note
401///
402/// - The input is the 4-bytes selector followed by the arguments of the called function
403/// in their SCALE encoded representation.
404/// - No prior interaction with the environment must take place before calling this
405/// procedure.
406///
407/// # Usage
408///
409/// Normally contracts define their own `enum` dispatch types respective
410/// to their exported constructors and messages that implement `scale::Decode`
411/// according to the constructors or messages selectors and their arguments.
412/// These `enum` dispatch types are then given to this procedure as the `T`.
413///
414/// When using ink! users do not have to construct those enum dispatch types
415/// themselves as they are normally generated by the ink! code generation
416/// automatically.
417///
418/// # Errors
419///
420/// If the given `T` cannot be properly decoded from the expected input.
421pub fn decode_input<T>() -> core::result::Result<T, DispatchError>
422where
423 T: DecodeDispatch,
424{
425 <EnvInstance as OnInstance>::on_instance(|instance| {
426 EnvBackend::decode_input::<T>(instance)
427 })
428}
429
430/// Returns the value back to the caller of the executed contract.
431///
432/// # Note
433///
434/// This function stops the execution of the contract immediately.
435#[cfg(not(feature = "std"))]
436pub fn return_value<R>(return_flags: ReturnFlags, return_value: &R) -> !
437where
438 R: scale::Encode,
439{
440 <EnvInstance as OnInstance>::on_instance(|instance| {
441 EnvBackend::return_value::<R>(instance, return_flags, return_value)
442 })
443}
444
445/// Returns the value back to the caller of the executed contract.
446///
447/// # Note
448///
449/// When the `std` feature is used, the contract is allowed to
450/// return normally. This feature should only be used for integration tests.
451#[cfg(feature = "std")]
452pub fn return_value<R>(return_flags: ReturnFlags, return_value: &R)
453where
454 R: scale::Encode,
455{
456 <EnvInstance as OnInstance>::on_instance(|instance| {
457 EnvBackend::return_value::<R>(instance, return_flags, return_value)
458 })
459}
460
461/// Returns the *Solidity ABI encoded* value back to the caller of the executed contract.
462///
463/// # Note
464///
465/// This function stops the execution of the contract immediately.
466pub fn return_value_solidity<R>(return_flags: ReturnFlags, return_value: &R) -> !
467where
468 R: for<'a> SolResultEncode<'a>,
469{
470 <EnvInstance as OnInstance>::on_instance(|instance| {
471 EnvBackend::return_value_solidity::<R>(instance, return_flags, return_value)
472 })
473}
474
475/// Conducts the crypto hash of the given input and stores the result in `output`.
476///
477/// # Example
478///
479/// ```
480/// use ink_env::hash::{
481/// HashOutput,
482/// Sha2x256,
483/// };
484/// let input: &[u8] = &[13, 14, 15];
485/// let mut output = <Sha2x256 as HashOutput>::Type::default(); // 256-bit buffer
486/// let hash = ink_env::hash_bytes::<Sha2x256>(input, &mut output);
487/// ```
488pub fn hash_bytes<H>(input: &[u8], output: &mut <H as HashOutput>::Type)
489where
490 H: CryptoHash,
491{
492 <EnvInstance as OnInstance>::on_instance(|instance| {
493 instance.hash_bytes::<H>(input, output)
494 })
495}
496
497/// Conducts the crypto hash of the given encoded input and stores the result in `output`.
498///
499/// # Example
500///
501/// ```
502/// # use ink_env::hash::{Sha2x256, HashOutput};
503/// const EXPECTED: [u8; 32] = [
504/// 243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248, 29, 136, 145, 115, 186,
505/// 134, 14, 175, 178, 99, 183, 21, 4, 94, 92, 69, 199, 207, 241, 179,
506/// ];
507/// let encodable = (42, "foo", true); // Implements `scale::Encode`
508/// let mut output = <Sha2x256 as HashOutput>::Type::default(); // 256-bit buffer
509/// ink_env::hash_encoded::<Sha2x256, _>(&encodable, &mut output);
510/// assert_eq!(output, EXPECTED);
511/// ```
512pub fn hash_encoded<H, T>(input: &T, output: &mut <H as HashOutput>::Type)
513where
514 H: CryptoHash,
515 T: scale::Encode,
516{
517 <EnvInstance as OnInstance>::on_instance(|instance| {
518 instance.hash_encoded::<H, T>(input, output)
519 })
520}
521
522/// Recovers the compressed ECDSA public key for given `signature` and `message_hash`,
523/// and stores the result in `output`.
524///
525/// # Example
526///
527/// ```
528/// const signature: [u8; 65] = [
529/// 195, 218, 227, 165, 226, 17, 25, 160, 37, 92, 142, 238, 4, 41, 244, 211, 18, 94,
530/// 131, 116, 231, 116, 255, 164, 252, 248, 85, 233, 173, 225, 26, 185, 119, 235,
531/// 137, 35, 204, 251, 134, 131, 186, 215, 76, 112, 17, 192, 114, 243, 102, 166, 176,
532/// 140, 180, 124, 213, 102, 117, 212, 89, 89, 92, 209, 116, 17, 28,
533/// ];
534/// const message_hash: [u8; 32] = [
535/// 167, 124, 116, 195, 220, 156, 244, 20, 243, 69, 1, 98, 189, 205, 79, 108, 213,
536/// 78, 65, 65, 230, 30, 17, 37, 184, 220, 237, 135, 1, 209, 101, 229,
537/// ];
538/// const EXPECTED_COMPRESSED_PUBLIC_KEY: [u8; 33] = [
539/// 3, 110, 192, 35, 209, 24, 189, 55, 218, 250, 100, 89, 40, 76, 222, 208, 202, 127,
540/// 31, 13, 58, 51, 242, 179, 13, 63, 19, 22, 252, 164, 226, 248, 98,
541/// ];
542/// let mut output = [0; 33];
543/// ink_env::ecdsa_recover(&signature, &message_hash, &mut output);
544/// assert_eq!(output, EXPECTED_COMPRESSED_PUBLIC_KEY);
545/// ```
546pub fn ecdsa_recover(
547 signature: &[u8; 65],
548 message_hash: &[u8; 32],
549 output: &mut [u8; 33],
550) -> Result<()> {
551 <EnvInstance as OnInstance>::on_instance(|instance| {
552 instance.ecdsa_recover(signature, message_hash, output)
553 })
554}
555
556/// Returns an Ethereum address from the ECDSA compressed public key.
557///
558/// # Example
559///
560/// ```
561/// let pub_key = [
562/// 3, 110, 192, 35, 209, 24, 189, 55, 218, 250, 100, 89, 40, 76, 222, 208, 202, 127,
563/// 31, 13, 58, 51, 242, 179, 13, 63, 19, 22, 252, 164, 226, 248, 98,
564/// ];
565/// let EXPECTED_ETH_ADDRESS = [
566/// 253, 240, 181, 194, 143, 66, 163, 109, 18, 211, 78, 49, 177, 94, 159, 79, 207,
567/// 37, 21, 191,
568/// ];
569/// let mut output = [0; 20];
570/// ink_env::ecdsa_to_eth_address(&pub_key, &mut output);
571/// assert_eq!(output, EXPECTED_ETH_ADDRESS);
572/// ```
573///
574/// # Errors
575///
576/// - If the ECDSA public key cannot be recovered from the provided public key.
577#[cfg(feature = "unstable-hostfn")]
578pub fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result<()> {
579 <EnvInstance as OnInstance>::on_instance(|instance| {
580 instance.ecdsa_to_eth_address(pubkey, output)
581 })
582}
583
584/// Verifies a sr25519 signature.
585///
586/// # Example
587///
588/// ```
589/// let signature: [u8; 64] = [
590/// 184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247,
591/// 99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83,
592/// 85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90,
593/// 255, 228, 54, 115, 63, 30, 207, 205, 131,
594/// ];
595/// let message: &[u8; 11] = b"hello world";
596/// let pub_key: [u8; 32] = [
597/// 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44,
598/// 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125,
599/// ];
600///
601/// let result = ink::env::sr25519_verify(&signature, message.as_slice(), &pub_key);
602/// assert!(result.is_ok())
603/// ```
604///
605/// # Errors
606///
607/// - If sr25519 signature cannot be verified.
608///
609/// **WARNING**: this function is from the [unstable interface](https://github.com/paritytech/substrate/tree/master/frame/contracts#unstable-interfaces),
610/// which is unsafe and normally is not available on production chains.
611#[cfg(feature = "unstable-hostfn")]
612pub fn sr25519_verify(
613 signature: &[u8; 64],
614 message: &[u8],
615 pub_key: &[u8; 32],
616) -> Result<()> {
617 <EnvInstance as OnInstance>::on_instance(|instance| {
618 instance.sr25519_verify(signature, message, pub_key)
619 })
620}
621
622/// Checks whether the specified account is a contract.
623///
624/// # Errors
625///
626/// If the returned value cannot be properly decoded.
627#[cfg(feature = "unstable-hostfn")]
628pub fn is_contract(account: &Address) -> bool {
629 <EnvInstance as OnInstance>::on_instance(|instance| {
630 TypedEnvBackend::is_contract(instance, account)
631 })
632}
633
634/// Retrieves the code hash of the contract at the specified account id.
635///
636/// # Errors
637///
638/// - If no code hash was found for the specified account id.
639/// - If the returned value cannot be properly decoded.
640pub fn code_hash(addr: &Address) -> Result<H256> {
641 <EnvInstance as OnInstance>::on_instance(|instance| {
642 TypedEnvBackend::code_hash(instance, addr)
643 })
644}
645
646/// Retrieves the code hash of the currently executing contract.
647///
648/// # Errors
649///
650/// If the returned value cannot be properly decoded.
651pub fn own_code_hash() -> Result<H256> {
652 <EnvInstance as OnInstance>::on_instance(|instance| {
653 TypedEnvBackend::own_code_hash(instance)
654 })
655}
656
657/// Checks whether the caller of the current contract is the origin of the whole call
658/// stack.
659///
660/// Prefer this over [`is_contract`] when checking whether your contract is being called
661/// by a contract or a plain account. The reason is that it performs better since it does
662/// not need to do any storage lookups.
663///
664/// A return value of `true` indicates that this contract is being called by a plain
665/// account. and `false` indicates that the caller is another contract.
666///
667/// # Errors
668///
669/// If the returned value cannot be properly decoded.
670pub fn caller_is_origin<E>() -> bool
671where
672 E: Environment,
673{
674 <EnvInstance as OnInstance>::on_instance(|instance| {
675 TypedEnvBackend::caller_is_origin::<E>(instance)
676 })
677}
678
679/// Checks whether the caller of the current contract is root.
680///
681/// Note that only the origin of the call stack can be root. Hence this function returning
682/// `true` implies that the contract is being called by the origin.
683///
684/// A return value of `true` indicates that this contract is being called by a root
685/// origin, and `false` indicates that the caller is a signed origin.
686///
687/// # Errors
688///
689/// If the returned value cannot be properly decoded.
690pub fn caller_is_root<E>() -> bool
691where
692 E: Environment,
693{
694 <EnvInstance as OnInstance>::on_instance(|instance| {
695 TypedEnvBackend::caller_is_root::<E>(instance)
696 })
697}
698
699/// Replace the contract code at the specified address with new code.
700///
701/// # Note
702///
703/// There are a few important considerations which must be taken into account when
704/// using this API:
705///
706/// 1. The storage at the code hash will remain untouched.
707///
708/// Contract developers **must ensure** that the storage layout of the new code is
709/// compatible with that of the old code.
710///
711/// 2. The contract address (`AccountId`) remains the same, while the `code_hash` changes.
712///
713/// Contract addresses are initially derived from `hash(deploying_address ++ code_hash ++
714/// salt)`. This makes it possible to determine a contracts address (`AccountId`) using
715/// the `code_hash` of the *initial* code used to instantiate the contract.
716///
717/// However, because `set_code_hash` can modify the underlying `code_hash` of a contract,
718/// it should not be relied upon that a contracts address can always be derived from its
719/// stored `code_hash`.
720///
721/// 3. Re-entrant calls use new `code_hash`.
722///
723/// If a contract calls into itself after changing its code the new call would use the new
724/// code. However, if the original caller panics after returning from the sub call it
725/// would revert the changes made by `set_code_hash` and the next caller would use the old
726/// code.
727///
728/// # Errors
729///
730/// todo: this enum variant no longer exists
731/// `ReturnCode::CodeNotFound` in case the supplied `code_hash` cannot be found on-chain.
732///
733/// # Storage Compatibility
734///
735/// When the smart contract code is modified,
736/// it is important to observe an additional virtual restriction
737/// that is imposed on this procedure:
738/// you should not change the order in which the contract state variables
739/// are declared, nor their type.
740///
741/// Violating the restriction will not prevent a successful compilation,
742/// but will result in the mix-up of values or failure to read the storage correctly.
743/// This can result in severe errors in the application utilizing the contract.
744///
745/// If the storage of your contract looks like this:
746///
747/// ```ignore
748/// #[ink(storage)]
749/// pub struct YourContract {
750/// x: u32,
751/// y: bool,
752/// }
753/// ```
754///
755/// The procedures listed below will make it invalid:
756///
757/// Changing the order of variables:
758///
759/// ```ignore
760/// #[ink(storage)]
761/// pub struct YourContract {
762/// y: bool,
763/// x: u32,
764/// }
765/// ```
766///
767/// Removing existing variable:
768///
769/// ```ignore
770/// #[ink(storage)]
771/// pub struct YourContract {
772/// x: u32,
773/// }
774/// ```
775///
776/// Changing type of a variable:
777///
778/// ```ignore
779/// #[ink(storage)]
780/// pub struct YourContract {
781/// x: u64,
782/// y: bool,
783/// }
784/// ```
785///
786/// Introducing a new variable before any of the existing ones:
787///
788/// ```ignore
789/// #[ink(storage)]
790/// pub struct YourContract {
791/// z: Vec<u32>,
792/// x: u32,
793/// y: bool,
794/// }
795/// ```
796///
797/// Please refer to the
798/// [Open Zeppelin docs](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#modifying-your-contracts)
799/// for more details and examples.
800#[cfg(feature = "unstable-hostfn")]
801pub fn set_code_hash<E>(code_hash: &H256) -> Result<()>
802where
803 E: Environment,
804{
805 <EnvInstance as OnInstance>::on_instance(|instance| instance.set_code_hash(code_hash))
806}
807
808/// Execute an XCM message locally, using the contract's address as the origin.
809///
810/// For more details consult the
811/// [host function documentation](https://paritytech.github.io/polkadot-sdk/master/pallet_contracts/api_doc/trait.Current.html#tymethod.xcm_execute).
812///
813/// # Errors
814///
815/// - If the message cannot be properly decoded on the `pallet-revive` side.
816/// - If the XCM execution fails because of the runtime's XCM configuration.
817///
818/// # Panics
819///
820/// Panics in the off-chain environment.
821#[cfg(feature = "unstable-hostfn")]
822pub fn xcm_execute<E, Call>(msg: &xcm::VersionedXcm<Call>) -> Result<()>
823where
824 E: Environment,
825 Call: scale::Encode,
826{
827 <EnvInstance as OnInstance>::on_instance(|instance| {
828 TypedEnvBackend::xcm_execute::<E, _>(instance, msg)
829 })
830}
831
832/// Send an XCM message, using the contract's address as the origin.
833///
834/// The `msg` argument has to be SCALE encoded, it needs to be decodable to a valid
835/// instance of the `RuntimeCall` enum.
836///
837/// For more details consult
838/// [host function documentation](https://paritytech.github.io/polkadot-sdk/master/pallet_contracts/api_doc/trait.Current.html#tymethod.xcm_send).
839///
840/// # Errors
841///
842/// - If the message cannot be properly decoded on the `pallet-revive` side.
843///
844/// # Panics
845///
846/// Panics in the off-chain environment.
847#[cfg(feature = "unstable-hostfn")]
848pub fn xcm_send<E, Call>(
849 dest: &xcm::VersionedLocation,
850 msg: &xcm::VersionedXcm<Call>,
851) -> Result<xcm::v4::XcmHash>
852where
853 E: Environment,
854 Call: scale::Encode,
855{
856 <EnvInstance as OnInstance>::on_instance(|instance| {
857 TypedEnvBackend::xcm_send::<E, _>(instance, dest, msg)
858 })
859}
860
861/// Returns the size of the buffer that is remaining in the backend.
862pub fn remaining_buffer() -> usize {
863 <EnvInstance as OnInstance>::on_instance(|instance| {
864 EnvBackend::remaining_buffer(instance)
865 })
866}