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