Skip to content

Commit

Permalink
Merge pull request #986 from UniqueNetwork/feature/add_mint_bulk_cross
Browse files Browse the repository at this point in the history
Add mintBulkCross to NFT and RFT collections
  • Loading branch information
CertainLach authored Sep 25, 2023
2 parents 6486f2a + 752e2b0 commit 448629b
Show file tree
Hide file tree
Showing 20 changed files with 632 additions and 42 deletions.
2 changes: 1 addition & 1 deletion node/cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ pub fn run() -> Result<()> {
.map(|cfg| &cfg.registry);
let task_manager =
sc_service::TaskManager::new(runner.config().tokio_handle.clone(), *registry)
.map_err(|e| format!("Error: {:?}", e))?;
.map_err(|e| format!("Error: {e:?}"))?;
let info_provider = Some(timestamp_with_aura_info(12000));

runner.async_run(|config| -> Result<(Pin<Box<dyn Future<Output = _>>>, _)> {
Expand Down
2 changes: 1 addition & 1 deletion pallets/common/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl CrossAddress {
} else if self.sub == Default::default() {
Ok(Some(T::CrossAccountId::from_eth(self.eth)))
} else {
Err(format!("All fields of cross account is non zeroed {:?}", self).into())
Err(format!("All fields of cross account is non zeroed {self:?}").into())
}
}

Expand Down
41 changes: 39 additions & 2 deletions pallets/nonfungible/src/erc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use core::{
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};
use evm_coder::{abi::AbiType, AbiCoder, ToLog, generate_stubgen, solidity_interface, types::*};
use frame_support::BoundedVec;
use up_data_structs::{
TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,
Expand Down Expand Up @@ -64,6 +64,15 @@ pub enum ERC721TokenEvent {
},
}

/// Token minting parameters
#[derive(AbiCoder, Default, Debug)]
pub struct MintTokenData {
/// Minted token owner
pub owner: eth::CrossAddress,
/// Minted token properties
pub properties: Vec<eth::Property>,
}

frontier_contract! {
macro_rules! NonfungibleHandle_result {...}
impl<T: Config> Contract for NonfungibleHandle<T> {...}
Expand Down Expand Up @@ -981,13 +990,41 @@ where
Ok(true)
}

/// @notice Function to mint a token.
/// @param data Array of pairs of token owner and token's properties for minted token
#[weight(<SelfWeightOf<T>>::create_multiple_items(data.len() as u32) + <SelfWeightOf<T>>::set_token_properties(data.len() as u32))]
fn mint_bulk_cross(&mut self, caller: Caller, data: Vec<MintTokenData>) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let budget = self
.recorder
.weight_calls_budget(<StructureWeight<T>>::find_parent());

let mut create_nft_data = Vec::with_capacity(data.len());
for MintTokenData { owner, properties } in data {
let owner = owner.into_sub_cross_account::<T>()?;
create_nft_data.push(CreateItemData::<T> {
properties: properties
.into_iter()
.map(|property| property.try_into())
.collect::<Result<Vec<_>>>()?
.try_into()
.map_err(|_| "too many properties")?,
owner,
});
}

<Pallet<T>>::create_multiple_items(self, &caller, create_nft_data, &budget)
.map_err(dispatch_to_evm::<T>)?;
Ok(true)
}

/// @notice Function to mint multiple tokens with the given tokenUris.
/// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
/// numbers and first number should be obtained with `nextTokenId` method
/// @param to The new owner
/// @param tokens array of pairs of token ID and token URI for minted tokens
#[solidity(hide, rename_selector = "mintBulkWithTokenURI")]
#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32) + <SelfWeightOf<T>>::set_token_properties(tokens.len() as u32))]
#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32) + <SelfWeightOf<T>>::set_token_properties(tokens.len() as u32))]
fn mint_bulk_with_token_uri(
&mut self,
caller: Caller,
Expand Down
Binary file modified pallets/nonfungible/src/stubs/UniqueNFT.raw
Binary file not shown.
21 changes: 20 additions & 1 deletion pallets/nonfungible/src/stubs/UniqueNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ contract ERC721UniqueMintable is Dummy, ERC165 {
}

/// @title Unique extensions for ERC721.
/// @dev the ERC-165 identifier for this interface is 0x307b061a
/// @dev the ERC-165 identifier for this interface is 0x9b397d16
contract ERC721UniqueExtensions is Dummy, ERC165 {
/// @notice A descriptive name for a collection of NFTs in this contract
/// @dev EVM selector for this function is: 0x06fdde03,
Expand Down Expand Up @@ -997,6 +997,17 @@ contract ERC721UniqueExtensions is Dummy, ERC165 {
// return false;
// }

/// @notice Function to mint a token.
/// @param data Array of pairs of token owner and token's properties for minted token
/// @dev EVM selector for this function is: 0xab427b0c,
/// or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[])
function mintBulkCross(MintTokenData[] memory data) public returns (bool) {
require(false, stub_error);
data;
dummy = 0;
return false;
}

// /// @notice Function to mint multiple tokens with the given tokenUris.
// /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
// /// numbers and first number should be obtained with `nextTokenId` method
Expand Down Expand Up @@ -1044,6 +1055,14 @@ struct TokenUri {
string uri;
}

/// Token minting parameters
struct MintTokenData {
/// Minted token owner
CrossAddress owner;
/// Minted token properties
Property[] properties;
}

/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev the ERC-165 identifier for this interface is 0x780e9d63
Expand Down
69 changes: 68 additions & 1 deletion pallets/refungible/src/erc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use core::{
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
};
use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};
use evm_coder::{abi::AbiType, AbiCoder, ToLog, generate_stubgen, solidity_interface, types::*};
use frame_support::{BoundedBTreeMap, BoundedVec};
use pallet_common::{
CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
Expand Down Expand Up @@ -71,6 +71,24 @@ pub enum ERC721TokenEvent {
},
}

/// Token minting parameters
#[derive(AbiCoder, Default, Debug)]
pub struct OwnerPieces {
/// Minted token owner
pub owner: eth::CrossAddress,
/// Number of token pieces
pub pieces: u128,
}

/// Token minting parameters
#[derive(AbiCoder, Default, Debug)]
pub struct MintTokenData {
/// Minted token owner and number of pieces
pub owners: Vec<OwnerPieces>,
/// Minted token properties
pub properties: Vec<eth::Property>,
}

/// @title A contract that allows to set and delete token properties and change token property permissions.
#[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> RefungibleHandle<T> {
Expand Down Expand Up @@ -1021,6 +1039,55 @@ where
Ok(true)
}

/// @notice Function to mint a token.
/// @param tokenProperties Properties of minted token
#[weight(if token_properties.len() == 1 {
<SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(token_properties.iter().next().unwrap().owners.len() as u32)
} else {
<SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(token_properties.len() as u32)
} + <SelfWeightOf<T>>::set_token_properties(token_properties.len() as u32))]
fn mint_bulk_cross(
&mut self,
caller: Caller,
token_properties: Vec<MintTokenData>,
) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
let budget = self
.recorder
.weight_calls_budget(<StructureWeight<T>>::find_parent());
let has_multiple_tokens = token_properties.len() > 1;

let mut create_rft_data = Vec::with_capacity(token_properties.len());
for MintTokenData { owners, properties } in token_properties {
let has_multiple_owners = owners.len() > 1;
if has_multiple_tokens & has_multiple_owners {
return Err(
"creation of multiple tokens supported only if they have single owner each"
.into(),
);
}
let users: BoundedBTreeMap<_, _, _> = owners
.into_iter()
.map(|data| Ok((data.owner.into_sub_cross_account::<T>()?, data.pieces)))
.collect::<Result<BTreeMap<_, _>>>()?
.try_into()
.map_err(|_| "too many users")?;
create_rft_data.push(CreateItemData::<T> {
properties: properties
.into_iter()
.map(|property| property.try_into())
.collect::<Result<Vec<_>>>()?
.try_into()
.map_err(|_| "too many properties")?,
users,
});
}

<Pallet<T>>::create_multiple_items(self, &caller, create_rft_data, &budget)
.map_err(dispatch_to_evm::<T>)?;
Ok(true)
}

/// @notice Function to mint multiple tokens with the given tokenUris.
/// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
/// numbers and first number should be obtained with `nextTokenId` method
Expand Down
Binary file modified pallets/refungible/src/stubs/UniqueRefungible.raw
Binary file not shown.
29 changes: 28 additions & 1 deletion pallets/refungible/src/stubs/UniqueRefungible.sol
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ contract ERC721UniqueMintable is Dummy, ERC165 {
}

/// @title Unique extensions for ERC721.
/// @dev the ERC-165 identifier for this interface is 0x95c0f66c
/// @dev the ERC-165 identifier for this interface is 0x4abaabdb
contract ERC721UniqueExtensions is Dummy, ERC165 {
/// @notice A descriptive name for a collection of NFTs in this contract
/// @dev EVM selector for this function is: 0x06fdde03,
Expand Down Expand Up @@ -986,6 +986,17 @@ contract ERC721UniqueExtensions is Dummy, ERC165 {
// return false;
// }

/// @notice Function to mint a token.
/// @param tokenProperties Properties of minted token
/// @dev EVM selector for this function is: 0xdf7a5db7,
/// or in textual repr: mintBulkCross((((address,uint256),uint128)[],(string,bytes)[])[])
function mintBulkCross(MintTokenData[] memory tokenProperties) public returns (bool) {
require(false, stub_error);
tokenProperties;
dummy = 0;
return false;
}

// /// @notice Function to mint multiple tokens with the given tokenUris.
// /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
// /// numbers and first number should be obtained with `nextTokenId` method
Expand Down Expand Up @@ -1045,6 +1056,22 @@ struct TokenUri {
string uri;
}

/// Token minting parameters
struct MintTokenData {
/// Minted token owner and number of pieces
OwnerPieces[] owners;
/// Minted token properties
Property[] properties;
}

/// Token minting parameters
struct OwnerPieces {
/// Minted token owner
CrossAddress owner;
/// Number of token pieces
uint128 pieces;
}

/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev the ERC-165 identifier for this interface is 0x780e9d63
Expand Down
6 changes: 4 additions & 2 deletions pallets/scheduler-v2/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> ScheduledCall<T> {
let bound = EncodedCall::bound() as u32;
let mut len = match maybe_lookup_len {
Some(len) => {
len.min(<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2)
.max(bound) - 3
len.clamp(
bound,
<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2,
) - 3
}
None => bound.saturating_sub(4),
};
Expand Down
Binary file modified pallets/unique/src/eth/stubs/CollectionHelpers.raw
Binary file not shown.
29 changes: 14 additions & 15 deletions pallets/unique/src/eth/stubs/CollectionHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ contract CollectionHelpersEvents {
}

/// @title Contract, which allows users to operate with collections
/// @dev the ERC-165 identifier for this interface is 0x4135fff1
/// @dev the ERC-165 identifier for this interface is 0x94e5af0d
contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
/// Create a collection
/// @return address Address of the newly created collection
/// @dev EVM selector for this function is: 0xa765ee5b,
/// or in textual repr: createCollection(((address,uint256),string,string,string,uint8,uint8,(string,bytes)[],(string,(uint8,bool)[])[],(address,uint256)[],(bool,bool,address[]),(uint8,uint256)[],uint8))
/// @dev EVM selector for this function is: 0x72b5bea7,
/// or in textual repr: createCollection((string,string,string,uint8,uint8,(string,bytes)[],(string,(uint8,bool)[])[],(address,uint256)[],(bool,bool,address[]),(uint8,uint256)[],(address,uint256),uint8))
function createCollection(CreateCollectionData memory data) public payable returns (address) {
require(false, stub_error);
data;
Expand Down Expand Up @@ -170,8 +170,6 @@ contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {

/// Collection properties
struct CreateCollectionData {
/// Collection sponsor
CrossAddress pending_sponsor;
/// Collection name
string name;
/// Collection description
Expand All @@ -192,11 +190,12 @@ struct CreateCollectionData {
CollectionNestingAndPermission nesting_settings;
/// Collection limits
CollectionLimitValue[] limits;
/// Collection sponsor
CrossAddress pending_sponsor;
/// Extra collection flags
CollectionFlags flags;
}

/// Cross account struct
type CollectionFlags is uint8;

library CollectionFlagsLib {
Expand All @@ -207,13 +206,19 @@ library CollectionFlagsLib {
/// External collections can't be managed using `unique` api
CollectionFlags constant externalField = CollectionFlags.wrap(1);

/// Reserved bits
/// Reserved flags
function reservedField(uint8 value) public pure returns (CollectionFlags) {
require(value < 1 << 5, "out of bound value");
return CollectionFlags.wrap(value << 1);
}
}

/// Cross account struct
struct CrossAddress {
address eth;
uint256 sub;
}

/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
struct CollectionLimitValue {
CollectionLimitField field;
Expand Down Expand Up @@ -252,12 +257,6 @@ struct CollectionNestingAndPermission {
address[] restricted;
}

/// Cross account struct
struct CrossAddress {
address eth;
uint256 sub;
}

/// Ethereum representation of Token Property Permissions.
struct TokenPropertyPermission {
/// Token property key.
Expand Down Expand Up @@ -292,10 +291,10 @@ struct Property {

/// Type of tokens in collection
enum CollectionMode {
/// Fungible
Fungible,
/// Nonfungible
Nonfungible,
/// Fungible
Fungible,
/// Refungible
Refungible
}
1 change: 1 addition & 0 deletions runtime/common/ethereum/sponsoring/refungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ mod erc721 {
BurnFrom { .. }
| BurnFromCross { .. }
| MintBulk { .. }
| MintBulkCross { .. }
| MintBulkWithTokenUri { .. } => None,

MintCross { .. } => withdraw_create_item::<T>(
Expand Down
2 changes: 1 addition & 1 deletion runtime/common/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const PARA_ID: u32 = 2095;
const PARA_ID: u32 = 2037;

fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
TPublic::Pair::from_string(&format!("//{seed}"), None)
.expect("static values are valid; qed")
.public()
}
Expand Down
Loading

0 comments on commit 448629b

Please sign in to comment.