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/// Allows to instantiate a type from its little-endian bytes representation.
211pub trait FromLittleEndian {
212    /// The little-endian bytes representation.
213    type Bytes: Default + AsRef<[u8]> + AsMut<[u8]>;
214
215    /// Create a new instance from the little-endian bytes representation.
216    fn from_le_bytes(bytes: Self::Bytes) -> Self;
217}
218
219impl FromLittleEndian for u8 {
220    type Bytes = [u8; 1];
221
222    #[inline]
223    fn from_le_bytes(bytes: Self::Bytes) -> Self {
224        u8::from_le_bytes(bytes)
225    }
226}
227
228impl FromLittleEndian for u16 {
229    type Bytes = [u8; 2];
230
231    #[inline]
232    fn from_le_bytes(bytes: Self::Bytes) -> Self {
233        u16::from_le_bytes(bytes)
234    }
235}
236
237impl FromLittleEndian for u32 {
238    type Bytes = [u8; 4];
239
240    #[inline]
241    fn from_le_bytes(bytes: Self::Bytes) -> Self {
242        u32::from_le_bytes(bytes)
243    }
244}
245
246impl FromLittleEndian for u64 {
247    type Bytes = [u8; 8];
248
249    #[inline]
250    fn from_le_bytes(bytes: Self::Bytes) -> Self {
251        u64::from_le_bytes(bytes)
252    }
253}
254
255impl FromLittleEndian for u128 {
256    type Bytes = [u8; 16];
257
258    #[inline]
259    fn from_le_bytes(bytes: Self::Bytes) -> Self {
260        u128::from_le_bytes(bytes)
261    }
262}
263
264impl FromLittleEndian for U256 {
265    type Bytes = [u8; 32];
266
267    #[inline]
268    fn from_le_bytes(bytes: Self::Bytes) -> Self {
269        U256::from_little_endian(&bytes)
270        //U256::from_le_bytes(bytes)
271    }
272}
273
274/// todo remove
275/// A trait to enforce that a type should be an [`Environment::AccountId`].
276///
277/// If you have an [`Environment`] which uses an [`Environment::AccountId`] type other
278/// than the ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html)
279/// you will need to implement this trait for your [`Environment::AccountId`] concrete
280/// type.
281pub trait AccountIdGuard {}
282
283/// The ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html)
284/// used in the [`DefaultEnvironment`].
285impl AccountIdGuard for AccountId {}
286
287impl AccountIdGuard for Address {}
288
289cfg_if::cfg_if! {
290    if #[cfg(feature = "std")] {
291        pub trait CodecAsType: scale_decode::DecodeAsType + scale_encode::EncodeAsType {}
292        impl<T: scale_decode::DecodeAsType + scale_encode::EncodeAsType> CodecAsType for T {}
293    } else {
294        pub trait CodecAsType {}
295        impl<T> CodecAsType for T {}
296    }
297}
298
299/// The environmental types usable by contracts defined with ink!.
300///
301/// The types and consts in this trait must be the same as the chain to which
302/// the contract is deployed to. We have a mechanism in `cargo-contract` that
303/// attempts to check for type equality, but not everything can be compared.
304pub trait Environment: Clone {
305    /// The ratio between the decimal representation of the native `Balance` token
306    /// and the ETH token.
307    const NATIVE_TO_ETH_RATIO: u32;
308
309    /// The account id type.
310    type AccountId: 'static
311        + scale::Codec
312        + scale::MaxEncodedLen
313        + CodecAsType
314        + Clone
315        + PartialEq
316        + Eq
317        + Ord
318        + AsRef<[u8]>
319        + AsMut<[u8]>;
320
321    /// The type of balances.
322    type Balance: 'static
323        + scale::Codec
324        + CodecAsType
325        + Copy
326        + Clone
327        + PartialEq
328        + Eq
329        + AtLeast32BitUnsigned
330        + Into<U256>
331        + FromLittleEndian;
332
333    /// The type of hash.
334    type Hash: 'static
335        + scale::Codec
336        + scale::MaxEncodedLen
337        + CodecAsType
338        + Copy
339        + Clone
340        + Clear
341        + PartialEq
342        + Eq
343        + Ord
344        + AsRef<[u8]>
345        + AsMut<[u8]>;
346
347    /// The type of a timestamp.
348    type Timestamp: 'static
349        + scale::Codec
350        + CodecAsType
351        + Copy
352        + Clone
353        + PartialEq
354        + Eq
355        + AtLeast32BitUnsigned
356        + FromLittleEndian;
357
358    /// The type of block number.
359    type BlockNumber: 'static
360        + scale::Codec
361        + CodecAsType
362        + Copy
363        + Clone
364        + PartialEq
365        + Eq
366        + AtLeast32BitUnsigned
367        + FromLittleEndian;
368
369    /// TODO comment
370    type EventRecord: 'static + scale::Codec;
371
372    /// Converts from the generic `Balance` type to the Ethereum native `U256`.
373    ///
374    /// # Developer Note
375    ///
376    /// `pallet-revive` uses both types, hence we have to convert in between them
377    /// for certain functions. Notice that precision loss might occur when converting
378    /// the other way (from `U256` to `Balance`).
379    ///
380    /// See <https://github.com/paritytech/polkadot-sdk/pull/9101> for more details.
381    fn native_to_eth(value: Self::Balance) -> U256 {
382        value
383            .saturating_mul(Self::NATIVE_TO_ETH_RATIO.into())
384            .into()
385    }
386}
387
388/// The fundamental types of the default configuration.
389#[derive(Debug, Clone, PartialEq, Eq)]
390#[cfg_attr(feature = "std", derive(TypeInfo))]
391pub enum DefaultEnvironment {}
392
393impl Environment for DefaultEnvironment {
394    // This number was chosen as it's also what `pallet-revive`
395    // chooses by default. It's also the number present in the
396    // `ink_sandbox` and the `ink-node`.
397    const NATIVE_TO_ETH_RATIO: u32 = 100_000_000;
398
399    type AccountId = AccountId;
400    type Balance = Balance;
401    type Hash = Hash;
402    type Timestamp = Timestamp;
403    type BlockNumber = BlockNumber;
404    type EventRecord = EventRecord;
405}
406
407/// The default balance type.
408pub type Balance = u128;
409
410/// The default timestamp type.
411pub type Timestamp = u64;
412
413/// The default gas type.
414pub type Gas = u64;
415
416/// The default block number type.
417pub type BlockNumber = u32;
418
419// todo replace with ()
420#[derive(Encode, Decode, MaxEncodedLen, Debug)]
421pub struct RuntimeEvent();
422
423/// The default event record type.
424pub type EventRecord = EventRecordSpec<RuntimeEvent, Hash>;
425
426#[derive(Encode, Decode, Debug)]
427#[cfg_attr(feature = "std", derive(TypeInfo))]
428pub struct EventRecordSpec<E, H> {
429    /// The phase of the block it happened in.
430    pub phase: Phase,
431    /// The event itself.
432    pub event: E,
433    /// The list of the topics this event has.
434    pub topics: ink_prelude::vec::Vec<H>,
435}
436
437/// A phase of a block's execution.
438#[derive(Debug, Encode, Decode, MaxEncodedLen)]
439#[cfg_attr(feature = "std", derive(PartialEq, Eq, Clone, TypeInfo))]
440pub enum Phase {
441    /// Applying an extrinsic.
442    ApplyExtrinsic(u32),
443    /// Finalizing the block.
444    Finalization,
445    /// Initializing the block.
446    Initialization,
447}
448
449/// The type of origins supported by `pallet-revive`.
450#[derive(Clone, ::scale::Encode, ::scale::Decode, PartialEq)]
451#[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))]
452pub enum Origin<E: Environment> {
453    Root,
454    Signed(E::AccountId),
455}
456
457/// Copied from `pallet-revive`.
458pub struct AccountIdMapper {}
459impl AccountIdMapper {
460    pub fn to_address(account_id: &[u8]) -> Address {
461        let mut account_bytes: [u8; 32] = [0u8; 32];
462        account_bytes.copy_from_slice(&account_id[..32]);
463        if Self::is_eth_derived(account_id) {
464            // this was originally an eth address
465            // we just strip the 0xEE suffix to get the original address
466            Address::from_slice(&account_bytes[..20])
467        } else {
468            // this is an (ed|sr)25510 derived address
469            // avoid truncating the public key by hashing it first
470            let account_hash = keccak_256(account_bytes.as_ref());
471            Address::from_slice(&account_hash[12..])
472        }
473    }
474
475    /// Returns true if the passed account id is controlled by an Ethereum key.
476    ///
477    /// This is a stateless check that just compares the last 12 bytes. Please note that
478    /// it is theoretically possible to create an ed25519 keypair that passed this
479    /// filter. However, this can't be used for an attack. It also won't happen by
480    /// accident since everybody is using sr25519 where this is not a valid public key.
481    fn is_eth_derived(account_bytes: &[u8]) -> bool {
482        account_bytes[20..] == [0xEE; 12]
483    }
484}