lesson-3_メインコントラクトを作成しよう
🥮 AssetTokenization
コントラクトを作成する
フロントエンドとのデータのやりとり、FarmNftのデプロイと管理をする機能を持つAssetTokenization
コントラクトを作成します。
contracts
ディレクトリの下にAssetTokenization.sol
という名前のファイルを作成します。
AssetTokenization.sol
の中に以下のコードを貼り付けてください。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import "./FarmNft.sol";
contract AssetTokenization {
address[] private _farmers; // 農家のアドレスを保存します。
mapping(address => FarmNft) private _farmerToNftContract; // 農家のアドレスとデプロイしたFarmNftをマッピングします。
struct NftContractDetails {
address farmerAddress;
string farmerName;
string description;
uint256 totalMint;
uint256 availableMint;
uint256 price;
uint256 expirationDate;
}
}
もし、hardhat.config.ts
の中に記載されているSolidityのバージョンが0.8.17
でなかった場合は、FarmNft.sol
の中身をhardhat.config.ts
に記載されているバージョンに変更しましょう。
コントラクトのはじめに状態変数を定義しています。
その次にはNftContractDetails
という構造体を定義しています。
NftContractDetails
は、 フロントエンドへfarmNft
の情報を渡すために使用する型になります。
次にAssetTokenization
の最後の行に以下のコードを貼り付けてください。
function availableContract(address farmer) public view returns (bool) {
return address(_farmerToNftContract[farmer]) != address(0);
}
function _addFarmer(address newFarmer) internal {
for (uint256 index = 0; index < _farmers.length; index++) {
if (newFarmer == _farmers[index]) {
return;
}
}
_farmers.push(newFarmer);
}
function generateNftContract(
string memory _farmerName,
string memory _description,
uint256 _totalMint,
uint256 _price,
uint256 _expirationDate
) public {
address farmerAddress = msg.sender;
require(
availableContract(farmerAddress) == false,
"Your token is already deployed"
);
_addFarmer(farmerAddress);
FarmNft newNft = new FarmNft(
farmerAddress,
_farmerName,
_description,
_totalMint,
_price,
_expirationDate
);
_farmerToNftContract[farmerAddress] = newNft;
}
availableContract
では、(農家の)アドレスをもとにfarmNft
がデプロイされているのかを確認しています。
farmNft
がデプロイされていない場合、 または期限が切れマッピングからdeleteされた場合は、address()で表現すると0x0
になります。
_addFarmer
は農家のアドレスが新規だった場合に状態変数に保存します。
generateNftContract
は農家がNFTを作成する(=farmNft
をデプロイする)際に使用する関数です。
new FarmNft()
により新しくfarmNft
をデプロイします。
そして_farmerToNftContract
のマッピングに追加します。
次にAssetTokenization
の最後の行に以下のコードを貼り付けてください。
function getNftContractDetails(address farmerAddress)
public
view
returns (NftContractDetails memory)
{
require(availableContract(farmerAddress), "not available");
NftContractDetails memory details;
details = NftContractDetails(
_farmerToNftContract[farmerAddress].farmerAddress(),
_farmerToNftContract[farmerAddress].farmerName(),
_farmerToNftContract[farmerAddress].description(),
_farmerToNftContract[farmerAddress].totalMint(),
_farmerToNftContract[farmerAddress].availableMint(),
_farmerToNftContract[farmerAddress].price(),
_farmerToNftContract[farmerAddress].expirationDate()
);
return details;
}
function buyNft(address farmerAddress) public payable {
require(availableContract(farmerAddress), "Not yet deployed");
address buyerAddress = msg.sender;
_farmerToNftContract[farmerAddress].mintNFT{value: msg.value}(
buyerAddress
);
}
function getBuyers() public view returns (address[] memory) {
address farmerAddress = msg.sender;
require(availableContract(farmerAddress), "Not yet deployed");
return _farmerToNftContract[farmerAddress].getTokenOwners();
}
function getFarmers() public view returns (address[] memory) {
return _farmers;
}
getNftContractDetails
は指定されたfarmNft
の情報をNftContractDetails
型の変数に格納して返却する関数です。
buyNft
は指定されたfarmNft
のNFTを購入する関数です。
この関数は購入者から(NFTの価格分の)AVAXを付与して呼び出されることを想定しているので、 msg.value
によってその量の取得できます。さらにその量のAVAXを付与して指定されたfarmNft
のmintNFT
を呼び出しています。
getBuyers
は指定されたfarmNft
の購入者のアドレスを返却する関数です。