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