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 CrossAccount {72 pub(crate) eth: address,73 pub(crate) sub: uint256,74}7576impl CrossAccount {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}162163164#[derive(Debug, Default, AbiCoder)]165pub struct CollectionLimit {166 field: CollectionLimitField,167 status: bool,168 value: uint256,169}170171impl CollectionLimit {172 173 pub fn from_int(field: CollectionLimitField, value: u32) -> Self {174 Self {175 field,176 status: true,177 value: value.into(),178 }179 }180181 182 pub fn from_opt_int(field: CollectionLimitField, value: Option<u32>) -> Self {183 value184 .map(|v| Self {185 field,186 status: true,187 value: v.into(),188 })189 .unwrap_or(Self {190 field,191 status: false,192 value: Default::default(),193 })194 }195196 197 pub fn from_opt_bool(field: CollectionLimitField, value: Option<bool>) -> Self {198 value199 .map(|v| Self {200 field,201 status: true,202 value: if v {203 uint256::from(1)204 } else {205 Default::default()206 },207 })208 .unwrap_or(Self {209 field,210 status: false,211 value: Default::default(),212 })213 }214}215216impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {217 type Error = evm_coder::execution::Error;218219 fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {220 if !self.status {221 return Err(Self::Error::Revert("user can't disable limits".into()));222 }223224 let value = self.value.try_into().map_err(|error| {225 Self::Error::Revert(format!(226 "can't convert value to u32 \"{}\" because: \"{error}\"",227 self.value228 ))229 })?;230231 let convert_value_to_bool = || match value {232 0 => Ok(false),233 1 => Ok(true),234 _ => {235 return Err(Self::Error::Revert(format!(236 "can't convert value to boolean \"{value}\""237 )))238 }239 };240241 let mut limits = up_data_structs::CollectionLimits::default();242 match self.field {243 CollectionLimitField::AccountTokenOwnership => {244 limits.account_token_ownership_limit = Some(value);245 }246 CollectionLimitField::SponsoredDataSize => {247 limits.sponsored_data_size = Some(value);248 }249 CollectionLimitField::SponsoredDataRateLimit => {250 limits.sponsored_data_rate_limit =251 Some(up_data_structs::SponsoringRateLimit::Blocks(value));252 }253 CollectionLimitField::TokenLimit => {254 limits.token_limit = Some(value);255 }256 CollectionLimitField::SponsorTransferTimeout => {257 limits.sponsor_transfer_timeout = Some(value);258 }259 CollectionLimitField::SponsorApproveTimeout => {260 limits.sponsor_approve_timeout = Some(value);261 }262 CollectionLimitField::OwnerCanTransfer => {263 limits.owner_can_transfer = Some(convert_value_to_bool()?);264 }265 CollectionLimitField::OwnerCanDestroy => {266 limits.owner_can_destroy = Some(convert_value_to_bool()?);267 }268 CollectionLimitField::TransferEnabled => {269 limits.transfers_enabled = Some(convert_value_to_bool()?);270 }271 };272 Ok(limits)273 }274}275276277#[derive(Default, Debug, Clone, Copy, AbiCoder)]278#[repr(u8)]279pub enum CollectionPermissions {280 281 #[default]282 TokenOwner,283284 285 CollectionAdmin,286}287288289#[derive(AbiCoder, Copy, Clone, Default, Debug)]290#[repr(u8)]291pub enum TokenPermissionField {292 293 #[default]294 Mutable,295296 297 TokenOwner,298299 300 CollectionAdmin,301}302303304#[derive(Debug, Default, AbiCoder)]305pub struct PropertyPermission {306 307 code: TokenPermissionField,308 309 value: bool,310}311312impl PropertyPermission {313 314 pub fn into_vec(pp: up_data_structs::PropertyPermission) -> Vec<Self> {315 vec![316 PropertyPermission {317 code: TokenPermissionField::Mutable,318 value: pp.mutable,319 },320 PropertyPermission {321 code: TokenPermissionField::TokenOwner,322 value: pp.token_owner,323 },324 PropertyPermission {325 code: TokenPermissionField::CollectionAdmin,326 value: pp.collection_admin,327 },328 ]329 }330331 332 pub fn from_vec(permission: Vec<Self>) -> up_data_structs::PropertyPermission {333 let mut token_permission = up_data_structs::PropertyPermission::default();334335 for PropertyPermission { code, value } in permission {336 match code {337 TokenPermissionField::Mutable => token_permission.mutable = value,338 TokenPermissionField::TokenOwner => token_permission.token_owner = value,339 TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value,340 }341 }342 token_permission343 }344}345346347#[derive(Debug, Default, AbiCoder)]348pub struct TokenPropertyPermission {349 350 key: evm_coder::types::string,351 352 permissions: Vec<PropertyPermission>,353}354355impl356 From<(357 up_data_structs::PropertyKey,358 up_data_structs::PropertyPermission,359 )> for TokenPropertyPermission360{361 fn from(362 value: (363 up_data_structs::PropertyKey,364 up_data_structs::PropertyPermission,365 ),366 ) -> Self {367 let (key, permission) = value;368 let key = evm_coder::types::string::from_utf8(key.into_inner())369 .expect("Stored key must be valid");370 let permissions = PropertyPermission::into_vec(permission);371 Self { key, permissions }372 }373}374375impl TokenPropertyPermission {376 377 pub fn into_property_key_permissions(378 permissions: Vec<TokenPropertyPermission>,379 ) -> evm_coder::execution::Result<Vec<up_data_structs::PropertyKeyPermission>> {380 let mut perms = Vec::new();381382 for TokenPropertyPermission { key, permissions } in permissions {383 if permissions.len() > <TokenPermissionField as evm_coder::abi::AbiType>::FIELDS_COUNT {384 return Err(alloc::format!(385 "Actual number of fields {} for {}, which exceeds the maximum value of {}",386 permissions.len(),387 stringify!(EthTokenPermissions),388 <TokenPermissionField as evm_coder::abi::AbiType>::FIELDS_COUNT389 )390 .as_str()391 .into());392 }393394 let token_permission = PropertyPermission::from_vec(permissions);395396 perms.push(up_data_structs::PropertyKeyPermission {397 key: key.into_bytes().try_into().map_err(|_| "too long key")?,398 permission: token_permission,399 });400 }401 Ok(perms)402 }403}