mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			195 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| pragma solidity >=0.0;
 | |
| import "../Markets/Market.sol";
 | |
| import "../Tokens/Token.sol";
 | |
| import "../Events/Event.sol";
 | |
| import "../MarketMakers/MarketMaker.sol";
 | |
| 
 | |
| 
 | |
| /// @title Market factory contract - Allows to create market contracts
 | |
| /// @author Stefan George - <stefan@gnosis.pm>
 | |
| contract StandardMarket is Market {
 | |
|     using Math for *;
 | |
| 
 | |
|     /*
 | |
|      *  Constants
 | |
|      */
 | |
|     uint24 public constant FEE_RANGE = 1000000; // 100%
 | |
| 
 | |
|     /*
 | |
|      *  Modifiers
 | |
|      */
 | |
|     modifier isCreator () {
 | |
|         // Only creator is allowed to proceed
 | |
|         require(msg.sender == creator);
 | |
|         _;
 | |
|     }
 | |
| 
 | |
|     modifier atStage(Stages _stage) {
 | |
|         // Contract has to be in given stage
 | |
|         require(stage == _stage);
 | |
|         _;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      *  Public functions
 | |
|      */
 | |
|     /// @dev Constructor validates and sets market properties
 | |
|     /// @param _creator Market creator
 | |
|     /// @param _eventContract Event contract
 | |
|     /// @param _marketMaker Market maker contract
 | |
|     /// @param _fee Market fee
 | |
|     constructor(address _creator, Event _eventContract, MarketMaker _marketMaker, uint24 _fee)
 | |
|         public
 | |
|     {
 | |
|         // Validate inputs
 | |
|         require(address(_eventContract) != address(0) && address(_marketMaker) != address(0) && _fee < FEE_RANGE);
 | |
|         creator = _creator;
 | |
|         createdAtBlock = block.number;
 | |
|         eventContract = _eventContract;
 | |
|         netOutcomeTokensSold = new int[](eventContract.getOutcomeCount());
 | |
|         fee = _fee;
 | |
|         marketMaker = _marketMaker;
 | |
|         stage = Stages.MarketCreated;
 | |
|     }
 | |
| 
 | |
|     /// @dev Allows to fund the market with collateral tokens converting them into outcome tokens
 | |
|     /// @param _funding Funding amount
 | |
|     function fund(uint _funding)
 | |
|         public
 | |
|         isCreator
 | |
|         atStage(Stages.MarketCreated)
 | |
|     {
 | |
|         // Request collateral tokens and allow event contract to transfer them to buy all outcomes
 | |
|         require(   eventContract.collateralToken().transferFrom(msg.sender, address(this), _funding)
 | |
|                 && eventContract.collateralToken().approve(address(eventContract), _funding));
 | |
|         eventContract.buyAllOutcomes(_funding);
 | |
|         funding = _funding;
 | |
|         stage = Stages.MarketFunded;
 | |
|         emit MarketFunding(funding);
 | |
|     }
 | |
| 
 | |
|     /// @dev Allows market creator to close the markets by transferring all remaining outcome tokens to the creator
 | |
|     function close()
 | |
|         public
 | |
|         isCreator
 | |
|         atStage(Stages.MarketFunded)
 | |
|     {
 | |
|         uint8 outcomeCount = eventContract.getOutcomeCount();
 | |
|         for (uint8 i = 0; i < outcomeCount; i++)
 | |
|             require(eventContract.outcomeTokens(i).transfer(creator, eventContract.outcomeTokens(i).balanceOf(address(this))));
 | |
|         stage = Stages.MarketClosed;
 | |
|         emit MarketClosing();
 | |
|     }
 | |
| 
 | |
|     /// @dev Allows market creator to withdraw fees generated by trades
 | |
|     /// @return Fee amount
 | |
|     function withdrawFees()
 | |
|         public
 | |
|         isCreator
 | |
|         returns (uint fees)
 | |
|     {
 | |
|         fees = eventContract.collateralToken().balanceOf(address(this));
 | |
|         // Transfer fees
 | |
|         require(eventContract.collateralToken().transfer(creator, fees));
 | |
|         emit FeeWithdrawal(fees);
 | |
|     }
 | |
| 
 | |
|     /// @dev Allows to buy outcome tokens from market maker
 | |
|     /// @param outcomeTokenIndex Index of the outcome token to buy
 | |
|     /// @param outcomeTokenCount Amount of outcome tokens to buy
 | |
|     /// @param maxCost The maximum cost in collateral tokens to pay for outcome tokens
 | |
|     /// @return Cost in collateral tokens
 | |
|     function buy(uint8 outcomeTokenIndex, uint outcomeTokenCount, uint maxCost)
 | |
|         public
 | |
|         atStage(Stages.MarketFunded)
 | |
|         returns (uint cost)
 | |
|     {
 | |
|         // Calculate cost to buy outcome tokens
 | |
|         uint outcomeTokenCost = marketMaker.calcCost(this, outcomeTokenIndex, outcomeTokenCount);
 | |
|         // Calculate fees charged by market
 | |
|         uint fees = calcMarketFee(outcomeTokenCost);
 | |
|         cost = outcomeTokenCost.add(fees);
 | |
|         // Check cost doesn't exceed max cost
 | |
|         require(cost > 0 && cost <= maxCost);
 | |
|         // Transfer tokens to markets contract and buy all outcomes
 | |
|         require(   eventContract.collateralToken().transferFrom(msg.sender, address(this), cost)
 | |
|                 && eventContract.collateralToken().approve(address(eventContract), outcomeTokenCost));
 | |
|         // Buy all outcomes
 | |
|         eventContract.buyAllOutcomes(outcomeTokenCost);
 | |
|         // Transfer outcome tokens to buyer
 | |
|         require(eventContract.outcomeTokens(outcomeTokenIndex).transfer(msg.sender, outcomeTokenCount));
 | |
|         // Add outcome token count to market maker net balance
 | |
|         require(int(outcomeTokenCount) >= 0);
 | |
|         netOutcomeTokensSold[outcomeTokenIndex] = netOutcomeTokensSold[outcomeTokenIndex].add(int(outcomeTokenCount));
 | |
|         emit OutcomeTokenPurchase(msg.sender, outcomeTokenIndex, outcomeTokenCount, cost);
 | |
|     }
 | |
| 
 | |
|     /// @dev Allows to sell outcome tokens to market maker
 | |
|     /// @param outcomeTokenIndex Index of the outcome token to sell
 | |
|     /// @param outcomeTokenCount Amount of outcome tokens to sell
 | |
|     /// @param minProfit The minimum profit in collateral tokens to earn for outcome tokens
 | |
|     /// @return Profit in collateral tokens
 | |
|     function sell(uint8 outcomeTokenIndex, uint outcomeTokenCount, uint minProfit)
 | |
|         public
 | |
|         atStage(Stages.MarketFunded)
 | |
|         returns (uint profit)
 | |
|     {
 | |
|         // Calculate profit for selling outcome tokens
 | |
|         uint outcomeTokenProfit = marketMaker.calcProfit(this, outcomeTokenIndex, outcomeTokenCount);
 | |
|         // Calculate fee charged by market
 | |
|         uint fees = calcMarketFee(outcomeTokenProfit);
 | |
|         profit = outcomeTokenProfit.sub(fees);
 | |
|         // Check profit is not too low
 | |
|         require(profit > 0 && profit >= minProfit);
 | |
|         // Transfer outcome tokens to markets contract to sell all outcomes
 | |
|         require(eventContract.outcomeTokens(outcomeTokenIndex).transferFrom(msg.sender, address(this), outcomeTokenCount));
 | |
|         // Sell all outcomes
 | |
|         eventContract.sellAllOutcomes(outcomeTokenProfit);
 | |
|         // Transfer profit to seller
 | |
|         require(eventContract.collateralToken().transfer(msg.sender, profit));
 | |
|         // Subtract outcome token count from market maker net balance
 | |
|         require(int(outcomeTokenCount) >= 0);
 | |
|         netOutcomeTokensSold[outcomeTokenIndex] = netOutcomeTokensSold[outcomeTokenIndex].sub(int(outcomeTokenCount));
 | |
|         emit OutcomeTokenSale(msg.sender, outcomeTokenIndex, outcomeTokenCount, profit);
 | |
|     }
 | |
| 
 | |
|     /// @dev Buys all outcomes, then sells all shares of selected outcome which were bought, keeping
 | |
|     ///      shares of all other outcome tokens.
 | |
|     /// @param outcomeTokenIndex Index of the outcome token to short sell
 | |
|     /// @param outcomeTokenCount Amount of outcome tokens to short sell
 | |
|     /// @param minProfit The minimum profit in collateral tokens to earn for short sold outcome tokens
 | |
|     /// @return Cost to short sell outcome in collateral tokens
 | |
|     function shortSell(uint8 outcomeTokenIndex, uint outcomeTokenCount, uint minProfit)
 | |
|         public
 | |
|         returns (uint cost)
 | |
|     {
 | |
|         // Buy all outcomes
 | |
|         require(   eventContract.collateralToken().transferFrom(msg.sender, address(this), outcomeTokenCount)
 | |
|                 && eventContract.collateralToken().approve(address(eventContract), outcomeTokenCount));
 | |
|         eventContract.buyAllOutcomes(outcomeTokenCount);
 | |
|         // Short sell selected outcome
 | |
|         eventContract.outcomeTokens(outcomeTokenIndex).approve(address(this), outcomeTokenCount);
 | |
|         uint profit = this.sell(outcomeTokenIndex, outcomeTokenCount, minProfit);
 | |
|         cost = outcomeTokenCount - profit;
 | |
|         // Transfer outcome tokens to buyer
 | |
|         uint8 outcomeCount = eventContract.getOutcomeCount();
 | |
|         for (uint8 i = 0; i < outcomeCount; i++)
 | |
|             if (i != outcomeTokenIndex)
 | |
|                 require(eventContract.outcomeTokens(i).transfer(msg.sender, outcomeTokenCount));
 | |
|         // Send change back to buyer
 | |
|         require(eventContract.collateralToken().transfer(msg.sender, profit));
 | |
|         emit OutcomeTokenShortSale(msg.sender, outcomeTokenIndex, outcomeTokenCount, cost);
 | |
|     }
 | |
| 
 | |
|     /// @dev Calculates fee to be paid to market maker
 | |
|     /// @param outcomeTokenCost Cost for buying outcome tokens
 | |
|     /// @return Fee for trade
 | |
|     function calcMarketFee(uint outcomeTokenCost)
 | |
|         public
 | |
|         view
 | |
|         returns (uint)
 | |
|     {
 | |
|         return outcomeTokenCost * fee / FEE_RANGE;
 | |
|     }
 | |
| }
 |