Block_Chain_Project - 12 [텍스트 P2E게임] - Solidity

Lumi·2022년 2월 6일
0

Block_Chain_Project

목록 보기
30/30
post-thumbnail

🔥 개요

Solidity작업은 끝났습니다.

  • Autcion은 오프체인에서 다루고 거래가 되면 컨트랙트에서 NFT와 Token의 양을 이동시켜주는 방향으로 방향을 잡았습니다.

문제는 마이그레이션을 할수가 없습니다....

  • 코드 이름, 폴더 이름이 가장 큰 문제가 되고 있고
  • 작성한 코드 자체를 뜯어 고쳐야 해서... 이 부분에서 시간을 낭비하고 싶지 않다는 생각을 하였습니다.
  • 어차피 작성하는 부분은 하면 하는데 했던 과정을 반복하는 작업이기 떄문에

🔥 Solidity

Character

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.0;
import "./libraries/Token.sol";
import "./libraries/NFT.sol";

interface char {
    event NewUser(
        address indexed owner,
        uint256 indexed Pow,
        uint256 indexed limit
    );
    event TokenPurchased(
        address indexed account,
        uint256 indexed amount,
        address indexed server
    );

    event Token_Transfer_All(address[] indexed account, uint256 indexed value);

    event Token_Sell(
        address indexed account,
        uint256 indexed amount,
        address indexed server
    );

    event token_transferError(address account, uint256 amount);
}

contract check_User {
    mapping(address => bool) internal checkUser;
    address internal owner;
    modifier isOwner(address _address) {
        require(checkUser[_address] == true);
        _;
    }
    modifier onlyOwner() {
        require(owner == msg.sender, "Not adming address!");
        _;
    }
}

contract Character is char, check_User {
    mapping(address => Characters) private _Character;

    Token private gold;
    // 0xB202e69304628a9C19928960A042401AC5FFB37C
    NFT private nft;
    // 0x457FBe2b16f754cf3bE664131B12afA05bc42382

    uint256 PowFee = 30;
    uint256 limitFee = 50;

    struct Characters {
        uint32 Pow;
        uint32 limit;
    }

    modifier check_balance(address _address, uint256 value) {
        require(gold.balanceOf(_address) >= value);
        _;
    }

    constructor(address _token, address _NFT) {
        gold = Token(_token);
        nft = NFT(_NFT);
        owner = msg.sender;
    }

    function buyTokens() public payable {
        require(msg.sender != address(0x0), "No Existed address");
        // 단위 계산이 wei로 들어오기 때문에 나눠준다.
        uint256 tokenAmount = msg.value / 100000000000;

        Gold_transfer_eachOther(msg.sender, address(gold), tokenAmount);

        // 괜히 delegatecall을 사용해보고 싶어서 만지작 대다가... onlnyOwner이라는 문제와 msg.sender이라는 문제에 막혀서 그냥 다른 함수를 사용하였습니다.
        // (bool success, ) = address(this or gold).delegatecall(abi.encodeWithSignature("transfer(address,uint256)", msg.sender, tokenAmount));

        // if(!success){
        //     emit token_transferError(msg.sender, tokenAmount);
        //     revert();
        // }

        // Uniswap에서 pair pool을 만들떄에 CA값을 활용하는 것을 보고 처음에는 payable(address(gold))로 적고 시도를 해보았다.
        // 근데 CA에는 transfer가 안된다는 것을 까먹고 계속 뭐가 문제인지를 파악하지 못했다...
        // pair pool이라는 CA값에 너무 집중했는지 쓸데 없는 시간을 낭비했던 부분;;
        // Swap이라고 부르기도 좀 그렇지만 유동성문제를 해결할수 없기 떄문에 활용가능한 범위에서만 코드를 적었습니다.
        owner.transfer(msg.value);

        emit TokenPurchased(msg.sender, tokenAmount, address(gold));
    }

    function sellTokens(uint256 value) public payable {
        require(msg.sender != address(0x0), "No Existed address");
        // Token을 CA주소로 반환하는 행위
        Gold_transfer_eachOther(address(gold), msg.sender, value);
        // wei로 들어올떄 100000000000만큼 나누어 줌
        // 나갈떄에는 Token의 양에 100000000000만큼 곱해주면됨
        uint256 Wei_amount = value * 100000000000 wei;

        msg.sender.transfer(Wei_amount);

        emit Token_Sell(msg.sender, msg.value, address(gold));
    }

    function NFT_minting(string memory URI) public isOwner(msg.sender) {
        // 아이템을 뽑을떄 실행시킬 트랜잭션
        nft.mintNFT(msg.sender, URI);
    }

    function NFT_transfer(
        address buyer,
        uint256 Price,
        uint256 NFT_index
    ) public isOwner(msg.sender) {
        require(buyer != address(0), "Not Existed address");
        require(Gold_balanceOf(buyer) >= Price, "Buyer is not having Price");
        require(
            nft.ownerOf(NFT_index) == msg.sender,
            "The owner of this NFT is not msg.sender"
        );
        // 이전에는 1분마다 하루가 지난 거래를 확인하여 거래를 진행하였지만 이번에는
        // 사용자가 직접 원할떄에 버튼을 눌러서 거래가 되게 할 예정
        // 단순히 token 거래와 NFT이동만 시켜주면 된다.

        // 일단 토큰 거래를 해준다
        Gold_transfer_eachOther(msg.sender, buyer, Price);

        // 그후 NFT거래를 해준다.
        NFT_transferFrom(msg.sender, buyer, NFT_index);
    }

    function NFT_transferFrom(
        address owner,
        address buyer,
        uint256 NFT_index
    ) internal {
        nft.transferFrom(owner, buyer, NFT_index);
    }

    function Gold_transfer_eachOther(
        address recipient,
        address sender,
        uint256 value
    ) internal {
        // 이 부분은 CA와 사용자간의 거래를 하는 부분
        gold.transfer_To_CA(recipient, sender, value);
    }

    function Gold_transfer(address to, uint256 amount)
        public
        isOwner(to)
        onlyOwner
    {
        // 서버계정에서 사람들에게 token을 지급하는 부분
        gold.transfer(to, amount);
    }

    function Gold_mintAll(address[] memory account, uint256 amount)
        public
        onlyOwner
    {
        for (uint256 i = 0; i < account.length; i++) {
            require(checkUser[account[i]] != false, "not Existed User!");
            // 이런 검증 로직이 많아지면 가스비 소모가 증가하지만
            // 검증하는 부분을 뺴놓을수가 없어서...
        }
        gold.transfer_all(account, amount);
    }

    function Char_makeCharacter(address _address)
        public
        onlyOwner
        returns (bool)
    {
        // 기존에 없는 캐릭터여야 한다.
        // 서버가 실행하여 캐릭터를 만들어 준다.
        require(checkUser[_address] == false);
        checkUser[_address] = true;

        Characters storage character = _Character[_address];
        character.Pow = 1;
        character.limit = 300;

        emit NewUser(_address, character.Pow, character.limit);
        return true;
    }

    function Char_IncreaseLimit()
        public
        isOwner(msg.sender)
        check_balance(msg.sender, limitFee)
    {
        // 자신이 가지고 있는 토큰을 gold의 CA주소에 반환해야 한다.
        Gold_transfer_eachOther(address(gold), msg.sender, limitFee);

        Characters storage character = _Character[msg.sender];
        character.limit += 300;
    }

    function Char_IncreasePow()
        public
        isOwner(msg.sender)
        check_balance(msg.sender, PowFee)
    {
        // 자신이 가지고 있는 토큰을 gold의 CA주소에 반환해야 한다.
        Gold_transfer_eachOther(address(gold), msg.sender, PowFee);

        Characters storage character = _Character[msg.sender];
        character.Pow += uint32(Char_getStatus());
    }

    function Char_getPow(address _address)
        public
        view
        isOwner(_address)
        returns (uint32)
    {
        Characters memory character = _Character[_address];
        return character.Pow;
    }

    function Char_getLimit(address _address)
        public
        view
        isOwner(_address)
        returns (uint32)
    {
        Characters memory character = _Character[_address];
        return character.limit;
    }

    function Char_getUser(address _address)
        public
        view
        isOwner(_address)
        returns (Characters memory)
    {
        return _Character[_address];
    }

    function Char_getRandomNumber() internal view returns (uint256) {
        // 오라클적인 문제점을 해결하기 위해서
        // 계속 변화할수 있는 tokenCA가 가지고 있는 토큰의 양을 인자르 넘겨 주엇다
        // token트랜잭션에 따라서 계속 변화할 것이기 떄문에
        return
            uint256(
                keccak256(
                    abi.encodePacked(
                        block.timestamp,
                        Gold_balanceOf(address(gold))
                    )
                )
            ) % 100;
    }

    function Char_getStatus() private view onlyOwner returns (uint256) {
        // 이 함수는 따로 랜덤한 값을 받기 위해서 사용을 해야 하기 떄문에 public로 선언
        // 어차피 서버 계정만이 사용할 함수
        return Char_getRandomNumber() % 10;
    }

    function Gold_balanceOf(address _address) public view returns (uint256) {
        return gold.balanceOf(_address);
    }

    function getNFT_List(address owner)
        public
        view
        onlyOwner
        isOwner(owner)
        returns (string[] memory)
    {
        // 사용자가 소지한 모든 NFT를 받아오는 함수
        string[] memory NFT_List = new string[](nft.balanceOf(owner));
        uint256 index = 0;
        for (uint256 i = 0; i < nft.totalNFTAmount(); i++) {
            if (nft.getOwner(i) == owner) {
                NFT_List[index] = (nft.getTokenURIs(i));
                index++;
            }
        }
        return NFT_List;
    }
}
  • 주석을 통해서 설명을 해두었다고 생각을 하기 떄문에 다른 부분은 다루지 않고 후기를 적겠습니다.

🔥 후기

흠... 초기에는 뜯어 고치는 마이그레이션 작업이 별로 시간이 많이 소요되지 않고 손쉽게 해결이 될줄 알았습니다..

하지만 새롭게 작성하는 것보다 기존에 있던것을 뜯어 고치는 작업이 상당히 더 어렵다는걸 알게 되는 시간이였습니다...

  • 이 부분을 가장 뜻깊게 배운것 같습니다.

또한 부가적으로 코드를 구조적으로 짜임새 있게 잘 적어야 할꺼 같습니다.

물론 중간중간 집중을 하여 짜임새 있게 작성하였다고 생각하였던 부분도 있지만 다른 부분에서는 이러한 부분을 적용하지 못했습니다.

  • 그러다보니 최종적으로 마이그레이션은 수행하지 못했네요;;

배운 부분

  • 코드를 구조적으로 작성을 하여 후에 수정이 필요하다면 원활하게 적용하자!
  • 오만하지 말자... (요즘 이런 생각이 드는데 아직 많이 배워야 하는 사람이다~~!!)
profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글