[Solidity] Klaytn IDE를 이용한 토큰 스왑 & 전송 & 조회 간단 구현해보기 (클레이튼)
NFT 블록체인 마켓 앱 만들기 3기 / 멋쟁이사자처럼
🦁 [PROJECT LION] NFT 블록체인 마켓 앱 만들기 with 그라운드X 3기 - 챕터 3-9 회고
-1. 카이카스(Kaikas) 지갑에 두개의 계정을 준비합니다.
바오밥(Baobab) 테스트넷 👆
-2. 두개의 계정을 연결 후 솔리디티 코드를 입력하고 배포(Deploy)
👉 전체 코드는 하단에 있습니다
-3. 배포하고 나온 mintWithTokenURI
함수로 토큰 발행 (mint)
function mintWithTokenURI (address to, uint256 tokenId, string memory tokenURI) public returns (bool) {
// 토큰을 발행 하는 함수
tokenOwner[tokenId] = to; // to는 소유주 이기때문에 👉 msg.sender 으로도 쓸수 있다
// 토큰 번호를 입력하면 토큰 소유주의 주소가 나온다
tokenURIs[tokenId] = tokenURI; // 토큰 번호를 입력하면 토큰의 이름이 나온다
_ownedTokens[to].push(tokenId); // 주소를 입력하면 소유중인 토큰 번호들이 나온다
return true; // 리턴
}
to 👉 나의 지갑 주소
tokenId 👉 임의의 토큰 번호
tokenURI 👉 임의의 토큰 별명👉 입력 후
transcat
-4. 발행된 토큰의 조회 기능
tokenOwner[tokenId] = to; // to는 소유주 이기때문에 👉 msg.sender 으로도 쓸수 있다
// 토큰 번호를 입력하면 토큰 소유주의 주소가 나온다
tokenURIs[tokenId] = tokenURI; // 토큰 번호를 입력하면 토큰의 이름이 나온다
발행된 토큰의 번호를 입력하면
- tokenOwner 👉 토큰을 소유하고 있는 지갑주소 조회
- tokenURI 👉 토큰의 별명을 조회
👉트랜잭션을 발생시키지 않고 call( ) 한다
-5. 토큰을 추가 발행해보고 총 보유중인 토큰 조회
function ownedTokens (address owner) public view returns (uint256[] memory) {
// 내가 가지고 있는 모든 토큰들 조회
return _ownedTokens[owner]; // 조회하고자 하는 주소를 입력하면 토큰들(배열)이 나온다
}
토큰을 2번과 3번을 추가로 발행하고
ownedTokens
함수에 👉 지갑주소를 입력하여 통해 조회👉 조회는 트랜잭션을 발생시키지 않고 call( ) 한다
-6. 보유중인 토큰을 다른 주소로 전송
function safeTransferFrom(address from, address to, uint256 tokenId) public {
// 토큰을 전송하는 함수
require(from == msg.sender, "Not from"); // 토큰을 보내는 사람이 소유주일때만 실행 👉 아니면 에러
require(from == tokenOwner[tokenId], "NotTokenFrom"); // 토큰이 본인의 토큰일때만 실행 👉 아니면 에러
_removeTokenFromList(from, tokenId);
// 밑에서 정의한 함수를 여기서 사용 (토큰을 전송하면 내 목록에서 사라져야하기때문)
_ownedTokens[to].push(tokenId);
// 전송후에 상대방이 가지고 있는 토큰배열에 전송받은 토큰을 추가 해주기
tokenOwner[tokenId] = to; // from은 내 주소(소유쥬) to는 받는사람 토큰의 번호를 입력한다
}
👉 이 과정에서는 require
기능이 필요한데 ❗
조건에 맞으면 통과되고 아니면 에러메세지와 함께 실행이 중지된다
(에러핸들러 require
)
from 👉 나의 지갑 주소
to 👉 토큰을 전송받을 주소
tokenId 👉 전송할 토큰의 번호👉 입력 후
transcat
나의 지갑에 있던 토큰이 상대방의 지갑으로 전달되었으니
전달되는 과정에서 나의 지갑에 있던 토큰을
제거하는 작업을 해야한다 (스왑기능)
function _removeTokenFromList(address from, uint256 tokenId) private {
// [10, 15, 20, 23] 👈 20번을 삭제하고 싶을때
// [10, 15, 23, 20] 👈 20번과 23번을 스왑하고
// [10, 15, 23] 👈 배열의 마지막 제거
uint256 lastTokenIndex = _ownedTokens[from].length -1;
// 👆 배열의 마지막을 선택해주는 변수
for (uint256 i=0; i< _ownedTokens[from].length; i++) {
// 반복문실행 소유중인 토큰 번호(배열)
if (tokenId == _ownedTokens[from][i]) {
// 삭제하고싶은 토큰번호를 소유주의 배열에서 찾았다면
// 스왑기능 실행
_ownedTokens[from][i] = _ownedTokens[from][lastTokenIndex];
// 배열과 = 배열의 마지막 위치는 같다 선언함으로써 위치 변경
_ownedTokens[from][lastTokenIndex] = tokenId;
// 배열의 마지막이 삭제하고 싶은 토큰번호로 스왑됨
break;
}
}
_ownedTokens[from].length--; // 👈 배열의 맨마지막 제거
}
-7. 토큰 전송 후 각 지갑의 토큰보유 조회
ownedTokens
함수에 👉 각각 지갑주소를 입력하여 통해 조회원래 가지고 있던 토큰 1, 2, 3 번
👉 전송 후 지갑에 남은 토큰 2, 3번이 조회되고
👉 전송 받은 다른지갑에는 1번이 조회되는걸 확인 할 수 있다
Caver.js 를 이용하여 웹페이지 UI를 만들어서 실제 기능을 구현해볼 계획입니다 ! 🦁
전체코드
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.24 <=0.5.6;
contract NFTSimple {
string public name = "KlayLion"; // 토큰이름
string public symbol = "KL"; // 토큰심볼
mapping (uint256 => address) public tokenOwner; // 숫자를 넣으면 주소로 반환
mapping (uint256 => string) public tokenURIs; // 숫자를 넣으면 문자로 반환
mapping (address => uint256[]) private _ownedTokens; // 주소를 넣으면 숫자 배열로 반환
function mintWithTokenURI (address to, uint256 tokenId, string memory tokenURI) public returns (bool) {
// 토큰을 발행 하는 함수
tokenOwner[tokenId] = to; // to는 소유주 이기때문에 👉 msg.sender 으로도 쓸수 있다
// 토큰 번호를 입력하면 토큰 소유주의 주소가 나온다
tokenURIs[tokenId] = tokenURI; // 토큰 번호를 입력하면 토큰의 이름이 나온다
_ownedTokens[to].push(tokenId); // 주소를 입력하면 소유중인 토큰 번호들이 나온다
return true; // 리턴
}
function safeTransferFrom(address from, address to, uint256 tokenId) public {
// 토큰을 전송하는 함수
require(from == msg.sender, "Not from"); // 토큰을 보내는 사람이 소유주일때만 실행 👉 아니면 에러
require(from == tokenOwner[tokenId], "NotTokenFrom"); // 토큰이 본인의 토큰일때만 실행 👉 아니면 에러
_removeTokenFromList(from, tokenId);
// 밑에서 정의한 함수를 여기서 사용 (토큰을 전송하면 내 목록에서 사라져야하기때문)
_ownedTokens[to].push(tokenId);
// 전송후에 상대방이 가지고 있는 토큰배열에 전송받은 토큰을 추가 해주기
tokenOwner[tokenId] = to; // from은 내 주소(소유쥬) to는 받는사람 토큰의 번호를 입력한다
}
function _removeTokenFromList(address from, uint256 tokenId) private {
// [10, 15, 20, 23] 👈 20번을 삭제하고 싶을때
// [10, 15, 23, 20] 👈 20번과 23번을 스왑하고
// [10, 15, 23] 👈 배열의 마지막 제거
uint256 lastTokenIndex = _ownedTokens[from].length -1;
// 👆 배열의 마지막을 선택해주는 변수
for (uint256 i=0; i< _ownedTokens[from].length; i++) {
// 반복문실행 소유중인 토큰 번호(배열)
if (tokenId == _ownedTokens[from][i]) {
// 삭제하고싶은 토큰번호를 소유주의 배열에서 찾았다면
// 스왑기능 실행
_ownedTokens[from][i] = _ownedTokens[from][lastTokenIndex];
// 배열과 = 배열의 마지막 위치는 같다 선언함으로써 위치 변경
_ownedTokens[from][lastTokenIndex] = tokenId;
// 배열의 마지막이 삭제하고 싶은 토큰번호로 스왑됨
break;
}
}
_ownedTokens[from].length--; // 👈 배열의 맨마지막 제거
}
function ownedTokens (address owner) public view returns (uint256[] memory) {
// 내가 가지고 있는 토큰들 조회
return _ownedTokens[owner]; // 조회하고자 하는 주소를 입력하면 토큰들(배열)이 나온다
}
function setTokenURI (uint256 id, string memory uri) public {
// 토큰의 이름 바꾸기 함수
tokenURIs[id] = uri; // 바꾸고자 하는 토큰번호을 입력하고 바꾸고자 하는 토큰명을 입력한다
}
}
---