Block_Chain_Project - 2 [ERC-20, ERC-721거래]

Lumi·2021년 12월 28일
0

Block_Chain_Project

목록 보기
8/30
post-thumbnail

🔥 개요

일단 저는 로그인 및 회원가입을 mongoose를 통하여 관리를 하고 게시글을 작성할떄 토큰을 지급하는 방식이며

만약 게시글의 좋아요가 일정수 이상이 되면 해당 게시물 내용을 NFT로 만드는 이런 느낌의 웹페이지를 만들어 보고자 합니다.

steamit과 비슷합니다.

일단 전반적으로 프론트에는 많은 힘을 주고 싶지 않아서 정말 간단하게 보이게끔만 만들어 놓았으며 프론트 로직은 최대한 간다하게 구성을 하였습니다.

왜냐하면 저는 web3를 활용하는 로직에 좀더 시간을 투자하는 것이 맞다고 생각을 하였습니다.

현재 상황에서는 로그인, 회원가입, 게시글 등등 DB를 활용하는 부분은 대부분 만족스럽게 작동을 합니다.

  • 아쉬운점은 너무 급하게 만들다 보니 좀 가독성이 많이 떨어집니다..ㅠㅠ

현재 막히는 부분은 바로 NFT생성 부분 입니다.

뒤에서 다루어 보겠지만 일단 기존에 쓰이던 솔리디티 코드를 살짝 수정을 하여 사용을 하였으며 이 부분에서 조금 헤매고 있는 상황입니다.

DB, 프론트 부분은 따로 다루지 않겠습니다.

🔨 솔리디티 코드

솔리디티 코드는 모두 코드스테이츠 코드를 참고 하였습니다!

ERC-20

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.10;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract project_2_Token is ERC20, Ownable {
    constructor() ERC20("project_2_Token", "P2T") {
    }

    function mintToken(address to, uint256 amount) public onlyOwner returns (bool){
        require(to != address(0x0));
        require(amount > 0);
        _mint(to, amount);
        _approve(to, msg.sender, allowance(to, msg.sender) + amount);  // approve 추가

        return true;
    }
}

openzeppelin을 활용하여 최대한 간결하게 작성이 되었습니다.

  • 이 코드스테이츠 코드를 참고하였습니다!

저의 웹사이트에서 활용될 토큰을 만드는 함수는 mintToken 함수이며 서버에서 하나의 계정에 민팅을 시전하고 그 계정을 통해서 토큰을 지급하는 형식입니다.

ERC-721

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract TEst is ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    IERC20 token;
    uint256 nftPrice;

    constructor() ERC721("MyNFTs", "MNFT") {
        nftPrice = 1;
    }

    function mintNFT(address recipient, string memory tokenURI) public onlyOwner returns (uint256) {
        require(token.balanceOf(recipient) > nftPrice);

        token.transferFrom(recipient, msg.sender, nftPrice);
        
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }

    function setToken (address tokenAddress) public onlyOwner returns (bool) {
        require(tokenAddress != address(0x0));
        token = IERC20(tokenAddress);
        return true;
    }

   
}

다음은 NFT를 만드는 솔리디티 코드입니다.

일단 setToken함수를 통해서 NFT를 만들떄에 사용될 토큰을 설정하게 됩니다.

  • 이떄 ERC-20토큰의 CA주소를 넣어줌으로써 토큰 설정이 완료가 됩니다.

일단 테스트에 용이하게 nftPrice의 가격을 1로 설정을 해둔 상태 입니다.

🔨 web3 코드

let tx = {
        from: TokenAdmin,
        to: process.env.TOKEN_CA,
        gas: 50000,
        data: contract.mintToken(address, 3).encodeABI(),
      };
      await web3.eth.accounts
        .signTransaction(tx, process.env.private_Key)
        .then(async (signedTx) => {
          await web3.eth.sendSignedTransaction(
            signedTx.rawTransaction,
            (err, hash) => {
              if (!err) {
                console.log("Token 지급 트랜잭션");
              } else {
                console.log(err);
              }
            }
          );
        });

Contract를 불러오는 코드는 따로 다루지 않았습니다.

  • 이 부분은 검색 또는 제 블로그를 참고하면 자주 다루었기 떄문입니다.

이전의 프로젝트에서는 메타마스크를 통해서 트랜잭션을 검증하는 부분이였지만

이번에는 DB에서 따로 값을 가지고 있기 떄문에 이 부분을 통하여 바로 서명된 트랜잭션을 전송하게 됩니다.

  • 이후의 모든 web3코드는 이러한 로직을 따라가게 됩니다.

🔨 문제점

현재 문제가 되고 있는 부분은 소유하고 있는 이더입니다.

일반적으로 새로운 아이디를 만드는 사용자들은 가지고 있는 이더가 없을 것 입니다.

  • 테스트 이더를 말합니다.

하지만 서버 계정에서는 가스비로 사용될 이더를 가지고 잇고 이 이더를 통해서 트랜잭션을 발생 시키면 됩니다.

ERC-20 민팅 함수 같은 경우에는 단순하게 코드만 작성해 주면 되지만

현재 문제가 되고 있는 곳은 바로 NFT생성 부분 입니다.

처음 계속해서 Transaction has been reverted by the EVM: 와 같은 오류가 발생을 하길래

저는 require문이 통과가 안되나?? 라는 생각에

 function showTokenAmount (address recipient) public view returns (uint256){
        return token.balanceOf(recipient);
    }

function check (address recipient) public view returns (bool){
        return token.balanceOf(recipient) > nftPrice;
    }

이러한 코드를 추가하여 확인을 해 보았지만 이 부분은 정상적으로 작동을 하고 있습니다.

그럼 다음 문제는 바로 transferFrom부분 입니다.

이 부분에서는 중간 저장소에 저장해둔 값에서 뺴내가는 역할을 하고 있습니다.

  • 간단한 transfer과는 조금 다릅니다.

그러면 이 부분에서 중간에 저장해둔 값이 없다는 뜻이 되기 때문에 저희는 approve를 통해서 해결하면 되는 부분 이였습니다.

그래서 이 부분을 ERC-20 의 민팅 함수 내에서 찾아냈고 이를 통해서 해결해보고자 합니다.

시간이 살짝 늦어서 일단 개인적으로 해결을 해보고자 한뒤에 해결이 된다면 다시 블로깅을 하여 과정을 적어보고자 합니다!

🔥 추가 사항

지금 좀 너무 빠르게 작업을 와다다다하다 보니깐 좀 로직이 꼬여있기는 합니다...

  • 기존의 프로젝트 시간을 의논하는 시간을 가졌지만 결국 결과를 보지 못해서 좀 빠르게 하다보니..

그래서 인지 굉장히 난해한 코드가 되어 있지만 최대한 일단 기능적으로만 이라도 작동이 되게 만들어 보겠습니다!!

profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글