mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			170 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| pragma solidity ^0.4.11;
 | |
| import "../Oracles/Oracle.sol";
 | |
| import "../Events/EventFactory.sol";
 | |
| import "../Markets/MarketFactory.sol";
 | |
| 
 | |
| 
 | |
| /// @title Futarchy oracle contract - Allows to create an oracle based on market behaviour
 | |
| /// @author Stefan George - <stefan@gnosis.pm>
 | |
| contract FutarchyOracle is Oracle {
 | |
|     using Math for *;
 | |
| 
 | |
|     /*
 | |
|      *  Events
 | |
|      */
 | |
|     event FutarchyFunding(uint funding);
 | |
|     event FutarchyClosing();
 | |
|     event OutcomeAssignment(uint winningMarketIndex);
 | |
| 
 | |
|     /*
 | |
|      *  Constants
 | |
|      */
 | |
|     uint8 public constant LONG = 1;
 | |
| 
 | |
|     /*
 | |
|      *  Storage
 | |
|      */
 | |
|     address creator;
 | |
|     Market[] public markets;
 | |
|     CategoricalEvent public categoricalEvent;
 | |
|     uint public deadline;
 | |
|     uint public winningMarketIndex;
 | |
|     bool public isSet;
 | |
| 
 | |
|     /*
 | |
|      *  Modifiers
 | |
|      */
 | |
|     modifier isCreator () {
 | |
|         // Only creator is allowed to proceed
 | |
|         require(msg.sender == creator);
 | |
|         _;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      *  Public functions
 | |
|      */
 | |
|     /// @dev Constructor creates events and markets for futarchy oracle
 | |
|     /// @param _creator Oracle creator
 | |
|     /// @param eventFactory Event factory contract
 | |
|     /// @param collateralToken Tokens used as collateral in exchange for outcome tokens
 | |
|     /// @param oracle Oracle contract used to resolve the event
 | |
|     /// @param outcomeCount Number of event outcomes
 | |
|     /// @param lowerBound Lower bound for event outcome
 | |
|     /// @param upperBound Lower bound for event outcome
 | |
|     /// @param marketFactory Market factory contract
 | |
|     /// @param marketMaker Market maker contract
 | |
|     /// @param fee Market fee
 | |
|     /// @param _deadline Decision deadline
 | |
|     constructor(
 | |
|         address _creator,
 | |
|         EventFactory eventFactory,
 | |
|         Token collateralToken,
 | |
|         Oracle oracle,
 | |
|         uint8 outcomeCount,
 | |
|         int lowerBound,
 | |
|         int upperBound,
 | |
|         MarketFactory marketFactory,
 | |
|         MarketMaker marketMaker,
 | |
|         uint24 fee,
 | |
|         uint _deadline
 | |
|     )
 | |
|         public
 | |
|     {
 | |
|         // Deadline is in the future
 | |
|         require(_deadline > now);
 | |
|         // Create decision event
 | |
|         categoricalEvent = eventFactory.createCategoricalEvent(collateralToken, this, outcomeCount);
 | |
|         // Create outcome events
 | |
|         for (uint8 i = 0; i < categoricalEvent.getOutcomeCount(); i++) {
 | |
|             ScalarEvent scalarEvent = eventFactory.createScalarEvent(
 | |
|                 categoricalEvent.outcomeTokens(i),
 | |
|                 oracle,
 | |
|                 lowerBound,
 | |
|                 upperBound
 | |
|             );
 | |
|             markets.push(marketFactory.createMarket(scalarEvent, marketMaker, fee));
 | |
|         }
 | |
|         creator = _creator;
 | |
|         deadline = _deadline;
 | |
|     }
 | |
| 
 | |
|     /// @dev Funds all markets with equal amount of funding
 | |
|     /// @param funding Amount of funding
 | |
|     function fund(uint funding)
 | |
|         public
 | |
|         isCreator
 | |
|     {
 | |
|         // Buy all outcomes
 | |
|         require(   categoricalEvent.collateralToken().transferFrom(creator, address(this), funding)
 | |
|                 && categoricalEvent.collateralToken().approve(address(categoricalEvent), funding));
 | |
|         categoricalEvent.buyAllOutcomes(funding);
 | |
|         // Fund each market with outcome tokens from categorical event
 | |
|         for (uint8 i = 0; i < markets.length; i++) {
 | |
|             Market market = markets[i];
 | |
|             // Approve funding for market
 | |
|             require(market.eventContract().collateralToken().approve(address(market), funding));
 | |
|             market.fund(funding);
 | |
|         }
 | |
|         emit FutarchyFunding(funding);
 | |
|     }
 | |
| 
 | |
|     /// @dev Closes market for winning outcome and redeems winnings and sends all collateral tokens to creator
 | |
|     function close()
 | |
|         public
 | |
|         isCreator
 | |
|     {
 | |
|         // Winning outcome has to be set
 | |
|         Market market = markets[uint(getOutcome())];
 | |
|         require(categoricalEvent.isOutcomeSet() && market.eventContract().isOutcomeSet());
 | |
|         // Close market and transfer all outcome tokens from winning outcome to this contract
 | |
|         market.close();
 | |
|         market.eventContract().redeemWinnings();
 | |
|         market.withdrawFees();
 | |
|         // Redeem collateral token for winning outcome tokens and transfer collateral tokens to creator
 | |
|         categoricalEvent.redeemWinnings();
 | |
|         require(categoricalEvent.collateralToken().transfer(creator, categoricalEvent.collateralToken().balanceOf(address(this))));
 | |
|         emit FutarchyClosing();
 | |
|     }
 | |
| 
 | |
|     /// @dev Allows to set the oracle outcome based on the market with largest long position
 | |
|     function setOutcome()
 | |
|         public
 | |
|     {
 | |
|         // Outcome is not set yet and deadline has passed
 | |
|         require(!isSet && deadline <= now);
 | |
|         // Find market with highest marginal price for long outcome tokens
 | |
|         uint highestMarginalPrice = markets[0].marketMaker().calcMarginalPrice(markets[0], LONG);
 | |
|         uint highestIndex = 0;
 | |
|         for (uint8 i = 1; i < markets.length; i++) {
 | |
|             uint marginalPrice = markets[i].marketMaker().calcMarginalPrice(markets[i], LONG);
 | |
|             if (marginalPrice > highestMarginalPrice) {
 | |
|                 highestMarginalPrice = marginalPrice;
 | |
|                 highestIndex = i;
 | |
|             }
 | |
|         }
 | |
|         winningMarketIndex = highestIndex;
 | |
|         isSet = true;
 | |
|         emit OutcomeAssignment(winningMarketIndex);
 | |
|     }
 | |
| 
 | |
|     /// @dev Returns if winning outcome is set
 | |
|     /// @return Is outcome set?
 | |
|     function isOutcomeSet()
 | |
|         public
 | |
|         view
 | |
|         returns (bool)
 | |
|     {
 | |
|         return isSet;
 | |
|     }
 | |
| 
 | |
|     /// @dev Returns winning outcome
 | |
|     /// @return Outcome
 | |
|     function getOutcome()
 | |
|         public
 | |
|         view
 | |
|         returns (int)
 | |
|     {
 | |
|         return int(winningMarketIndex);
 | |
|     }
 | |
| }
 |