Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions contracts/crowdsale/ERC721/Crowdsale721.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
pragma solidity ^0.4.18;

import "../../math/SafeMath.sol";
import "../../ownership/Ownable.sol";
import "../../token/ERC721/ERC721Token.sol";
import "./Mintable721Token.sol";

/**
* @title Crowdsale721
* @dev Crowdsale721 is a base contract for managing a 721 token crowdsale.
* It is strongly based on zeppelin solidity ERC20 crowdsale contract
* Crowdsales have a start and end timestamps, where investors can make
* token purchases and the crowdsale will mint their tokens.
* Funds collected are forwarded to a wallet as they arrive.
*/
contract Crowdsale721 is MintingUtility {

using SafeMath for uint256;

// start and end timestamps where investments are allowed (both inclusive)
uint256 public startTime;
uint256 public endTime;

// address where funds are collected
address public wallet;

// dynamic price of token
uint256 public startPrice;

// amount of raised money in wei
uint256 public weiRaised;

// This token exposes minting on the 721 standard token contract
// Either be owner of the NFT contract for minting purposes,
// or share the same owner to allow minting from here
Mintable721Token public nftContract_;
uint32 public tokenBatchSize_ = 64;

/*
@dev This contract owns the token contract until the ILO is over
*/
function Crowdsale721(
uint256 _startTime,
uint256 _endTime,
uint256 _price,
address _wallet,
address _nftContract
)
public
{
require(_startTime >= now);
require(_endTime >= _startTime);

wallet = _wallet;
startTime = _startTime;
endTime = _endTime;
startPrice = _price;
nftContract_ = Mintable721Token(_nftContract);
}

event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint8 tokens);

// low level token purchase function
function buyTokens(
uint64[] _tokenIds,
address _beneficiary
)
limitBatchSize(_tokenIds)
public
payable
{
require(_beneficiary != address(0));
require(validPurchase(_tokenIds));

uint256 weiAmount = msg.value;

// update state
weiRaised = weiRaised.add(weiAmount);

TokenPurchase(msg.sender, _beneficiary, weiAmount, uint8(_tokenIds.length));

forwardFunds(); // calls up to refundable crowdsale

// mint externally on mintable crowdsale
nftContract_.mint(_beneficiary, _tokenIds);
}

// @return true if crowdsale event has ended
function hasEnded() public view returns (bool) {
return now > endTime;
}

// send ether to the fund collection wallet
// override to create custom fund forwarding mechanisms
function forwardFunds() internal {
// not actually used, this is overridden by refundable crowdsale
wallet.transfer(msg.value);
}

// @param _tokenIds - pass the tokens to price
// @return true if the transaction can buy tokens
// override to change the price/quantity rates
function validPurchase(uint64[] _tokenIds) internal view returns (bool) {
bool withinPeriod = now >= startTime && now <= endTime;
bool correctPayment = msg.value >= price(_tokenIds);
return withinPeriod && correctPayment;
}

// calculates the price for all tokens
// override to customize the pricing for tokens being minted
function price(uint64[] _tokenIds) public view returns (uint256) {
return startPrice.mul(_tokenIds.length);
}
}
101 changes: 101 additions & 0 deletions contracts/crowdsale/ERC721/Mintable721Token.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
pragma solidity ^0.4.18;

import "../../lifecycle/Pausable.sol";
import "../../token/ERC721/ERC721Token.sol";
import "../../math/SafeMath.sol";
import "./MintingUtility.sol";

contract Mintable721Token is ERC721Token, MintingUtility {
using SafeMath for uint256;

// Name and Symbol if needed
string public constant name = "Mintable721";
string public constant symbol = "M721";

/*
@dev Establishes ownership and brings token into existence AKA minting a token
@param _beneficiary - who gets the the tokens
@param _tokenIds - tokens.
*/
function mint(
address _beneficiary,
uint64[] _tokenIds
)
limitBatchSize(_tokenIds)
onlyMinter
whenNotPaused
public
{
for (uint i = 0; i < _tokenIds.length; i++) {
// This will assign ownership, and also emit the Transfer event
_mint(_beneficiary, _tokenIds[i]);
}
}

/***** TRANSFERS *****/

/*
@dev Transfer multiple tokens at once
@param _from - Who we are transferring from.
@param _to - beneficiary of token.
@param _tokenIds - tokens to transfer.
@param sender - approved for transfer of tokens
*/
function transferFromMany(
address _from,
address _to,
uint64[] _tokenIds
)
limitBatchSize(_tokenIds)
whenNotPaused
public
{
for (uint i = 0; i < _tokenIds.length; i++) {
require(isApprovedFor(msg.sender, _tokenIds[i]));
clearApprovalAndTransfer(_from, _to, _tokenIds[i]);
}
}

/***** APPROVALS *****/

/*
@dev Approves a list of tokens for transfer
@param sender - must be owner of tokens
@param _tokenIds - tokens to approve.
*/
function approveMany(
address _to,
uint64[] _tokenIds
)
limitBatchSize(_tokenIds)
whenNotPaused
public
{
for (uint i = 0; i < _tokenIds.length; i++) {
approve(_to, _tokenIds[i]);
}
}

/*
@dev Check if an owner owns all tokens
@param _owner - possible owner of tokens
@param _tokenIds - tokens to check ownership.
*/
function ownsTokens(
address _owner,
uint64[] _tokenIds
)
public
constant
limitBatchSize(_tokenIds)
returns (bool)
{
for (uint i = 0; i < _tokenIds.length; i++) {
if (ownerOf(_tokenIds[i]) != _owner) {
return false;
}
}
return true;
}

}
55 changes: 55 additions & 0 deletions contracts/crowdsale/ERC721/MintingUtility.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
pragma solidity ^0.4.18;

import "../../lifecycle/Pausable.sol";

contract MintingUtility is Pausable {
uint8 public _tokenBatchSize = 64;
mapping (address => bool) public _authorizedMinters;

function setTokenBatchSize(
uint8 _size
)
external
onlyOwner
{
_tokenBatchSize = _size;
}

/*
@dev Validates the lenght of an input tokens is not over block limit estimation
@param _tokenIds - tokens.
*/
modifier limitBatchSize(
uint64[] _tokenIds
) {
require(_tokenIds.length <= _tokenBatchSize);
_;
}

/*
@dev Will add a contract or address that can call minting function on
token contract
@param _authorized address of minter to add
@param _isAuthorized set authorized or not
*/
function setAuthorizedMinter(
address _authorized,
bool _isAuthorized
)
external
onlyOwner
{
_authorizedMinters[_authorized] = _isAuthorized;
}

/*
Only minter contracts can access via this modifier
Also, a minter either owns this contract or is in authorized list
*/
modifier onlyMinter()
{
bool isAuthorized = _authorizedMinters[msg.sender];
require(isAuthorized || msg.sender == owner);
_;
}
}
Loading