12345678910111213141516171819use alloc::format;2021use evm_coder::{22 types::{Address, String},23 AbiCoder,24};25pub use pallet_evm::{account::CrossAccountId, Config};26use pallet_evm_coder_substrate::execution::Error;27use sp_core::{H160, U256};28use sp_std::{vec, vec::Vec};29use up_data_structs::{CollectionFlags, CollectionId};30313233const ETH_COLLECTION_PREFIX: [u8; 16] = [34 0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,35];363738pub fn map_eth_to_id(eth: &Address) -> Option<CollectionId> {39 if eth[0..16] != ETH_COLLECTION_PREFIX {40 return None;41 }42 let mut id_bytes = [0; 4];43 id_bytes.copy_from_slice(ð[16..20]);44 Some(CollectionId(u32::from_be_bytes(id_bytes)))45}464748pub fn collection_id_to_address(id: CollectionId) -> Address {49 let mut out = [0; 20];50 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);51 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));52 H160(out)53}545556pub fn is_collection(address: &Address) -> bool {57 address[0..16] == ETH_COLLECTION_PREFIX58}596061pub fn convert_uint256_to_cross_account<T: Config>(from: U256) -> T::CrossAccountId62where63 T::AccountId: From<[u8; 32]>,64{65 let mut new_admin_arr = [0_u8; 32];66 from.to_big_endian(&mut new_admin_arr);67 let account_id = T::AccountId::from(new_admin_arr);68 T::CrossAccountId::from_sub(account_id)69}707172#[derive(Debug, Default, AbiCoder)]73pub struct CrossAddress {74 pub(crate) eth: Address,75 pub(crate) sub: U256,76}7778impl CrossAddress {79 80 pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self81 where82 T: pallet_evm::Config,83 T::AccountId: AsRef<[u8; 32]>,84 {85 if cross_account_id.is_canonical_substrate() {86 Self::from_sub::<T>(cross_account_id.as_sub())87 } else {88 Self::from_eth(*cross_account_id.as_eth())89 }90 }91 92 pub fn from_sub<T>(account_id: &T::AccountId) -> Self93 where94 T: pallet_evm::Config,95 T::AccountId: AsRef<[u8; 32]>,96 {97 Self {98 eth: Default::default(),99 sub: U256::from_big_endian(account_id.as_ref()),100 }101 }102 103 pub fn from_eth(address: Address) -> Self {104 Self {105 eth: address,106 sub: Default::default(),107 }108 }109110 111 pub fn into_option_sub_cross_account<T>(&self) -> Result<Option<T::CrossAccountId>, Error>112 where113 T: pallet_evm::Config,114 T::AccountId: From<[u8; 32]>,115 {116 if self.eth == Default::default() && self.sub == Default::default() {117 Ok(None)118 } else if self.eth == Default::default() {119 Ok(Some(convert_uint256_to_cross_account::<T>(self.sub)))120 } else if self.sub == Default::default() {121 Ok(Some(T::CrossAccountId::from_eth(self.eth)))122 } else {123 Err(format!("All fields of cross account is non zeroed {self:?}").into())124 }125 }126127 128 pub fn into_sub_cross_account<T>(&self) -> Result<T::CrossAccountId, Error>129 where130 T: pallet_evm::Config,131 T::AccountId: From<[u8; 32]>,132 {133 if self.eth == Default::default() && self.sub == Default::default() {134 Err("All fields of cross account is zeroed".into())135 } else if self.eth == Default::default() {136 Ok(convert_uint256_to_cross_account::<T>(self.sub))137 } else if self.sub == Default::default() {138 Ok(T::CrossAccountId::from_eth(self.eth))139 } else {140 Err("All fields of cross account is non zeroed".into())141 }142 }143}144145146#[derive(AbiCoder, Copy, Clone, Default, Debug, PartialEq)]147#[repr(u8)]148pub enum CollectionMode {149 150 #[default]151 Nonfungible,152 153 Fungible,154 155 Refungible,156}157158159#[derive(Debug, Default, AbiCoder)]160pub struct Property {161 key: evm_coder::types::String,162 value: evm_coder::types::Bytes,163}164165impl Property {166 167 pub fn key(&self) -> &str {168 self.key.as_str()169 }170171 172 pub fn value(&self) -> &[u8] {173 self.value.0.as_slice()174 }175}176177impl TryFrom<up_data_structs::Property> for Property {178 type Error = Error;179180 fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {181 let key = evm_coder::types::String::from_utf8(from.key.into())182 .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {e}")))?;183 let value = evm_coder::types::Bytes(from.value.to_vec());184 Ok(Property { key, value })185 }186}187188impl TryInto<up_data_structs::Property> for Property {189 type Error = Error;190191 fn try_into(self) -> Result<up_data_structs::Property, Self::Error> {192 let key = <Vec<u8>>::from(self.key)193 .try_into()194 .map_err(|_| "key too large")?;195196 let value = self.value.0.try_into().map_err(|_| "value too large")?;197198 Ok(up_data_structs::Property { key, value })199 }200}201202203#[derive(Debug, Default, Clone, Copy, AbiCoder)]204#[repr(u8)]205pub enum CollectionLimitField {206 207 #[default]208 AccountTokenOwnership,209210 211 SponsoredDataSize,212213 214 SponsoredDataRateLimit,215216 217 TokenLimit,218219 220 SponsorTransferTimeout,221222 223 SponsorApproveTimeout,224225 226 OwnerCanTransfer,227228 229 OwnerCanDestroy,230231 232 TransferEnabled,233}234235236#[derive(Debug, Default, AbiCoder)]237pub struct CollectionLimit {238 field: CollectionLimitField,239 value: Option<U256>,240}241242impl CollectionLimit {243 244 pub fn new(field: CollectionLimitField, value: Option<u32>) -> Self {245 Self {246 field,247 value: value.map(|value| value.into()),248 }249 }250 251 pub fn has_value(&self) -> bool {252 self.value.is_some()253 }254255 256 pub fn apply_limit(&self, limits: &mut up_data_structs::CollectionLimits) -> Result<(), Error> {257 let value = self258 .value259 .ok_or::<Error>("can't convert `None` value to boolean".into())?;260 let value = Some(value.try_into().map_err(|error| {261 Error::Revert(format!(262 "can't convert value to u32 \"{value}\" because: \"{error}\""263 ))264 })?);265266 let convert_value_to_bool = || match value {267 Some(value) => match value {268 0 => Ok(Some(false)),269 1 => Ok(Some(true)),270 _ => Err(Error::Revert(format!(271 "can't convert value to boolean \"{value}\""272 ))),273 },274 None => Ok(None),275 };276277 match self.field {278 CollectionLimitField::AccountTokenOwnership => {279 limits.account_token_ownership_limit = value;280 }281 CollectionLimitField::SponsoredDataSize => {282 limits.sponsored_data_size = value;283 }284 CollectionLimitField::SponsoredDataRateLimit => {285 limits.sponsored_data_rate_limit =286 value.map(up_data_structs::SponsoringRateLimit::Blocks);287 }288 CollectionLimitField::TokenLimit => {289 limits.token_limit = value;290 }291 CollectionLimitField::SponsorTransferTimeout => {292 limits.sponsor_transfer_timeout = value;293 }294 CollectionLimitField::SponsorApproveTimeout => {295 limits.sponsor_approve_timeout = value;296 }297 CollectionLimitField::OwnerCanTransfer => {298 limits.owner_can_transfer = convert_value_to_bool()?;299 }300 CollectionLimitField::OwnerCanDestroy => {301 limits.owner_can_destroy = convert_value_to_bool()?;302 }303 CollectionLimitField::TransferEnabled => {304 limits.transfers_enabled = convert_value_to_bool()?;305 }306 };307 Ok(())308 }309}310311312#[derive(Debug, Default, AbiCoder)]313pub struct CollectionLimitValue {314 field: CollectionLimitField,315 value: U256,316}317318impl CollectionLimitValue {319 320 pub fn new(field: CollectionLimitField, value: u32) -> Self {321 Self {322 field,323 value: value.into(),324 }325 }326327 328 pub fn apply_limit(&self, limits: &mut up_data_structs::CollectionLimits) -> Result<(), Error> {329 let value = self.value;330 let value: u32 = value.try_into().map_err(|error| {331 Error::Revert(format!(332 "can't convert value to u32 \"{value}\" because: \"{error}\""333 ))334 })?;335336 let convert_value_to_bool = || match value {337 0 => Ok(Some(false)),338 1 => Ok(Some(true)),339 _ => Err(Error::Revert(format!(340 "can't convert value to boolean \"{value}\""341 ))),342 };343344 match self.field {345 CollectionLimitField::AccountTokenOwnership => {346 limits.account_token_ownership_limit = Some(value);347 }348 CollectionLimitField::SponsoredDataSize => {349 limits.sponsored_data_size = Some(value);350 }351 CollectionLimitField::SponsoredDataRateLimit => {352 limits.sponsored_data_rate_limit =353 Some(up_data_structs::SponsoringRateLimit::Blocks(value));354 }355 CollectionLimitField::TokenLimit => {356 limits.token_limit = Some(value);357 }358 CollectionLimitField::SponsorTransferTimeout => {359 limits.sponsor_transfer_timeout = Some(value);360 }361 CollectionLimitField::SponsorApproveTimeout => {362 limits.sponsor_approve_timeout = Some(value);363 }364 CollectionLimitField::OwnerCanTransfer => {365 limits.owner_can_transfer = convert_value_to_bool()?;366 }367 CollectionLimitField::OwnerCanDestroy => {368 limits.owner_can_destroy = convert_value_to_bool()?;369 }370 CollectionLimitField::TransferEnabled => {371 limits.transfers_enabled = convert_value_to_bool()?;372 }373 };374 Ok(())375 }376}377378impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {379 type Error = Error;380381 fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {382 let mut limits = up_data_structs::CollectionLimits::default();383 self.apply_limit(&mut limits)?;384 Ok(limits)385 }386}387388impl FromIterator<CollectionLimitValue> for Result<up_data_structs::CollectionLimits, Error> {389 fn from_iter<T: IntoIterator<Item = CollectionLimitValue>>(390 iter: T,391 ) -> Result<up_data_structs::CollectionLimits, Error> {392 let mut limits = up_data_structs::CollectionLimits::default();393 for value in iter.into_iter() {394 value.apply_limit(&mut limits)?;395 }396 Ok(limits)397 }398}399400401#[derive(Default, Debug, Clone, Copy, AbiCoder)]402#[repr(u8)]403pub enum CollectionPermissionField {404 405 #[default]406 TokenOwner,407408 409 CollectionAdmin,410}411412413#[derive(AbiCoder, Copy, Clone, Default, Debug)]414#[repr(u8)]415pub enum TokenPermissionField {416 417 #[default]418 Mutable,419420 421 TokenOwner,422423 424 CollectionAdmin,425}426427428#[derive(Debug, Default, AbiCoder)]429pub struct PropertyPermission {430 431 code: TokenPermissionField,432 433 value: bool,434}435436impl PropertyPermission {437 438 pub fn into_vec(pp: up_data_structs::PropertyPermission) -> Vec<Self> {439 vec![440 PropertyPermission {441 code: TokenPermissionField::Mutable,442 value: pp.mutable,443 },444 PropertyPermission {445 code: TokenPermissionField::TokenOwner,446 value: pp.token_owner,447 },448 PropertyPermission {449 code: TokenPermissionField::CollectionAdmin,450 value: pp.collection_admin,451 },452 ]453 }454455 456 pub fn from_vec(permission: Vec<Self>) -> up_data_structs::PropertyPermission {457 let mut token_permission = up_data_structs::PropertyPermission::default();458459 for PropertyPermission { code, value } in permission {460 match code {461 TokenPermissionField::Mutable => token_permission.mutable = value,462 TokenPermissionField::TokenOwner => token_permission.token_owner = value,463 TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value,464 }465 }466 token_permission467 }468}469470471#[derive(Debug, Default, AbiCoder)]472pub struct TokenPropertyPermission {473 474 key: evm_coder::types::String,475 476 permissions: Vec<PropertyPermission>,477}478479impl480 From<(481 up_data_structs::PropertyKey,482 up_data_structs::PropertyPermission,483 )> for TokenPropertyPermission484{485 fn from(486 value: (487 up_data_structs::PropertyKey,488 up_data_structs::PropertyPermission,489 ),490 ) -> Self {491 let (key, permission) = value;492 let key = evm_coder::types::String::from_utf8(key.into_inner())493 .expect("Stored key must be valid");494 let permissions = PropertyPermission::into_vec(permission);495 Self { key, permissions }496 }497}498499impl TokenPropertyPermission {500 501 pub fn into_property_key_permissions(502 permissions: Vec<TokenPropertyPermission>,503 ) -> Result<Vec<up_data_structs::PropertyKeyPermission>, Error> {504 let mut perms = Vec::new();505506 for TokenPropertyPermission { key, permissions } in permissions {507 let token_permission = PropertyPermission::from_vec(permissions);508509 perms.push(up_data_structs::PropertyKeyPermission {510 key: key.into_bytes().try_into().map_err(|_| "too long key")?,511 permission: token_permission,512 });513 }514 Ok(perms)515 }516}517518519#[derive(Debug, AbiCoder)]520pub struct TokenUri {521 522 pub id: U256,523524 525 pub uri: String,526}527528529#[derive(Debug, Default, AbiCoder)]530pub struct CollectionNestingAndPermission {531 532 pub token_owner: bool,533 534 pub collection_admin: bool,535 536 pub restricted: Vec<Address>,537}538539impl CollectionNestingAndPermission {540 541 pub fn new(token_owner: bool, collection_admin: bool, restricted: Vec<Address>) -> Self {542 Self {543 token_owner,544 collection_admin,545 restricted,546 }547 }548}549550551#[derive(Debug, Default, AbiCoder)]552pub struct CreateCollectionData {553 554 pub name: String,555 556 pub description: String,557 558 pub token_prefix: String,559 560 pub mode: CollectionMode,561 562 pub decimals: u8,563 564 pub properties: Vec<Property>,565 566 pub token_property_permissions: Vec<TokenPropertyPermission>,567 568 pub admin_list: Vec<CrossAddress>,569 570 pub nesting_settings: CollectionNestingAndPermission,571 572 pub limits: Vec<CollectionLimitValue>,573 574 pub pending_sponsor: CrossAddress,575 576 pub flags: CollectionFlags,577}578579580#[derive(Debug, Default, AbiCoder)]581pub struct CollectionNesting {582 token_owner: bool,583 ids: Vec<U256>,584}585586impl CollectionNesting {587 588 pub fn new(token_owner: bool, ids: Vec<U256>) -> Self {589 Self { token_owner, ids }590 }591}592593594#[derive(Debug, Default, AbiCoder)]595pub struct CollectionNestingPermission {596 field: CollectionPermissionField,597 value: bool,598}599600impl CollectionNestingPermission {601 602 pub fn new(field: CollectionPermissionField, value: bool) -> Self {603 Self { field, value }604 }605}606607608#[derive(AbiCoder, Copy, Clone, Default, Debug)]609#[repr(u8)]610pub enum AccessMode {611 612 #[default]613 Normal,614 615 AllowList,616}617618impl From<up_data_structs::AccessMode> for AccessMode {619 fn from(value: up_data_structs::AccessMode) -> Self {620 match value {621 up_data_structs::AccessMode::Normal => AccessMode::Normal,622 up_data_structs::AccessMode::AllowList => AccessMode::AllowList,623 }624 }625}626627impl From<AccessMode> for up_data_structs::AccessMode {628 fn from(value: AccessMode) -> Self {629 match value {630 AccessMode::Normal => up_data_structs::AccessMode::Normal,631 AccessMode::AllowList => up_data_structs::AccessMode::AllowList,632 }633 }634}