Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add external marketplace #6

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions contracts/KittyCore.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import "./utils/Ownable.sol";
import "./KittyMarketPlace.sol";
import "./KittyOwnership.sol";

pragma solidity ^0.5.0;

contract KittyCore is Ownable, KittyMarketPlace {
contract KittyCore is Ownable, KittyOwnership {

uint256 public constant CREATION_LIMIT_GEN0 = 10;

// Counts the number of cats the contract owner has created.
uint256 public gen0Counter;

constructor() public {
// We are creating the first kitty at index 0
_createKitty(0, 0, 0, uint256(-1), address(0));
// We are creating the first kitty at index 0
_createKitty(0, 0, 0, uint256(-1), address(msg.sender));
}

/*
Expand Down Expand Up @@ -46,8 +46,7 @@ contract KittyCore is Ownable, KittyMarketPlace {
function Breeding(uint256 _dadId, uint256 _mumId) public {
require(_owns(msg.sender, _dadId), "The user doesn't own the token");
require(_owns(msg.sender, _mumId), "The user doesn't own the token");

require(_mumId != _dadId), "The cat can't reproduce himself");
require(_mumId != _dadId, "The cat can't reproduce himself");

( uint256 Dadgenes,,,,uint256 DadGeneration ) = getKitty(_dadId);

Expand Down Expand Up @@ -105,8 +104,7 @@ contract KittyCore is Ownable, KittyMarketPlace {
gen0Counter++;

// Gen0 have no owners they are own by the contract
uint256 tokenId = _createKitty(0, 0, 0, _genes, msg.sender);
setOffer(0.2 ether, tokenId);
_createKitty(0, 0, 0, _genes, msg.sender);
}

function getKitty(uint256 _id)
Expand Down
168 changes: 97 additions & 71 deletions contracts/KittyMarketPlace.sol
Original file line number Diff line number Diff line change
@@ -1,86 +1,112 @@
import "./KittyOwnership.sol";

pragma solidity ^0.5.0;

contract KittyMarketPlace is KittyOwnership {

struct Offer {
address payable seller;
uint256 price;
}

Offer [] offers;

mapping (uint256 => Offer) tokenIdToOffer;

event MarketTransaction(string TxType, address owner, uint256 tokenId);

function getOffer(uint256 _tokenId)
public
view
returns
(
address seller,
uint256 price
) {
Offer storage offer = tokenIdToOffer[_tokenId];
return (
offer.seller,
offer.price
);
}

function setOffer(uint256 _price, uint256 _tokenId)
public
{
/*
* We give the contract the ability to transfer kitties
* As the kitties will be in the market place we need to be able to transfert them
* We are checking if the user is owning the kitty inside the approve function
*/
require(_price > 0.009 ether, "Cat price should be greater than 0.01");
require(tokenIdToOffer[_tokenId].price == 0, "You can't sell twice the same offers ");
import "./KittyCore.sol";
import "./utils/Ownable.sol";

/*
* Market place to trade kitties (should **in theory** be used for any ERC721 token)
* It needs an existing Kitty contract to interact with
* Note: it does not inherit from the kitty contracts
* Note: It takes ownership of the kitty for the duration that it is on the marketplace
*/
contract KittyMarketPlace is Ownable {
KittyCore public kittyContract;

struct Offer {
address payable seller;
uint256 price;
}

event OfferCreated(uint256 kittyId, uint256 price);
event OfferCancelled(uint256 kittyId);
event OfferSuccess(uint256 kittyId, uint256 price, address newOwner);

mapping(uint256 => Offer) kittyIdToOffer;

approve(address(this), _tokenId);
function setKittyContract(address _kittyContractAddress) public onlyOwner {
kittyContract = KittyCore(_kittyContractAddress);
}

tokenIdToOffer[_tokenId].seller = msg.sender;
tokenIdToOffer[_tokenId].price = _price;
emit MarketTransaction("Create offer", msg.sender, _tokenId);
}
constructor(address _kittyContractAddress) public onlyOwner {
setKittyContract(_kittyContractAddress);
}

function removeOffer(uint256 _tokenId)
public
{
require(_owns(msg.sender, _tokenId), "The user doesn't own the token");
function _ownsKitty(address _address, uint256 _kittyId)
internal
view
returns (bool)
{
return (kittyContract.ownerOf(_kittyId) == _address);
}

Offer memory offer = tokenIdToOffer[_tokenId];
require(offer.seller == msg.sender, "You should own the kitty to be able to remove this offer");
function _addOffer(uint256 _kittyId, Offer memory _offer) internal {
kittyIdToOffer[_kittyId] = _offer;

delete tokenIdToOffer[_tokenId];
_deleteApproval(_tokenId)
emit OfferCreated(_kittyId, _offer.price);
}

emit MarketTransaction("Remove offer", msg.sender, _tokenId);
}
function _cancelOffer(uint256 _kittyId, address _seller) internal {
delete kittyIdToOffer[_kittyId];
_returnKitty(_seller, _kittyId);

function buyKitty(uint256 _tokenId)
public
payable
{
Offer memory offer = tokenIdToOffer[_tokenId];
require(msg.value == offer.price, "The price is not correct");

delete tokenIdToOffer[_tokenId];
emit OfferCancelled(_kittyId);
}

/* TMP REMOVE THIS*/
_approve(_tokenId, msg.sender);
function _completeOffer(uint256 _kittyId, Offer memory offer) internal {
// Important: delete the kitty from the mapping BEFORE paying out to prevent reentry attacks
delete kittyIdToOffer[_kittyId];

// Transfer the funds to the seller
// TODO: make this logic pull instead of push?
if (offer.price > 0) {
offer.seller.transfer(offer.price);
}

transferFrom(offer.seller, msg.sender, _tokenId);
// Transfer ownership of the kitty
kittyContract.transfer(msg.sender, _kittyId);

emit OfferSuccess(_kittyId, offer.price, msg.sender);
}

offer.seller.transfer(msg.value);
emit MarketTransaction("Buy", msg.sender, _tokenId);
}

function _returnKitty(address _owner, uint256 _kittyId) internal {
kittyContract.transfer(_owner, _kittyId);
}

}
/*
* Create a new offer based for the given kittyId and price
*/
function createOffer(uint256 _kittyId, uint256 _price) public {
require(
_ownsKitty(msg.sender, _kittyId),
"You are not the owner of that kitty"
);
require(_price > 0.009 ether, "Cat price should be greater than 0.01");
require(kittyContract.getApproved(_kittyId) == address(this), "Contract needs to be approved to transfer the kitty");

Offer memory offer = Offer(msg.sender, _price);
_addOffer(_kittyId, offer);
}

/*
* Remove an existing offer
*/
function removeOffer(uint256 _kittyId) public {
Offer memory offer = kittyIdToOffer[_kittyId];
require(
offer.seller == msg.sender,
"You are not the seller of that kitty"
);

_cancelOffer(_kittyId, offer.seller);
}

/*
* Accept an offer and buy the kitty
*/
function buyKitty(uint256 _kittyId) public payable {
Offer memory offer = kittyIdToOffer[_kittyId];
require(msg.value == offer.price, "The price is incorrect");

_completeOffer(_kittyId, offer);
}
}
18 changes: 11 additions & 7 deletions contracts/KittyOwnership.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,24 @@ contract KittyOwnership is KittyFactory{
address _to,
uint256 _tokenId
)
public
external
{
require(_owns(msg.sender, _tokenId));
require(_owns(msg.sender, _tokenId), "You do not own this kitty");

_approve(_tokenId, _to);
emit Approval(msg.sender, _to, _tokenId);
}

function getApproved(uint256 _tokenId) external view returns (address) {
return kittyIndexToApproved[_tokenId];
}


function transfer(
address _to,
uint256 _tokenId
)
public
external
{
require(_to != address(0));
require(_owns(msg.sender, _tokenId));
Expand All @@ -101,11 +106,10 @@ contract KittyOwnership is KittyFactory{
address _to,
uint256 _tokenId
)
public
external
{
require(_to != address(0));
require(_approvedFor(msg.sender, _tokenId));
require(_owns(_from, _tokenId));
require(_to != address(0), "Cannot send to addresss 0");
require(_approvedFor(msg.sender, _tokenId) || _owns(_from, _tokenId), "You need to be approved or owner");

_transfer(_from, _to, _tokenId);
}
Expand Down
21 changes: 18 additions & 3 deletions migrations/2_KittyCore_migration.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
const KittyCore = artifacts.require("./KittyCore");
const KittyCore = artifacts.require("KittyCore");
const KittyMarketPlace = artifacts.require("KittyMarketPlace");

module.exports = function(deployer) {
deployer.deploy(KittyCore);
module.exports = async (deployer, network, accounts) => {
const ownerAddress = accounts[0];
const initialKittyPrice = web3.utils.toWei("0.05", "ether")

// Deploy contracts
await deployer.deploy(KittyCore, {from :ownerAddress});
await deployer.deploy(KittyMarketPlace, KittyCore.address, {from :ownerAddress});

const kittyCoreInstance = await KittyCore.deployed();
const kittyMarketPlaceInstance = await KittyMarketPlace.deployed();

// Set first initial offer in marketplace
const createdKitties = await kittyCoreInstance.tokensOfOwner(ownerAddress)
const createdKitty = createdKitties[0]
await kittyCoreInstance.approve(KittyMarketPlace.address,createdKitty)
await kittyMarketPlaceInstance.createOffer(createdKitty, initialKittyPrice, {from : ownerAddress})
};