You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All my code seems to be working (contract, deployments etc.)
However, with regards to minting the dynamic SVG NFT, I always seem to get a price of 0, which means I always get the frowny smiley.
While doing the unit tests, the contract actually worked in the rigth way, so I am thinking it has something to do with the MockV3Aggregator, but I can't find what. Here is my code:
Contract
// SPDX-License-Identifier: MITpragma solidity^0.8.8;
import"@openzeppelin/contracts/token/ERC721/ERC721.sol";
import"base64-sol/base64.sol";
import"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contractDynamicSvgNftisERC721 {
// mint// store our SVG information somewhere// Show x image, or Y image based on Zuint256private s_tokenCounter;
stringprivate i_lowImageUri;
stringprivate i_highImageUri;
stringprivate constant base64EncodedSvgPrefix ="data:image/svg+xml;base64,";
AggregatorV3Interface internalimmutable i_priceFeed;
mapping(uint256=>int256) public s_tokenIdToHighValue;
event CreatedNft(uint256indexedtokenId, int256highValue);
constructor(
addresspriceFeedAddress,
stringmemorylowSvg,
stringmemoryhighSvg
) ERC721("Dynamic SVG NFT", "DSN") {
s_tokenCounter =0;
i_lowImageUri =svgToImageUri(lowSvg);
i_highImageUri =svgToImageUri(highSvg);
i_priceFeed =AggregatorV3Interface(priceFeedAddress);
}
// We can't just paste the SVG code, since this will not generate an image URI.// Hence, we need a function to convert this SVG code to an image URI// For this, we need to use Base64// We needfunction svgToImageUri(stringmemorysvg) publicpurereturns (stringmemory) {
// we are gonna give this function an SVG, passed in from our constructor// we are gonna return a string, the base64 encoded URLstringmemory svgBase64Encoded = Base64.encode(bytes(string(abi.encodePacked(svg))));
returnstring(abi.encodePacked(base64EncodedSvgPrefix, svgBase64Encoded));
// we are encoding them to our bytes implementation, and then typecasting them back from bytes to strings (see notes in Word)
}
function mintNft(int256highValue) public {
s_tokenIdToHighValue[s_tokenCounter] = highValue;
_safeMint(msg.sender, s_tokenCounter);
s_tokenCounter = s_tokenCounter +1;
// must be beneath the functionemitCreatedNft(s_tokenCounter, highValue);
}
function _baseURI() internalpureoverridereturns (stringmemory) {
return"data:application/json;base64,";
}
function tokenURI(uint256tokenId) publicviewoverridereturns (stringmemory) {
address owner =_ownerOf(tokenId);
if (owner ==address(0)) {
revertERC721NonexistentToken(tokenId);
}
(, int256price, , , ) = i_priceFeed.latestRoundData();
stringmemory imageURI = i_lowImageUri;
if (price >= s_tokenIdToHighValue[tokenId]) {
imageURI = i_highImageUri;
}
returnstring(
abi.encodePacked(
_baseURI(),
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
name(), // You can add whatever name here'", "description":"An NFT that changes based on the Chainlink Feed", ',
'"attributes": [{"trait_type": "coolness", "value": 100}], "image":"',
imageURI,
'"}'
)
)
)
)
);
}
function getLowSVG() publicviewreturns (stringmemory) {
return i_lowImageUri;
}
function getHighSVG() publicviewreturns (stringmemory) {
return i_highImageUri;
}
function getPriceFeed() publicviewreturns (AggregatorV3Interface) {
return i_priceFeed;
}
function getTokenCounter() publicviewreturns (uint256) {
return s_tokenCounter;
}
}
Unit Test (all succesfull)
const{ deployments, ethers, network }=require("hardhat")const{ assert, expect }=require("chai")const{ developmentChains }=require("../../helper-hardhat-config")const{ check }=require("prettier")constlowSVGImageuri="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8c3ZnIHdpZHRoPSIxMDI0cHgiIGhlaWdodD0iMTAyNHB4IiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGZpbGw9IiMzMzMiIGQ9Ik01MTIgNjRDMjY0LjYgNjQgNjQgMjY0LjYgNjQgNTEyczIwMC42IDQ0OCA0NDggNDQ4IDQ0OC0yMDAuNiA0NDgtNDQ4Uzc1OS40IDY0IDUxMiA2NHptMCA4MjBjLTIwNS40IDAtMzcyLTE2Ni42LTM3Mi0zNzJzMTY2LjYtMzcyIDM3Mi0zNzIgMzcyIDE2Ni42IDM3MiAzNzItMTY2LjYgMzcyLTM3MiAzNzJ6Ii8+CiAgPHBhdGggZmlsbD0iI0U2RTZFNiIgZD0iTTUxMiAxNDBjLTIwNS40IDAtMzcyIDE2Ni42LTM3MiAzNzJzMTY2LjYgMzcyIDM3MiAzNzIgMzcyLTE2Ni42IDM3Mi0zNzItMTY2LjYtMzcyLTM3Mi0zNzJ6TTI4OCA0MjFhNDguMDEgNDguMDEgMCAwIDEgOTYgMCA0OC4wMSA0OC4wMSAwIDAgMS05NiAwem0zNzYgMjcyaC00OC4xYy00LjIgMC03LjgtMy4yLTguMS03LjRDNjA0IDYzNi4xIDU2Mi41IDU5NyA1MTIgNTk3cy05Mi4xIDM5LjEtOTUuOCA4OC42Yy0uMyA0LjItMy45IDcuNC04LjEgNy40SDM2MGE4IDggMCAwIDEtOC04LjRjNC40LTg0LjMgNzQuNS0xNTEuNiAxNjAtMTUxLjZzMTU1LjYgNjcuMyAxNjAgMTUxLjZhOCA4IDAgMCAxLTggOC40em0yNC0yMjRhNDguMDEgNDguMDEgMCAwIDEgMC05NiA0OC4wMSA0OC4wMSAwIDAgMSAwIDk2eiIvPgogIDxwYXRoIGZpbGw9IiMzMzMiIGQ9Ik0yODggNDIxYTQ4IDQ4IDAgMSAwIDk2IDAgNDggNDggMCAxIDAtOTYgMHptMjI0IDExMmMtODUuNSAwLTE1NS42IDY3LjMtMTYwIDE1MS42YTggOCAwIDAgMCA4IDguNGg0OC4xYzQuMiAwIDcuOC0zLjIgOC4xLTcuNCAzLjctNDkuNSA0NS4zLTg4LjYgOTUuOC04OC42czkyIDM5LjEgOTUuOCA4OC42Yy4zIDQuMiAzLjkgNy40IDguMSA3LjRINjY0YTggOCAwIDAgMCA4LTguNEM2NjcuNiA2MDAuMyA1OTcuNSA1MzMgNTEyIDUzM3ptMTI4LTExMmE0OCA0OCAwIDEgMCA5NiAwIDQ4IDQ4IDAgMSAwLTk2IDB6Ii8+Cjwvc3ZnPgo="consthighSVGimageUri="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAwIDIwMCIgd2lkdGg9IjQwMCIgIGhlaWdodD0iNDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxjaXJjbGUgY3g9IjEwMCIgY3k9IjEwMCIgZmlsbD0ieWVsbG93IiByPSI3OCIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgPGcgY2xhc3M9ImV5ZXMiPgogICAgPGNpcmNsZSBjeD0iNjEiIGN5PSI4MiIgcj0iMTIiLz4KICAgIDxjaXJjbGUgY3g9IjEyNyIgY3k9IjgyIiByPSIxMiIvPgogIDwvZz4KICA8cGF0aCBkPSJtMTM2LjgxIDExNi41M2MuNjkgMjYuMTctNjQuMTEgNDItODEuNTItLjczIiBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IGJsYWNrOyBzdHJva2Utd2lkdGg6IDM7Ii8+Cjwvc3ZnPg=="consthighTokenUri="data:application/json;base64,eyJuYW1lIjoiRHluYW1pYyBTVkcgTkZUIiwgImRlc2NyaXB0aW9uIjoiQW4gTkZUIHRoYXQgY2hhbmdlcyBiYXNlZCBvbiB0aGUgQ2hhaW5saW5rIEZlZWQiLCAiYXR0cmlidXRlcyI6IFt7InRyYWl0X3R5cGUiOiAiY29vbG5lc3MiLCAidmFsdWUiOiAxMDB9XSwgImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCMmFXVjNRbTk0UFNJd0lEQWdNakF3SURJd01DSWdkMmxrZEdnOUlqUXdNQ0lnSUdobGFXZG9kRDBpTkRBd0lpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaVBnb2dJRHhqYVhKamJHVWdZM2c5SWpFd01DSWdZM2s5SWpFd01DSWdabWxzYkQwaWVXVnNiRzkzSWlCeVBTSTNPQ0lnYzNSeWIydGxQU0ppYkdGamF5SWdjM1J5YjJ0bExYZHBaSFJvUFNJeklpOCtDaUFnUEdjZ1kyeGhjM005SW1WNVpYTWlQZ29nSUNBZ1BHTnBjbU5zWlNCamVEMGlOakVpSUdONVBTSTRNaUlnY2owaU1USWlMejRLSUNBZ0lEeGphWEpqYkdVZ1kzZzlJakV5TnlJZ1kzazlJamd5SWlCeVBTSXhNaUl2UGdvZ0lEd3ZaejRLSUNBOGNHRjBhQ0JrUFNKdE1UTTJMamd4SURFeE5pNDFNMk11TmprZ01qWXVNVGN0TmpRdU1URWdOREl0T0RFdU5USXRMamN6SWlCemRIbHNaVDBpWm1sc2JEcHViMjVsT3lCemRISnZhMlU2SUdKc1lXTnJPeUJ6ZEhKdmEyVXRkMmxrZEdnNklETTdJaTgrQ2p3dmMzWm5QZz09In0="constlowTokenUri="data:application/json;base64,eyJuYW1lIjoiRHluYW1pYyBTVkcgTkZUIiwgImRlc2NyaXB0aW9uIjoiQW4gTkZUIHRoYXQgY2hhbmdlcyBiYXNlZCBvbiB0aGUgQ2hhaW5saW5rIEZlZWQiLCAiYXR0cmlidXRlcyI6IFt7InRyYWl0X3R5cGUiOiAiY29vbG5lc3MiLCAidmFsdWUiOiAxMDB9XSwgImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQRDk0Yld3Z2RtVnljMmx2YmowaU1TNHdJaUJ6ZEdGdVpHRnNiMjVsUFNKdWJ5SS9QZ284YzNabklIZHBaSFJvUFNJeE1ESTBjSGdpSUdobGFXZG9kRDBpTVRBeU5IQjRJaUIyYVdWM1FtOTRQU0l3SURBZ01UQXlOQ0F4TURJMElpQjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaVBnb2dJRHh3WVhSb0lHWnBiR3c5SWlNek16TWlJR1E5SWswMU1USWdOalJETWpZMExqWWdOalFnTmpRZ01qWTBMallnTmpRZ05URXljekl3TUM0MklEUTBPQ0EwTkRnZ05EUTRJRFEwT0MweU1EQXVOaUEwTkRndE5EUTRVemMxT1M0MElEWTBJRFV4TWlBMk5IcHRNQ0E0TWpCakxUSXdOUzQwSURBdE16Y3lMVEUyTmk0MkxUTTNNaTB6TnpKek1UWTJMall0TXpjeUlETTNNaTB6TnpJZ016Y3lJREUyTmk0MklETTNNaUF6TnpJdE1UWTJMallnTXpjeUxUTTNNaUF6TnpKNklpOCtDaUFnUEhCaGRHZ2dabWxzYkQwaUkwVTJSVFpGTmlJZ1pEMGlUVFV4TWlBeE5EQmpMVEl3TlM0MElEQXRNemN5SURFMk5pNDJMVE0zTWlBek56SnpNVFkyTGpZZ016Y3lJRE0zTWlBek56SWdNemN5TFRFMk5pNDJJRE0zTWkwek56SXRNVFkyTGpZdE16Y3lMVE0zTWkwek56SjZUVEk0T0NBME1qRmhORGd1TURFZ05EZ3VNREVnTUNBd0lERWdPVFlnTUNBME9DNHdNU0EwT0M0d01TQXdJREFnTVMwNU5pQXdlbTB6TnpZZ01qY3lhQzAwT0M0eFl5MDBMaklnTUMwM0xqZ3RNeTR5TFRndU1TMDNMalJETmpBMElEWXpOaTR4SURVMk1pNDFJRFU1TnlBMU1USWdOVGszY3kwNU1pNHhJRE01TGpFdE9UVXVPQ0E0T0M0Mll5MHVNeUEwTGpJdE15NDVJRGN1TkMwNExqRWdOeTQwU0RNMk1HRTRJRGdnTUNBd0lERXRPQzA0TGpSak5DNDBMVGcwTGpNZ056UXVOUzB4TlRFdU5pQXhOakF0TVRVeExqWnpNVFUxTGpZZ05qY3VNeUF4TmpBZ01UVXhMalpoT0NBNElEQWdNQ0F4TFRnZ09DNDBlbTB5TkMweU1qUmhORGd1TURFZ05EZ3VNREVnTUNBd0lERWdNQzA1TmlBME9DNHdNU0EwT0M0d01TQXdJREFnTVNBd0lEazJlaUl2UGdvZ0lEeHdZWFJvSUdacGJHdzlJaU16TXpNaUlHUTlJazB5T0RnZ05ESXhZVFE0SURRNElEQWdNU0F3SURrMklEQWdORGdnTkRnZ01DQXhJREF0T1RZZ01IcHRNakkwSURFeE1tTXRPRFV1TlNBd0xURTFOUzQySURZM0xqTXRNVFl3SURFMU1TNDJZVGdnT0NBd0lEQWdNQ0E0SURndU5HZzBPQzR4WXpRdU1pQXdJRGN1T0MwekxqSWdPQzR4TFRjdU5DQXpMamN0TkRrdU5TQTBOUzR6TFRnNExqWWdPVFV1T0MwNE9DNDJjemt5SURNNUxqRWdPVFV1T0NBNE9DNDJZeTR6SURRdU1pQXpMamtnTnk0MElEZ3VNU0EzTGpSSU5qWTBZVGdnT0NBd0lEQWdNQ0E0TFRndU5FTTJOamN1TmlBMk1EQXVNeUExT1RjdU5TQTFNek1nTlRFeUlEVXpNM3B0TVRJNExURXhNbUUwT0NBME9DQXdJREVnTUNBNU5pQXdJRFE0SURRNElEQWdNU0F3TFRrMklEQjZJaTgrQ2p3dmMzWm5QZ289In0="!developmentChains.includes(network.name)
? describe.skip
: describe("Dynamic SVG NFT Unit Tests",function(){letdynamicSvgNft,signer,mockV3AggregatorbeforeEach(async()=>{constaccounts=awaitethers.getSigners()signer=accounts[0]awaitdeployments.fixture(["all"])constdynamicSvgNftDeployment=awaitdeployments.get("DynamicSvgNft")dynamicSvgNft=awaitethers.getContractAt(dynamicSvgNftDeployment.abi,dynamicSvgNftDeployment.address,signer,)constmockV3AggregatorDeployment=awaitdeployments.get("MockV3Aggregator")mockV3Aggregator=awaitethers.getContractAt(mockV3AggregatorDeployment.abi,mockV3AggregatorDeployment.address,signer,)})it("contract was deployed",async()=>{assert(dynamicSvgNft.target)})describe("Constructor",function(){it("Sets starting values correctly",async()=>{constlowSvg=awaitdynamicSvgNft.getLowSVG()consthighSvg=awaitdynamicSvgNft.getHighSVG()constpriceFeed=awaitdynamicSvgNft.getPriceFeed()assert.equal(lowSvg,lowSVGImageuri)assert.equal(highSvg,highSVGimageUri)assert.equal(priceFeed,mockV3Aggregator.target)})})describe("mintNft",function(){it("emits an event and creates an NFT",async()=>{consthighValue=ethers.parseEther("1")// 1 dollar per etherawaitexpect(dynamicSvgNft.mintNft(highValue)).to.emit(dynamicSvgNft,"CreatedNft",)consttokenCounter=awaitdynamicSvgNft.getTokenCounter()assert.equal(tokenCounter.toString(),"1")consttokenURI=awaitdynamicSvgNft.tokenURI(0)assert.equal(tokenURI,highTokenUri)})it("shifts the token URI to lower when the price doesn't surpass the highvalue",async()=>{consthighValue=ethers.parseEther("100000000")// 100,000,000 dollar per ethertxResponse=awaitdynamicSvgNft.mintNft(highValue)txResponse.wait(1)consttokenURI=awaitdynamicSvgNft.tokenURI(0)assert.equal(tokenURI,lowTokenUri)})})describe("tokenURI",function(){it("Reverts if the `tokenId` doesn't have a current owner",async()=>{consthighValue=ethers.parseEther("100000000")txResponse=awaitdynamicSvgNft.mintNft(highValue)txResponse.wait(1)awaitexpect(dynamicSvgNft.tokenURI(1)).to.be.revertedWithCustomError(dynamicSvgNft,"ERC721NonexistentToken",)})})})
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
All my code seems to be working (contract, deployments etc.)
However, with regards to minting the dynamic SVG NFT, I always seem to get a price of 0, which means I always get the frowny smiley.
While doing the unit tests, the contract actually worked in the rigth way, so I am thinking it has something to do with the MockV3Aggregator, but I can't find what. Here is my code:
Contract
Unit Test (all succesfull)
Deploy scripts - 03 deploy dynamic svg nft
Deploy scripts - 04 deploy mint
Any help would be greatly appreciated, stuck for days!
Beta Was this translation helpful? Give feedback.
All reactions