728x90
반응형
ERC-721 interface 소스 코드
pragma solidity ^0.4.20;
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
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) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
Token의 전송
1. 일반 계정으로 전송.
- 유져들간의 token 전송 입니다.
2. contract 계정으로 전송
- contract 을 배포했을때 나오는 주소를 contract 계정이라고도 합니다.
- token을 전송받은 contract가 token을 다루는 기능이 없으면 token을 분실이 발생 합니다.
(구제할 방법이 없음)
3. token 승인이란?
- 소유자의 token을 다른 계정이 대신 전송 할 수 있도록 권한을 부여하는것
Ex) A가 B에세 token을 맏겨서 B가 token을 전송 할 수 있게 권하는 주는것
- 일반 계정에 권한을 부여해서 다른 계정으로 대신 전송하는 기능을 구현
ERC-721 interface 구현 Code 해설
pragma solidity ^0.4.20;
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
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);
}
interface ERC721TokenReceiver {
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) public returns(bytes4);
}
contract ERC721Implementation is ERC721 {
// token의 Id를 키로해서 계정을 리턴하는 mapping
// token의 주인이 누구인지 확인해 준다.
mapping(uint256 => address) tokenOwner;
// address를 키로 사용하여 uint256를 value로 mapping한다.
// 계정 주소를 입력하면 해당 계정이 몇개의 token을 가지고 있나 숫자로 리턴
mapping(address => uint256) ownedTokenCount;
//토큰 발생 함수
// mint의 뜻은 발생한다 이다.
// _to: 발생된 token을 누가 소유하게 될것 인지 명시
// _tokenId : 몇번째 token 인지 명시
// tokenId는 차례대로 1씩 증가한다.
mapping(uint256 => address) tokenApprovals;
// 누가 누구에게 권한 부여를 했는가를 의미한다.
mapping(address => mapping(address => bool)) operatorApproavlas;
function mint(address _to, uint _tokenId) public {
//_tokenId를 tokenOwner의 키로하여 _to를 mapping
tokenOwner[_tokenId] = _to;
ownedTokenCount[_to] += 1;
}
// 계정의 token 개수를 구한다.
function balanceOf(address _owner) public view returns (uint256) {
return ownedTokenCount[_owner];
}
// token의 주인이 누구인지 반환한다.
function ownerOf(uint256 _tokenId) public view returns (address) {
return tokenOwner[_tokenId];
}
// tokenId를 가진 token을 소유하고있는from 계정에서to 계증으로 옮기겠다.
function transferFrom(address _from, address _to, uint256 _tokenId) public {
// tokenId의 소유자 계정을 불러온다.
address owner = ownerOf(_tokenId);
// msg.sender : 함수를 호출한 계정
// 1. require를 하용하여 함수를 호출한 계정과 owner가 일치하는지 확인
// 2. tokenId를 대신 전달 할수 있는 권한을 가진 계정인지 확인
require(msg.sender == owner || getApproved(_tokenId) == msg.sender || isApprovedForAll(owner, msg.sender));
// from과 to에 대항 검증
// address(0) 은 비어있다를 의미한다.
require(_from != address(0));
require(_to != address(0));
//from의 token 개수를 하나 줄임
ownedTokenCount[tokenOwner[_tokenId]] -= 1;
//tokenId의 소유권을 삭제
tokenOwner[_tokenId] = address(0);
//token의 새로운 소유자 지정
ownedTokenCount[_to] +=1;
tokenOwner[_tokenId] = _to;
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId) public {
transferFrom(_from, _to, _tokenId);
// _to 주소가 contract인지 확인 하는 과정
if (isContract(_to)) {
//contract가 token을 받을수 있는 contract 인지 판단이 필요.
// ERC721TokenReceiver(_to) 의 해석 :
// _to 주소에 ERC721TokenReceiver interface가 존재 한다라는 뜻
// ERC721TokenReceiver(_to).onERC721Received
// onERC721Received가 구현 되어 있다면 magic value(function signature) 를 리턴 한다
bytes4 returnValue = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, '');
require(returnValue == 0x150b7a02);
}
}
// _approved : 권한을 받게 되는 계정
// tokenId를 사용할 수 있는 계정을 추가한다.
function approve(address _approved, uint256 _tokenId) public {
//1 . 권한을 받게되는 계정이 이미 tokenId를 소유하고 있지 않는 확인 한다.
//유효성을 확인한다.
address owner = ownerOf(_tokenId);
// 권한을 받게 되는 계정이 소유자 계정이 아니어야 한다.
require(_approved != owner);
// aprrove를 호출한 계정이 token의 소유자여야 한다.
require(msg.sender == owner);
tokenApprovals[_tokenId] = _approved;
}
// 내가 가진 모든 토큰에 대한 전송 권한을 준다.
function setApprovalForAll(address _operator, bool _approved) public {
// 내가 나한테 권한을 주는것을 방지
require(_operator != msg.sender);
// 누가 누구에게 권한을 줄지를 설정
// msg.sender가 _operator에게 권한을 부여할 것인지를 설정
operatorApproavlas[msg.sender][_operator] = _approved;
}
// _owner가 _operator에게 권한을 부여했는지 확인
function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
return operatorApproavlas[_owner][_operator];
}
// token의
function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}
// address contract 계정인지 확인
function isContract(address _address) private view returns (bool) {
uint256 size;
// 주소 contract 인지 확인을
// extcodesize에 주소를 넘겨서 린턴하는게
// 0 이면 일반계정,
// 0 보다 크면 contract 계정
assembly { size:= extcodesize(_address)}
return size > 0;
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) public {
transferFrom(_from, _to, _tokenId);
// _to 주소가 contract인지 확인 하는 과정
if (isContract(_to)) {
//contract가 token을 받을수 있는 contract 인지 판단이 필요.
// ERC721TokenReceiver(_to) 의 해석 :
// _to 주소에 ERC721TokenReceiver interface가 존재 한다라는 뜻
// ERC721TokenReceiver(_to).onERC721Received
// onERC721Received가 구현 되어 있다면 magic value(function signature) 를 리턴 한다
bytes4 returnValue = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, data);
require(returnValue == 0x150b7a02);
}
}
}
contract Auction is ERC721TokenReceiver {
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) public returns(bytes4) {
return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
}
}
728x90
반응형
'내맘대로 Study > 블록체인' 카테고리의 다른 글
[클레이튼] 개발 환경 (0) | 2022.04.27 |
---|---|
[solidity] 개발자를 위한 속성 문법 2 (0) | 2022.04.25 |
[블록체인] token 과 coin 비교 (0) | 2022.04.20 |
[solidity] 개발자를 위한 속성 문법 (2) | 2022.04.11 |
[클레이튼] smart contract 배포 과정 이해하기 (0) | 2022.04.05 |