Klaytn 스마트 컨트랙트 간 연동하기
Web 3.0/Klaytn

Klaytn 스마트 컨트랙트 간 연동하기

스마트 컨트랙트(이하 컨트랙트)는 블록체인 상에서 하나의 개인과 같이 주소를 가지는데, 다른 컨트랙트에 직접 토큰을 전송할 수 있다.

 

어떤 컨트랙트가 누군가로부터 토큰을 받았다면, 목적에 따라 이 토큰을 컨트랙트 내 특정 개인에게 토큰을 전송할 수 있다.

 

추가로, 컨트랙트 자체도 클레이를 가질 수 있다.

 

 

먼저, 컨트랙트를 서로 연결하려면 그 컨트랙트에 무엇이 있는지 사전에 알고 있어야 한다.

 

즉, 컨트랙트의 인터페이스를 알아야 한다.

 

실습코드

/* link-contracts.sol */

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;

    // mint(tokenId, uri, owner)
    // transferFrom(from, to, tokenId) -> owner가 from에서 to로 바뀌는 것을 의미함

    function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public returns (bool) {
        // to에게 tokenId(일련번호)를 발행하겠다.
        // 적힐 글자는 tokenURI
        tokenOwner[tokenId] = to; 
        tokenURIs[tokenId] = tokenURI;

        /*
        to: 0x5329220B8b8e57D033D6F6C5B0d66249f72fdfb9
        tokenId: 0
        tokenURI: pretty

        -> tokenURIs : 0 call하면 -> 0: string: pretty 출력됨
        */
        
        // add token to the list
        _ownedTokens[to].push(tokenId);

        return true;
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        // 보낸 사람이 from하고 같아야 하며
        require(from == msg.sender, "from != msg.sender");
        // 보낸 사람이 토큰 소유주여야 아래 코드에서 to로 토큰을 주게 됨
        require(from == tokenOwner[tokenId], "you r not the owner of the token");
        tokenOwner[tokenId ] = to; 

        _removeTokenFromList(from, tokenId);
        _ownedTokens[to].push(tokenId);

        tokenOwner[tokenId] = to;

    }

    function _removeTokenFromList(address from, uint256 tokenId) private{
        // 만약에 19벙 토큰을 삭제한다고 하면 아래와 같이 swap하여 배열을 조작함 
        // [10, 15, 19, 20]
        // [10, 15, 20, 19]
        // [10, 15, 20] 
        uint256 lastTokenIndex = _ownedTokens[from].length-1;

        for(uint256 i=0; i<_ownedTokens[from].length; i++){
            if (tokenId == _ownedTokens[from][i]) {
                // swap last token with deleting token 
                _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;
        // if setToeknUri(10, "HelloKlay") -> tokenURIs(10) -> 0: string: HelloKlay 출력
    }
}

contract NFTMarket {
     function buyNFT(uint256 tokenId, address NFTAddress, address to) public returns (bool) {
         // to에게 토큰을 전송하는 코드
         // 여기서 address(this)는 NFTMarket 컨트랙트의 주소임
         NFTSimple(NFTAddress).safeTransferFrom(address(this), to, tokenId);

         return true;
     }
}

 

NFTSimple 컨트랙트에서 NFTMarket 컨트랙트로 토큰을 전송하고 나면, 아래 사진과 같이 tokenOwner의 주소가 변경된 것을 확인할 수 있다.

NFTSimple 컨트랙트에서 NFTMarket 컨트랙트로 토큰을 전송하고 나면, 위 그림과 같이 tokenOwner의 주소가 변경된 것을 확인할 수 있다.

 

미리 작성해 놓은 buyNFT 함수로 NFTSimple 컨트랙트의 사용자가 NFTMarket 컨트랙트에 있는 토큰을 구매할 수도 있다.

 

즉, NFTMarket에서 NFTSimple이라는 다른 컨트랙트를 호출해서 safeTransferFrom 함수로 컨트랙트가 보유한 토큰을 다른 이에게 옮기는 것이다.

 

실습 결과는 설명과 함께 그림으로 아래에 첨부하였다.