Created
June 20, 2017 20:24
-
-
Save Arachnid/b9886ef91d5b47c31d2e3c8022eeea27 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
import "SafeMath.sol"; | |
import "IERC20Token.sol"; | |
/** | |
* @dev Implements a capped token sale using a second-price auction. | |
* | |
* @author Nick Johnson <[email protected]> | |
* | |
* WARNING WARNING WARNING | |
* This contract code is intended as a proof-of-concept demonstration. No | |
* testing has been performed other than verifying that it compiles. DO NOT under | |
* any circumstances use this in its current state for any reason. | |
* WARNING WARNING WARNING | |
* | |
* Users can deposits funds for the auction any time before endTimestamp. After | |
* doing so, they send a signed message to the party running the auction with a bid. | |
* Bids are `(price, quantity)` tuples, where `price` is the maximum amount of | |
* ether a user is willing to pay per token, and `quantity` is the number of | |
* tokens the user wants to buy. | |
* | |
* At the end of the bidding period, the seller sets a 'strike price'. All bids | |
* with a price at least as high as the strike price are filled, and all bids | |
* under this strike price are returned. The strike price is calculated | |
* offchain by the seller. Once set, anyone - bidder, seller, or third party - | |
* can submit the signed bid to the contract, which will issue tokens to winning | |
* bidders. | |
* | |
* A hard cap on the amount of ether raised is specified at the time the | |
* contract is deployed, with extra funds being returned to users. | |
* | |
* A week after the end of the contract, users can unilaterally withdraw any | |
* remaining funds. | |
*/ | |
contract TokenSale is SafeMath { | |
event Deposit(address indexed bidder, uint price); | |
event StrikePriceSet(uint strikePrice); | |
mapping(address=>uint) public deposits; | |
uint public depositCount; // Count of bids | |
address public owner; | |
IERC20Token token; | |
uint public salesTarget; // Total number of ether to be raised | |
uint public strikePrice; // Price at which tokens are sold, set after sale completes | |
uint public strikePricePct; // Percentage of total qty to sell to bidders who bid exactly the strike price | |
uint public endTimestamp; // Time at which sale ends | |
modifier beforeSale { | |
require(now <= endTimestamp); | |
_; | |
} | |
modifier afterSale { | |
require(endTimestamp <= now && strikePrice != 0); | |
_; | |
} | |
modifier afterTimeout { | |
require(endTimestamp + 1 weeks <= now); | |
_; | |
} | |
modifier ownerOnly { | |
require(msg.sender == owner); | |
_; | |
} | |
function TokenSale(IERC20Token _token, uint _salesTarget, uint _startTimestamp, uint _endTimestamp) { | |
token = _token; | |
owner = msg.sender; | |
salesTarget = _salesTarget; | |
endTimestamp = _endTimestamp; | |
} | |
function deposit() beforeSale payable { | |
deposits[msg.sender] += msg.value; | |
depositCount += 1; | |
Deposit(msg.sender, msg.value); | |
} | |
function() payable { | |
deposit(); | |
} | |
function setStrikePrice(uint128 price, uint pct) ownerOnly { | |
require(endTimestamp <= now && strikePrice == 0 && price != 0); | |
strikePrice = price; | |
strikePricePct == pct; | |
StrikePriceSet(price); | |
} | |
function acceptBid(uint price, uint quantity, uint8 v, bytes32 r, bytes32 s) afterSale { | |
var tokensLeft = token.balanceOf(this); | |
var bidHash = sha3(address(this), price, quantity); | |
var bidder = ecrecover(bidHash, v, r, s); | |
var total = safeMul(price, quantity); | |
require(total <= deposits[bidder]); | |
uint filledQuantity = quantity; | |
// If the user bid under the strike price, they get no tokens | |
if(price < strikePrice) { | |
filledQuantity = 0; | |
} else if(price == strikePrice) { | |
// For bidders at exactly the strike price, part-fill their bids | |
filledQuantity = (filledQuantity * strikePricePct) / 100; | |
} | |
// If there's not enough tokens left, they get the remaining tokens | |
if(tokensLeft < filledQuantity) { | |
filledQuantity = tokensLeft; | |
} | |
// If there's not enough funds left under the cap, sell them the remainder | |
var filledTotal = safeMul(strikePrice, filledQuantity); | |
if(filledTotal > salesTarget) { | |
filledQuantity = salesTarget / strikePrice; | |
filledTotal = safeMul(strikePrice, filledQuantity); | |
} | |
if(filledTotal > 0) { | |
// Sell the user the tokens | |
owner.transfer(filledTotal); | |
salesTarget -= filledTotal; | |
tokensLeft -= filledQuantity; | |
} | |
if(deposits[bidder] > filledTotal) { | |
// Send back any extra funds | |
bidder.transfer(deposits[bidder] - filledTotal); | |
deposits[bidder] = 0; | |
} | |
depositCount -= 1; | |
token.transfer(bidder, filledQuantity); | |
} | |
function withdrawTokens() afterTimeout { | |
var total = deposits[msg.sender]; | |
deposits[msg.sender] = 0; | |
msg.sender.transfer(total); | |
} | |
} |
Wouldn't it make sense to check that pct is !=0 in function setStrikePrice? Assuming that bidders who bid exactly the strike price get something?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
At L90, I believe you want to change == to =