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