๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
D.evelop/BlockChian \ NFT

[NFT] 2์ฃผ์ฐจ(3) ํ† ํฐ ์ „์†ก safeTransferFrom - ๋ธ”๋ก์ฒด์ธ ๋งˆ์ผ“ ์•ฑ ๋งŒ๋“ค๊ธฐ with ๊ทธ๋ผ์šด๋“œX

by Danne 2022. 9. 30.

๐Ÿ‘‰ NFT

  • ๊ธ€์ž
  • ์†Œ์œ ์ž

๐Ÿ‘‰ ํ† ํฐ์ด ์กด์žฌํ•˜๋ ค๋ฉด

  1. ๋ฐœํ–‰ (์ผ๋ จ๋ฒˆํ˜ธ, ๊ธ€์ž, ์†Œ์œ ์ž)
  2. ์ „์†ก (๋ˆ„๊ฐ€, ๋ˆ„๊ตฌ์—๊ฒŒ, ๋ฌด์—‡์„)

 

โœ… ํ† ํฐ์„ ์ฃผ๊ณ  ๋ฐ›๋Š” smart contract ๋งŒ๋“ค์–ด๋ณด๊ธฐ

  • ์ „์†กํ•  ํ† ํฐ์˜ id๋ฅผ ์‚ฌ์šฉ ํ•ด ์†Œ์œ ์ฃผ์˜ ์ง€๊ฐ‘์—์„œ ํ•ด๋‹น ํ† ํฐ ์‚ญ์ œ
  • ์ „์†ก๋  ํ† ํฐ์˜ id๋ฅผ ์‚ฌ์šฉ ํ•ด ์ˆ˜์‹ ์ž์˜ ์ง€๊ฐ‘์— ํ•ด๋‹น ํ† ํฐ ์ถ”๊ฐ€
pragma solidity >=0.4.24 <=0.5.6;

contract Practice {
    string public name = 'KlayLion';
    string public symbol = "DD";
    
    mapping (uint256 => address) public tokenOwner;
    mapping (uint256 => string) public tokenURIs;

    // ์†Œ์œ ํ•œ ํ† ํฐ ๋ฆฌ์ŠคํŠธ
    mapping (address => uint256[]) private _ownedTokens;
    
    // mint(tokenId, uri, owner)
    // transferForm(form, 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;

        // add token to the list
        _ownedTokens[to].push(tokenId);

        return true;
    }

    // ์ „์†ก 
    function safeTransferFrom(address from, address to, uint256 tokenId) public {   
        require(from == msg.sender, "form != msg.sender"); // ๋ณด๋‚ธ ์‚ฌ๋žŒ์ด fromํ•˜๊ณ  ๊ฐ™์„ ๋•Œ
        require(from == tokenOwner[tokenId], "your are not the owner of the token"); // ๋ณด๋‚ธ ์‚ฌ๋žŒ์ด ํ† ํฐ์˜ ์†Œ์œ ์ฃผ์ผ ๋•Œ
        // ํ•ด๋‹น ํ† ํฐ๋งŒ ์ง€์šฐ๊ณ 
        _removeTokenFromList(from, tokenId);
        // ์ „์†ก ๋ฐ›๋Š” ๊ณณ์— ํ•ด๋‹นํ† ํฐ ์ถ”๊ฐ€
        _ownedTokens[to].push(tokenId);
        // ํ•ด๋‹น ํ† ํฐ์„ ์ „์†ก
        tokenOwner[tokenId] = to; // ์ด๊ฒƒ๋งŒ ์žˆ์œผ๋ฉด ์•„๋ฌด๋‚˜ ํ† ํฐ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ๋‹ค.
    }

    // ๊ธฐ์กด ํ† ํฐ ์†Œ์œ ์ฃผ์˜ ํ† ํฐ ์‚ญ์ œ
    // ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ์•ˆ์—์„œ๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์œผ๋ฉด private
    function _removeTokenFromList(address from, uint256 tokenId) private { 
        // [10, 15, 19, 20] -> 19๋ฒˆ ์‚ญ์ œํ•˜๊ณ  ์‹ถ๋‹ค
        // [10, 15, 20, 19]
        // [10, 15, 20]
        uint256 lastTokenIndex = _ownedTokens[from].length - 1;

        for(uint256 i=0 ; i<_ownedTokens[from].length; i++){
            // Swap last token with deleting token.
            if(tokenId == _ownedTokens[from][i]){
                _ownedTokens[from][i] = _ownedTokens[from][lastTokenIndex];
                _ownedTokens[from][lastTokenIndex] = tokenId;
                break;
            }
        }
        _ownedTokens[from].length--;
        
    }

    // ์†Œ์œ ์ค‘์ธ ํ† ํฐ
    function ownerToken(address owner) public view returns (uint256[] memory){
        return _ownedTokens[owner];
    }
    

    function setTokenUri(uint256 id, string memory uri) public{
        tokenURIs[id] = uri;
    }
}

 

โœ… ํ† ํฐ ๋ฏผํŒ…

ํ† ํฐ์˜ ์†Œ์œ ์ฃผ๋ฅผ ์กฐํšŒํ•˜๋ฉด ๋ฏผํŒ… ๋•Œ ๋„ฃ์€ address to์˜ ์ง€๊ฐ‘์ฃผ์†Œ(0x403E...)๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

โœ… ์†Œ์œ ์ฃผ ๋ณ€๊ฒฝํ•ด๋ณด๊ธฐ

safeTransferFrom์— ์†Œ์œ ์ฃผ์˜ ์ฃผ์†Œ (0x403E...) (address from), ๋ฐ›๋Š” ์ด์˜ ์ฃผ์†Œ (0x00f3...) (address to), ์ „๋‹ฌํ•  ํ† ํฐ id 0 (uint256 tokenId)๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

 

transaction์ด ์„ฑ๊ณตํ•˜๋ฉด ํ•ด๋‹น ํ† ํฐ id์กฐํšŒ ์‹œ ์†Œ์œ ์ž์˜ ์ฃผ์†Œ๊ฐ€ (0x00f3...)๋กœ ๋ฐ”๋€ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

โ—๏ธ์†Œ์œ ์ฃผ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๋’ค ๊ธฐ์กด ์†Œ์œ ์ฃผ์˜ ์ฃผ์†Œ (0x403E...)๋ฅผ from ์œผ๋กœ ์‚ฌ์šฉ ์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค.

 

 

 

โœ… safeTransferFrom

 

  • id๊ฐ€ 10, 11์ธ ํ† ํฐ์„ 0x403E... ์ง€๊ฐ‘์— ๋ฏผํŒ…
  • 10์„ 0x00f3...๋กœ ์ „์†ก
  • 0x403E... ์˜ ์†Œ์œ  ํ† ํฐ ์กฐํšŒ : 11
  • 0x00f3... ์˜ ์†Œ์œ  ํ† ํฐ ์กฐํšŒ : 10

 

 

 

 

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€