git.delta.rocks / unique-network / refs/commits / da8dccd94122

difftreelog

source

pallets/nft/src/eth/erc.rs7.8 KiBsourcehistory
1use core::char::{decode_utf16, REPLACEMENT_CHARACTER};2use evm_coder::{ToLog, execution::Result, solidity, solidity_interface, types::*};3use core::convert::TryInto;4use alloc::format;5use crate::{Allowances, Module, Balance, CollectionHandle, CollectionMode, Config, NftItemList};6use frame_support::storage::StorageDoubleMap;7use pallet_evm::AddressMapping;8use super::account::CrossAccountId;9use sp_std::vec::Vec;1011#[solidity_interface(name = "ERC165")]12impl<T: Config> CollectionHandle<T> {13	fn supports_interface(&self, interface_id: bytes4) -> Result<bool> {14		Ok(match self.mode {15			CollectionMode::Fungible(_) => UniqueFungibleCall::supports_interface(interface_id),16			CollectionMode::NFT => UniqueNFTCall::supports_interface(interface_id),17			_ => false,18		})19	}20}2122#[solidity_interface(name = "InlineNameSymbol")]23impl<T: Config> CollectionHandle<T> {24	fn name(&self) -> Result<string> {25		Ok(decode_utf16(self.name.iter().copied())26			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))27			.collect::<string>())28	}2930	fn symbol(&self) -> Result<string> {31		Ok(string::from_utf8_lossy(&self.token_prefix).into())32	}33}3435#[solidity_interface(name = "InlineTotalSupply")]36impl<T: Config> CollectionHandle<T> {37	fn total_supply(&self) -> Result<uint256> {38		// TODO: we do not track total amount of all tokens39		Ok(0.into())40	}41}4243#[solidity_interface(name = "ERC721Metadata", inline_is(InlineNameSymbol))]44impl<T: Config> CollectionHandle<T> {45	fn token_uri(&self, token_id: uint256) -> Result<string> {46		// TODO: We should standartize url prefix, maybe via offchain schema?47		Ok(format!("unique.network/{}/{}", self.id, token_id))48	}49}5051#[solidity_interface(name = "ERC721Enumerable", inline_is(InlineTotalSupply))]52impl<T: Config> CollectionHandle<T> {53	fn token_by_index(&self, index: uint256) -> Result<uint256> {54		Ok(index)55	}5657	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {58		// TODO: Not implemetable59		Err("not implemented".into())60	}61}6263#[derive(ToLog)]64pub enum ERC721Events {65	Transfer {66		#[indexed]67		from: address,68		#[indexed]69		to: address,70		#[indexed]71		token_id: uint256,72	},73	Approval {74		#[indexed]75		owner: address,76		#[indexed]77		approved: address,78		#[indexed]79		token_id: uint256,80	},81	#[allow(dead_code)]82	ApprovalForAll {83		#[indexed]84		owner: address,85		#[indexed]86		operator: address,87		approved: bool,88	},89}9091#[solidity_interface(name = "ERC721", is(ERC165), events(ERC721Events))]92impl<T: Config> CollectionHandle<T> {93	#[solidity(rename_selector = "balanceOf")]94	fn balance_of_nft(&self, owner: address) -> Result<uint256> {95		let owner = T::EvmAddressMapping::into_account_id(owner);96		let balance = <Balance<T>>::get(self.id, owner);97		Ok(balance.into())98	}99	fn owner_of(&self, token_id: uint256) -> Result<address> {100		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;101		let token = <NftItemList<T>>::get(self.id, token_id).ok_or("unknown token")?;102		Ok(*token.owner.as_eth())103	}104	fn safe_transfer_from_with_data(105		&mut self,106		_from: address,107		_to: address,108		_token_id: uint256,109		_data: bytes,110		_value: value,111	) -> Result<void> {112		// TODO: Not implemetable113		Err("not implemented".into())114	}115	fn safe_transfer_from(116		&mut self,117		_from: address,118		_to: address,119		_token_id: uint256,120		_value: value,121	) -> Result<void> {122		// TODO: Not implemetable123		Err("not implemented".into())124	}125126	fn transfer_from(127		&mut self,128		caller: caller,129		from: address,130		to: address,131		token_id: uint256,132		_value: value,133	) -> Result<void> {134		let caller = T::CrossAccountId::from_eth(caller);135		let from = T::CrossAccountId::from_eth(from);136		let to = T::CrossAccountId::from_eth(to);137		let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;138139		<Module<T>>::transfer_from_internal(&caller, &from, &to, self, token_id, 1)140			.map_err(|_| "transferFrom error")?;141		Ok(())142	}143144	fn approve(145		&mut self,146		caller: caller,147		approved: address,148		token_id: uint256,149		_value: value,150	) -> Result<void> {151		let caller = T::CrossAccountId::from_eth(caller);152		let approved = T::CrossAccountId::from_eth(approved);153		let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;154155		<Module<T>>::approve_internal(&caller, &approved, self, token_id, 1)156			.map_err(|_| "approve internal")?;157		Ok(())158	}159160	fn set_approval_for_all(161		&mut self,162		_caller: caller,163		_operator: address,164		_approved: bool,165	) -> Result<void> {166		// TODO: Not implemetable167		Err("not implemented".into())168	}169170	fn get_approved(&self, _token_id: uint256) -> Result<address> {171		// TODO: Not implemetable172		Err("not implemented".into())173	}174175	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {176		// TODO: Not implemetable177		Err("not implemented".into())178	}179}180181#[solidity_interface(name = "ERC721UniqueExtensions")]182impl<T: Config> CollectionHandle<T> {183	#[solidity(rename_selector = "transfer")]184	fn transfer_nft(185		&mut self,186		caller: caller,187		to: address,188		token_id: uint256,189		_value: value,190	) -> Result<void> {191		let caller = T::CrossAccountId::from_eth(caller);192		let to = T::CrossAccountId::from_eth(to);193		let token_id = token_id.try_into().map_err(|_| "amount overflow")?;194195		<Module<T>>::transfer_internal(&caller, &to, self, token_id, 1)196			.map_err(|_| "transfer error")?;197		Ok(())198	}199}200201#[solidity_interface(202	name = "UniqueNFT",203	is(204		ERC165,205		ERC721,206		ERC721Metadata,207		ERC721Enumerable,208		ERC721UniqueExtensions209	)210)]211impl<T: Config> CollectionHandle<T> {}212213#[derive(ToLog)]214pub enum ERC20Events {215	Transfer {216		#[indexed]217		from: address,218		#[indexed]219		to: address,220		value: uint256,221	},222	Approval {223		#[indexed]224		owner: address,225		#[indexed]226		spender: address,227		value: uint256,228	},229}230231#[solidity_interface(232	name = "ERC20",233	inline_is(InlineNameSymbol, InlineTotalSupply),234	events(ERC20Events)235)]236impl<T: Config> CollectionHandle<T> {237	fn decimals(&self) -> Result<uint8> {238		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {239			*decimals240		} else {241			unreachable!()242		})243	}244	fn balance_of(&self, owner: address) -> Result<uint256> {245		let owner = T::EvmAddressMapping::into_account_id(owner);246		let balance = <Balance<T>>::get(self.id, owner);247		Ok(balance.into())248	}249	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {250		let caller = T::CrossAccountId::from_eth(caller);251		let to = T::CrossAccountId::from_eth(to);252		let amount = amount.try_into().map_err(|_| "amount overflow")?;253254		<Module<T>>::transfer_internal(&caller, &to, self, 1, amount)255			.map_err(|_| "transfer error")?;256		Ok(true)257	}258	#[solidity(rename_selector = "transferFrom")]259	fn transfer_from_fungible(260		&mut self,261		caller: caller,262		from: address,263		to: address,264		amount: uint256,265	) -> Result<bool> {266		let caller = T::CrossAccountId::from_eth(caller);267		let from = T::CrossAccountId::from_eth(from);268		let to = T::CrossAccountId::from_eth(to);269		let amount = amount.try_into().map_err(|_| "amount overflow")?;270271		<Module<T>>::transfer_from_internal(&caller, &from, &to, self, 1, amount)272			.map_err(|_| "transferFrom error")?;273		Ok(true)274	}275	#[solidity(rename_selector = "approve")]276	fn approve_fungible(277		&mut self,278		caller: caller,279		spender: address,280		amount: uint256,281	) -> Result<bool> {282		let caller = T::CrossAccountId::from_eth(caller);283		let spender = T::CrossAccountId::from_eth(spender);284		let amount = amount.try_into().map_err(|_| "amount overflow")?;285286		<Module<T>>::approve_internal(&caller, &spender, self, 1, amount)287			.map_err(|_| "approve internal")?;288		Ok(true)289	}290	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {291		let owner = T::CrossAccountId::from_eth(owner);292		let spender = T::CrossAccountId::from_eth(spender);293294		Ok(<Allowances<T>>::get(self.id, (1, owner.as_sub(), spender.as_sub())).into())295	}296}297298#[solidity_interface(name = "UniqueFungible", is(ERC165, ERC20))]299impl<T: Config> CollectionHandle<T> {}