git.delta.rocks / unique-network / refs/commits / 118b8d5eaba9

difftreelog

feature: add `createERC721MetadataCompatibleRFTCollection` method

Trubnikov Sergey2022-07-25parent: #e516992.patch.diff
in: master

4 files changed

modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -237,6 +237,33 @@
 		Ok(address)
 	}
 
+	#[weight(<SelfWeightOf<T>>::create_collection())]
+	#[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")]
+	fn create_refungible_collection_with_properties(
+		&mut self,
+		caller: caller,
+		name: string,
+		description: string,
+		token_prefix: string,
+		base_uri: string,
+	) -> Result<address> {
+		let (caller, name, description, token_prefix, base_uri_value) =
+			convert_data::<T>(caller, name, description, token_prefix, base_uri)?;
+		let data = make_data::<T>(
+			name,
+			CollectionMode::NFT,
+			description,
+			token_prefix,
+			base_uri_value,
+			true,
+		)?;
+		let collection_id = <pallet_refungible::Pallet<T>>::init_collection(caller.clone(), data)
+			.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+
+		let address = pallet_common::eth::collection_id_to_address(collection_id);
+		Ok(address)
+	}
+
 	/// Check if a collection exists
 	/// @param collection_address Address of the collection in question
 	/// @return bool Does the collection exist?
addedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+// Common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+// Selector: 7d9262e6
+interface Collection is Dummy, ERC165 {
+	// Set collection property.
+	//
+	// @param key Property key.
+	// @param value Propery value.
+	//
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		external;
+
+	// Delete collection property.
+	//
+	// @param key Property key.
+	//
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) external;
+
+	// Get collection property.
+	//
+	// @dev Throws error if key not found.
+	//
+	// @param key Property key.
+	// @return bytes The property corresponding to the key.
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		external
+		view
+		returns (bytes memory);
+
+	// Set the sponsor of the collection.
+	//
+	// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	//
+	// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	//
+	// Selector: setCollectionSponsor(address) 7623402e
+	function setCollectionSponsor(address sponsor) external;
+
+	// Collection sponsorship confirmation.
+	//
+	// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	//
+	// Selector: confirmCollectionSponsorship() 3c50e97a
+	function confirmCollectionSponsorship() external;
+
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"accountTokenOwnershipLimit",
+	// 	"sponsoredDataSize",
+	// 	"sponsoredDataRateLimit",
+	// 	"tokenLimit",
+	// 	"sponsorTransferTimeout",
+	// 	"sponsorApproveTimeout"
+	// @param value Value of the limit.
+	//
+	// Selector: setCollectionLimit(string,uint32) 6a3841db
+	function setCollectionLimit(string memory limit, uint32 value) external;
+
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"ownerCanTransfer",
+	// 	"ownerCanDestroy",
+	// 	"transfersEnabled"
+	// @param value Value of the limit.
+	//
+	// Selector: setCollectionLimit(string,bool) 993b7fba
+	function setCollectionLimit(string memory limit, bool value) external;
+
+	// Get contract address.
+	//
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() external view returns (address);
+
+	// Add collection admin by substrate address.
+	// @param new_admin Substrate administrator address.
+	//
+	// Selector: addCollectionAdminSubstrate(uint256) 5730062b
+	function addCollectionAdminSubstrate(uint256 newAdmin) external;
+
+	// Remove collection admin by substrate address.
+	// @param admin Substrate administrator address.
+	//
+	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
+	function removeCollectionAdminSubstrate(uint256 admin) external;
+
+	// Add collection admin.
+	// @param new_admin Address of the added administrator.
+	//
+	// Selector: addCollectionAdmin(address) 92e462c7
+	function addCollectionAdmin(address newAdmin) external;
+
+	// Remove collection admin.
+	//
+	// @param new_admin Address of the removed administrator.
+	//
+	// Selector: removeCollectionAdmin(address) fafd7b42
+	function removeCollectionAdmin(address admin) external;
+
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	//
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) external;
+
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// @param collections Addresses of collections that will be available for nesting.
+	//
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		external;
+
+	// Set the collection access method.
+	// @param mode Access mode
+	// 	0 for Normal
+	// 	1 for AllowList
+	//
+	// Selector: setCollectionAccess(uint8) 41835d4c
+	function setCollectionAccess(uint8 mode) external;
+
+	// Add the user to the allowed list.
+	//
+	// @param user Address of a trusted user.
+	//
+	// Selector: addToCollectionAllowList(address) 67844fe6
+	function addToCollectionAllowList(address user) external;
+
+	// Remove the user from the allowed list.
+	//
+	// @param user Address of a removed user.
+	//
+	// Selector: removeFromCollectionAllowList(address) 85c51acb
+	function removeFromCollectionAllowList(address user) external;
+
+	// Switch permission for minting.
+	//
+	// @param mode Enable if "true".
+	//
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) external;
+}
+
+interface UniqueRefungible is Dummy, ERC165, Collection {}
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -72,7 +72,7 @@
   });
 });
 
-describe('Check ERC721 token URI', () => {
+describe('Check ERC721 token URI for NFT', () => {
   itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';17import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';
18import {createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';
19import reFungibleTokenAbi from './reFungibleTokenAbi.json';19import reFungibleTokenAbi from './reFungibleTokenAbi.json';
2020
21import chai from 'chai';21import chai from 'chai';
73 });73 });
74});74});
75
76// FIXME: Need erc721 for ReFubgible.
77describe.skip('Check ERC721 token URI for ReFungible', () => {
78 itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
79 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
80 const helper = evmCollectionHelpers(web3, owner);
81 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();
82 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
83 const receiver = createEthAccount(web3);
84 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
85
86 const nextTokenId = await contract.methods.nextTokenId().call();
87 expect(nextTokenId).to.be.equal('1');
88 result = await contract.methods.mint(
89 receiver,
90 nextTokenId,
91 ).send();
92
93 const events = normalizeEvents(result.events);
94 const address = collectionIdToAddress(collectionId);
95
96 expect(events).to.be.deep.equal([
97 {
98 address,
99 event: 'Transfer',
100 args: {
101 from: '0x0000000000000000000000000000000000000000',
102 to: receiver,
103 tokenId: nextTokenId,
104 },
105 },
106 ]);
107
108 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
109 });
110
111 itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {
112 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
113 const helper = evmCollectionHelpers(web3, owner);
114 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
115 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
116 const receiver = createEthAccount(web3);
117 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
118
119 const nextTokenId = await contract.methods.nextTokenId().call();
120 expect(nextTokenId).to.be.equal('1');
121 result = await contract.methods.mint(
122 receiver,
123 nextTokenId,
124 ).send();
125
126 // Set URL
127 await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
128
129 const events = normalizeEvents(result.events);
130 const address = collectionIdToAddress(collectionId);
131
132 expect(events).to.be.deep.equal([
133 {
134 address,
135 event: 'Transfer',
136 args: {
137 from: '0x0000000000000000000000000000000000000000',
138 to: receiver,
139 tokenId: nextTokenId,
140 },
141 },
142 ]);
143
144 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
145 });
146
147 itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {
148 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
149 const helper = evmCollectionHelpers(web3, owner);
150 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
151 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
152 const receiver = createEthAccount(web3);
153 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
154
155 const nextTokenId = await contract.methods.nextTokenId().call();
156 expect(nextTokenId).to.be.equal('1');
157 result = await contract.methods.mint(
158 receiver,
159 nextTokenId,
160 ).send();
161
162 const events = normalizeEvents(result.events);
163 const address = collectionIdToAddress(collectionId);
164
165 expect(events).to.be.deep.equal([
166 {
167 address,
168 event: 'Transfer',
169 args: {
170 from: '0x0000000000000000000000000000000000000000',
171 to: receiver,
172 tokenId: nextTokenId,
173 },
174 },
175 ]);
176
177 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
178 });
179
180 itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {
181 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
182 const helper = evmCollectionHelpers(web3, owner);
183 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
184 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
185 const receiver = createEthAccount(web3);
186 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
187
188 const nextTokenId = await contract.methods.nextTokenId().call();
189 expect(nextTokenId).to.be.equal('1');
190 result = await contract.methods.mint(
191 receiver,
192 nextTokenId,
193 ).send();
194
195 // Set suffix
196 const suffix = '/some/suffix';
197 await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();
198
199 const events = normalizeEvents(result.events);
200 const address = collectionIdToAddress(collectionId);
201
202 expect(events).to.be.deep.equal([
203 {
204 address,
205 event: 'Transfer',
206 args: {
207 from: '0x0000000000000000000000000000000000000000',
208 to: receiver,
209 tokenId: nextTokenId,
210 },
211 },
212 ]);
213
214 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
215 });
216});
75217
76describe('Refungible: Plain calls', () => {218describe('Refungible: Plain calls', () => {
77 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {219 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {