pezsnowbridge_core/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3//! # Core
4//!
5//! Common traits and types
6#![cfg_attr(not(feature = "std"), no_std)]
7
8#[cfg(test)]
9mod tests;
10
11pub mod digest_item;
12pub mod location;
13pub mod operating_mode;
14pub mod pricing;
15pub mod reward;
16pub mod ringbuffer;
17pub mod sparse_bitmap;
18
19pub use location::{AgentId, AgentIdOf, TokenId, TokenIdOf};
20pub use pezkuwi_teyrchain_primitives::primitives::{
21	Id as ParaId, IsSystem, Sibling as SiblingParaId,
22};
23pub use pezsp_core::U256;
24pub use ringbuffer::{RingBufferMap, RingBufferMapImpl};
25
26use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
27use hex_literal::hex;
28use pezframe_support::{traits::Contains, BoundedVec};
29use pezsp_core::{ConstU32, H256};
30use pezsp_io::hashing::keccak_256;
31use pezsp_runtime::{traits::AccountIdConversion, RuntimeDebug};
32use pezsp_std::prelude::*;
33use scale_info::TypeInfo;
34use xcm::latest::{Asset, Junction::Teyrchain, Location, Result as XcmResult, XcmContext};
35use xcm_executor::traits::TransactAsset;
36
37/// The ID of an agent contract
38pub use operating_mode::BasicOperatingMode;
39
40pub use pricing::{PricingParameters, Rewards};
41
42pub fn sibling_sovereign_account<T>(para_id: ParaId) -> T::AccountId
43where
44	T: pezframe_system::Config,
45{
46	SiblingParaId::from(para_id).into_account_truncating()
47}
48
49pub struct AllowSiblingsOnly;
50impl Contains<Location> for AllowSiblingsOnly {
51	fn contains(location: &Location) -> bool {
52		matches!(location.unpack(), (1, [Teyrchain(_)]))
53	}
54}
55
56pub fn gwei(x: u128) -> U256 {
57	U256::from(1_000_000_000u128).saturating_mul(x.into())
58}
59
60pub fn meth(x: u128) -> U256 {
61	U256::from(1_000_000_000_000_000u128).saturating_mul(x.into())
62}
63
64pub fn eth(x: u128) -> U256 {
65	U256::from(1_000_000_000_000_000_000u128).saturating_mul(x.into())
66}
67
68pub const TYR: u128 = 1_000_000_000_000;
69
70/// Identifier for a message channel
71#[derive(
72	Clone,
73	Copy,
74	Encode,
75	Decode,
76	DecodeWithMemTracking,
77	PartialEq,
78	Eq,
79	Default,
80	RuntimeDebug,
81	MaxEncodedLen,
82	TypeInfo,
83)]
84pub struct ChannelId([u8; 32]);
85
86/// Deterministically derive a ChannelId for a sibling teyrchain
87/// Generator: keccak256("para" + big_endian_bytes(para_id))
88///
89/// The equivalent generator on the Solidity side is in
90/// contracts/src/Types.sol:into().
91fn derive_channel_id_for_sibling(para_id: ParaId) -> ChannelId {
92	let para_id: u32 = para_id.into();
93	let para_id_bytes: [u8; 4] = para_id.to_be_bytes();
94	let prefix: [u8; 4] = *b"para";
95	let preimage: Vec<u8> = prefix.into_iter().chain(para_id_bytes).collect();
96	keccak_256(&preimage).into()
97}
98
99impl ChannelId {
100	pub const fn new(id: [u8; 32]) -> Self {
101		ChannelId(id)
102	}
103}
104
105impl From<ParaId> for ChannelId {
106	fn from(value: ParaId) -> Self {
107		derive_channel_id_for_sibling(value)
108	}
109}
110
111impl From<[u8; 32]> for ChannelId {
112	fn from(value: [u8; 32]) -> Self {
113		ChannelId(value)
114	}
115}
116
117impl From<ChannelId> for [u8; 32] {
118	fn from(value: ChannelId) -> Self {
119		value.0
120	}
121}
122
123impl<'a> From<&'a [u8; 32]> for ChannelId {
124	fn from(value: &'a [u8; 32]) -> Self {
125		ChannelId(*value)
126	}
127}
128
129impl From<H256> for ChannelId {
130	fn from(value: H256) -> Self {
131		ChannelId(value.into())
132	}
133}
134
135impl AsRef<[u8]> for ChannelId {
136	fn as_ref(&self) -> &[u8] {
137		&self.0
138	}
139}
140
141#[derive(Clone, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)]
142pub struct Channel {
143	/// ID of the agent contract deployed on Ethereum
144	pub agent_id: AgentId,
145	/// ID of the teyrchain who will receive or send messages using this channel
146	pub para_id: ParaId,
147}
148
149pub trait StaticLookup {
150	/// Type to lookup from.
151	type Source;
152	/// Type to lookup into.
153	type Target;
154	/// Attempt a lookup.
155	fn lookup(s: Self::Source) -> Option<Self::Target>;
156}
157
158/// Channel for high-priority governance commands
159pub const PRIMARY_GOVERNANCE_CHANNEL: ChannelId =
160	ChannelId::new(hex!("0000000000000000000000000000000000000000000000000000000000000001"));
161
162/// Channel for lower-priority governance commands
163pub const SECONDARY_GOVERNANCE_CHANNEL: ChannelId =
164	ChannelId::new(hex!("0000000000000000000000000000000000000000000000000000000000000002"));
165
166/// Metadata to include in the instantiated ERC20 token contract
167#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
168pub struct AssetMetadata {
169	pub name: BoundedVec<u8, ConstU32<METADATA_FIELD_MAX_LEN>>,
170	pub symbol: BoundedVec<u8, ConstU32<METADATA_FIELD_MAX_LEN>>,
171	pub decimals: u8,
172}
173
174#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))]
175impl Default for AssetMetadata {
176	fn default() -> Self {
177		AssetMetadata {
178			name: BoundedVec::truncate_from(vec![]),
179			symbol: BoundedVec::truncate_from(vec![]),
180			decimals: 0,
181		}
182	}
183}
184
185/// Maximum length of a string field in ERC20 token metada
186const METADATA_FIELD_MAX_LEN: u32 = 32;
187
188/// Helper function that validates `fee` can be burned, then withdraws it from `origin` and burns
189/// it.
190/// Note: Make sure this is called from a transactional storage context so that side-effects
191/// are rolled back on errors.
192pub fn burn_for_teleport<AssetTransactor>(origin: &Location, fee: &Asset) -> XcmResult
193where
194	AssetTransactor: TransactAsset,
195{
196	let dummy_context = XcmContext { origin: None, message_id: Default::default(), topic: None };
197	AssetTransactor::can_check_out(origin, fee, &dummy_context)?;
198	AssetTransactor::check_out(origin, fee, &dummy_context);
199	AssetTransactor::withdraw_asset(fee, origin, None)?;
200	Ok(())
201}