Block_Chain_Project - 6 [텍스트 P2E게임]

Lumi·2022년 1월 17일
1

Block_Chain_Project

목록 보기
19/30
post-thumbnail

🔥 개요

  • 현재에는 거래소쫌 부분을 좀더 css작업을 해놓았습니다.

음.. 일단 프론트와 백엔드를 혼자서 작업을 다해버리다 보니 조금 시간이 소요되었습니다.

  • 그렇게 막 만족스럽지도 않고요..ㅠㅠ

그래도 이번 프로젝트는 좀 최대한 많은것을 구현해보고자 혼자서라도 최대한 진행중 입니다.

이번에는 새로운 DB모델을 만들고 해당 DB모델에서 NFT거래에 관한것을 총괄하여 처리를 하고 있습니다.

  • 아직 web3를 연결하지는 않았습니다.

저희가 추구하는 방향은 중앙화되어있는 서버를 통해서 DB를 통해서 게임이 작동이 되며 후에 실제 블록체인 기록되는 데이터들은 따로 처리를 해주는 방법입니다.

  • 이 부분이 betchServer가 담당을 하고 있습니다.

거의 반 독학으로 프로그래밍을 공부하다 보니 아키텍처 부분이나 코드적으로 완벽하지는 않지만 그래도 구현이 된다는 것을 보면 뿌듯하기는 하네요 ^^

🔥 솔리디티

기존에는 CA의 값을 거래가 발생할때마다 계속 배포하는 방식을 생각하였습니다.

하지만 이러한 방식은 확실히 데이터 관리가 불가능에 가깝다고 생각을 하기 떄문에

하나의 Auction이라는 컨트랙트에서 거래를 모두 기록하는 방향으로 바꾸게 되었습니다.

저의 팀원분도 한개 작성해 보셨고 저도 개인적으로 한개 작성을 해보았습니다.

  • 오전에 시간이 살짝 남아서 오전에 작성을 해보았는데 팀원분도 작성을 해보셨다고 하시네용 ㅎ

팀원분의 코드

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

contract Auction2 {
    enum Phase {
        Init,
        Bidding,
        Done
    }
    address owner;

    struct auction {
        address seller;
        address buyer;
        uint256 id;
        uint256 price;
        Phase state;
    }

    auction[] auctions;

    modifier validPhase(uint256 id, Phase phase) {
        require(auctions[id].state == phase);
        _;
    }

    // modifier isSeller(){
    //     require(msg.sender == seller);
    //     _;
    // }

    Token private gold;
    NFT private item;

    constructor(address token, address nft) {
        gold = Token(token);
        item = NFT(nft);
    }

    mapping(uint256 => uint256) private AuctionNum;
    mapping(uint256 => bool) private isReg;
    uint256 counter = 0;

    function makeAuction(uint256 id, uint256 price) public {
        require(isReg[id] == false, "already registered");
        address seller = item.ownerOf(id);
        auctions.push(auction(seller, seller, id, price, Phase.Bidding));
        AuctionNum[id] = counter++;
        isReg[id] = true;
    }

    function nextState(uint256 id) public {
        uint256 num = AuctionNum[id];
        if (auctions[num].state == Phase.Done) revert();
        if (auctions[num].state == Phase.Init)
            auctions[num].state = Phase.Bidding;
        else {
            auctions[num].state = Phase.Done;
            trade(id);
        }
    }

    function Bid(
        uint256 id,
        address bidder,
        uint256 price
    ) public validPhase(id, Phase.Bidding) {
        uint256 num = AuctionNum[id];
        uint256 balance = gold.balanceOf(bidder);
        require(price < balance, "price exceeds balance");
        require(
            price < auctions[num].price,
            "need to be higher than highest price"
        );
        auctions[num].price = price;
        auctions[num].buyer = bidder;
    }

    function showPrice(uint256 id) public view returns (uint256) {
        uint256 num = AuctionNum[id];
        return auctions[num].price;
    }

    function showBuyer(uint256 id) public view returns (address) {
        uint256 num = AuctionNum[id];
        return auctions[num].buyer;
    }

    function showSeller(uint256 id) public view returns (address) {
        uint256 num = AuctionNum[id];
        return auctions[num].seller;
    }

    function trade(uint256 id) public validPhase(id, Phase.Done) {
        require(item.ownerOf(id) == showSeller(id), "seller is not owner");
        uint256 fee = (showPrice(id) * 5) / 100;
        address seller = showSeller(id);
        address buyer = showBuyer(id);
        gold.transfer(buyer, owner, fee);
        gold.transfer(buyer, seller, showPrice(id) - fee);
        item.transferFrom(seller, buyer, id);
        isReg[id] = false;
    }
}

나의 코드

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

interface Auction_test {
    function Bid(
        uint256 price,
        address _address,
        uint256 room_number
    ) external returns (bool);

    function make_trade(
        address _owner,
        uint256 _price,
        uint256 _item
    ) external returns (bool);

    event BidEvent(uint256 indexed price, address indexed _address);
    event make_trade_event(
        address indexed _owner,
        uint256 indexed _price,
        uint256 indexed _item
    );
    event trade_end(
        address indexed _owner,
        address indexed _buyer,
        uint256 indexed _price
    );
    event trade_end_tax(uint256 indexed _number, uint256 indexed tax);
}

contract Auction is Auction_test {
    enum Status {
        // 게임의 상태
        start,
        delling,
        end
    }

    address private seller;
    address private buyer;

    uint256 private ID;
    uint256 private highestPrice;
    uint256 private total_Room_Number = 1;

    // 거래가 이루어지는 방을 의미
    mapping(uint256 => Room) private Room_Number;
    // 존재하는 방 인지를 확인
    mapping(uint256 => bool) private check_room;
    // 들어오는 nft의 번호에 해당하는 room_number를 반환
    mapping(uint256 => uint256) private NFT_Room_number;

    Token private gold;
    NFT private item;

    struct Room {
        address seller;
        address buyer;
        uint256 price;
        uint256 product;
        Status status;
    }

    constructor(address token, address nft) {
        gold = Token(token);
        item = NFT(nft);
        // 경매를 진행하려면 실제로 NFT가 만들어 져 있어야 한다.
    }

    function make_trade(
        address _owner,
        uint256 _price,
        uint256 _item
    ) public returns (bool) {
        require(item.ownerOf(_item) == _owner, "not your Item!!!");
        Room_Number[total_Room_Number] = Room({
            seller: _owner,
            buyer: address(0x0),
            price: _price,
            product: _item,
            status: Status.start
        });
        check_room[total_Room_Number] = true;
        NFT_Room_number[_item] = total_Room_Number;
        total_Room_Number++;
        emit make_trade_event(_owner, _price, _item);
        return true;
    }

    function Bid(
        uint256 price,
        address _buyer,
        uint256 Room_number
    ) public returns (bool) {
        uint256 balance = gold.balanceOf(_buyer);
        require(price < balance, "price exceeds balance");
        require(check_room[Room_number] == true, "No existed Room!!!");
        Room storage room = Room_Number[Room_number];
        require(room.price < price, "need to be higher than highest price");
        require(room.status != Status.end, "already end delling");
        room.buyer = _buyer;
        room.price = price;
        room.status = Status.delling;
        emit BidEvent(price, _buyer);
        return true;
    }

    function trade(uint256 room_number) public returns (bool) {
        require(check_room[room_number] == true, "No existed Room!!!");
        Room storage room = Room_Number[room_number];
        require(room.status == Status.delling, "Not yet delling!!");
        uint256 fee = room.price / 10;
        uint256 amount = room.price - fee;
        gold.transfer(room.buyer, room.seller, amount);
        gold.transfer(room.buyer, msg.sender, fee);
        item.transferFrom(room.seller, room.buyer, room.product);
        room.status = Status.end;
        emit trade_end(room.seller, room.buyer, room.price);
        emit trade_end_tax(room_number, fee);
        return true;
    }

    function showRoom(uint256 room_number) public view returns (Room memory) {
        require(check_room[room_number] == true, "No existed Room!!!");
        return Room_Number[room_number];
    }

    function highest(uint256 room_number) public view returns (uint256) {
        require(check_room[room_number] == true, "No existed Room!!!");
        Room memory room = Room_Number[room_number];
        return room.price;
    }

    function showBuyer(uint256 room_number) public view returns (address) {
        require(check_room[room_number] == true, "No existed Room!!!");
        Room memory room = Room_Number[room_number];
        return room.buyer;
    }

    function showSeller(uint256 room_number) public view returns (address) {
        require(check_room[room_number] == true, "No existed Room!!!");
        Room memory room = Room_Number[room_number];
        return room.seller;
    }
}

팀원분의 코드나 저의 코드나 다른점은 한가지로 보입니다.

  • mapping을 사용했냐 array를 사용했냐의 차이인것 같습니다.

둘다 room_number를 기록을 하면서 해당 Room_number에서 거래가 이루어 집니다.

아직은 web3를 적용하지 않아서 실질적으로 어떻게 적용될지는 모르겠지만

물품 거래는 등록한 순간부터 하루안에서만 거래가 진행이 되는 방식으로 작성을 해볼 것이며

솔리디티 딴에도 block.timestamp를 통해서 시간을 설정할수 있지만

저희 시스템은 컨트랙트 자체는 다른 시간에 배포를 하기 떄문에

컨트랙트에서보다는 node.js에서 시간을 기록하여 데이터를 처리할 것같습니다.

이또한 특정 시간마다 거래소 목록을 모두 뒤져봐서 하루가 지난 데이터는 처리해주는 방식으로 작동이 될것 같습니다.

const SellingSchema = mongoose.Schema({
  id: Number,
  seller: String,
  buyer: {
    type: String,
    default: "none",
  },
  price: Number,
  time: String,

  item: Object,
});

export const SellingItemDB = mongoose.model("SellingItem", SellingSchema);
  • 부수적으로 거래소에서 이용된 DB모델 입니다.
  • id값은 room_number값을 활용하는데에 이용이 됨과 동시에
  • nft를 가르키는 번호로 사용이 되고 있습니다.

🔥 후기

오늘은 뭔가 코딩하는것이 즐겁고 재미있어서 열심히 했던것 같습니다.

web3를 구동시키는 것은 이떄까지 해왔던 코드를 반복하는 것과 비슷하기 떄문에 내일 안에 마무리가 될것 같습니다.

이후에 어떤작업을 해야할지 팀원분과 고민을 하고 있습니다.

  • multisig, voting등등 해보고싶은 구현은 많지만 저희 게임에서 어떤 방식으로 활용이 될지를 모르겠습니다.

다음글은 최소한 web3작업이 마무리되는것 이후가 될꺼 같습니다.

감사합니다!

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

1개의 댓글

comment-user-thumbnail
2022년 1월 19일

안녕하세요. 꾸준히 올려주신 블록체인 관련 글들 잘 보구 있습니다. 저희는 여행플랫폼 운영중인 스타트업인데 클레이튼 기반 BAPP 개발 및 여행생태계 구축을 기획하고 있습니다. 저희와 함께 할 수 있는 기회가 있으면 좋을 거 같아 먼저 연락 드립니다. 일단 한번 만나서 이야기 나누고 싶습니다. :) 괜찮으시다면 ykseok@gmail.com/010-5101-1344로 연락처 한번 부탁드릴게요. 따로 연락을 드릴수 있는 방법이 없어, 여러번 댓글로 남깁니다.

답글 달기