일단 저는 로그인 및 회원가입을 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를 만들떄에 사용될 토큰을 설정하게 됩니다.
일단 테스트에 용이하게 nftPrice의 가격을 1로 설정을 해둔 상태 입니다.
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에서 따로 값을 가지고 있기 떄문에 이 부분을 통하여 바로 서명된 트랜잭션을 전송하게 됩니다.
현재 문제가 되고 있는 부분은 소유하고 있는 이더입니다.
일반적으로 새로운 아이디를 만드는 사용자들은 가지고 있는 이더가 없을 것 입니다.
하지만 서버 계정에서는 가스비로 사용될 이더를 가지고 잇고 이 이더를 통해서 트랜잭션을 발생 시키면 됩니다.
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
부분 입니다.
이 부분에서는 중간 저장소에 저장해둔 값에서 뺴내가는 역할을 하고 있습니다.
그러면 이 부분에서 중간에 저장해둔 값이 없다는 뜻이 되기 때문에 저희는 approve
를 통해서 해결하면 되는 부분 이였습니다.
그래서 이 부분을 ERC-20 의 민팅 함수 내에서 찾아냈고 이를 통해서 해결해보고자 합니다.
시간이 살짝 늦어서 일단 개인적으로 해결을 해보고자 한뒤에 해결이 된다면 다시 블로깅을 하여 과정을 적어보고자 합니다!
지금 좀 너무 빠르게 작업을 와다다다하다 보니깐 좀 로직이 꼬여있기는 합니다...
그래서 인지 굉장히 난해한 코드가 되어 있지만 최대한 일단 기능적으로만 이라도 작동이 되게 만들어 보겠습니다!!