12345678910111213141516171819use alloc::format;20use sp_std::{vec, vec::Vec};21use evm_coder::{22 AbiCoder,23 types::{uint256, address},24};25pub use pallet_evm::{Config, account::CrossAccountId};26use sp_core::H160;27use up_data_structs::CollectionId;28293031const ETH_COLLECTION_PREFIX: [u8; 16] = [32 0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,33];343536pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {37 if eth[0..16] != ETH_COLLECTION_PREFIX {38 return None;39 }40 let mut id_bytes = [0; 4];41 id_bytes.copy_from_slice(ð[16..20]);42 Some(CollectionId(u32::from_be_bytes(id_bytes)))43}444546pub fn collection_id_to_address(id: CollectionId) -> H160 {47 let mut out = [0; 20];48 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);49 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));50 H160(out)51}525354pub fn is_collection(address: &H160) -> bool {55 address[0..16] == ETH_COLLECTION_PREFIX56}575859pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId60where61 T::AccountId: From<[u8; 32]>,62{63 let mut new_admin_arr = [0_u8; 32];64 from.to_big_endian(&mut new_admin_arr);65 let account_id = T::AccountId::from(new_admin_arr);66 T::CrossAccountId::from_sub(account_id)67}686970#[derive(Debug, Default, AbiCoder)]71pub struct EthCrossAccount {72 pub(crate) eth: address,73 pub(crate) sub: uint256,74}7576impl EthCrossAccount {77 78 pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self79 where80 T: pallet_evm::Config,81 T::AccountId: AsRef<[u8; 32]>,82 {83 if cross_account_id.is_canonical_substrate() {84 Self::from_sub::<T>(cross_account_id.as_sub())85 } else {86 Self {87 eth: *cross_account_id.as_eth(),88 sub: Default::default(),89 }90 }91 }92 93 pub fn from_sub<T>(account_id: &T::AccountId) -> Self94 where95 T: pallet_evm::Config,96 T::AccountId: AsRef<[u8; 32]>,97 {98 Self {99 eth: Default::default(),100 sub: uint256::from_big_endian(account_id.as_ref()),101 }102 }103 104 pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>105 where106 T: pallet_evm::Config,107 T::AccountId: From<[u8; 32]>,108 {109 if self.eth == Default::default() && self.sub == Default::default() {110 Err("All fields of cross account is zeroed".into())111 } else if self.eth == Default::default() {112 Ok(convert_uint256_to_cross_account::<T>(self.sub))113 } else if self.sub == Default::default() {114 Ok(T::CrossAccountId::from_eth(self.eth))115 } else {116 Err("All fields of cross account is non zeroed".into())117 }118 }119}120121122#[derive(Debug, Default, AbiCoder)]123pub struct Property {124 125 pub key: evm_coder::types::string,126 127 pub value: evm_coder::types::bytes,128}129130131#[derive(Debug, Default, Clone, Copy, AbiCoder)]132#[repr(u8)]133pub enum CollectionLimitField {134 135 #[default]136 AccountTokenOwnership,137138 139 SponsoredDataSize,140141 142 SponsoredDataRateLimit,143144 145 TokenLimit,146147 148 SponsorTransferTimeout,149150 151 SponsorApproveTimeout,152153 154 OwnerCanTransfer,155156 157 OwnerCanDestroy,158159 160 TransferEnabled,161}162163#[derive(Debug, Default, AbiCoder)]164pub struct CollectionLimit {165 field: CollectionLimitField,166 status: bool,167 value: uint256,168}169170impl CollectionLimit {171 pub fn from_int(field: CollectionLimitField, value: u32) -> Self {172 Self {173 field,174 status: true,175 value: value.into(),176 }177 }178179 pub fn from_opt_int(field: CollectionLimitField, value: Option<u32>) -> Self {180 value181 .map(|v| Self {182 field,183 status: true,184 value: v.into(),185 })186 .unwrap_or(Self {187 field,188 status: false,189 value: Default::default(),190 })191 }192193 pub fn from_opt_bool(field: CollectionLimitField, value: Option<bool>) -> Self {194 value195 .map(|v| Self {196 field,197 status: true,198 value: if v {199 uint256::from(1)200 } else {201 Default::default()202 },203 })204 .unwrap_or(Self {205 field,206 status: false,207 value: Default::default(),208 })209 }210}211212impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {213 type Error = evm_coder::execution::Error;214215 fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {216 if !self.status {217 return Err(Self::Error::Revert("user can't disable limits".into()));218 }219220 let value = self.value.try_into().map_err(|error| {221 Self::Error::Revert(format!(222 "can't convert value to u32 \"{}\" because: \"{error}\"",223 self.value224 ))225 })?;226227 let convert_value_to_bool = || match value {228 0 => Ok(false),229 1 => Ok(true),230 _ => {231 return Err(Self::Error::Revert(format!(232 "can't convert value to boolean \"{value}\""233 )))234 }235 };236237 let mut limits = up_data_structs::CollectionLimits::default();238 match self.field {239 CollectionLimitField::AccountTokenOwnership => {240 limits.account_token_ownership_limit = Some(value);241 }242 CollectionLimitField::SponsoredDataSize => {243 limits.sponsored_data_size = Some(value);244 }245 CollectionLimitField::SponsoredDataRateLimit => {246 limits.sponsored_data_rate_limit =247 Some(up_data_structs::SponsoringRateLimit::Blocks(value));248 }249 CollectionLimitField::TokenLimit => {250 limits.token_limit = Some(value);251 }252 CollectionLimitField::SponsorTransferTimeout => {253 limits.sponsor_transfer_timeout = Some(value);254 }255 CollectionLimitField::SponsorApproveTimeout => {256 limits.sponsor_approve_timeout = Some(value);257 }258 CollectionLimitField::OwnerCanTransfer => {259 limits.owner_can_transfer = Some(convert_value_to_bool()?);260 }261 CollectionLimitField::OwnerCanDestroy => {262 limits.owner_can_destroy = Some(convert_value_to_bool()?);263 }264 CollectionLimitField::TransferEnabled => {265 limits.transfers_enabled = Some(convert_value_to_bool()?);266 }267 };268 Ok(limits)269 }270}271272273#[derive(Default, Debug, Clone, Copy, AbiCoder)]274#[repr(u8)]275pub enum CollectionPermissions {276 277 #[default]278 TokenOwner,279280 281 CollectionAdmin,282}283284285#[derive(AbiCoder, Copy, Clone, Default, Debug)]286#[repr(u8)]287pub enum TokenPermissionField {288 289 #[default]290 Mutable,291292 293 TokenOwner,294295 296 CollectionAdmin,297}298299300#[derive(Debug, Default, AbiCoder)]301pub struct PropertyPermission {302 303 code: TokenPermissionField,304 305 value: bool,306}307308impl PropertyPermission {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 pub fn from_vec(permission: Vec<Self>) -> up_data_structs::PropertyPermission {327 let mut token_permission = up_data_structs::PropertyPermission::default();328329 for PropertyPermission { code, value } in permission {330 match code {331 TokenPermissionField::Mutable => token_permission.mutable = value,332 TokenPermissionField::TokenOwner => token_permission.token_owner = value,333 TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value,334 }335 }336 token_permission337 }338}339340341#[derive(Debug, Default, AbiCoder)]342pub struct TokenPropertyPermission {343 344 key: evm_coder::types::string,345 346 permissions: Vec<PropertyPermission>,347}348349impl350 From<(351 up_data_structs::PropertyKey,352 up_data_structs::PropertyPermission,353 )> for TokenPropertyPermission354{355 fn from(356 value: (357 up_data_structs::PropertyKey,358 up_data_structs::PropertyPermission,359 ),360 ) -> Self {361 let (key, permission) = value;362 let key = evm_coder::types::string::from_utf8(key.into_inner())363 .expect("Stored key must be valid");364 let permissions = PropertyPermission::into_vec(permission);365 Self { key, permissions }366 }367}368369impl TokenPropertyPermission {370 pub fn into_property_key_permissions(371 permissions: Vec<TokenPropertyPermission>,372 ) -> evm_coder::execution::Result<Vec<up_data_structs::PropertyKeyPermission>> {373 let mut perms = Vec::new();374375 for TokenPropertyPermission { key, permissions } in permissions {376 if permissions.len() > <TokenPermissionField as evm_coder::abi::AbiType>::FIELDS_COUNT {377 return Err(alloc::format!(378 "Actual number of fields {} for {}, which exceeds the maximum value of {}",379 permissions.len(),380 stringify!(EthTokenPermissions),381 <TokenPermissionField as evm_coder::abi::AbiType>::FIELDS_COUNT382 )383 .as_str()384 .into());385 }386387 let token_permission = PropertyPermission::from_vec(permissions);388389 perms.push(up_data_structs::PropertyKeyPermission {390 key: key.into_bytes().try_into().map_err(|_| "too long key")?,391 permission: token_permission,392 });393 }394 Ok(perms)395 }396}