참고문헌, 그림출처
참고할 소스코드[복붙용]
pragma solidity ^0.4.20;
interface ERC721 /* is ERC165 */ {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) public view returns (uint256);
function ownerOf(uint256 _tokenId) public view returns (address);
// function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) public;
// function safeTransferFrom(address _from, address _to, uint256 _tokenId) public;
// function transferFrom(address _from, address _to, uint256 _tokenId) public;
// function approve(address _approved, uint256 _tokenId) public;
// function setApprovalForAll(address _operator, bool _approved) public;
// function getApproved(uint256 _tokenId) public view returns (address);
// function isApprovedForAll(address _owner, address _operator) public view returns (bool);
}
contract ERC721Implementation is ERC721{
mapping(uint256 => address) tokenOwner;
mapping(address => uint256) ownedTokensCount;
function mint(address _to, uint _tokenId) public {
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] += 1;
}
function balanceOf(address _owner) public view returns (uint256){
return ownedTokensCount[_owner];
}
function ownerOf(uint256 _tokenId) public view returns (address){
return tokenOwner[_tokenId];
}
}
Solidity
복사
•
본 실습은 ERC721에서 정의한 balanceOf 함수와 ownOf 함수를 이용하는 실습을 진행하고자 한다.
•
상기의 코드에서 아래의 2개의 코드를 이용한다.
function balanceOf(address _owner) public view returns (uint256);
function ownerOf(uint256 _tokenId) public view returns (address);
Solidity
복사
•
balanceOf 함수는 매개변수로 _owner주소를 받고 uint를 리턴한다. 즉, 계정에 몇개의 토큰이 있는지 확인가능한 함수이다.
•
이걸 ERC721Implementation 컨트랙 안에서 다음과 같은 코드로 넣는다.
function balanceOf(address _owner) public view returns (uint256){
return ownedTokensCount[_owner];
}
Solidity
복사
•
매개변수로 받은 _owner를 매핑의 키값으로 넘기면 _owner계정이 소유한 토큰의 개수를 리턴하는 구조로 되어 있다.
ownerOf 함수 사용법
•
이번에는 ownerOf 함수를 사용해본다.
function ownerOf(uint256 _tokenId) public view returns (address);
Solidity
복사
•
컨트랙 안에는 아래와 같은 코드를 입력한다.
function ownerOf(uint256 _tokenId) public view returns (address){
return tokenOwner[_tokenId];
}
Solidity
복사
•
_tokenId를 매개변수로 받아서 주소형을 리턴하는 것으로써 즉, 토큰의 주인이 누구냐를 알 수 있게하는 함수이다. _tokenId를 키값으로해서 토큰의 소유자 계정을 리턴한다.
실행
•
지금부터 이 함수가 잘 작동하나 확인해보자
•
왼쪽에 클레이튼 로고 모양 탭을 클릭하면 아래와 같은 화면이 나온다.
•
ENVIRONMENT : Baobab
•
ACCOUNT : 저번에 만든 계정 3개(json)을 등록하기 위해서 ACCOUNT 탭에 있는 플러스 모양을 클릭해서 추가한다. (keystore 탭 클릭해서)
•
CONTRACT : ERC721Implementation을 클릭한다.
•
여기까지 다하면 Deploy 클릭
•
그럼 콘솔창에 초록색 체크박스로 잘했다고 뜨고
•
아래의 화면이 나오면 정상
•
첫번째 어카운트 선택하고, 오른쪽에 계정 복사가 된걸 클릭한다.
•
옆에 아이콘눌러서 계정을 복사하고 내려와서
•
mint 탭을 누르면
•
이렇게 보이는데 여기 _to에다가 복사한 계정 붙여넣고 _tokenId는 1 하고 transact하면 콘솔창에 잘 되었다고 나오고
•
balanceOf 함수에 아까 복사했던 계정을 붙여넣고 balanceOf를 누르면
•
1이 리턴되는걸 볼 수 있다. 이 뜻은 주소가 소유하고있는 토큰 개수가 총 1개라는것을 의미한다.
•
이번에는 ownerOf에다가 _tokenId 1을 넣으면
•
이렇게 1토큰의 소유자 계정이 나온다.
두번째 실습
•
다음은 transgerForm 함수를 사용해보도록 한다.
•
interface ERC721 안에 아래와 같은 함수를 살려본다.
function transferFrom(address _from, address _to, uint256 _tokenId) public;
Solidity
복사
•
새로 만들어야 하는 것은 _from계정과 _to계정 그리고 _tokenId를 매개변수로 받는다. 즉 어떤_tokenId를 소유하고 있는 _from 계정에서 _to 계정으로 옮기겠다라는 뜻이다.
•
이 함수를 실행하기 앞서서 몇가지 유효성 검사를 해야한다. 이 transfer 함수로 호출한 계정이 해당 _tokenId을 가지고 있는지 확인해야만 한다.
•
그러기 위해서 컨트렉에 아래와 같은 코드를 입력한다.
function transferFrom(address _from, address _to, uint256 _tokenId) public{
address owner = ownerOf(_tokenId);
}
Solidity
복사
•
기존에 만든 ownerOf 라는 함수를 호출해서 _tokenId를 매개변수로 받아 토큰의 소유자 계정을 호출하는 형식으로 구성되어있다.
•
ownerOf함수로 호출한 계정이 owner계정과 동일한지 체크해야함
function transferFrom(address _from, address _to, uint256 _tokenId) public{
address owner = ownerOf(_tokenId);
require(msg.sender == owner);
}
Solidity
복사
•
위의 함수를 보면 msg.sender는 transferFrom으로 호출한 계정, 이 계정이 ownerOf로 호출한 계정과 같아야 통과가된다.
•
다음 작업은 _from계정과 _to계정이 비어있는 계정이 아닌지 확인해야한다.
function transferFrom(address _from, address _to, uint256 _tokenId) public{
address owner = ownerOf(_tokenId);
require(msg.sender == owner);
require(_from != address(0));
require(_to != address(0));
}
Solidity
복사
•
상기 코드 안에 있는 address(0)의 의미는 계정이 비어있다는 뜻 그래서 연산자를 통해 넘어온 _from계정과 _to 계정이 진짜있는 계정인지 확인을 했다.
•
다음할 일은 토큰을 전송하는 일이다. 그러고나면 _from 계정과 _to계정의 토큰 총 개수가 변하게 된다.
function transferFrom(address _from, address _to, uint256 _tokenId) public{
address owner = ownerOf(_tokenId);
require(msg.sender == owner);
require(_from != address(0));
require(_to != address(0));
ownedTokensCount[_from] -= 1;
tokenOwner[_tokenId] = address(0);
ownedTokensCount[_to] += 1;
tokenOwner[_tokenId] = _to;
}
Solidity
복사
상세 코드 설명
•
ownedTokensCount[_from] -= 1;
◦
토큰을 보낸 계정의 총 토큰 수 가 하나 줄어든다는 뜻
•
tokenOwner[_tokenId] = address(0);
◦
address(0)을 대입하여 토큰 소유권을 삭제한다. 더이상 토큰의 소유자가 아니라는 뜻
•
ownedTokensCount[_to] += 1;
◦
반대로 토큰을 받은 계정은 총 토큰 수를 하나 늘리는 작업이다.
•
tokenOwner[_tokenId] = _to;
◦
_to 계정이 해당 토큰의 새로운 소유자라고 매핑이다.
최종코드
pragma solidity >=0.4.24 <=0.5.6;
interface ERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) public view returns (uint256);
function ownerOf(uint256 _tokenId) public view returns (address);
//function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) public;
// function safeTransferFrom(address _from, address _to, uint256 _tokenId) public;
function transferFrom(address _from, address _to, uint256 _tokenId) public;
// function approve(address _approved, uint256 _tokenId) public;
//function setApprovalForAll(address _operator, bool _approved) public;
// function getApproved(uint256 _tokenId) public view returns (address);
// function isApprovedForAll(address _owner, address _operator) public view returns (bool);
}
contract ERC721Implementation is ERC721{
mapping(uint256 => address) tokenOwner;
mapping(address => uint256) ownedTokensCount;
function mint(address _to, uint _tokenId) public {
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] += 1;
}
function balanceOf(address _owner) public view returns (uint256){
return ownedTokensCount[_owner];
}
function ownerOf(uint256 _tokenId) public view returns (address){
return tokenOwner[_tokenId];
}
function transferFrom(address _from, address _to, uint256 _tokenId) public{
address owner = ownerOf(_tokenId);
require(msg.sender == owner);
require(_from != address(0));
require(_to != address(0));
ownedTokensCount[_from] -= 1;
tokenOwner[_tokenId] = address(0);
ownedTokensCount[_to] += 1;
tokenOwner[_tokenId] = _to;
}
}
Solidity
복사
실행
•
기존에 있던 클레이튼 Run 탭에 들어와서 기존에 배포된 컨트랙을 휴지통 아이콘 눌러서 삭제한다.
•
이전과 동일하게 ERC721Implementation 선택해서 deploy를 누른다.
•
첫번째 계정으로 토큰1을 만들고
•
ownerOf를 통해 토큰1의 소유자를 확인
•
_from에 토큰 1을 가지고있는 첫번째 계정을 넣고 _to에 넘겨주려는 새로운 계정을 넣고 토큰 아이디 1을 넣은 다음
•
위에 계정을 토큰1을 가지고있는 첫번째 계정으로 바꿔줘야한다. 이때 이 account에 들어가는 계정이 함수를 호출하는데 쓰이는 계정이다. 그리고 transact 누른다.
•
그리고 다시 토큰1 의 소유자가 누구인지 확인하기위해 ownerOf함수에 1을 넣으면 아래와 같이 소유자가 바뀐것을 볼 수 있다.
•
그리고 토큰을 전송 받은 두번째 계정이 갖고있는 토큰 개수를 확인해보면 아래와 같이 1개가 나오게 된다.
•
토큰을 전송해준 첫번째 계정이 갖고있는 토큰 개수를 확인해보면 0개가 나오는 것을 확인할 수 있다.