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    /// ERC-20 Assets precompile index, for trust backed assets
310    /// (i.e. trust comes from the issuer).
311    const TRUST_BACKED_ASSETS_PRECOMPILE_INDEX: u16;
312
313    /// ERC-20 Assets precompile index, for pool assets
314    /// (i.e. trust comes from on-chain collateral accounting).
315    const POOL_ASSETS_PRECOMPILE_INDEX: u16;
316
317    /// The account id type.
318    type AccountId: 'static
319        + scale::Codec
320        + scale::MaxEncodedLen
321        + CodecAsType
322        + Clone
323        + PartialEq
324        + Eq
325        + Ord
326        + AsRef<[u8]>
327        + AsMut<[u8]>;
328
329    /// The type of balances.
330    type Balance: 'static
331        + scale::Codec
332        + CodecAsType
333        + Copy
334        + Clone
335        + PartialEq
336        + Eq
337        + AtLeast32BitUnsigned
338        + Into<U256>
339        + FromLittleEndian;
340
341    /// The type of hash.
342    type Hash: 'static
343        + scale::Codec
344        + scale::MaxEncodedLen
345        + CodecAsType
346        + Copy
347        + Clone
348        + Clear
349        + PartialEq
350        + Eq
351        + Ord
352        + AsRef<[u8]>
353        + AsMut<[u8]>;
354
355    /// The type of a timestamp.
356    type Timestamp: 'static
357        + scale::Codec
358        + CodecAsType
359        + Copy
360        + Clone
361        + PartialEq
362        + Eq
363        + AtLeast32BitUnsigned
364        + FromLittleEndian;
365
366    /// The type of block number.
367    type BlockNumber: 'static
368        + scale::Codec
369        + CodecAsType
370        + Copy
371        + Clone
372        + PartialEq
373        + Eq
374        + AtLeast32BitUnsigned
375        + FromLittleEndian;
376
377    /// TODO comment
378    type EventRecord: 'static + scale::Codec;
379
380    /// Converts from the generic `Balance` type to the Ethereum native `U256`.
381    ///
382    /// # Developer Note
383    ///
384    /// `pallet-revive` uses both types, hence we have to convert in between them
385    /// for certain functions. Notice that precision loss might occur when converting
386    /// the other way (from `U256` to `Balance`).
387    ///
388    /// See <https://github.com/paritytech/polkadot-sdk/pull/9101> for more details.
389    fn native_to_eth(value: Self::Balance) -> U256 {
390        value
391            .saturating_mul(Self::NATIVE_TO_ETH_RATIO.into())
392            .into()
393    }
394}
395
396/// The fundamental types of the default configuration.
397#[derive(Debug, Clone, PartialEq, Eq)]
398#[cfg_attr(feature = "std", derive(TypeInfo))]
399pub enum DefaultEnvironment {}
400
401impl Environment for DefaultEnvironment {
402    // This number was chosen as it's also what `pallet-revive`
403    // chooses by default. It's also the number present in the
404    // `ink_sandbox` and the `ink-node`.
405    const NATIVE_TO_ETH_RATIO: u32 = 100_000_000;
406
407    // These const's correspond to the settings of Asset Hub and
408    // `ink-node`.
409    const TRUST_BACKED_ASSETS_PRECOMPILE_INDEX: u16 = 0x0120;
410    const POOL_ASSETS_PRECOMPILE_INDEX: u16 = 0x0320;
411
412    type AccountId = AccountId;
413    type Balance = Balance;
414    type Hash = Hash;
415    type Timestamp = Timestamp;
416    type BlockNumber = BlockNumber;
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
470/// Copied from `pallet-revive`.
471pub struct AccountIdMapper {}
472impl AccountIdMapper {
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 everybody is using sr25519 where this is not a valid public key.
494    fn is_eth_derived(account_bytes: &[u8]) -> bool {
495        account_bytes[20..] == [0xEE; 12]
496    }
497}