イーサリアムの開発言語であるSolidityで扱う、ERC721規格でApprove→Transfer実装する方法について紹介しています。
ERC721規格に沿ったインターフェースを作成
まずは、ERC721規格に沿ったインターフェースの作成が必要です。ERC721規格というのは、NFTの実装を標準化するための規格になります。
OpenZeppelinで実装例が公開されているので、詳しく知りたい方は参考にしてください。
ここでは、最低限の実装を紹介していきます。
contract IERC721 {
//転送イベント
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
//承認イベント
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
//残高を返す関数
function balanceOf(address _owner) external view returns (uint256);
//所有者を返す関数
function ownerOf(uint256 _tokenId) external view returns (address);
//転送を行う関数
function transferFrom(address _from, address _to, uint256 _tokenId) external;
//承認を行う関数
function approve(address _approved, uint256 _tokenId) external;
}
インターフェースを継承して、コントラクトを作成
作成したインターフェースを継承して、トークンのコントラクトを作成します。
具体的には、インタフェース内で定義した関数に対して、処理を実装していきます。各処理の説明は、コメントに記載しています。
import "./ierc721.sol";
contract MyContract is IERC721 {
//トークンIDから、承認済みアドレスへのマッピング
mapping (uint => address) approvals;
//トークンIDから、所有アドレスへのマッピング
mapping (uint => address) public owner;
//アドレスから、所有数へのマッピング
mapping (address => uint) ownerCount;
function balanceOf(address _owner) external view returns (uint256) {
//引数のアドレスから、所有数を取得して返却
return ownerCount[_owner];
}
function ownerOf(uint256 _tokenId) external view returns (address) {
//引数のトークンIDから、所有アドレスを取得して返却
return owner[_tokenId];
}
//転送を実行するためのプライベート関数
function _transfer(address _from, address _to, uint256 _tokenId) private {
//転送元の所有数をマイナス、転送先の所有数をプラス
ownerCount[_to]++;
ownerCount[_from]--;
//所有アドレスを転送先のアドレスで更新
owner[_tokenId] = _to;
//転送イベントを発火
emit Transfer(_from, _to, _tokenId);
}
function transferFrom(address _from, address _to, uint256 _tokenId) external {
//実行アドレスが所有者、もしくは承認済みアドレスの場合のみ転送を実行する
require (owner[_tokenId] == msg.sender || approvals[_tokenId] == msg.sender);
_transfer(_from, _to, _tokenId);
}
function approve(address _approved, uint256 _tokenId) external {
//トークンIDに対して、承認アドレスを設定する
require(msg.sender == owner[_tokenId])
approvals[_tokenId] = _approved;
//承認イベントを発火
emit Approval(msg.sender, _approved, _tokenId);
}
}
