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!.
324///
325/// The types and consts in this trait must be the same as the chain to which
326/// the contract is deployed to. We have a mechanism in `cargo-contract` that
327/// attempts to check for type equality, but not everything can be compared.
328pub trait Environment: Clone {
329    /// The ratio between the decimal representation of the native `Balance` token
330    /// and the ETH token.
331    const NATIVE_TO_ETH_RATIO: u32;
332
333    /// The account id type.
334    type AccountId: 'static
335        + scale::Codec
336        + scale::MaxEncodedLen
337        + CodecAsType
338        + Clone
339        + PartialEq
340        + Eq
341        + Ord
342        + AsRef<[u8]>
343        + AsMut<[u8]>;
344
345    /// The type of balances.
346    type Balance: 'static
347        + scale::Codec
348        + CodecAsType
349        + Copy
350        + Clone
351        + PartialEq
352        + Eq
353        + AtLeast32BitUnsigned
354        + Into<U256>
355        + FromLittleEndian;
356
357    /// The type of hash.
358    type Hash: 'static
359        + scale::Codec
360        + scale::MaxEncodedLen
361        + CodecAsType
362        + Copy
363        + Clone
364        + Clear
365        + PartialEq
366        + Eq
367        + Ord
368        + AsRef<[u8]>
369        + AsMut<[u8]>;
370
371    /// The type of a timestamp.
372    type Timestamp: 'static
373        + scale::Codec
374        + CodecAsType
375        + Copy
376        + Clone
377        + PartialEq
378        + Eq
379        + AtLeast32BitUnsigned
380        + FromLittleEndian;
381
382    /// The type of block number.
383    type BlockNumber: 'static
384        + scale::Codec
385        + CodecAsType
386        + Copy
387        + Clone
388        + PartialEq
389        + Eq
390        + AtLeast32BitUnsigned
391        + FromLittleEndian;
392
393    /// TODO comment
394    type EventRecord: 'static + scale::Codec;
395
396    /// Converts from the generic `Balance` type to the Ethereum native `U256`.
397    ///
398    /// # Developer Note
399    ///
400    /// `pallet-revive` uses both types, hence we have to convert in between them
401    /// for certain functions. Notice that precision loss might occur when converting
402    /// the other way (from `U256` to `Balance`).
403    ///
404    /// See <https://github.com/paritytech/polkadot-sdk/pull/9101> for more details.
405    fn native_to_eth(value: Self::Balance) -> U256 {
406        value
407            .saturating_mul(Self::NATIVE_TO_ETH_RATIO.into())
408            .into()
409    }
410}
411
412/// The fundamental types of the default configuration.
413#[derive(Debug, Clone, PartialEq, Eq)]
414#[cfg_attr(feature = "std", derive(TypeInfo))]
415pub enum DefaultEnvironment {}
416
417impl Environment for DefaultEnvironment {
418    // This number was chosen as it's also what `pallet-revive`
419    // chooses by default. It's also the number present in the
420    // `ink_sandbox` and the `ink-node`.
421    const NATIVE_TO_ETH_RATIO: u32 = 100_000_000;
422
423    type AccountId = AccountId;
424    type Balance = Balance;
425    type Hash = Hash;
426    type Timestamp = Timestamp;
427    type BlockNumber = BlockNumber;
428    type EventRecord = EventRecord;
429}
430
431/// The default balance type.
432pub type Balance = u128;
433
434/// The default timestamp type.
435pub type Timestamp = u64;
436
437/// The default gas type.
438pub type Gas = u64;
439
440/// The default block number type.
441pub type BlockNumber = u32;
442
443// todo replace with ()
444#[derive(Encode, Decode, MaxEncodedLen, Debug)]
445pub struct RuntimeEvent();
446
447/// The default event record type.
448pub type EventRecord = EventRecordSpec<RuntimeEvent, Hash>;
449
450#[derive(Encode, Decode, Debug)]
451#[cfg_attr(feature = "std", derive(TypeInfo))]
452pub struct EventRecordSpec<E, H> {
453    /// The phase of the block it happened in.
454    pub phase: Phase,
455    /// The event itself.
456    pub event: E,
457    /// The list of the topics this event has.
458    pub topics: ink_prelude::vec::Vec<H>,
459}
460
461/// A phase of a block's execution.
462#[derive(Debug, Encode, Decode, MaxEncodedLen)]
463#[cfg_attr(feature = "std", derive(PartialEq, Eq, Clone, TypeInfo))]
464pub enum Phase {
465    /// Applying an extrinsic.
466    ApplyExtrinsic(u32),
467    /// Finalizing the block.
468    Finalization,
469    /// Initializing the block.
470    Initialization,
471}
472
473/// The type of origins supported by `pallet-revive`.
474#[derive(Clone, ::scale::Encode, ::scale::Decode, PartialEq)]
475#[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))]
476pub enum Origin<E: Environment> {
477    Root,
478    Signed(E::AccountId),
479}
480
481/// Copied from `pallet-revive`.
482pub struct AccountIdMapper {}
483impl AccountIdMapper {
484    pub fn to_address(account_id: &[u8]) -> Address {
485        let mut account_bytes: [u8; 32] = [0u8; 32];
486        account_bytes.copy_from_slice(&account_id[..32]);
487        if Self::is_eth_derived(account_id) {
488            // this was originally an eth address
489            // we just strip the 0xEE suffix to get the original address
490            Address::from_slice(&account_bytes[..20])
491        } else {
492            // this is an (ed|sr)25510 derived address
493            // avoid truncating the public key by hashing it first
494            let account_hash = keccak_256(account_bytes.as_ref());
495            Address::from_slice(&account_hash[12..])
496        }
497    }
498
499    /// Returns true if the passed account id is controlled by an Ethereum key.
500    ///
501    /// This is a stateless check that just compares the last 12 bytes. Please note that
502    /// it is theoretically possible to create an ed25519 keypair that passed this
503    /// filter. However, this can't be used for an attack. It also won't happen by
504    /// accident since everybody is using sr25519 where this is not a valid public key.
505    fn is_eth_derived(account_bytes: &[u8]) -> bool {
506        account_bytes[20..] == [0xEE; 12]
507    }
508}