difftreelog
feat bulk mint/get/set metadata
in: master
5 files changed
pallets/nft/src/eth/erc.rsdiffbeforeafterboth--- a/pallets/nft/src/eth/erc.rs
+++ b/pallets/nft/src/eth/erc.rs
@@ -8,6 +8,7 @@
};
use frame_support::storage::{StorageMap, StorageDoubleMap};
use pallet_evm::AddressMapping;
+use pallet_evm_coder_substrate::dispatch_to_evm;
use super::account::CrossAccountId;
use sp_std::{vec, vec::Vec};
@@ -299,6 +300,90 @@
.ok_or("item id overflow")?
.into())
}
+
+ fn set_variable_metadata(
+ &mut self,
+ caller: caller,
+ token_id: uint256,
+ data: bytes,
+ ) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let token_id = token_id.try_into().map_err(|_| "token id overflow")?;
+
+ <Module<T>>::set_variable_meta_data_internal(&caller, self, token_id, data)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {
+ let token_id = token_id.try_into().map_err(|_| "token id overflow")?;
+
+ <Module<T>>::get_variable_metadata(self, token_id).map_err(dispatch_to_evm::<T>)
+ }
+
+ fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let mut expected_index = <ItemListIndex>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?;
+
+ let total_tokens = token_ids.len();
+ for id in token_ids.into_iter() {
+ let id: u32 = id.try_into().map_err(|_| "token id overflow")?;
+ if id != expected_index {
+ return Err("item id should be next".into());
+ }
+ expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
+ }
+
+ let data = (0..total_tokens)
+ .map(|_| {
+ CreateItemData::NFT(CreateNftData {
+ const_data: vec![].try_into().unwrap(),
+ variable_data: vec![].try_into().unwrap(),
+ })
+ })
+ .collect();
+
+ <Module<T>>::create_multiple_items_internal(&caller, self, &to, data)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+
+ #[solidity(rename_selector = "mintBulkWithTokenURI")]
+ fn mint_bulk_with_token_uri(
+ &mut self,
+ caller: caller,
+ to: address,
+ tokens: Vec<(uint256, string)>,
+ ) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let mut expected_index = <ItemListIndex>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?;
+
+ let mut data = Vec::with_capacity(tokens.len());
+ for (id, token_uri) in tokens {
+ let id: u32 = id.try_into().map_err(|_| "token id overflow")?;
+ if id != expected_index {
+ panic!("item id should be next ({}) but got {}", expected_index, id);
+ }
+ expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
+
+ data.push(CreateItemData::NFT(CreateNftData {
+ const_data: Vec::<u8>::from(token_uri)
+ .try_into()
+ .map_err(|_| "token uri is too long")?,
+ variable_data: vec![].try_into().unwrap(),
+ }));
+ }
+
+ <Module<T>>::create_multiple_items_internal(&caller, self, &to, data)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
}
#[solidity_interface(
pallets/nft/src/eth/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nft/src/eth/stubs/UniqueNFT.soldiffbeforeafterboth1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56// Common stubs holder7contract Dummy {8 uint8 dummy;9 string stub_error = "this contract is implemented in native";10}1112// Inline13contract ERC721Events {14 event Transfer(15 address indexed from,16 address indexed to,17 uint256 indexed tokenId18 );19 event Approval(20 address indexed owner,21 address indexed approved,22 uint256 indexed tokenId23 );24 event ApprovalForAll(25 address indexed owner,26 address indexed operator,27 bool approved28 );29}3031// Inline32contract ERC721MintableEvents {33 event MintingFinished();34}3536// Inline37contract InlineNameSymbol is Dummy {38 function name() public view returns (string memory) {39 require(false, stub_error);40 dummy;41 return "";42 }4344 function symbol() public view returns (string memory) {45 require(false, stub_error);46 dummy;47 return "";48 }49}5051// Inline52contract InlineTotalSupply is Dummy {53 function totalSupply() public view returns (uint256) {54 require(false, stub_error);55 dummy;56 return 0;57 }58}5960contract ERC165 is Dummy {61 function supportsInterface(uint32 interfaceId) public view returns (bool) {62 require(false, stub_error);63 interfaceId;64 dummy;65 return false;66 }67}6869contract ERC721 is Dummy, ERC165, ERC721Events {70 function balanceOf(address owner) public view returns (uint256) {71 require(false, stub_error);72 owner;73 dummy;74 return 0;75 }7677 function ownerOf(uint256 tokenId) public view returns (address) {78 require(false, stub_error);79 tokenId;80 dummy;81 return 0x0000000000000000000000000000000000000000;82 }8384 function safeTransferFromWithData(85 address from,86 address to,87 uint256 tokenId,88 bytes memory data89 ) public {90 require(false, stub_error);91 from;92 to;93 tokenId;94 data;95 dummy = 0;96 }9798 function safeTransferFrom(99 address from,100 address to,101 uint256 tokenId102 ) public {103 require(false, stub_error);104 from;105 to;106 tokenId;107 dummy = 0;108 }109110 function transferFrom(111 address from,112 address to,113 uint256 tokenId114 ) public {115 require(false, stub_error);116 from;117 to;118 tokenId;119 dummy = 0;120 }121122 function approve(address approved, uint256 tokenId) public {123 require(false, stub_error);124 approved;125 tokenId;126 dummy = 0;127 }128129 function setApprovalForAll(address operator, bool approved) public {130 require(false, stub_error);131 operator;132 approved;133 dummy = 0;134 }135136 function getApproved(uint256 tokenId) public view returns (address) {137 require(false, stub_error);138 tokenId;139 dummy;140 return 0x0000000000000000000000000000000000000000;141 }142143 function isApprovedForAll(address owner, address operator)144 public145 view146 returns (address)147 {148 require(false, stub_error);149 owner;150 operator;151 dummy;152 return 0x0000000000000000000000000000000000000000;153 }154}155156contract ERC721Burnable is Dummy {157 function burn(uint256 tokenId) public {158 require(false, stub_error);159 tokenId;160 dummy = 0;161 }162}163164contract ERC721Enumerable is Dummy, InlineTotalSupply {165 function tokenByIndex(uint256 index) public view returns (uint256) {166 require(false, stub_error);167 index;168 dummy;169 return 0;170 }171172 function tokenOfOwnerByIndex(address owner, uint256 index)173 public174 view175 returns (uint256)176 {177 require(false, stub_error);178 owner;179 index;180 dummy;181 return 0;182 }183}184185contract ERC721Metadata is Dummy, InlineNameSymbol {186 function tokenURI(uint256 tokenId) public view returns (string memory) {187 require(false, stub_error);188 tokenId;189 dummy;190 return "";191 }192}193194contract ERC721Mintable is Dummy, ERC721MintableEvents {195 function mintingFinished() public view returns (bool) {196 require(false, stub_error);197 dummy;198 return false;199 }200201 function mint(address to, uint256 tokenId) public returns (bool) {202 require(false, stub_error);203 to;204 tokenId;205 dummy = 0;206 return false;207 }208209 function mintWithTokenURI(210 address to,211 uint256 tokenId,212 string memory tokenUri213 ) public returns (bool) {214 require(false, stub_error);215 to;216 tokenId;217 tokenUri;218 dummy = 0;219 return false;220 }221222 function finishMinting() public returns (bool) {223 require(false, stub_error);224 dummy = 0;225 return false;226 }227}228229contract ERC721UniqueExtensions is Dummy {230 function transfer(address to, uint256 tokenId) public {231 require(false, stub_error);232 to;233 tokenId;234 dummy = 0;235 }236237 function nextTokenId() public view returns (uint256) {238 require(false, stub_error);239 dummy;240 return 0;241 }242}243244contract UniqueNFT is245 Dummy,246 ERC165,247 ERC721,248 ERC721Metadata,249 ERC721Enumerable,250 ERC721UniqueExtensions,251 ERC721Mintable,252 ERC721Burnable253{}1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}1112// Common stubs holder13contract Dummy {14 uint8 dummy;15 string stub_error = "this contract is implemented in native";16}1718// Inline19contract ERC721Events {20 event Transfer(21 address indexed from,22 address indexed to,23 uint256 indexed tokenId24 );25 event Approval(26 address indexed owner,27 address indexed approved,28 uint256 indexed tokenId29 );30 event ApprovalForAll(31 address indexed owner,32 address indexed operator,33 bool approved34 );35}3637// Inline38contract ERC721MintableEvents {39 event MintingFinished();40}4142// Inline43contract InlineNameSymbol is Dummy {44 function name() public view returns (string memory) {45 require(false, stub_error);46 dummy;47 return "";48 }4950 function symbol() public view returns (string memory) {51 require(false, stub_error);52 dummy;53 return "";54 }55}5657// Inline58contract InlineTotalSupply is Dummy {59 function totalSupply() public view returns (uint256) {60 require(false, stub_error);61 dummy;62 return 0;63 }64}6566contract ERC165 is Dummy {67 function supportsInterface(uint32 interfaceId) public view returns (bool) {68 require(false, stub_error);69 interfaceId;70 dummy;71 return false;72 }73}7475contract ERC721 is Dummy, ERC165, ERC721Events {76 function balanceOf(address owner) public view returns (uint256) {77 require(false, stub_error);78 owner;79 dummy;80 return 0;81 }8283 function ownerOf(uint256 tokenId) public view returns (address) {84 require(false, stub_error);85 tokenId;86 dummy;87 return 0x0000000000000000000000000000000000000000;88 }8990 function safeTransferFromWithData(91 address from,92 address to,93 uint256 tokenId,94 bytes memory data95 ) public {96 require(false, stub_error);97 from;98 to;99 tokenId;100 data;101 dummy = 0;102 }103104 function safeTransferFrom(105 address from,106 address to,107 uint256 tokenId108 ) public {109 require(false, stub_error);110 from;111 to;112 tokenId;113 dummy = 0;114 }115116 function transferFrom(117 address from,118 address to,119 uint256 tokenId120 ) public {121 require(false, stub_error);122 from;123 to;124 tokenId;125 dummy = 0;126 }127128 function approve(address approved, uint256 tokenId) public {129 require(false, stub_error);130 approved;131 tokenId;132 dummy = 0;133 }134135 function setApprovalForAll(address operator, bool approved) public {136 require(false, stub_error);137 operator;138 approved;139 dummy = 0;140 }141142 function getApproved(uint256 tokenId) public view returns (address) {143 require(false, stub_error);144 tokenId;145 dummy;146 return 0x0000000000000000000000000000000000000000;147 }148149 function isApprovedForAll(address owner, address operator)150 public151 view152 returns (address)153 {154 require(false, stub_error);155 owner;156 operator;157 dummy;158 return 0x0000000000000000000000000000000000000000;159 }160}161162contract ERC721Burnable is Dummy {163 function burn(uint256 tokenId) public {164 require(false, stub_error);165 tokenId;166 dummy = 0;167 }168}169170contract ERC721Enumerable is Dummy, InlineTotalSupply {171 function tokenByIndex(uint256 index) public view returns (uint256) {172 require(false, stub_error);173 index;174 dummy;175 return 0;176 }177178 function tokenOfOwnerByIndex(address owner, uint256 index)179 public180 view181 returns (uint256)182 {183 require(false, stub_error);184 owner;185 index;186 dummy;187 return 0;188 }189}190191contract ERC721Metadata is Dummy, InlineNameSymbol {192 function tokenURI(uint256 tokenId) public view returns (string memory) {193 require(false, stub_error);194 tokenId;195 dummy;196 return "";197 }198}199200contract ERC721Mintable is Dummy, ERC721MintableEvents {201 function mintingFinished() public view returns (bool) {202 require(false, stub_error);203 dummy;204 return false;205 }206207 function mint(address to, uint256 tokenId) public returns (bool) {208 require(false, stub_error);209 to;210 tokenId;211 dummy = 0;212 return false;213 }214215 function mintWithTokenURI(216 address to,217 uint256 tokenId,218 string memory tokenUri219 ) public returns (bool) {220 require(false, stub_error);221 to;222 tokenId;223 tokenUri;224 dummy = 0;225 return false;226 }227228 function finishMinting() public returns (bool) {229 require(false, stub_error);230 dummy = 0;231 return false;232 }233}234235contract ERC721UniqueExtensions is Dummy {236 function transfer(address to, uint256 tokenId) public {237 require(false, stub_error);238 to;239 tokenId;240 dummy = 0;241 }242243 function nextTokenId() public view returns (uint256) {244 require(false, stub_error);245 dummy;246 return 0;247 }248249 // Selector: setVariableMetadata(uint256,bytes) d4eac26d250 function setVariableMetadata(uint256 tokenId, bytes memory data) public {251 require(false, stub_error);252 tokenId;253 data;254 dummy = 0;255 }256257 // Selector: getVariableMetadata(uint256) e6c5ce6f258 function getVariableMetadata(uint256 tokenId)259 public260 view261 returns (bytes memory)262 {263 require(false, stub_error);264 tokenId;265 dummy;266 return hex"";267 }268269 // Selector: mintBulk(address,uint256[]) 44a9945e270 function mintBulk(address to, uint256[] memory tokenIds)271 public272 returns (bool)273 {274 require(false, stub_error);275 to;276 tokenIds;277 dummy = 0;278 return false;279 }280281 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006282 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)283 public284 returns (bool)285 {286 require(false, stub_error);287 to;288 tokens;289 dummy = 0;290 return false;291 }292}293294contract UniqueNFT is295 Dummy,296 ERC165,297 ERC721,298 ERC721Metadata,299 ERC721Enumerable,300 ERC721UniqueExtensions,301 ERC721Mintable,302 ERC721Burnable303{}pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -1501,6 +1501,14 @@
Ok(())
}
+ pub fn get_variable_metadata(collection: &CollectionHandle<T>, item_id: TokenId) -> Result<Vec<u8>, DispatchError> {
+ Ok(match collection.mode {
+ CollectionMode::NFT => <NftItemList<T>>::get(collection.id, item_id).ok_or(Error::<T>::TokenNotFound)?.variable_data,
+ CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection.id, item_id).ok_or(Error::<T>::TokenNotFound)?.variable_data,
+ _ => fail!(Error::<T>::UnexpectedCollectionType),
+ })
+ }
+
pub fn create_multiple_items_internal(
sender: &T::CrossAccountId,
collection: &CollectionHandle<T>,
tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -3,6 +3,12 @@
pragma solidity >=0.8.0 <0.9.0;
+// Anonymous struct
+struct Tuple0 {
+ uint256 field_0;
+ string field_1;
+}
+
// Common stubs holder
interface Dummy {
@@ -119,6 +125,25 @@
function transfer(address to, uint256 tokenId) external;
function nextTokenId() external view returns (uint256);
+
+ // Selector: setVariableMetadata(uint256,bytes) d4eac26d
+ function setVariableMetadata(uint256 tokenId, bytes memory data) external;
+
+ // Selector: getVariableMetadata(uint256) e6c5ce6f
+ function getVariableMetadata(uint256 tokenId)
+ external
+ view
+ returns (bytes memory);
+
+ // Selector: mintBulk(address,uint256[]) 44a9945e
+ function mintBulk(address to, uint256[] memory tokenIds)
+ external
+ returns (bool);
+
+ // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
+ function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+ external
+ returns (bool);
}
interface UniqueNFT is