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