記事を書いたきっかけ
にゃあ。猫になりたいです。大学生をやったり渋谷でエンジニアをやったりしてます、lowzzyです。最近は友達とNFTをせかせか作っております。
NFTを作っている人なら一度は思うでしょう
「NFTを自分たちが発行した通貨で買えるようにしたい、、、!」
はい。僕も思いました。調べるとそれっぽいやつはちょこちょこ出てきますが、大体英語だったり、コードが微妙だったりと、もう少しわかりやすい日本語版書けばNFT挑戦するハードル下がるよなあ。。。
と思ったので書いた所存です。
使用する言語とかの説明
いわゆるスマートコントラクトを書きます。solidity。
スマートコントラクトは「契約を締結して自動で処理が走る〜」みたいな説明されることが多いけど、あんまり好きじゃないです。分かりにくいので。誰かが言ってたんですけど、スマートコントラクトは「ちっちゃいプログラム」みたいに思ってくれたら多分大丈夫です。
NFTを生成することを「mint」すると言います。
NFTはERC721とかERC1155とかいろんな規格がありますが、今回はERC1155を採用します。
また、通貨はERC20という規格を採用します。
今回はETHのテストネットであるRinkebyを使います。
rinkebyはテスト環境なのでここでのネイティブ通貨ETHは金銭的価値を持ちません。
https://rinkebyfaucet.com/
faucetというところでETHが貰えるので「rinkeby faucet」みたいに調べてもらってきてください。
NFTはLowzzy, 通貨はLWZという名前で発行します。LWZはとりあえず1000枚発行します。
余談ですが、2021年の終わりにAdidasとコラボしてたBoredApeYachtClub通称BAYCは10億枚発行しているみたいです。
コード
コードはこちら
NFT
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Lowzzy is ERC1155, Ownable{
string baseMetadataURIPrefix;
string baseMetadataURISuffix;
uint256 constant SampleTokenId = 0;
constructor() ERC1155("") {
// メタデータが取得できるURIをここで定義している
// URI -> baseMetadataURIPrefix + トークンID + baseMetadataURISuffix
baseMetadataURIPrefix = "https://staging--goldfish-japan.netlify.app/.netlify/functions/tokenURI/";
baseMetadataURISuffix = "";
}
// 使用する通貨と、1個当たりの価格を定義してる
struct TokenInfo {
IERC20 paytoken;
uint256 costvalue;
}
// publicにしてることで変数callできる
TokenInfo[] public AllowedCrypto;
using Strings for uint256;
// tokenInfo追加する関数
function addCurrency(
IERC20 _paytoken,
uint256 _costvalue
) public onlyOwner {
AllowedCrypto.push(
TokenInfo({
paytoken: _paytoken,
costvalue: _costvalue
})
);
}
// uri確かめる関数。
function uri(uint256 _id) public view override returns (string memory) {
return string(abi.encodePacked(
baseMetadataURIPrefix,
Strings.toString(_id),
baseMetadataURISuffix
));
}
// お金払わずにNFTを生成することができる関数です。
// onlyOwnerとあるように、ownerしか使用できないようにしてます。
// いらなかったら消してください
function ownerMint(uint256 _amount) public onlyOwner() {
_mint(msg.sender, SampleTokenId, _amount, "");
}
// この記事の1番理解して欲しいところ
// 第1引数 -> _mintAmount : 生成する数
// 第2引数 -> _pid : 使用する通貨
function publicMint(uint256 _mintAmount, uint256 _pid) public payable {
TokenInfo storage tokens = AllowedCrypto[_pid];
IERC20 paytoken;
paytoken = tokens.paytoken;
uint256 cost;
cost = tokens.costvalue;
require(!paused); // pausedされてたら(paused == trueだったら)エラー吐かせる
require(_mintAmount > 0);// 0以上かどうか確かめてる(じゃないならエラー)
// paytoken(この記事だとLWZ)のコントラクトに生えている関数「allowance」を呼び出し
// おろす許可があるLWZはどれくらいあるかを取得している
uint256 allowCost = paytoken.allowance(msg.sender,address(this));
// 許可されているLWZがNFTをmintするのに必要分足りているかを確認している(足りなかったらエラー吐く)
require(allowCost >= cost * _mintAmount, "Not enough balance to complete transaction.");
// ここでLWZをこのスマコンのアドレスにtransferしてもらっている(支払い処理)
paytoken.transferFrom(msg.sender, address(this), cost * _mintAmount);
// msg.senderのアドレスに_mintAmount個のSampleTokenId番目のトークンをmint(生成)している
_mint(msg.sender, SampleTokenId, _mintAmount, "");
}
// この関数を使うとトークンのURIが変更できます。
function setBaseMetadataURI(string memory _prefix, string memory _suffix) public onlyOwner(){
baseMetadataURIPrefix = _prefix;
baseMetadataURISuffix = _suffix;
}
}
通貨
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract LWZ is ERC20 {
constructor(
string memory name,
string memory symbol,
uint256 totalSupply_
) ERC20(name, symbol) {
_mint(msg.sender, totalSupply_);
}
}
コードは以上です。
次はRinkebyチェーンへのデプロイについて書きます。
デプロイ
RemixってIDEを使います。
コード書く~デプロイ~関数呼び出し
など、色々できます。これできればNFTコレクション作れる。
Deployボタン押すとメタマスクが発火するので確認してお金を払う。
右上からConfirmed transactionってきたので成功。
Deployする時に、1000枚しかLWZ発行しないって言ってたのに、0がめちゃめちゃ多いやん!まちがっているやん!と言われそうですが、これは違います。10^18をつけるのがERC20では一般的です。なので発行総量が1000枚の場合は1000x10^18、つまり1000 000000000000000000をtotal supplyに入れましょう。NameとかSymbolとかはなんでも好きなので良きです。
そしたら、左の方にデプロイされたコントラクトが2つあるはず。Lowzzyって方がNFTで、LWZが通貨。
タブを開くと、生えている関数が見れたりしますね。
デプロイが終わったら今度はpublicMint(通貨を使用してmint)をしてみましょう。
コントラクトアドレスをコピーして
AddCurrencyをします。価格(costValue)を10^18するのをお忘れなく(今回は30x10^18にしてる)。第一引数は通貨のコントラクトアドレス(コピーしたやつ)です。
Approveします。お金使っていいよ〜って許可出す処理です。今回は面倒なので全部(1000x10^18)を入力しました。
そしたらついにpublicMintです。
先ほど追加した通貨は配列のindex = 0(pid = 0)だと思うので、第一引数に0を入力。
なんとなく5枚欲しいので第二引数には5を入力。
わーい、5枚mintできていました。https://testnets.opensea.io/assets/rinkeby/0x55b9e5c2880c9d7bd31efc385ca6f664df009fa5/0
1000枚あったLWZ、850枚になっているはずだなあ、確認するか〜ってなったので、トークンをメタマスクにimportして、、
ってことでmint成功ですにゃ
間違えてたりしたら教えてください〜
それでは!