12345678910111213141516171819use alloc::format;20use sp_std::{vec, vec::Vec};21use evm_coder::{AbiCoder, types::Address};22pub use pallet_evm::{Config, account::CrossAccountId};23use sp_core::{H160, U256};24use up_data_structs::CollectionId;25262728const ETH_COLLECTION_PREFIX: [u8; 16] = [29 0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,30];313233pub fn map_eth_to_id(eth: &Address) -> Option<CollectionId> {34 if eth[0..16] != ETH_COLLECTION_PREFIX {35 return None;36 }37 let mut id_bytes = [0; 4];38 id_bytes.copy_from_slice(ð[16..20]);39 Some(CollectionId(u32::from_be_bytes(id_bytes)))40}414243pub fn collection_id_to_address(id: CollectionId) -> Address {44 let mut out = [0; 20];45 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);46 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));47 H160(out)48}495051pub fn is_collection(address: &Address) -> bool {52 address[0..16] == ETH_COLLECTION_PREFIX53}545556pub fn convert_uint256_to_cross_account<T: Config>(from: U256) -> T::CrossAccountId57where58 T::AccountId: From<[u8; 32]>,59{60 let mut new_admin_arr = [0_u8; 32];61 from.to_big_endian(&mut new_admin_arr);62 let account_id = T::AccountId::from(new_admin_arr);63 T::CrossAccountId::from_sub(account_id)64}656667#[derive(Debug, Default, AbiCoder)]68pub struct CrossAddress {69 pub(crate) eth: Address,70 pub(crate) sub: U256,71}7273impl CrossAddress {74 75 pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self76 where77 T: pallet_evm::Config,78 T::AccountId: AsRef<[u8; 32]>,79 {80 if cross_account_id.is_canonical_substrate() {81 Self::from_sub::<T>(cross_account_id.as_sub())82 } else {83 Self {84 eth: *cross_account_id.as_eth(),85 sub: Default::default(),86 }87 }88 }89 90 pub fn from_sub<T>(account_id: &T::AccountId) -> Self91 where92 T: pallet_evm::Config,93 T::AccountId: AsRef<[u8; 32]>,94 {95 Self {96 eth: Default::default(),97 sub: U256::from_big_endian(account_id.as_ref()),98 }99 }100 101 pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>102 where103 T: pallet_evm::Config,104 T::AccountId: From<[u8; 32]>,105 {106 if self.eth == Default::default() && self.sub == Default::default() {107 Err("All fields of cross account is zeroed".into())108 } else if self.eth == Default::default() {109 Ok(convert_uint256_to_cross_account::<T>(self.sub))110 } else if self.sub == Default::default() {111 Ok(T::CrossAccountId::from_eth(self.eth))112 } else {113 Err("All fields of cross account is non zeroed".into())114 }115 }116}117118119#[derive(Debug, Default, AbiCoder)]120pub struct Property {121 key: evm_coder::types::String,122 value: evm_coder::types::Bytes,123}124125impl TryFrom<up_data_structs::Property> for Property {126 type Error = evm_coder::execution::Error;127128 fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {129 let key = evm_coder::types::String::from_utf8(from.key.into())130 .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;131 let value = evm_coder::types::Bytes(from.value.to_vec());132 Ok(Property { key, value })133 }134}135136impl TryInto<up_data_structs::Property> for Property {137 type Error = evm_coder::execution::Error;138139 fn try_into(self) -> Result<up_data_structs::Property, Self::Error> {140 let key = <Vec<u8>>::from(self.key)141 .try_into()142 .map_err(|_| "key too large")?;143144 let value = self.value.0.try_into().map_err(|_| "value too large")?;145146 Ok(up_data_structs::Property { key, value })147 }148}149150151#[derive(Debug, Default, Clone, Copy, AbiCoder)]152#[repr(u8)]153pub enum CollectionLimitField {154 155 #[default]156 AccountTokenOwnership,157158 159 SponsoredDataSize,160161 162 SponsoredDataRateLimit,163164 165 TokenLimit,166167 168 SponsorTransferTimeout,169170 171 SponsorApproveTimeout,172173 174 OwnerCanTransfer,175176 177 OwnerCanDestroy,178179 180 TransferEnabled,181}182183184#[derive(Debug, Default, AbiCoder)]185pub struct CollectionLimit {186 field: CollectionLimitField,187 value: Option<U256>,188}189190impl CollectionLimit {191 192 pub fn new(field: CollectionLimitField, value: Option<u32>) -> Self {193 Self {194 field,195 value: match value {196 Some(value) => Some(value.into()),197 None => None,198 },199 }200 }201 202 pub fn has_value(&self) -> bool {203 self.value.is_some()204 }205}206207impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {208 type Error = evm_coder::execution::Error;209210 fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {211 let value = self212 .value213 .ok_or::<Self::Error>("can't convert `None` value to boolean".into())?;214 let value = Some(value.try_into().map_err(|error| {215 Self::Error::Revert(format!(216 "can't convert value to u32 \"{}\" because: \"{error}\"",217 value218 ))219 })?);220221 let convert_value_to_bool = || match value {222 Some(value) => match value {223 0 => Ok(Some(false)),224 1 => Ok(Some(true)),225 _ => {226 return Err(Self::Error::Revert(format!(227 "can't convert value to boolean \"{value}\""228 )))229 }230 },231 None => Ok(None),232 };233234 let mut limits = up_data_structs::CollectionLimits::default();235 match self.field {236 CollectionLimitField::AccountTokenOwnership => {237 limits.account_token_ownership_limit = value;238 }239 CollectionLimitField::SponsoredDataSize => {240 limits.sponsored_data_size = value;241 }242 CollectionLimitField::SponsoredDataRateLimit => {243 limits.sponsored_data_rate_limit = match value {244 Some(value) => Some(up_data_structs::SponsoringRateLimit::Blocks(value)),245 None => None,246 };247 }248 CollectionLimitField::TokenLimit => {249 limits.token_limit = value;250 }251 CollectionLimitField::SponsorTransferTimeout => {252 limits.sponsor_transfer_timeout = value;253 }254 CollectionLimitField::SponsorApproveTimeout => {255 limits.sponsor_approve_timeout = value;256 }257 CollectionLimitField::OwnerCanTransfer => {258 limits.owner_can_transfer = convert_value_to_bool()?;259 }260 CollectionLimitField::OwnerCanDestroy => {261 limits.owner_can_destroy = convert_value_to_bool()?;262 }263 CollectionLimitField::TransferEnabled => {264 limits.transfers_enabled = convert_value_to_bool()?;265 }266 };267 Ok(limits)268 }269}270271272#[derive(Default, Debug, Clone, Copy, AbiCoder)]273#[repr(u8)]274pub enum CollectionPermissionField {275 276 #[default]277 TokenOwner,278279 280 CollectionAdmin,281}282283284#[derive(AbiCoder, Copy, Clone, Default, Debug)]285#[repr(u8)]286pub enum TokenPermissionField {287 288 #[default]289 Mutable,290291 292 TokenOwner,293294 295 CollectionAdmin,296}297298299#[derive(Debug, Default, AbiCoder)]300pub struct PropertyPermission {301 302 code: TokenPermissionField,303 304 value: bool,305}306307impl PropertyPermission {308 309 pub fn into_vec(pp: up_data_structs::PropertyPermission) -> Vec<Self> {310 vec![311 PropertyPermission {312 code: TokenPermissionField::Mutable,313 value: pp.mutable,314 },315 PropertyPermission {316 code: TokenPermissionField::TokenOwner,317 value: pp.token_owner,318 },319 PropertyPermission {320 code: TokenPermissionField::CollectionAdmin,321 value: pp.collection_admin,322 },323 ]324 }325326 327 pub fn from_vec(permission: Vec<Self>) -> up_data_structs::PropertyPermission {328 let mut token_permission = up_data_structs::PropertyPermission::default();329330 for PropertyPermission { code, value } in permission {331 match code {332 TokenPermissionField::Mutable => token_permission.mutable = value,333 TokenPermissionField::TokenOwner => token_permission.token_owner = value,334 TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value,335 }336 }337 token_permission338 }339}340341342#[derive(Debug, Default, AbiCoder)]343pub struct TokenPropertyPermission {344 345 key: evm_coder::types::String,346 347 permissions: Vec<PropertyPermission>,348}349350impl351 From<(352 up_data_structs::PropertyKey,353 up_data_structs::PropertyPermission,354 )> for TokenPropertyPermission355{356 fn from(357 value: (358 up_data_structs::PropertyKey,359 up_data_structs::PropertyPermission,360 ),361 ) -> Self {362 let (key, permission) = value;363 let key = evm_coder::types::String::from_utf8(key.into_inner())364 .expect("Stored key must be valid");365 let permissions = PropertyPermission::into_vec(permission);366 Self { key, permissions }367 }368}369370impl TokenPropertyPermission {371 372 pub fn into_property_key_permissions(373 permissions: Vec<TokenPropertyPermission>,374 ) -> evm_coder::execution::Result<Vec<up_data_structs::PropertyKeyPermission>> {375 let mut perms = Vec::new();376377 for TokenPropertyPermission { key, permissions } in permissions {378 let token_permission = PropertyPermission::from_vec(permissions);379380 perms.push(up_data_structs::PropertyKeyPermission {381 key: key.into_bytes().try_into().map_err(|_| "too long key")?,382 permission: token_permission,383 });384 }385 Ok(perms)386 }387}388389390#[derive(Debug, Default, AbiCoder)]391pub struct CollectionNesting {392 token_owner: bool,393 ids: Vec<U256>,394}395396impl CollectionNesting {397 398 pub fn new(token_owner: bool, ids: Vec<U256>) -> Self {399 Self { token_owner, ids }400 }401}402403404#[derive(Debug, Default, AbiCoder)]405pub struct CollectionNestingPermission {406 field: CollectionPermissionField,407 value: bool,408}409410impl CollectionNestingPermission {411 412 pub fn new(field: CollectionPermissionField, value: bool) -> Self {413 Self { field, value }414 }415}416417418#[derive(AbiCoder, Copy, Clone, Default, Debug)]419#[repr(u8)]420pub enum AccessMode {421 422 #[default]423 Normal,424 425 AllowList,426}427428impl From<up_data_structs::AccessMode> for AccessMode {429 fn from(value: up_data_structs::AccessMode) -> Self {430 match value {431 up_data_structs::AccessMode::Normal => AccessMode::Normal,432 up_data_structs::AccessMode::AllowList => AccessMode::AllowList,433 }434 }435}436437impl Into<up_data_structs::AccessMode> for AccessMode {438 fn into(self) -> up_data_structs::AccessMode {439 match self {440 AccessMode::Normal => up_data_structs::AccessMode::Normal,441 AccessMode::AllowList => up_data_structs::AccessMode::AllowList,442 }443 }444}