ink_primitives/
types.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
15use core::{
16    array::TryFromSliceError,
17    borrow::Borrow,
18};
19use derive_more::From;
20use primitive_types::{
21    H160,
22    U256,
23};
24use scale::{
25    Decode,
26    Encode,
27    MaxEncodedLen,
28};
29use sp_core::keccak_256;
30#[cfg(feature = "std")]
31use {
32    scale_decode::DecodeAsType,
33    scale_encode::EncodeAsType,
34    scale_info::TypeInfo,
35};
36
37use crate::arithmetic::{
38    AtLeast32BitUnsigned,
39    Saturating,
40};
41
42/// The default environment `AccountId` type.
43///
44/// # Note
45///
46/// This is a mirror of the `AccountId` type used in the default configuration
47/// of PALLET contracts.
48#[derive(
49    Debug,
50    Copy,
51    Clone,
52    PartialEq,
53    Eq,
54    Ord,
55    PartialOrd,
56    Hash,
57    Decode,
58    Encode,
59    MaxEncodedLen,
60    From,
61)]
62#[cfg_attr(feature = "std", derive(TypeInfo, DecodeAsType, EncodeAsType))]
63pub struct AccountId(pub [u8; 32]);
64
65impl AsRef<[u8; 32]> for AccountId {
66    #[inline]
67    fn as_ref(&self) -> &[u8; 32] {
68        &self.0
69    }
70}
71
72impl AsMut<[u8; 32]> for AccountId {
73    #[inline]
74    fn as_mut(&mut self) -> &mut [u8; 32] {
75        &mut self.0
76    }
77}
78
79impl AsRef<[u8]> for AccountId {
80    #[inline]
81    fn as_ref(&self) -> &[u8] {
82        &self.0[..]
83    }
84}
85
86impl AsMut<[u8]> for AccountId {
87    #[inline]
88    fn as_mut(&mut self) -> &mut [u8] {
89        &mut self.0[..]
90    }
91}
92
93impl<'a> TryFrom<&'a [u8]> for AccountId {
94    type Error = TryFromSliceError;
95
96    fn try_from(bytes: &'a [u8]) -> Result<Self, TryFromSliceError> {
97        let address = <[u8; 32]>::try_from(bytes)?;
98        Ok(Self(address))
99    }
100}
101
102impl Borrow<[u8; 32]> for AccountId {
103    fn borrow(&self) -> &[u8; 32] {
104        &self.0
105    }
106}
107
108/// A Solidity compatible `address` type.
109///
110/// # Note
111///
112/// This is a type alias for the `H160` type used for addresses in `pallet-revive`.
113// For rationale for using `H160` as the `address` type,
114// see https://github.com/use-ink/ink/pull/2441#discussion_r2021230718.
115pub type Address = H160;
116
117/// The default environment `Hash` type.
118///
119/// # Note
120///
121/// This is a mirror of the `Hash` type used in the default configuration
122/// of PALLET contracts.
123#[derive(
124    Debug,
125    Copy,
126    Clone,
127    PartialEq,
128    Eq,
129    Ord,
130    PartialOrd,
131    Hash,
132    Decode,
133    Encode,
134    MaxEncodedLen,
135    From,
136    Default,
137)]
138#[cfg_attr(feature = "std", derive(TypeInfo, DecodeAsType, EncodeAsType))]
139pub struct Hash([u8; 32]);
140
141impl<'a> TryFrom<&'a [u8]> for Hash {
142    type Error = TryFromSliceError;
143
144    fn try_from(bytes: &'a [u8]) -> Result<Self, TryFromSliceError> {
145        let hash = <[u8; 32]>::try_from(bytes)?;
146        Ok(Self(hash))
147    }
148}
149
150impl AsRef<[u8]> for Hash {
151    fn as_ref(&self) -> &[u8] {
152        &self.0[..]
153    }
154}
155
156impl AsMut<[u8]> for Hash {
157    fn as_mut(&mut self) -> &mut [u8] {
158        &mut self.0[..]
159    }
160}
161
162impl From<Hash> for [u8; 32] {
163    fn from(hash: Hash) -> Self {
164        hash.0
165    }
166}
167
168impl Borrow<[u8; 32]> for Hash {
169    fn borrow(&self) -> &[u8; 32] {
170        &self.0
171    }
172}
173
174/// The equivalent of `Zero` for hashes.
175///
176/// A hash that consists only of 0 bits is clear.
177pub trait Clear {
178    /// The clear hash.
179    const CLEAR_HASH: Self;
180
181    /// Returns `true` if the hash is clear.
182    fn is_clear(&self) -> bool;
183}
184
185impl Clear for [u8; 32] {
186    const CLEAR_HASH: Self = [0x00; 32];
187
188    fn is_clear(&self) -> bool {
189        self == &Self::CLEAR_HASH
190    }
191}
192
193impl Clear for Hash {
194    const CLEAR_HASH: Self = Self(<[u8; 32] as Clear>::CLEAR_HASH);
195
196    fn is_clear(&self) -> bool {
197        <[u8; 32] as Clear>::is_clear(&self.0)
198    }
199}
200
201// todo
202// impl Clear for H256 {
203// const CLEAR_HASH: Self = H256::CLEAR_HASH;
204//
205// fn is_clear(&self) -> bool {
206// self.as_bytes().iter().all(|&byte| byte == 0x00)
207// }
208// }
209
210#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode)]
211#[cfg_attr(
212    feature = "std",
213    derive(
214        scale_info::TypeInfo,
215        EncodeAsType,
216        serde::Serialize,
217        serde::Deserialize
218    )
219)]
220pub enum DepositLimit<Balance> {
221    /// Allows bypassing all balance transfer checks.
222    UnsafeOnlyForDryRun,
223
224    /// Specifies a maximum allowable balance for a deposit.
225    Balance(Balance),
226}
227
228impl<T> From<T> for DepositLimit<T> {
229    fn from(value: T) -> Self {
230        Self::Balance(value)
231    }
232}
233
234/// Allows to instantiate a type from its little-endian bytes representation.
235pub trait FromLittleEndian {
236    /// The little-endian bytes representation.
237    type Bytes: Default + AsRef<[u8]> + AsMut<[u8]>;
238
239    /// Create a new instance from the little-endian bytes representation.
240    fn from_le_bytes(bytes: Self::Bytes) -> Self;
241}
242
243impl FromLittleEndian for u8 {
244    type Bytes = [u8; 1];
245
246    #[inline]
247    fn from_le_bytes(bytes: Self::Bytes) -> Self {
248        u8::from_le_bytes(bytes)
249    }
250}
251
252impl FromLittleEndian for u16 {
253    type Bytes = [u8; 2];
254
255    #[inline]
256    fn from_le_bytes(bytes: Self::Bytes) -> Self {
257        u16::from_le_bytes(bytes)
258    }
259}
260
261impl FromLittleEndian for u32 {
262    type Bytes = [u8; 4];
263
264    #[inline]
265    fn from_le_bytes(bytes: Self::Bytes) -> Self {
266        u32::from_le_bytes(bytes)
267    }
268}
269
270impl FromLittleEndian for u64 {
271    type Bytes = [u8; 8];
272
273    #[inline]
274    fn from_le_bytes(bytes: Self::Bytes) -> Self {
275        u64::from_le_bytes(bytes)
276    }
277}
278
279impl FromLittleEndian for u128 {
280    type Bytes = [u8; 16];
281
282    #[inline]
283    fn from_le_bytes(bytes: Self::Bytes) -> Self {
284        u128::from_le_bytes(bytes)
285    }
286}
287
288impl FromLittleEndian for U256 {
289    type Bytes = [u8; 32];
290
291    #[inline]
292    fn from_le_bytes(bytes: Self::Bytes) -> Self {
293        U256::from_little_endian(&bytes)
294        //U256::from_le_bytes(bytes)
295    }
296}
297
298/// todo remove
299/// A trait to enforce that a type should be an [`Environment::AccountId`].
300///
301/// If you have an [`Environment`] which uses an [`Environment::AccountId`] type other
302/// than the ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html)
303/// you will need to implement this trait for your [`Environment::AccountId`] concrete
304/// type.
305pub trait AccountIdGuard {}
306
307/// The ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html)
308/// used in the [`DefaultEnvironment`].
309impl AccountIdGuard for AccountId {}
310
311impl AccountIdGuard for Address {}
312
313cfg_if::cfg_if! {
314    if #[cfg(feature = "std")] {
315        pub trait CodecAsType: scale_decode::DecodeAsType + scale_encode::EncodeAsType {}
316        impl<T: scale_decode::DecodeAsType + scale_encode::EncodeAsType> CodecAsType for T {}
317    } else {
318        pub trait CodecAsType {}
319        impl<T> CodecAsType for T {}
320    }
321}
322
323/// The environmental types usable by contracts defined with ink!.
324pub trait Environment: Clone {
325    /// The maximum number of supported event topics provided by the runtime.
326    ///
327    /// The value must match the maximum number of supported event topics of the used
328    /// runtime.
329    // TODO: (@davidsemakula) Remove, no longer configurable in `pallet-revive`.
330    const MAX_EVENT_TOPICS: usize;
331
332    /// The ratio between the decimal representation of the native `Balance` token
333    /// and the ETH token.
334    const NATIVE_TO_ETH_RATIO: u32;
335
336    /// The account id type.
337    type AccountId: 'static
338        + scale::Codec
339        + scale::MaxEncodedLen
340        + CodecAsType
341        + Clone
342        + PartialEq
343        + Eq
344        + Ord
345        + AsRef<[u8]>
346        + AsMut<[u8]>;
347
348    /// The type of balances.
349    type Balance: 'static
350        + scale::Codec
351        + CodecAsType
352        + Copy
353        + Clone
354        + PartialEq
355        + Eq
356        + AtLeast32BitUnsigned
357        + Into<U256>
358        + FromLittleEndian;
359
360    /// The type of hash.
361    type Hash: 'static
362        + scale::Codec
363        + scale::MaxEncodedLen
364        + CodecAsType
365        + Copy
366        + Clone
367        + Clear
368        + PartialEq
369        + Eq
370        + Ord
371        + AsRef<[u8]>
372        + AsMut<[u8]>;
373
374    /// The type of a timestamp.
375    type Timestamp: 'static
376        + scale::Codec
377        + CodecAsType
378        + Copy
379        + Clone
380        + PartialEq
381        + Eq
382        + AtLeast32BitUnsigned
383        + FromLittleEndian;
384
385    /// The type of block number.
386    type BlockNumber: 'static
387        + scale::Codec
388        + CodecAsType
389        + Copy
390        + Clone
391        + PartialEq
392        + Eq
393        + AtLeast32BitUnsigned
394        + FromLittleEndian;
395
396    /// The chain extension for the environment.
397    ///
398    /// This is a type that is defined through the `#[ink::chain_extension]` procedural
399    /// macro. For more information about usage and definition click
400    /// [this][chain_extension] link.
401    ///
402    /// [chain_extension]: https://use-ink.github.io/ink/ink/attr.chain_extension.html
403    type ChainExtension;
404
405    /// TODO comment
406    type EventRecord: 'static + scale::Codec;
407
408    /// Converts from the generic `Balance` type to the Ethereum native `U256`.
409    ///
410    /// # Developer Note
411    ///
412    /// `pallet-revive` uses both types, hence we have to convert in between them
413    /// for certain functions. Notice that precision loss might occur when converting
414    /// the other way (from `U256` to `Balance`).
415    ///
416    /// See <https://github.com/paritytech/polkadot-sdk/pull/9101> for more details.
417    fn native_to_eth(value: Self::Balance) -> U256 {
418        value
419            .saturating_mul(Self::NATIVE_TO_ETH_RATIO.into())
420            .into()
421    }
422}
423
424/// Placeholder for chains that have no defined chain extension.
425#[cfg_attr(feature = "std", derive(TypeInfo))]
426pub enum NoChainExtension {}
427
428/// The fundamental types of the default configuration.
429#[derive(Debug, Clone, PartialEq, Eq)]
430#[cfg_attr(feature = "std", derive(TypeInfo))]
431pub enum DefaultEnvironment {}
432
433impl Environment for DefaultEnvironment {
434    const MAX_EVENT_TOPICS: usize = 4;
435
436    // This number was chosen as it's also what `pallet-revive`
437    // chooses by default. It's also the number present in the
438    // `ink_sandbox` and the `ink-node`.
439    const NATIVE_TO_ETH_RATIO: u32 = 100_000_000;
440
441    type AccountId = AccountId;
442    type Balance = Balance;
443    type Hash = Hash;
444    type Timestamp = Timestamp;
445    type BlockNumber = BlockNumber;
446    type ChainExtension = NoChainExtension;
447    type EventRecord = EventRecord;
448}
449
450/// The default balance type.
451pub type Balance = u128;
452
453/// The default timestamp type.
454pub type Timestamp = u64;
455
456/// The default gas type.
457pub type Gas = u64;
458
459/// The default block number type.
460pub type BlockNumber = u32;
461
462// todo replace with ()
463#[derive(Encode, Decode, MaxEncodedLen, Debug)]
464pub struct RuntimeEvent();
465
466/// The default event record type.
467pub type EventRecord = EventRecordSpec<RuntimeEvent, Hash>;
468
469#[derive(Encode, Decode, Debug)]
470#[cfg_attr(feature = "std", derive(TypeInfo))]
471pub struct EventRecordSpec<E, H> {
472    /// The phase of the block it happened in.
473    pub phase: Phase,
474    /// The event itself.
475    pub event: E,
476    /// The list of the topics this event has.
477    pub topics: ink_prelude::vec::Vec<H>,
478}
479
480/// A phase of a block's execution.
481#[derive(Debug, Encode, Decode, MaxEncodedLen)]
482#[cfg_attr(feature = "std", derive(PartialEq, Eq, Clone, TypeInfo))]
483pub enum Phase {
484    /// Applying an extrinsic.
485    ApplyExtrinsic(u32),
486    /// Finalizing the block.
487    Finalization,
488    /// Initializing the block.
489    Initialization,
490}
491
492/// The type of origins supported by `pallet-revive`.
493#[derive(Clone, ::scale::Encode, ::scale::Decode, PartialEq)]
494#[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))]
495pub enum Origin<E: Environment> {
496    Root,
497    Signed(E::AccountId),
498}
499
500pub struct AccountIdMapper {}
501impl AccountIdMapper {
502    pub fn to_address(account_id: &[u8]) -> Address {
503        let mut account_bytes: [u8; 32] = [0u8; 32];
504        account_bytes.copy_from_slice(&account_id[..32]);
505        if Self::is_eth_derived(account_id) {
506            // this was originally an eth address
507            // we just strip the 0xEE suffix to get the original address
508            Address::from_slice(&account_bytes[..20])
509        } else {
510            // this is an (ed|sr)25510 derived address
511            // avoid truncating the public key by hashing it first
512            let account_hash = keccak_256(account_bytes.as_ref());
513            Address::from_slice(&account_hash[12..])
514        }
515    }
516
517    /// Returns true if the passed account id is controlled by an Ethereum key.
518    ///
519    /// This is a stateless check that just compares the last 12 bytes. Please note that
520    /// it is theoretically possible to create an ed25519 keypair that passed this
521    /// filter. However, this can't be used for an attack. It also won't happen by
522    /// accident since everybody is using sr25519 where this is not a valid public key.
523    fn is_eth_derived(account_bytes: &[u8]) -> bool {
524        account_bytes[20..] == [0xEE; 12]
525    }
526}