Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- pragma solidity 0.4.10;
- /// @title Abstract token contract - Functions to be implemented by token contracts.
- contract Token {
- function transfer(address to, uint256 value) returns (bool success);
- function transferFrom(address from, address to, uint256 value) returns (bool success);
- function approve(address spender, uint256 value) returns (bool success);
- // This is not an abstract function, because solc won't recognize generated getter functions for public variables as functions.
- function totalSupply() constant returns (uint256 supply) {}
- function balanceOf(address owner) constant returns (uint256 balance);
- function allowance(address owner, address spender) constant returns (uint256 remaining);
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(address indexed owner, address indexed spender, uint256 value);
- }
- /// @title Dutch auction contract - distribution of Gnosis tokens using an auction.
- /// @author Stefan George - <stefan.george@consensys.net>
- contract DutchAuction {
- /*
- * Events
- */
- event BidSubmission(address indexed sender, uint256 amount);
- /*
- * Constants
- */
- uint constant public MAX_TOKENS_SOLD = 9000000 * 10**18; // 9M
- uint constant public WAITING_PERIOD = 7 days;
- /*
- * Storage
- */
- Token public gnosisToken;
- address public wallet;
- address public owner;
- uint public ceiling;
- uint public priceFactor;
- uint public startBlock;
- uint public endTime;
- uint public totalReceived;
- uint public finalPrice;
- mapping (address => uint) public bids;
- Stages public stage;
- /*
- * Enums
- */
- enum Stages {
- AuctionDeployed,
- AuctionSetUp,
- AuctionStarted,
- AuctionEnded,
- TradingStarted
- }
- /*
- * Modifiers
- */
- modifier atStage(Stages _stage) {
- if (stage != _stage)
- // Contract not in expected state
- throw;
- _;
- }
- modifier isOwner() {
- if (msg.sender != owner)
- // Only owner is allowed to proceed
- throw;
- _;
- }
- modifier isWallet() {
- if (msg.sender != wallet)
- // Only wallet is allowed to proceed
- throw;
- _;
- }
- modifier isValidPayload() {
- if (msg.data.length != 4 && msg.data.length != 36)
- throw;
- _;
- }
- modifier timedTransitions() {
- if (stage == Stages.AuctionStarted && calcTokenPrice() <= calcStopPrice())
- finalizeAuction();
- if (stage == Stages.AuctionEnded && now > endTime + WAITING_PERIOD)
- stage = Stages.TradingStarted;
- _;
- }
- /*
- * Public functions
- */
- /// @dev Contract constructor function sets owner.
- /// @param _wallet Gnosis wallet.
- /// @param _ceiling Auction ceiling.
- /// @param _priceFactor Auction price factor.
- function DutchAuction(address _wallet, uint _ceiling, uint _priceFactor)
- public
- {
- if (_wallet == 0 || _ceiling == 0 || _priceFactor == 0)
- // Arguments are null.
- throw;
- owner = msg.sender;
- wallet = _wallet;
- ceiling = _ceiling;
- priceFactor = _priceFactor;
- stage = Stages.AuctionDeployed;
- }
- /// @dev Setup function sets external contracts' addresses.
- /// @param _gnosisToken Gnosis token address.
- function setup(address _gnosisToken)
- public
- isOwner
- atStage(Stages.AuctionDeployed)
- {
- if (_gnosisToken == 0)
- // Argument is null.
- throw;
- gnosisToken = Token(_gnosisToken);
- // Validate token balance
- if (gnosisToken.balanceOf(this) != MAX_TOKENS_SOLD)
- throw;
- stage = Stages.AuctionSetUp;
- }
- /// @dev Starts auction and sets startBlock.
- function startAuction()
- public
- isWallet
- atStage(Stages.AuctionSetUp)
- {
- stage = Stages.AuctionStarted;
- startBlock = block.number;
- }
- /// @dev Changes auction ceiling and start price factor before auction is started.
- /// @param _ceiling Updated auction ceiling.
- /// @param _priceFactor Updated start price factor.
- function changeSettings(uint _ceiling, uint _priceFactor)
- public
- isWallet
- atStage(Stages.AuctionSetUp)
- {
- ceiling = _ceiling;
- priceFactor = _priceFactor;
- }
- /// @dev Calculates current token price.
- /// @return Returns token price.
- function calcCurrentTokenPrice()
- public
- timedTransitions
- returns (uint)
- {
- if (stage == Stages.AuctionEnded || stage == Stages.TradingStarted)
- return finalPrice;
- return calcTokenPrice();
- }
- /// @dev Returns correct stage, even if a function with timedTransitions modifier has not yet been called yet.
- /// @return Returns current auction stage.
- function updateStage()
- public
- timedTransitions
- returns (Stages)
- {
- return stage;
- }
- /// @dev Allows to send a bid to the auction.
- /// @param receiver Bid will be assigned to this address if set.
- function bid(address receiver)
- public
- payable
- isValidPayload
- timedTransitions
- atStage(Stages.AuctionStarted)
- returns (uint amount)
- {
- // If a bid is done on behalf of a user via ShapeShift, the receiver address is set.
- if (receiver == 0)
- receiver = msg.sender;
- amount = msg.value;
- // Prevent that more than 90% of tokens are sold. Only relevant if cap not reached.
- uint maxWei = (MAX_TOKENS_SOLD / 10**18) * calcTokenPrice() - totalReceived;
- uint maxWeiBasedOnTotalReceived = ceiling - totalReceived;
- if (maxWeiBasedOnTotalReceived < maxWei)
- maxWei = maxWeiBasedOnTotalReceived;
- // Only invest maximum possible amount.
- if (amount > maxWei) {
- amount = maxWei;
- // Send change back to receiver address. In case of a ShapeShift bid the user receives the change back directly.
- if (!receiver.send(msg.value - amount))
- // Sending failed
- throw;
- }
- // Forward funding to ether wallet
- if (amount == 0 || !wallet.send(amount))
- // No amount sent or sending failed
- throw;
- bids[receiver] += amount;
- totalReceived += amount;
- if (maxWei == amount)
- // When maxWei is equal to the big amount the auction is ended and finalizeAuction is triggered.
- finalizeAuction();
- BidSubmission(receiver, amount);
- }
- /// @dev Claims tokens for bidder after auction.
- /// @param receiver Tokens will be assigned to this address if set.
- function claimTokens(address receiver)
- public
- isValidPayload
- timedTransitions
- atStage(Stages.TradingStarted)
- {
- if (receiver == 0)
- receiver = msg.sender;
- uint tokenCount = bids[receiver] * 10**18 / finalPrice;
- bids[receiver] = 0;
- gnosisToken.transfer(receiver, tokenCount);
- }
- /// @dev Calculates stop price.
- /// @return Returns stop price.
- function calcStopPrice()
- constant
- public
- returns (uint)
- {
- return totalReceived * 10**18 / MAX_TOKENS_SOLD + 1;
- }
- /// @dev Calculates token price.
- /// @return Returns token price.
- function calcTokenPrice()
- constant
- public
- returns (uint)
- {
- return priceFactor * 10**18 / (block.number - startBlock + 7500) + 1;
- }
- /*
- * Private functions
- */
- function finalizeAuction()
- private
- {
- stage = Stages.AuctionEnded;
- if (totalReceived == ceiling)
- finalPrice = calcTokenPrice();
- else
- finalPrice = calcStopPrice();
- uint soldTokens = totalReceived * 10**18 / finalPrice;
- // Auction contract transfers all unsold tokens to Gnosis inventory multisig
- gnosisToken.transfer(wallet, MAX_TOKENS_SOLD - soldTokens);
- endTime = now;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement