음.. 일단 프론트와 백엔드를 혼자서 작업을 다해버리다 보니 조금 시간이 소요되었습니다.
그래도 이번 프로젝트는 좀 최대한 많은것을 구현해보고자 혼자서라도 최대한 진행중 입니다.
이번에는 새로운 DB모델을 만들고 해당 DB모델에서 NFT거래에 관한것을 총괄하여 처리를 하고 있습니다.
저희가 추구하는 방향은 중앙화되어있는 서버를 통해서 DB를 통해서 게임이 작동이 되며 후에 실제 블록체인 기록되는 데이터들은 따로 처리를 해주는 방법입니다.
거의 반 독학으로 프로그래밍을 공부하다 보니 아키텍처 부분이나 코드적으로 완벽하지는 않지만 그래도 구현이 된다는 것을 보면 뿌듯하기는 하네요 ^^
기존에는 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;
}
}
팀원분의 코드나 저의 코드나 다른점은 한가지로 보입니다.
둘다 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);
오늘은 뭔가 코딩하는것이 즐겁고 재미있어서 열심히 했던것 같습니다.
web3를 구동시키는 것은 이떄까지 해왔던 코드를 반복하는 것과 비슷하기 떄문에 내일 안에 마무리가 될것 같습니다.
이후에 어떤작업을 해야할지 팀원분과 고민을 하고 있습니다.
다음글은 최소한 web3작업이 마무리되는것 이후가 될꺼 같습니다.
감사합니다!