///
Search
🎃

(220326) Klaytn IDE 환경에서 ERC-721 실습 (토큰발행 부터 전송 까지)

참고문헌, 그림출처

참고할 소스코드[복붙용]

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개가 나오는 것을 확인할 수 있다.