//tips
//smart contract
構造として気になっていたのが、今回のNFTのmintにおいて、ArtCollectible is Ownable, ERC721という新たなコントラクトをdeployした後に、その後のコントラクトの機能を元にそのコントラクトを経由してNFTをmintしているのだが、その際にインスタンス化との絡みはどうなっているのかという点である。
https://rinkeby.etherscan.io/tx/0x4766863982dbdf9104587a6047b20f8066a1cdb08c373469866c0fa0fc9bfd45
https://rinkeby.etherscan.io/tx/0x84a4c26b9c619daa9121d232cbbee513af989ff167859066f184fd2bda04082a
Ethscanの中身を見て、順に確認していく。
まずコントラクトとしてdeployされると、
metamaskのrinkbyアカウントから[Contract 0x1c6b57226b96bdd3616fe26c74df6f0d6e983857Created]
として新たなアカウントを作成する。コントラクトであり、ウォレットであるという認識。
このコントラクト/ウォレットに対して、自身のrinkbyアカウントからInteracted With (To):という形でコントラクトに指令を出す。
そうするとコントラクトがインスタンスを生成し、メソッドを実行。
そのメソッドの内容が実行された結果。
自身のrinkbyアカウントへARTCがmintされる。この場合創造であるため0x0000000000000000000000000000000000000000の記載となる。
Tokens Transferred:
From 0x0000000000000000000000000000000000000000
To 0xa242fcb2acbb118ea1b6829efe8b7e2087b43986
For ERC-721 Token ID [1] artCollectib... (ARTC)
ERC-721 Token ID [1] artCollectib... (ARTC)の記載の部分は、contract ArtCollectibleに記載された発行されるNFTを1ATRCにするという処理。constructor() public ERC721("artCollectible", "ARTC") {}
artCollectible (ARTC)生成の際に対価は必要としなかったので、コントラクトのbalanceは0のまま。
0x1C6b57226B96bdd3616Fe26c74DF6f0d6E983857
truffle migrate // デプロイとコンパイルの同時実行
truffle console // 起動ずみのノードに接続
Migrateとconsoleの違いはmigrateはデプロイとコンパイルの実行を行うのに対して、consoleはノードに接続し、ノードにコマンドを実行させることができるため、ここでインスタンスの作成の上メソッドの実行やコントラクトの値の取得を行うことができる。
Consoleはmigrateをコマンドに含み、その後にインスタンス化を行うことでメソッドを実行させることができる。
const art=await ArtCollectible.deployed()
await art.ownerOf(1)
await art.claimItem(‘https://ipfs.io/ipfs/QmXYfhz3uup6Hd4PnbVsHowi8yYDU7J56Z’)
ArtCollectible.にあるclaimItemを呼び出している。
function claimItem(string memory tokenURI) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
_safeMintは継承したERC721.solの中にあり、さらに_mintもこちらにある。
function _safeMint(
address to,
uint256 tokenId,
bytes memory data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId);
}
tokenの移動はtransferで行なっている。mintの実態はtransferだけなのか。
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
先のmint引数となっているtokenURIの中にERC721では、NFTのメタデータを設定できるようになっている。
メタデータは下記のような、属性や名前、詳細、デジタルデータの保存先であるipfsのurlを保存したものとなっている。
{
"attributes": [
{
"trait_type": "Color",
"value": "Pink"
}
],
"description": "Paul predicts future!",
"image": "https://ipfs.io/ipfs/QmQYE35JdthxvBZahG77w5XSuPKL2jNkJdtxQo4Pc57U1n",
"name": "Paul The Octopus"
}
このtokenURIは誰にでも見れるので、etherscanの中のtokenURIのtokenId(Uint256)にて任意の数字(1など)を押すとid1で生成されたNFTの情報一式を取得できる。
読んでいくと重要なmappingがあったのでメモ。
// Mapping from token ID to owner address
mapping(uint256 => address) private _owners;
Tokenidの番号に対応したトークンの所持者のaddressのリスト。
// Mapping owner address to token count
mapping(address => uint256) private _balances;
トークン所有アカウントがいくつトークンを保持しているかのリスト。
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
これは少し調べたが、approveは関数を呼びたした人の残高から_value分のTokenを引き出すことを許可する関数で、ERC721では個々のトークンはユニークで代替不可能すなわち唯一無二あることから、トークンの量(_value)ではなく、トークンのID(_tokenId)を引数で指定するとのこと。
つまり、コントラクトに対して、引き出し権限を与えている。
プラットフォームの文脈で言うと、資産の転送の権限をプラットフォーム側と共有することになる。
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
ownerが、addressをOperator仲介者として承認しているかの真偽
https://ethereumnavi.com/2021/11/09/contract-study-2-solidity-erc721/
https://qiita.com/ywzx/items/fe6f0fa1086c25a5dfef
コントラクターは初期化設定。
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}