difftreelog
feature: make collection creation methods `payable`
in: master
19 files changed
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -560,6 +560,7 @@
selector: u32,
args: Vec<MethodArg>,
has_normal_args: bool,
+ has_value_args: bool,
mutability: Mutability,
result: Type,
weight: Option<Expr>,
@@ -647,14 +648,20 @@
.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));
let mut selector_str = camel_name.clone();
selector_str.push('(');
- let mut has_normal_args = false;
- for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {
- if i != 0 {
- selector_str.push(',');
+ let mut normal_args_count = 0u32;
+ let mut has_value_args = false;
+ for arg in args.iter() {
+ if arg.is_value() {
+ has_value_args = true;
+ } else if !arg.is_special() {
+ if normal_args_count != 0 {
+ selector_str.push(',');
+ }
+ write!(selector_str, "{}", arg.selector_ty()).unwrap();
+ normal_args_count = normal_args_count.saturating_add(1);
}
- write!(selector_str, "{}", arg.selector_ty()).unwrap();
- has_normal_args = true;
}
+ let has_normal_args = normal_args_count > 0;
selector_str.push(')');
let selector = fn_selector_str(&selector_str);
@@ -667,6 +674,7 @@
selector,
args,
has_normal_args,
+ has_value_args,
mutability,
result: result.clone(),
weight,
@@ -823,7 +831,7 @@
let docs = &self.docs;
let selector_str = &self.selector_str;
let selector = self.selector;
-
+ let is_payable = self.has_value_args;
quote! {
SolidityFunction {
docs: &[#(#docs),*],
@@ -831,6 +839,7 @@
selector: #selector,
name: #camel_name,
mutability: #mutability,
+ is_payable: #is_payable,
args: (
#(
#args,
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -422,6 +422,7 @@
pub args: A,
pub result: R,
pub mutability: SolidityMutability,
+ pub is_payable: bool,
}
impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {
fn solidity_name(
@@ -452,6 +453,9 @@
SolidityMutability::View => write!(writer, " view")?,
SolidityMutability::Mutable => {}
}
+ if self.is_payable {
+ write!(writer, " payable")?;
+ }
if !self.result.is_empty() {
write!(writer, " returns (")?;
self.result.solidity_name(writer, tc)?;
pallets/common/src/dispatch.rsdiffbeforeafterboth78 /// * `data` - Description of the created collection.78 /// * `data` - Description of the created collection.79 fn create(79 fn create(80 sender: T::CrossAccountId,80 sender: T::CrossAccountId,81 payer: T::CrossAccountId,81 data: CreateCollectionData<T::AccountId>,82 data: CreateCollectionData<T::AccountId>,82 ) -> Result<CollectionId, DispatchError>;83 ) -> Result<CollectionId, DispatchError>;8384pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -866,6 +866,7 @@
/// * `flags` - Extra flags to store.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
flags: CollectionFlags,
) -> Result<CollectionId, DispatchError> {
@@ -939,7 +940,7 @@
),
);
<T as Config>::Currency::settle(
- owner.as_sub(),
+ payer.as_sub(),
imbalance,
WithdrawReasons::TRANSFER,
ExistenceRequirement::KeepAlive,
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/lib.rs
+++ b/pallets/foreign-assets/src/lib.rs
@@ -309,9 +309,10 @@
mode: CollectionMode::Fungible(md.decimals),
..Default::default()
};
-
+ let owner = T::CrossAccountId::from_sub(owner);
let bounded_collection_id = <PalletFungible<T>>::init_foreign_collection(
- CrossAccountId::from_sub(owner),
+ owner.clone(),
+ owner,
data,
)?;
let foreign_asset_id =
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -210,18 +210,21 @@
/// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())
+ <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())
}
/// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise.
pub fn init_foreign_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
let id = <PalletCommon<T>>::init_collection(
owner,
+ payer,
data,
CollectionFlags {
foreign: true,
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -405,11 +405,13 @@
/// - `data`: Contains settings for collection limits and permissions.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
is_external: bool,
) -> Result<CollectionId, DispatchError> {
<PalletCommon<T>>::init_collection(
owner,
+ payer,
data,
CollectionFlags {
external: is_external,
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -1448,7 +1448,7 @@
data: CreateCollectionData<T::AccountId>,
properties: impl Iterator<Item = Property>,
) -> Result<CollectionId, DispatchError> {
- let collection_id = <PalletNft<T>>::init_collection(sender, data, true);
+ let collection_id = <PalletNft<T>>::init_collection(sender.clone(), sender, data, true);
if let Err(DispatchError::Arithmetic(_)) = &collection_id {
return Err(<Error<T>>::NoAvailableCollectionId.into());
pallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -251,7 +251,7 @@
};
let collection_id_res =
- <PalletNft<T>>::init_collection(cross_sender.clone(), data, true);
+ <PalletNft<T>>::init_collection(cross_sender.clone(), cross_sender.clone(), data, true);
if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
return Err(<Error<T>>::NoAvailableBaseId.into());
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -373,9 +373,10 @@
/// - `data`: Contains settings for collection limits and permissions.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())
+ <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())
}
/// Destroy RFT collection
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -28,7 +28,7 @@
static_property::{key, value as property_value},
},
};
-use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
+use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};
use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};
use up_data_structs::{
CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,
@@ -156,6 +156,7 @@
T: Config + pallet_nonfungible::Config + pallet_refungible::Config,
>(
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
@@ -172,8 +173,16 @@
base_uri_value,
add_properties,
)?;
+ let value = value.as_u128();
+ let creation_price: Result<u128> = T::CollectionCreationPrice::get()
+ .try_into()
+ .map_err(|_| "collection creation price should be convertible to u128".into());
+ if value != creation_price? {
+ return Err("Sent amount not equals to collection creation price".into());
+ }
+ let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
- let collection_id = T::CollectionDispatch::create(caller.clone(), data)
+ let collection_id = T::CollectionDispatch::create(caller.clone(), collection_helpers_address, data)
.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
Ok(address)
@@ -183,7 +192,7 @@
#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]
impl<T> EvmCollectionHelpers<T>
where
- T: Config + pallet_nonfungible::Config + pallet_refungible::Config,
+ T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,
{
/// Create an NFT collection
/// @param name Name of the collection
@@ -209,8 +218,17 @@
Default::default(),
false,
)?;
- let collection_id = T::CollectionDispatch::create(caller, data)
- .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+ let value = value.as_u128();
+ let creation_price: Result<u128> = T::CollectionCreationPrice::get()
+ .try_into()
+ .map_err(|_| "collection creation price should be convertible to u128".into());
+ let creation_price = creation_price?;
+ if value != creation_price {
+ return Err(format!("Sent amount not equals to collection creation price ({0})", creation_price).into());
+ }
+ let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
+ let collection_id =
+ T::CollectionDispatch::create(caller, collection_helpers_address, data).map_err(dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
Ok(address)
@@ -221,6 +239,7 @@
fn create_nonfungible_collection_with_properties(
&mut self,
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
@@ -236,7 +255,15 @@
base_uri_value,
true,
)?;
- let collection_id = T::CollectionDispatch::create(caller, data)
+ let value = value.as_u128();
+ let creation_price: Result<u128> = T::CollectionCreationPrice::get()
+ .try_into()
+ .map_err(|_| "collection creation price should be convertible to u128".into());
+ if value != creation_price? {
+ return Err("Sent amount not equals to collection creation price".into());
+ }
+ let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
+ let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)
.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
@@ -248,12 +275,14 @@
fn create_refungible_collection(
&mut self,
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
) -> Result<address> {
create_refungible_collection_internal::<T>(
caller,
+ value,
name,
description,
token_prefix,
@@ -267,6 +296,7 @@
fn create_refungible_collection_with_properties(
&mut self,
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
@@ -274,6 +304,7 @@
) -> Result<address> {
create_refungible_collection_internal::<T>(
caller,
+ value,
name,
description,
token_prefix,
pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth--- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol
+++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol
@@ -36,7 +36,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -52,7 +52,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -68,7 +68,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -84,7 +84,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -344,8 +344,8 @@
let sender = ensure_signed(origin)?;
// =========
-
- let _id = T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;
+ let sender = T::CrossAccountId::from_sub(sender);
+ let _id = T::CollectionDispatch::create(sender.clone(), sender, data)?;
Ok(())
}
runtime/common/dispatch.rsdiffbeforeafterboth--- a/runtime/common/dispatch.rs
+++ b/runtime/common/dispatch.rs
@@ -55,21 +55,22 @@
{
fn create(
sender: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
let id = match data.mode {
- CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
+ CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, payer, data, false)?,
CollectionMode::Fungible(decimal_points) => {
// check params
ensure!(
decimal_points <= MAX_DECIMAL_POINTS,
pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
);
- <PalletFungible<T>>::init_collection(sender, data)?
+ <PalletFungible<T>>::init_collection(sender, payer, data)?
}
#[cfg(feature = "refungible")]
- CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
+ CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, payer, data)?,
#[cfg(not(feature = "refungible"))]
CollectionMode::ReFungible => return unsupported!(T),
tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth--- a/tests/src/eth/api/CollectionHelpers.sol
+++ b/tests/src/eth/api/CollectionHelpers.sol
@@ -31,7 +31,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xa634a5f9,
/// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)
@@ -40,7 +40,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xab173450,
/// or in textual repr: createRFTCollection(string,string,string)
@@ -48,7 +48,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xa5596388,
/// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)
@@ -57,7 +57,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) external returns (address);
+ ) external payable returns (address);
/// Check if a collection exists
/// @param collectionAddress Address of the collection in question
tests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth--- a/tests/src/eth/collectionHelpersAbi.json
+++ b/tests/src/eth/collectionHelpersAbi.json
@@ -27,7 +27,7 @@
],
"name": "createERC721MetadataCompatibleCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -39,7 +39,7 @@
],
"name": "createERC721MetadataCompatibleRFTCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -50,7 +50,7 @@
],
"name": "createNonfungibleCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -61,7 +61,7 @@
],
"name": "createRFTCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth--- a/tests/src/eth/fractionalizer/Fractionalizer.sol
+++ b/tests/src/eth/fractionalizer/Fractionalizer.sol
@@ -18,7 +18,8 @@
mapping(address => bool) nftCollectionAllowList;
mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;
mapping(address => Token) public rft2nftMapping;
- bytes32 refungibleCollectionType = keccak256(bytes("ReFungible"));
+ //use constant to reduce gas cost
+ bytes32 constant refungibleCollectionType = keccak256(bytes("ReFungible"));
receive() external payable onlyOwner {}
@@ -51,11 +52,12 @@
/// Throws if `msg.sender` is not owner or admin of provided RFT collection.
/// Can only be called by contract owner.
/// @param _collection address of RFT collection.
- function setRFTCollection(address _collection) public onlyOwner {
+ function setRFTCollection(address _collection) external onlyOwner {
require(rftCollection == address(0), "RFT collection is already set");
UniqueRefungible refungibleContract = UniqueRefungible(_collection);
string memory collectionType = refungibleContract.uniqueCollectionType();
+ // compare hashed to reduce gas cost
require(
keccak256(bytes(collectionType)) == refungibleCollectionType,
"Wrong collection type. Collection is not refungible."
@@ -79,7 +81,7 @@
string calldata _name,
string calldata _description,
string calldata _tokenPrefix
- ) public onlyOwner {
+ ) external onlyOwner {
require(rftCollection == address(0), "RFT collection is already set");
address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection(_name, _description, _tokenPrefix);
@@ -90,7 +92,7 @@
/// @dev Can only be called by contract owner.
/// @param collection NFT token address.
/// @param status `true` to allow and `false` to disallow NFT token.
- function setNftCollectionIsAllowed(address collection, bool status) public onlyOwner {
+ function setNftCollectionIsAllowed(address collection, bool status) external onlyOwner {
nftCollectionAllowList[collection] = status;
emit AllowListSet(collection, status);
}
@@ -109,7 +111,7 @@
address _collection,
uint256 _token,
uint128 _pieces
- ) public {
+ ) external {
require(rftCollection != address(0), "RFT collection is not set");
UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
require(
@@ -148,7 +150,7 @@
/// Throws if `msg.sender` isn't owner of all RFT token pieces.
/// @param _collection RFT collection address
/// @param _token id of RFT token
- function rft2nft(address _collection, uint256 _token) public {
+ function rft2nft(address _collection, uint256 _token) external {
require(rftCollection != address(0), "RFT collection is not set");
require(rftCollection == _collection, "Wrong RFT collection");
UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
tests/src/eth/payable.test.tsdiffbeforeafterboth--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -140,16 +140,13 @@
});
itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {
- const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
const deployer = await helper.eth.createAccountWithBalance(donor);
const caller = await helper.eth.createAccountWithBalance(donor);
const contract = await deployProxyContract(helper, deployer);
-
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
- const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller})).events.CollectionCreated.returnValues.collection;
+ const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection;
const initialCallerBalance = await helper.balance.getEthereum(caller);
const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
await contract.methods.mintNftToken(collectionAddress).send({from: caller});
@@ -160,22 +157,18 @@
});
itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {
- const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();
-
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
const deployer = await helper.eth.createAccountWithBalance(donor);
const caller = await helper.eth.createAccountWithBalance(donor);
const contract = await deployProxyContract(helper, deployer);
-
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
const initialCallerBalance = await helper.balance.getEthereum(caller);
const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
- await contract.methods.createNonfungibleCollection().send({from: caller});
+ await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)});
const finalCallerBalance = await helper.balance.getEthereum(caller);
const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
expect(finalCallerBalance < initialCallerBalance).to.be.true;
- expect(finalContractBalance < initialContractBalance).to.be.true;
+ expect(finalContractBalance == initialContractBalance).to.be.true;
});
async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
@@ -189,6 +182,8 @@
import {CollectionHelpers} from "../api/CollectionHelpers.sol";
import {UniqueNFT} from "../api/UniqueNFT.sol";
+ error Value(uint256 value);
+
contract ProxyContract {
bool value = false;
address flipper;
@@ -207,30 +202,30 @@
Flipper(flipper).flip();
}
- function createNonfungibleCollection() public {
+ function createNonfungibleCollection() external payable {
address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
- address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection("A", "B", "C");
+ address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection{value: msg.value}("A", "B", "C");
emit CollectionCreated(nftCollection);
}
- function mintNftToken(address collectionAddress) public {
+ function mintNftToken(address collectionAddress) external {
UniqueNFT collection = UniqueNFT(collectionAddress);
uint256 tokenId = collection.nextTokenId();
collection.mint(msg.sender, tokenId);
emit TokenMinted(tokenId);
}
- function getValue() public view returns (bool) {
+ function getValue() external view returns (bool) {
return Flipper(flipper).getValue();
}
}
contract Flipper {
bool value = false;
- function flip() public {
+ function flip() external {
value = !value;
}
- function getValue() public view returns (bool) {
+ function getValue() external view returns (bool) {
return value;
}
}