Hi, this is my contract Marketplace (my contract is more different because i would create a little game nft for tryning my skills)
N.B. my code my code is very messy.
Code MarketplaceStiki.sol (i will check security and bugs, and miss âeventsâ )
// SPDX-License-Identifier: Leluk911
pragma solidity 0.8.7;
import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "../contracts/interface/INewStikiNft.sol";
import "../contracts/stikiToken.sol";
import "../node_modules/@openzeppelin/contracts/access/Ownable.sol";
import "../node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract MarketplaceStiki is Ownable, ReentrancyGuard {
IERC721 private Ierc721;
IStikiNFT private Isnft;
constructor(address _NftContract) {
require(_NftContract != address(0), "Set correct Address");
Ierc721 = IERC721(_NftContract);
Isnft = IStikiNFT(_NftContract);
}
// buyer
struct OfferBuy {
address payable Buyer;
uint256 price;
uint256 index;
uint256 tokenId;
bool active;
}
OfferBuy[] public offersBuy;
// tokenID => offerSeller
mapping(uint256 => OfferBuy[]) TokenIdToOfferBuyer;
//Seller
struct OfferSeller {
address payable Seller;
uint256 price;
uint256 tokenId;
}
OfferSeller public offersSell;
// tokenID => offerBuyer
mapping(uint256 => OfferSeller) TokenToOfferSeller;
function setNewStikiContract(address _contract)
external
onlyOwner
nonReentrant
{
require(_contract != address(0), "Set correct Address");
Ierc721 = IERC721(_contract);
Isnft = IStikiNFT(_contract);
}
// Function Seller
//ricevuta di deposito
// bool =>(address=>tokenId)
mapping(address => mapping(uint256 => bool)) receiptDeposit;
function _putSell(
address payable _to,
uint256 _tokenId,
uint256 _price
) internal {
require(_to == Ierc721.ownerOf(_tokenId), "Not Owner Stiki NFT");
require(receiptDeposit[_to][_tokenId] == false, "Nft just in list");
Ierc721.transferFrom(_to, address(this), _tokenId);
receiptDeposit[_to][_tokenId] = true;
//OfferSeller memory off = OfferSeller(_to, _price, _tokenId);
TokenToOfferSeller[_tokenId] = OfferSeller(_to, _price, _tokenId);
//TokenToOfferSeller[_tokenId] = offersSell;
}
function putSell(uint256 _tokenId, uint256 _price) external nonReentrant {
_putSell(payable(msg.sender), _tokenId, _price);
}
function _removePutSell(address _to, uint256 _tokenId) internal {
require(
TokenToOfferSeller[_tokenId].Seller == _to,
"This isnt your put"
);
delete TokenToOfferSeller[_tokenId];
receiptDeposit[_to][_tokenId] = false;
Ierc721.approve(address(this), _tokenId);
Ierc721.transferFrom(address(this), _to, _tokenId);
}
function removePutSell(uint256 _tokenId) external {
_removePutSell(msg.sender, _tokenId);
}
function viewPuttSell(uint256 _tokenId)
public
view
returns (OfferSeller memory)
{
return TokenToOfferSeller[_tokenId];
}
// Proventi della vedita
mapping(address => uint256) balanceSelling;
function fillPutSell(uint256 _tokenId) external payable nonReentrant {
//chek
require(
receiptDeposit[TokenToOfferSeller[_tokenId].Seller][_tokenId] ==
true,
"nft not in selling"
);
require(
msg.value == TokenToOfferSeller[_tokenId].price,
"Set correct value"
);
//transaction
//(bool success, ) = TokenToOfferSeller[_tokenId].Seller.call{
// value: msg.value
//}("");
//require(success, "transaction payment faill");
//modifie
balanceSelling[TokenToOfferSeller[_tokenId].Seller] += msg.value;
receiptDeposit[TokenToOfferSeller[_tokenId].Seller][_tokenId] = false;
delete TokenToOfferSeller[_tokenId];
// result
Ierc721.transferFrom(address(this), msg.sender, _tokenId);
require(Ierc721.ownerOf(_tokenId) == msg.sender, "transfer NFt faill");
}
function viewBalance(address _owner) public view returns (uint256) {
return balanceSelling[_owner];
}
function widrowProfitSell() external nonReentrant {
require(
address(this).balance >= viewBalance(msg.sender),
"balance low"
);
uint256 profit = viewBalance(msg.sender);
balanceSelling[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: profit}("");
require(success, "Widrow fail");
}
/**
struct OfferBuy {
address payable Buyer;
uint256 price;
uint256 index;
uint256 tokenId;
bool active;
}
OfferBuy[] public offersBuy;
// tokenID => offerSeller
mapping(uint256 => OfferBuy) TokenIdToOfferBuyer; */
mapping(address => uint256) depositEthBuyer;
function putBuyOffer(uint256 _price, uint256 _tokenId) external payable {
require(Ierc721.ownerOf(_tokenId) != msg.sender, "already owner");
require(
msg.value == _price,
"Send correct Eth in contract for your offer"
);
depositEthBuyer[msg.sender] += msg.value;
address payable _to = payable(msg.sender);
_putBuyOffer(_to, _tokenId, msg.value);
}
function _putBuyOffer(
address payable _to,
uint256 _tokenId,
uint256 _price
) internal {
uint256 index = TokenIdToOfferBuyer[_tokenId].length;
OfferBuy memory Offer = OfferBuy(_to, _price, index, _tokenId, true);
TokenIdToOfferBuyer[_tokenId].push(Offer);
}
function deactiveBuyOffer(uint256 _tokenId, uint256 _index) external {
require(
TokenIdToOfferBuyer[_tokenId][_index].Buyer == msg.sender,
"this not is your offer"
);
require(
TokenIdToOfferBuyer[_tokenId][_index].active == true,
"this offer is already deactive"
);
TokenIdToOfferBuyer[_tokenId][_index].active = false;
}
function reactiveBuyOffer(uint256 _tokenId, uint256 _index) external {
require(
TokenIdToOfferBuyer[_tokenId][_index].Buyer == msg.sender,
"this not is your offer"
);
require(
TokenIdToOfferBuyer[_tokenId][_index].active == false,
"this offer is already active"
);
TokenIdToOfferBuyer[_tokenId][_index].active = true;
}
function _deletOfferBuyer(
address _to,
uint256 _tokenId,
uint256 _index
) internal {
require(
TokenIdToOfferBuyer[_tokenId][_index].Buyer == msg.sender,
"this not is your offer"
);
uint256 repay = TokenIdToOfferBuyer[_tokenId][_index].price;
depositEthBuyer[msg.sender] -= repay;
TokenIdToOfferBuyer[_tokenId][_index] = TokenIdToOfferBuyer[_tokenId][
TokenIdToOfferBuyer[_tokenId].length - 1
];
TokenIdToOfferBuyer[_tokenId].pop();
(bool success, ) = _to.call{value: repay}("");
require(success, "Repay Eth faill");
}
function deletOfferBuyer(uint256 _tokenId, uint256 _index)
external
nonReentrant
{
_deletOfferBuyer(msg.sender, _tokenId, _index);
}
// buyer => nft == riceipt for deposit
mapping(address => mapping(uint256 => bool)) recptNftBuy;
function _fillBuyerOffer(
address _to,
uint256 _tokenId,
uint256 _index
) internal {
require(
Ierc721.ownerOf(_tokenId) == _to,
"you haven't owner's dirict on this nft "
);
require(
TokenIdToOfferBuyer[_tokenId][_index].active == true,
"this offer is deactive"
);
Ierc721.transferFrom(_to, address(this), _tokenId);
uint256 price = TokenIdToOfferBuyer[_tokenId][_index].price;
address buyer = TokenIdToOfferBuyer[_tokenId][_index].Buyer;
//delet Offer
TokenIdToOfferBuyer[_tokenId][_index] = TokenIdToOfferBuyer[_tokenId][
TokenIdToOfferBuyer[_tokenId].length - 1
];
TokenIdToOfferBuyer[_tokenId].pop();
depositEthBuyer[buyer] -= price;
balanceSelling[_to] += price;
recptNftBuy[buyer][_tokenId] = true;
}
function fillBuyerOffer(uint256 _tokenId, uint256 _index) external {
_fillBuyerOffer(msg.sender, _tokenId, _index);
}
function _widrowlNftBuy(address _to, uint256 _tokenId) internal {
require(recptNftBuy[_to][_tokenId] == true, "not avalible for widrowl");
recptNftBuy[_to][_tokenId] == false;
Ierc721.transferFrom(address(this), _to, _tokenId);
}
function widrowlNftBuy(uint256 _tokenId) external nonReentrant {
_widrowlNftBuy(msg.sender, _tokenId);
}
function viewBuyOfferForToken(uint256 _tokenId)
public
view
returns (OfferBuy[] memory)
{
return TokenIdToOfferBuyer[_tokenId];
}
}
This is test :
const mockUsdc = artifacts.require("mockUsdc");
const stikiToken = artifacts.require("stikiToken");
const NewStikiNFT = artifacts.require("NewStikiNFT");
const MintContract = artifacts.require("MintContract");
const MarketplaceStiki = artifacts.require("MarketplaceStiki");
const Turnament = artifacts.require("Turnament");
const truffleAssert = require("truffle-assertions");
contract("Stiki Marketplace", accounts => {
const account = accounts[0];
const account2 = accounts[1];
//console.log(account);
it("Mint 1 nft", async () => {
const stk = await stikiToken.deployed();
const contMinter = await MintContract.deployed();
const nft = await NewStikiNFT.deployed()
const usdc = await mockUsdc.deployed();
await contMinter.setAddrStikiNft(nft.address)
await usdc.approve(contMinter.address, 1000);
await contMinter.BuyStikiToken(account, 1000);
await stk.approve(contMinter.address, 100);
await contMinter.MintStiki("impostore", 11, 1, 1, 1, 1);
const nft1 = await nft.viewStat(0);
})
it("deposit 3 nft in put Sell", async () => {
const stk = await stikiToken.deployed();
const contMinter = await MintContract.deployed();
const nft = await NewStikiNFT.deployed()
const usdc = await mockUsdc.deployed();
const market = await MarketplaceStiki.deployed()
await contMinter.setAddrStikiNft(nft.address)
await usdc.approve(contMinter.address, 1000);
await contMinter.BuyStikiToken(account, 1000);
await stk.approve(contMinter.address, 300);
await contMinter.MintStiki("venduto", 11, 1, 1, 1, 1);
await contMinter.MintStiki("non venduto", 11, 1, 1, 1, 1);
await contMinter.MintStiki("ritirato", 11, 1, 1, 1, 1);
//MarketplaceStiki
// deposito
await nft.approve(market.address, 0);
await nft.approve(market.address, 1);
await nft.approve(market.address, 2);
await market.putSell(0, (1000));
await market.putSell(1, (2000));
await market.putSell(2, (3000));
let nft0 = await market.viewPuttSell(0);
let nft1 = await market.viewPuttSell(1);
let nft2 = await market.viewPuttSell(2);
//console.log(nft0)
//console.log(nft1)
//console.log(nft2)
})
it("Fill offer sel NFT", async () => {
const contMinter = await MintContract.deployed();
const nft = await NewStikiNFT.deployed()
const market = await MarketplaceStiki.deployed()
await contMinter.setAddrStikiNft(nft.address)
let nft0 = await market.viewPuttSell(0);
let nft1 = await market.viewPuttSell(1);
let nft2 = await market.viewPuttSell(2);
//console.log(nft0)
//console.log(nft1)
//console.log(nft2)
// fill offer sell
await market.fillPutSell(0, { from: account2, value: 1000 })
nft0 = await market.viewPuttSell(0);
})
it("widrowl ETH", async () => {
const market = await MarketplaceStiki.deployed()
let bal = await market.viewBalance(account)
//console.log(bal.toString())
await market.widrowProfitSell();
})
it("Ower nft buy", async () => {
const nft = await NewStikiNFT.deployed()
let ownerNft = await nft.ownerOf(0)
//console.log(account2)
//console.log(ownerNft)
})
it("Set 3 offerBuyr", async () => {
const market = await MarketplaceStiki.deployed()
const nft = await NewStikiNFT.deployed()
await nft.ownerOf(3);
await market.putBuyOffer(10000, 3, { from: account2, value: 10000 });
await market.putBuyOffer(20000, 3, { from: account2, value: 20000 });
await market.putBuyOffer(30000, 3, { from: account2, value: 30000 });
let listOffer = await market.viewBuyOfferForToken(3);
console.log(listOffer);
})
it("Sell with fill Buyer offer", async () => {
const market = await MarketplaceStiki.deployed()
const nft = await NewStikiNFT.deployed()
await nft.approve(market.address, 3);
await market.fillBuyerOffer(3, 2)
listOffer = await market.viewBuyOfferForToken(3);
//console.log(listOffer);
})
it("Parts widrowl Eth and Nft", async () => {
const market = await MarketplaceStiki.deployed()
const nft = await NewStikiNFT.deployed()
await market.widrowlNftBuy(3, { from: account2 });
let newOwner = await nft.ownerOf(3);
console.log(newOwner, account2)
await market.widrowProfitSell()
})
it("deactive one offer Buy", async () => {
const market = await MarketplaceStiki.deployed()
;
await market.deactiveBuyOffer(3, 1, { from: account2 })
listOffer = await market.viewBuyOfferForToken(3);
console.log(listOffer);
})
it("deactive one offer Buy already deactive", async () => {
const market = await MarketplaceStiki.deployed();
await truffleAssert.reverts(
market.deactiveBuyOffer(3, 1, { from: account2 })
)
listOffer = await market.viewBuyOfferForToken(3);
console.log(listOffer);
})
it("Sell with fill Buyer offer deactive", async () => {
const market = await MarketplaceStiki.deployed()
const stk = await stikiToken.deployed();
const contMinter = await MintContract.deployed();
const nft = await NewStikiNFT.deployed()
const usdc = await mockUsdc.deployed();
await contMinter.setAddrStikiNft(nft.address)
await usdc.approve(contMinter.address, 1000);
await contMinter.BuyStikiToken(account, 1000);
await stk.approve(contMinter.address, 100);
await contMinter.MintStiki("impostore", 11, 1, 1, 1, 1);
await market.putBuyOffer(10000, 4, { from: account2, value: 10000 });
await nft.approve(market.address, 4);
await market.deactiveBuyOffer(4, 0, { from: account2 })
await truffleAssert.reverts(
market.fillBuyerOffer(4, 0)
)
})
it("delete offer Buy", async () => {
const market = await MarketplaceStiki.deployed();
await market.deletOfferBuyer(3, 1, { from: account2 });
listOffer = await market.viewBuyOfferForToken(3);
console.log(listOffer);
})
//await truffleAssert.reverts
})