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