From 988703213763fed0d34cba15ec80558008409848 Mon Sep 17 00:00:00 2001 From: adriandelgg Date: Mon, 14 Jun 2021 00:41:15 -0700 Subject: [PATCH] Created Token URI smart contract and added new mint function --- contracts/ColorMinter.sol | 4 +- contracts/ERC721URIStorage.sol | 81 ++++++++++++++++++++++++++++++++++ contracts/Exchange.sol | 6 ++- test/Exchange.test.js | 46 ++++++++++++++++++- 4 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 contracts/ERC721URIStorage.sol diff --git a/contracts/ColorMinter.sol b/contracts/ColorMinter.sol index 31e59d3..3c6eed9 100644 --- a/contracts/ColorMinter.sol +++ b/contracts/ColorMinter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "./ERC721URIStorage.sol"; /** * @title An NFT minter @@ -10,7 +10,7 @@ import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721En // Charge a few in order to mint a token // Set Token URI w/ IPFS metadata -contract ColorMinter is ERC721Enumerable { +contract ColorMinter is ERC721URIStorage { // The token ID that will be given to new minted tokens. uint256 private _tokenId; diff --git a/contracts/ERC721URIStorage.sol b/contracts/ERC721URIStorage.sol new file mode 100644 index 0000000..d85904c --- /dev/null +++ b/contracts/ERC721URIStorage.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; + +/** + * @title ERC721 implementing Token URI + * @dev ERC721 token with storage based token URI management. + */ +abstract contract ERC721URIStorage is ERC721Enumerable { + using Strings for uint256; + + // Optional mapping for token URIs + mapping(uint256 => string) private _tokenURIs; + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) + public + view + virtual + override + returns (string memory) + { + require( + _exists(tokenId), + "ERC721URIStorage: URI query for nonexistent token" + ); + + string memory _tokenURI = _tokenURIs[tokenId]; + string memory base = _baseURI(); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). + if (bytes(_tokenURI).length > 0) { + return string(abi.encodePacked(base, _tokenURI)); + } + + return super.tokenURI(tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) + internal + virtual + { + require( + _exists(tokenId), + "ERC721URIStorage: URI set of nonexistent token" + ); + _tokenURIs[tokenId] = _tokenURI; + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual override { + super._burn(tokenId); + + if (bytes(_tokenURIs[tokenId]).length != 0) { + delete _tokenURIs[tokenId]; + } + } +} diff --git a/contracts/Exchange.sol b/contracts/Exchange.sol index 42eb592..cce2fc0 100644 --- a/contracts/Exchange.sol +++ b/contracts/Exchange.sol @@ -51,9 +51,13 @@ contract Exchange is Ownable, ColorMinter, ERC721Holder { return _tokenInfo[_tokenId]; } + /** + * @dev Mints a new NFT & tethers a URI to it. Also accepts + * 1e12 ETH as payment for minting. + */ function mintNFT(string memory _tokenUri) public payable { uint256 tokenId = mint(_tokenUri); - // _setTokenURI(tokenId, _tokenUri); //Needs to set tokenURI + _setTokenURI(tokenId, _tokenUri); } /** diff --git a/test/Exchange.test.js b/test/Exchange.test.js index 29d6b4a..bf7a9ca 100644 --- a/test/Exchange.test.js +++ b/test/Exchange.test.js @@ -173,7 +173,7 @@ contract('Exchange', accounts => { console.log(result); }); - it('should let seller get their token back after selling to exchange', async () => { + xit('should let seller get their token back after selling to exchange', async () => { await contract.mint('#FFFFF'); await contract.sellNFT(1, 3e12); @@ -191,5 +191,49 @@ contract('Exchange', accounts => { assert.equal(newOwner, alice); }); + + xit('should set URI', async () => { + await contract.mintNFT( + 'https://ipfs.io/ipfs/QmQEVVLJUR1WLN15S49rzDJsSP7za9DxeqpUzWuG4aondg', + { value: 1e12 } + ); + + const result = await contract.tokenURI(1); + + console.log(result); + assert.equal( + result, + 'https://ipfs.io/ipfs/QmQEVVLJUR1WLN15S49rzDJsSP7za9DxeqpUzWuG4aondg' + ); + + const total = await web3.eth.getBalance(contract.address); + console.log(total); + assert.equal(total, 1e12); + }); + + it('should withdraw all ETH', async () => { + await contract.mintNFT( + 'https://ipfs.io/ipfs/QmQEVVLJUR1WLN15S49rzDJsSP7za9DxeqpUzWuG4aondg', + { from: alice, value: 1e12 } + ); + + const owner = await contract.owner(); + + assert.equal(owner, alice); + + // const before = await web3.eth.getBalance(contract.address); + const alicebefore = await web3.eth.getBalance(alice); + + const result = await contract.withdrawAll(); + + // const after = await web3.eth.getBalance(contract.address); + const aliceafter = await web3.eth.getBalance(alice); + + console.log(alicebefore); + console.log(aliceafter); + + // console.log(alicebefore); + // console.log(aliceafter); + }); }); });