이번 챕터에서는 ERC-721 토큰
의 전반적인 코드와 SafeMath
라이브러리에 대해서 주로 학습을 하였다.
별로 코드 자체가 어렵지 않았기 때문에 간단하게 분석만 다루어 보겠다.
contract ERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
function balanceOf(address _owner) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function transfer(address _to, uint256 _tokenId) public;
function approve(address _to, uint256 _tokenId) public;
function takeOwnership(uint256 _tokenId) public;
}
이 부분은 어떠한 함수가 있는지를 정리해 두는 곳이다.
pragma solidity ^0.4.19;
import "./zombieattack.sol";
import "./erc721.sol";
import "./safemath.sol";
contract ZombieOwnership is ZombieAttack, ERC721 {
using SafeMath for uint256;
mapping (uint => address) zombieApprovals;
function balanceOf(address _owner) public view returns (uint256 _balance) {
return ownerZombieCount[_owner];
}
function ownerOf(uint256 _tokenId) public view returns (address _owner) {
return zombieToOwner[_tokenId];
}
function _transfer(address _from, address _to, uint256 _tokenId) private {
ownerZombieCount[_to] = ownerZombieCount[_to].add(1);
ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1);
zombieToOwner[_tokenId] = _to;
Transfer(_from, _to, _tokenId);
}
function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
_transfer(msg.sender, _to, _tokenId);
}
function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
zombieApprovals[_tokenId] = _to;
Approval(msg.sender, _to, _tokenId);
}
function takeOwnership(uint256 _tokenId) public {
require(zombieApprovals[_tokenId] == msg.sender);
address owner = ownerOf(_tokenId);
_transfer(owner, msg.sender, _tokenId);
}
}
앞서 있던 ERC-721.sol
부분을 상속받음으로써 오버라이딩 가능하게 해준다.
SafeMath
부분은 후에 다루어 보겠다.ERC-721에는 토큰을 전송할 떄 2개의 다른 방식이 있다.
transfer함수 같은 경우에는 돈을 전송할 송신자가 직접 호출하여 수신자에게 돈을 송금하는 방법이다.
반대로 approve는 수신자가 송신자가 맡겨놓은 돈을 가져가는 방식이다.
_transfer함수는 그저 로직이 중복되는 것을 막기위해 선언한 함수이다.
transfer
함수 같은 경우에는 단순하게 돈을 보내고자 하는 송신자가 값을 입력하고 호출하면 된다.
approve
함수는 일단 송신자가 허가를 받은 사용자에 한에서 승인을 해주어야만 전송이 가능한 함수이다.
그후 수신자가 takeOwnership
송신자가 맡겨놓은 돈을 가져가면 된다.
중요한점
ERC-721토큰에 대해서 기본적인 함수 조건들만 지키면 된다.
- 이전에 적은 인터페이스부분에 있는 함수들만 구현하면 된다.
이러한 함수들만 구현이 된 이후에는 입맛에 따라 함수를 추가해도 된다.
- 클레이튼 같은 경우에는 4가지의 함수를 추가 하였다.
즉 ERC-721은 일종의 예시코드일 뿐이지 굳이 이 방식을 따라가지 않아도 된다.
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
오버 플로우, 언더 플로우 같은 오류를 방지하기 위해 사용하는 라이브러리 이다.
라이브러리를 사용할 경우에는
using SafeMath for uint256;
이런식으로 사용해야 하며
uint의 형에 따라서 사용방법이 달린다.
using SafeMath32 for uint32
, using SafeMath16 for uint16
이 라이브러리를 사용하는 것은 별로 어렵지 않기 떄문에 간단한 예시만 보고 넘어가도록 하겠다.
기존에는 ownerZombieCount[msg.sender]++;
이렇게 사용하던 로직을
ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1);
과 같이 수정하여 사용 가능하다.