Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| pragma solidity ^0.6.0; | |
| import "@openzeppelin/contracts/access/Ownable.sol"; | |
| import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
| import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | |
| /** | |
| * @title Classifieds | |
| * @notice Implements the classifieds board market. The market will be governed | |
| * by an ERC20 token as currency, and an ERC721 token that represents the | |
| * ownership of the items being traded. Only ads for selling items are | |
| * implemented. The item tokenization is responsibility of the ERC721 contract | |
| * which should encode any item details. | |
| */ | |
| contract Classifieds { | |
| event TradeStatusChange(uint256 ad, bytes32 status); | |
| IERC20 currencyToken; | |
| IERC721 itemToken; | |
| struct Trade { | |
| address poster; | |
| uint256 item; | |
| uint256 price; | |
| bytes32 status; // Open, Executed, Cancelled | |
| } | |
| mapping(uint256 => Trade) public trades; | |
| uint256 tradeCounter; | |
| constructor (address _currencyTokenAddress, address _itemTokenAddress) | |
| public | |
| virtual | |
| { | |
| currencyToken = IERC20(_currencyTokenAddress); | |
| itemToken = IERC721(_itemTokenAddress); | |
| tradeCounter = 0; | |
| } | |
| /** | |
| * @dev Returns the details for a trade. | |
| * @param _trade The id for the trade. | |
| */ | |
| function getTrade(uint256 _trade) | |
| public | |
| virtual | |
| view | |
| returns(address, uint256, uint256, bytes32) | |
| { | |
| Trade memory trade = trades[_trade]; | |
| return (trade.poster, trade.item, trade.price, trade.status); | |
| } | |
| /** | |
| * @dev Opens a new trade. Puts _item in escrow. | |
| * @param _item The id for the item to trade. | |
| * @param _price The amount of currency for which to trade the item. | |
| */ | |
| function openTrade(uint256 _item, uint256 _price) | |
| public | |
| virtual | |
| { | |
| itemToken.transferFrom(msg.sender, address(this), _item); | |
| trades[tradeCounter] = Trade({ | |
| poster: msg.sender, | |
| item: _item, | |
| price: _price, | |
| status: "Open" | |
| }); | |
| tradeCounter += 1; | |
| emit TradeStatusChange(tradeCounter - 1, "Open"); | |
| } | |
| /** | |
| * @dev Executes a trade. Must have approved this contract to transfer the | |
| * amount of currency specified to the poster. Transfers ownership of the | |
| * item to the filler. | |
| * @param _trade The id of an existing trade | |
| */ | |
| function executeTrade(uint256 _trade) | |
| public | |
| virtual | |
| { | |
| Trade memory trade = trades[_trade]; | |
| require(trade.status == "Open", "Trade is not Open."); | |
| currencyToken.transferFrom(msg.sender, trade.poster, trade.price); | |
| itemToken.transferFrom(address(this), msg.sender, trade.item); | |
| trades[_trade].status = "Executed"; | |
| emit TradeStatusChange(_trade, "Executed"); | |
| } | |
| /** | |
| * @dev Cancels a trade by the poster. | |
| * @param _trade The trade to be cancelled. | |
| */ | |
| function cancelTrade(uint256 _trade) | |
| public | |
| virtual | |
| { | |
| Trade memory trade = trades[_trade]; | |
| require( | |
| msg.sender == trade.poster, | |
| "Trade can be cancelled only by poster." | |
| ); | |
| require(trade.status == "Open", "Trade is not Open."); | |
| itemToken.transferFrom(address(this), trade.poster, trade.item); | |
| trades[_trade].status = "Cancelled"; | |
| emit TradeStatusChange(_trade, "Cancelled"); | |
| } | |
| } |