lesson-3_ipfsをつかってmintしよう!
🪄 IPFS を使おう
IPFSに写真をアップロードできたところで、その写真を使ってNFTを作ってみましょう。
Web3Mint.sol
を下記のように更新してみましょう。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
//OpenZeppelinが提供するヘルパー機能をインポートします。
import "@openzeppelin/contracts/utils/Counters.sol";
import "./libraries/Base64.sol";
import "hardhat/console.sol";
contract Web3Mint is ERC721 {
struct NftAttributes {
string name;
string imageURL;
}
NftAttributes[] Web3Nfts;
using Counters for Counters.Counter;
// tokenIdはNFTの一意な識別子で、0, 1, 2, .. N のように付与されます。
Counters.Counter private _tokenIds;
constructor() ERC721("NFT", "nft") {
console.log("This is my NFT contract.");
}
// ユーザーが NFT を取得するために実行する関数です。
function mintIpfsNFT(string memory name, string memory imageURI) public {
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
Web3Nfts.push(NftAttributes({name: name, imageURL: imageURI}));
console.log(
"An NFT w/ ID %s has been minted to %s",
newItemId,
msg.sender
);
_tokenIds.increment();
}
function tokenURI(
uint256 _tokenId
) public view override returns (string memory) {
string memory json = Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "',
Web3Nfts[_tokenId].name,
" -- NFT #: ",
Strings.toString(_tokenId),
'", "description": "An epic NFT", "image": "ipfs://',
Web3Nfts[_tokenId].imageURL,
'"}'
)
)
)
);
string memory output = string(
abi.encodePacked("data:application/json;base64,", json)
);
return output;
}
}
解説していきましょう
// Web3Mint.sol
import "./libraries/Base64.sol";
tokenURI
には、NFTデータをJSON形式で渡さなければいけません。
Base64のやり方は、project3 のやり方を参考にしています。
なぜ、Base64で渡す必要があるのかを調べてみてください!
まずはpackages/contract/contracts
ディレクトリの直下にlibraries
ディレクトリを作成します。
そのlibraries
ディレクトリの下にBase64.sol
ファイルを作成して、下記のコードを貼り付けてください
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/// [MIT License]
/// @title Base64
/// @notice Provides a function for encoding some bytes in base64
/// @author Brecht Devos <brecht@loopring.org>
library Base64 {
bytes internal constant TABLE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/// @notice Encodes some bytes to the base64 representation
function encode(bytes memory data) internal pure returns (string memory) {
uint256 len = data.length;
if (len == 0) return "";
// multiply by 4/3 rounded up
uint256 encodedLen = 4 * ((len + 2) / 3);
// Add some extra buffer at the end
bytes memory result = new bytes(encodedLen + 32);
bytes memory table = TABLE;
assembly {
let tablePtr := add(table, 1)
let resultPtr := add(result, 32)
for {
let i := 0
} lt(i, len) {
} {
i := add(i, 3)
let input := and(mload(add(data, i)), 0xffffff)
let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
out := shl(8, out)
out := add(
out,
and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)
)
out := shl(8, out)
out := add(
out,
and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)
)
out := shl(8, out)
out := add(
out,
and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)
)
out := shl(224, out)
mstore(resultPtr, out)
resultPtr := add(resultPtr, 4)
}
switch mod(len, 3)
case 1 {
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
}
case 2 {
mstore(sub(resultPtr, 1), shl(248, 0x3d))
}
mstore(result, encodedLen)
}
return string(result);
}
}