Merge pull request #1 from rstormsf/removeWhitelist

remove whitelist, add minimum amount
This commit is contained in:
Roman Storm 2017-11-10 15:42:14 -05:00 committed by GitHub
commit b2b099d75d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 250 additions and 277 deletions

126
README.md
View File

@ -3,6 +3,8 @@
[![Coverage Status](https://coveralls.io/repos/github/rstormsf/oracles-presale/badge.svg?branch=master)](https://coveralls.io/github/rstormsf/oracles-presale?branch=master)
[Full Test Report](https://rstormsf.github.io/oracles-presale/mochawesome.html)
Presale contract that records investor's balances and sends ether to presale owner.
It allows to set minimum Contrubution amount, start Date, end Date.
To use:
1. Flat [contracts/PresaleOracles.sol](contracts/PresaleOracles.sol) by using [oracles-combine-solidity](github.com/oraclesorg/oracles-combine-solidity/commits/master)
@ -15,74 +17,100 @@ To use:
-cap in wei format
-minimumContribution in wei format
-vault (eth address where funds will be collected)
Example:
"1510291574","1610291574","100000000000000000000","0x0039f22efb07a647557c7c5d17854cfd6d489ef3"
"1510291574","1610291574","100000000000000000000","100000000000000000","0x0039f22efb07a647557c7c5d17854cfd6d489ef3"
startTime: `Friday, November 10, 2017 5:26:14 AM `
endTime: `Sunday, January 10, 2021 3:12:54 PM `
cap: `100 eth `
minimum: `0.1 eth `
vault: `0x0039f22efb07a647557c7c5d17854cfd6d489ef3`
4. Whitelist investors by calling `whitelistInvestors` with array of addresses. Example:
["0x62D9FB3358B4b83dB0280Eacc6a0fA5C6dDc7B4d","0xc15Ac3555FD6d6b569B9762D5289A3cc31325B1b"]
5. Let whitelisted investors send money to contract's address
4. Let investors send money to contract's address OR to send to `buy` method (`0xa6f2ae3a`)
```
·------------------------------------------------------------------------|-----------------------------------·
│ Gas · Block limit: 17592186044415 gas │
··········································|······························|····································
│ Methods · 1 gwei/gas · 320.09 usd/eth │
···················|······················|·········|··········|·········|················|···················
│ Contract · Method · Min · Max · Avg · # calls · usd (avg) │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · blacklistInvestor · 19691 · 23538 · 21615 · 2 · 0.01 │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · buy · - · - · - · 0 · - │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · claimTokens · - · - · - · 0 · - │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · initialize · 23128 · 125421 · 46650 · 9 · 0.01 │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · Presale · - · - · - · 0 · - │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · transferOwnership · - · - · - · 0 · - │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · whitelistInvestor · 23428 · 64377 · 57552 · 6 · 0.02 │
···················|······················|·········|··········|·········|················|···················
│ PresaleOracles · whitelistInvestors · 23688 · 119866 · 87807 · 3 · 0.03 │
·------------------|----------------------|---------|----------|---------|----------------|------------------·
Contract: Presale
✓ constructor should set owner
✓ can not buy if not initialized (22623 gas)
#initilize
✓ rejects if not sent by owner (25358 gas)
✓ sets values (131519 gas)
✓ cannot initialize twice (157189 gas)
✓ startTime cannot be 0 (25102 gas)
✓ endTime cannot be 0 (25166 gas)
✓ endTime cannot be less than startTime (25358 gas)
✓ cap cannot be 0 (24910 gas)
✓ vault cannot be 0x0 (24078 gas)
✓ minimumContribution cannot be 0 (24910 gas)
#buy
✓ cannot buy if not value is 0 (64231 gas)
✓ cannot buy if not value is less than minimum (64231 gas)
✓ can not buy if time is not within startTime&endTime (116233 gas)
✓ can not buy more than cap (64236 gas)
✓ happy path (178974 gas)
22 passing (3m)
```
·-----------------------------------------------------------------------|-----------------------------------·
│ Gas · Block limit: 17592186044415 gas │
·········································|······························|····································
│ Methods · 1 gwei/gas · 297.51 usd/eth │
···················|·····················|·········|··········|·········|················|···················
│ Contract · Method · Min · Max · Avg · # calls · usd (avg) │
···················|·····················|·········|··········|·········|················|···················
│ PresaleOracles · buy · - · - · - · 0 · - │
···················|·····················|·········|··········|·········|················|···················
│ PresaleOracles · claimTokens · - · - · - · 0 · - │
···················|·····················|·········|··········|·········|················|···················
│ PresaleOracles · initialize · 24078 · 131519 · 46359 · 10 · 0.01 │
···················|·····················|·········|··········|·········|················|···················
│ PresaleOracles · Presale · - · - · - · 0 · - │
···················|·····················|·········|··········|·········|················|···················
│ PresaleOracles · transferOwnership · - · - · - · 0 · - │
·------------------|---------------------|---------|----------|---------|----------------|------------------·
16 passing (2m)
```
# Testnet deployment
Contract Deployment: https://kovan.etherscan.io/address/0x19001af36808e4c573a237bfc58ce282616f05b3#code
Contract Deployment: https://kovan.etherscan.io/address/0xb9b49e21e77d2d89a9e4c7ef4f684ad2a4e99663#code
Called Initialize by Owner with params: "1510291574","1610291574","100000000000000000000","0x0039f22efb07a647557c7c5d17854cfd6d489ef3"
https://kovan.etherscan.io/tx/0xd83f75af7f8ebb02c6f79cd8a6e57ce619311b65f41ec618936558de3c116af9
Called Initialize by Owner with params:
"1510291574","1610291574","40000000000000000000000","1000000000000000000","0x0039f22efb07a647557c7c5d17854cfd6d489ef3"
(40000 eth cap, 1 eth minimum)
https://kovan.etherscan.io/tx/0xc95047493d8eead08c3bef52c54cc2ffcbd2e0ef89c1ba1a719d28bd98011c84
Called whitelist with params: 0x0039f22efb07a647557c7c5d17854cfd6d489ef3
https://kovan.etherscan.io/tx/0x9781564e4365a35fc64694a777268de04bd21066126f6341f7eb3678fb820889
Called fallback with 0.5 ether: (expected error)
https://kovan.etherscan.io/tx/0x6f7335f55257a56f9382d47dfeacf26e482f3c6238e829dfbc5e143d6972f0e0
Called fallback with 0 ether: (expected error)
https://kovan.etherscan.io/tx/0x84abaa77a9f8b42799c00348a4d439db0af9b67ab45d252e7885b768e7ca9930
Called buy(`0xa6f2ae3a`) with 1 ether:
https://kovan.etherscan.io/tx/0xdbf29ed04dcb1a71e90f3a404739b6e3bb2c526b7788547ad9dc66e5eb64c79f
Verified forwarded funds as internal transaction.
Called fallback with 0.03 ether:
https://kovan.etherscan.io/tx/0xdc32fa666a60fe8aa590d8fc7538b9e70852a2ae62750b7c0687d46e263d18ac
Verified forwarded funds as internal transaction:
https://kovan.etherscan.io/address/0x19001af36808e4c573a237bfc58ce282616f05b3#internaltx
Called fallback with 0.1 ether to add to already contributer 1 eth from the same address:
https://kovan.etherscan.io/tx/0x76b38e3211ad5ce465edce69faf0d69837b924e47f705ec16cf4e30fc163781e
Called blacklist by owner with params: 0x0039f22efb07a647557c7c5d17854cfd6d489ef3
https://kovan.etherscan.io/tx/0xe17dfeabd9bc2f7adc28ec3b83c4bf011e1864066c02ef689cbcbee4d9aeef51
Cap tests:
Deployed contract: https://kovan.etherscan.io/address/0x9acf295c782e14ac86b87a3545e444256a3a7e56#readContract
"1510291574","1610291574","500000000000000000","100000000000000000","0x0039f22efb07a647557c7c5d17854cfd6d489ef3"
(cap 0.5 eth, min 0.1 eth)
Called fallback by non-whitelisted investor (expected an error) with 0.3 ether:
https://kovan.etherscan.io/tx/0x391c1e4d838876e38e4631279a3c9856cc08e5ecedd2a4d0fae6990e127af432
Send 1 eth over cap(expected error):
https://kovan.etherscan.io/tx/0xb0c4a7f64bd392fae8b174a1304d91691c1cb3acdec0d290fd3a734a725cbcaa
Send 0.5 to match cap:
https://kovan.etherscan.io/tx/0x5709e2ca2b4406a89c4ecedc2f1913b7ce9cdef66670b694851650a4fe037ae2
Send additional 0.00001 to over cap(expected error):
https://kovan.etherscan.io/tx/0x826229102f3a235c21173295434507a9664ad3f822edc1b9af488bdc3f01e32d
Time tests:
Send after sale ends(expected error):
"1507667268","1507753668","500000000000000000","100000000000000000","0x0039f22efb07a647557c7c5d17854cfd6d489ef3"
https://kovan.etherscan.io/address/0xec1afb89f87cb0ac296cad6e73dbeeab5b006050#readContract
Send 0.1 ether to get rejected:
https://kovan.etherscan.io/tx/0xd859be5b5b58303a4cbc61902f8927efa9de96a3739ce39a18e1f6949a154c2b
Called whitelistInvestors with params: [
"0x62D9FB3358B4b83dB0280Eacc6a0fA5C6dDc7B4d","0xc15Ac3555FD6d6b569B9762D5289A3cc31325B1b"
]
https://kovan.etherscan.io/tx/0x048978a970e317e0117a5e342c875032a044ce65f8c1f35a3e18f7b4e29f25de

View File

@ -1,4 +1,3 @@
// Build and Tested by Roman Storm rstormsf@gmail.com
import "zeppelin-solidity/contracts/math/SafeMath.sol";
import "zeppelin-solidity/contracts/token/BasicToken.sol";
import "zeppelin-solidity/contracts/ownership/Ownable.sol";
@ -6,16 +5,22 @@ import "zeppelin-solidity/contracts/ownership/Ownable.sol";
pragma solidity ^0.4.17;
contract PresaleOracles is Ownable {
/*
* PresaleOracles
* Simple Presale contract
* built by github.com/rstormsf Roman Storm
*/
using SafeMath for uint256;
uint256 public startTime;
uint256 public endTime;
uint256 public cap;
uint256 public rate;
bool public isInitialized = false;
uint256 public totalInvestedInWei;
mapping(address => uint256) public investorBalances;
mapping(address => bool) public whitelist;
uint256 public investorsLength;
uint256 public minimumContribution;
mapping(address => uint256) public investorBalances;
address public vault;
bool public isInitialized = false;
// TESTED by Roman Storm
function () public payable {
buy();
@ -24,26 +29,27 @@ contract PresaleOracles is Ownable {
function Presale() public {
}
//TESTED by Roman Storm
function initialize(uint256 _startTime, uint256 _endTime, uint256 _cap, address _vault) public onlyOwner {
function initialize(uint256 _startTime, uint256 _endTime, uint256 _cap, uint256 _minimumContribution, address _vault) public onlyOwner {
require(!isInitialized);
require(_startTime != 0);
require(_endTime != 0);
require(_endTime > _startTime);
require(_cap != 0);
require(_minimumContribution != 0);
require(_vault != 0x0);
require(_cap > _minimumContribution);
startTime = _startTime;
endTime = _endTime;
cap = _cap;
isInitialized = true;
minimumContribution =_minimumContribution;
vault = _vault;
}
//TESTED by Roman Storm
function buy() public payable {
require(whitelist[msg.sender]);
require(msg.value > 0);
require(isValidPurchase(msg.value));
require(isInitialized);
require(getTime() >= startTime && getTime() <= endTime);
require(totalInvestedInWei + msg.value <= cap);
address investor = msg.sender;
investorBalances[investor] += msg.value;
totalInvestedInWei += msg.value;
@ -54,7 +60,7 @@ contract PresaleOracles is Ownable {
function forwardFunds(uint256 _amount) internal {
vault.transfer(_amount);
}
//TESTED by Roman Storm
function claimTokens(address _token) public onlyOwner {
if (_token == 0x0) {
owner.transfer(this.balance);
@ -66,32 +72,14 @@ contract PresaleOracles is Ownable {
token.transfer(owner, balance);
}
function whitelistInvestor(address _newInvestor) public onlyOwner {
if(!whitelist[_newInvestor]) {
whitelist[_newInvestor] = true;
investorsLength++;
}
}
function whitelistInvestors(address[] _investors) external onlyOwner {
require(_investors.length <= 250);
for(uint8 i=0; i<_investors.length;i++) {
address newInvestor = _investors[i];
if(!whitelist[newInvestor]) {
whitelist[newInvestor] = true;
investorsLength++;
}
}
}
function blacklistInvestor(address _investor) public onlyOwner {
if(whitelist[_investor]) {
delete whitelist[_investor];
if(investorsLength != 0) {
investorsLength--;
}
}
}
function getTime() internal view returns(uint256) {
return now;
}
//TESTED by Roman Storm
function isValidPurchase(uint256 _amount) public view returns(bool) {
bool nonZero = _amount > 0;
bool hasMinimumAmount = investorBalances[msg.sender].add(_amount) >= minimumContribution;
bool withinCap = totalInvestedInWei.add(_amount) <= cap;
return hasMinimumAmount && withinCap && nonZero;
}
}

View File

@ -1,87 +1,123 @@
pragma solidity ^0.4.18;
/*
* ERC20Basic
* Simpler version of ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20Basic {
uint public totalSupply;
function balanceOf(address who) constant returns (uint);
function transfer(address to, uint value);
event Transfer(address indexed from, address indexed to, uint value);
}
/**
* Math operations with safety checks
*/
contract SafeMath {
function safeMul(uint a, uint b) internal returns (uint) {
uint c = a * b;
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeSub(uint a, uint b) internal returns (uint) {
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint a, uint b) internal returns (uint) {
uint c = a + b;
assert(c>=a && c>=b);
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
function assert(bool assertion) internal {
if (!assertion) throw;
}
}
// Build and Tested by Roman Storm rstormsf@gmail.com
/*
* Basic token
* Basic version of StandardToken, with no allowances
*/
contract BasicToken is ERC20Basic, SafeMath {
mapping(address => uint) balances;
function transfer(address _to, uint _value) {
if (balances[msg.sender] < _value) {
throw;
}
balances[msg.sender] = safeSub(balances[msg.sender], _value);
balances[_to] = safeAdd(balances[_to], _value);
Transfer(msg.sender, _to, _value);
}
function balanceOf(address _owner) constant returns (uint balance) {
return balances[_owner];
}
}
/*
* Ownable
*
* Base contract with an owner.
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() {
owner = msg.sender;
}
modifier onlyOwner() {
if (msg.sender == owner)
_;
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transfer(address newOwner) onlyOwner {
if (newOwner != address(0)) owner = newOwner;
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner public {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract ERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) public constant returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public constant returns (uint256 balance) {
return balances[_owner];
}
}
contract PresaleOracles is Ownable {
/*
* PresaleOracles
* Simple Presale contract
* built by github.com/rstormsf Roman Storm
*/
using SafeMath for uint256;
uint256 public startTime;
uint256 public endTime;
uint256 public cap;
uint256 public rate;
bool public isInitialized = false;
uint256 public totalInvestedInWei;
mapping(address => uint256) public investorBalances;
mapping(address => bool) public whitelist;
uint256 public investorsLength;
uint256 public minimumContribution;
mapping(address => uint256) public investorBalances;
address public vault;
bool public isInitialized = false;
// TESTED by Roman Storm
function () public payable {
buy();
@ -90,26 +126,27 @@ contract PresaleOracles is Ownable {
function Presale() public {
}
//TESTED by Roman Storm
function initialize(uint256 _startTime, uint256 _endTime, uint256 _cap, address _vault) public onlyOwner {
function initialize(uint256 _startTime, uint256 _endTime, uint256 _cap, uint256 _minimumContribution, address _vault) public onlyOwner {
require(!isInitialized);
require(_startTime != 0);
require(_endTime != 0);
require(_endTime > _startTime);
require(_cap != 0);
require(_minimumContribution != 0);
require(_vault != 0x0);
require(_cap > _minimumContribution);
startTime = _startTime;
endTime = _endTime;
cap = _cap;
isInitialized = true;
minimumContribution =_minimumContribution;
vault = _vault;
}
//TESTED by Roman Storm
function buy() public payable {
require(whitelist[msg.sender]);
require(msg.value > 0);
require(isValidPurchase(msg.value));
require(isInitialized);
require(getTime() >= startTime && getTime() <= endTime);
require(totalInvestedInWei + msg.value <= cap);
address investor = msg.sender;
investorBalances[investor] += msg.value;
totalInvestedInWei += msg.value;
@ -120,7 +157,7 @@ contract PresaleOracles is Ownable {
function forwardFunds(uint256 _amount) internal {
vault.transfer(_amount);
}
//TESTED by Roman Storm
function claimTokens(address _token) public onlyOwner {
if (_token == 0x0) {
owner.transfer(this.balance);
@ -131,31 +168,16 @@ contract PresaleOracles is Ownable {
uint256 balance = token.balanceOf(this);
token.transfer(owner, balance);
}
function whitelistInvestor(address _newInvestor) public onlyOwner {
if(!whitelist[_newInvestor]) {
whitelist[_newInvestor] = true;
investorsLength++;
}
}
function whitelistInvestors(address[] _investors) external onlyOwner {
require(_investors.length <= 250);
for(uint8 i=0; i<_investors.length;i++) {
address newInvestor = _investors[i];
if(!whitelist[newInvestor]) {
whitelist[newInvestor] = true;
investorsLength++;
}
}
}
function blacklistInvestor(address _investor) public onlyOwner {
if(whitelist[_investor]) {
delete whitelist[_investor];
if(investorsLength != 0) {
investorsLength--;
}
}
}
function getTime() internal view returns(uint256) {
return now;
}
}
//TESTED by Roman Storm
function isValidPurchase(uint256 _amount) public view returns(bool) {
bool nonZero = _amount > 0;
bool hasMinimumAmount = investorBalances[msg.sender].add(_amount) >= minimumContribution;
bool withinCap = totalInvestedInWei.add(_amount) <= cap;
return hasMinimumAmount && withinCap && nonZero;
}
}

View File

@ -42,11 +42,11 @@ contract('Presale', function(accounts) {
PRESALE_END_DATE = moment('2017-12-18T16:00:00Z').unix();
})
it('rejects if not sent by owner', async () => {
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER, accounts[1], {from: accounts[1]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('sets values', async () => {
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER, accounts[1], {from: accounts[0]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[0]})
true.should.be.equal(
await presaleContract.isInitialized()
)
@ -56,42 +56,51 @@ contract('Presale', function(accounts) {
PRESALE_END_DATE.should.be.bignumber.equal(
await presaleContract.endTime()
)
ETHER.should.be.bignumber.equal(
ETHER.mul(40000).should.be.bignumber.equal(
await presaleContract.cap()
)
accounts[1].should.be.equal(
await presaleContract.vault()
)
ETHER.mul(100).should.be.bignumber.equal(
await presaleContract.minimumContribution()
)
})
it('cannot initialize twice', async () => {
// require(!isInitialized);
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER, accounts[1], {from: accounts[0]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER, accounts[1], {from: accounts[0]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[0]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[0]})
.should.be.rejectedWith(REVERT_MSG);
})
it('startTime cannot be 0', async () => {
// require(_startTime != 0);
await presaleContract.initialize(0, PRESALE_END_DATE, ETHER, accounts[1], {from: accounts[1]})
await presaleContract.initialize(0, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('endTime cannot be 0', async () => {
// require(_endTime != 0);
await presaleContract.initialize(PRESALE_START_DATE, 0, ETHER, accounts[1], {from: accounts[1]})
await presaleContract.initialize(PRESALE_START_DATE, 0, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('endTime cannot be less than startTime', async () => {
// require(_endTime > _startTime);
await presaleContract.initialize(PRESALE_END_DATE, PRESALE_START_DATE, ETHER, accounts[1], {from: accounts[1]})
await presaleContract.initialize(PRESALE_END_DATE, PRESALE_START_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('cap cannot be 0', async () => {
// require(_cap != 0);
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, 0, accounts[1], {from: accounts[1]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, 0, ETHER.mul(100), accounts[1], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('vault cannot be 0x0', async () => {
// require(_vault != 0x0);
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER, '0x0', {from: accounts[1]})
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), '0x0', {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('minimumContribution cannot be 0', async () => {
// require(_vault != 0x0);
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), 0, accounts[1], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
})
@ -101,43 +110,36 @@ contract('Presale', function(accounts) {
beforeEach(async () => {
PRESALE_START_DATE = moment('2017-12-11T16:00:00Z').unix();
PRESALE_END_DATE = moment('2017-12-18T16:00:00Z').unix();
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(2), accounts[1], {from: accounts[0]})
})
it('cannot buy if not whitelisted', async () => {
// require(whitelist[msg.sender]);
await presaleContract.sendTransaction({amount: ETHER})
.should.be.rejectedWith(REVERT_MSG);
await presaleContract.initialize(PRESALE_START_DATE, PRESALE_END_DATE, ETHER.mul(40000), ETHER.mul(100), accounts[1], {from: accounts[0]})
})
it('cannot buy if not value is 0', async () => {
// require(msg.value > 0);
await presaleContract.setTime(PRESALE_START_DATE);
await presaleContract.whitelistInvestor(accounts[0]);
await presaleContract.sendTransaction({value: 0})
.should.be.rejectedWith(REVERT_MSG);
})
it('can not buy if not initialized', async () => {
// require(isInitialized);
await presaleContract.sendTransaction({amount: ETHER})
.should.be.rejectedWith('VM Exception while processing transaction: revert');
it('cannot buy if not value is less than minimum', async () => {
// require(msg.value > 0);
await presaleContract.setTime(PRESALE_START_DATE);
await presaleContract.sendTransaction({value: ETHER.mul(99)})
.should.be.rejectedWith(REVERT_MSG);
})
it('can not buy if time is not within startTime&endTime', async ()=> {
// require(now >= startTime && now <= endTime);
await presaleContract.setTime(PRESALE_START_DATE - 1);
await presaleContract.whitelistInvestor(accounts[0]);
await presaleContract.sendTransaction({value: ETHER})
await presaleContract.sendTransaction({value: ETHER.mul(100)})
.should.be.rejectedWith(REVERT_MSG);
await presaleContract.setTime(PRESALE_END_DATE + 1);
await presaleContract.sendTransaction({value: ETHER})
await presaleContract.sendTransaction({value: ETHER.mul(100)})
.should.be.rejectedWith(REVERT_MSG);
})
it('can not buy more than cap', async () => {
// require(totalInvestedInWei + msg.value <= cap);
// bool withinCap = totalInvestedInWei.add(msg.value) <= cap;
await presaleContract.setTime(PRESALE_START_DATE);
await presaleContract.whitelistInvestor(accounts[0]);
await presaleContract.sendTransaction({value: ETHER.mul(2) + 1})
await presaleContract.sendTransaction({value: ETHER.mul(40000).add(1)})
.should.be.rejectedWith(REVERT_MSG);
})
@ -148,99 +150,32 @@ contract('Presale', function(accounts) {
const vault = accounts[1];
const preVaultBalance = await web3.eth.getBalance(vault);
await presaleContract.setTime(PRESALE_START_DATE);
await presaleContract.whitelistInvestor(accounts[0]);
await presaleContract.sendTransaction({value: ETHER});
ETHER.should.be.bignumber.equal(
await presaleContract.sendTransaction({value: ETHER.mul(100)});
ETHER.mul(100).should.be.bignumber.equal(
await presaleContract.investorBalances(accounts[0])
)
ETHER.should.be.bignumber.equal(
ETHER.mul(100).should.be.bignumber.equal(
await presaleContract.totalInvestedInWei()
)
preVaultBalance.add(ETHER).should.be.bignumber.equal(
preVaultBalance.add(ETHER.mul(100)).should.be.bignumber.equal(
await web3.eth.getBalance(vault)
)
await presaleContract.sendTransaction({value: ETHER});
await presaleContract.sendTransaction({value: ETHER.mul(2)});
ETHER.mul(2).should.be.bignumber.equal(
ETHER.mul(100).add(ETHER.mul(2)).should.be.bignumber.equal(
await presaleContract.investorBalances(accounts[0])
)
ETHER.mul(2).should.be.bignumber.equal(
ETHER.mul(100).add(ETHER.mul(2)).should.be.bignumber.equal(
await presaleContract.totalInvestedInWei()
)
preVaultBalance.add(ETHER.mul(2)).should.be.bignumber.equal(
preVaultBalance.add(ETHER.mul(100).add(ETHER.mul(2))).should.be.bignumber.equal(
await web3.eth.getBalance(vault)
)
await presaleContract.sendTransaction({value: ETHER.mul(40000-100-2).add(1)})
.should.be.rejectedWith(REVERT_MSG);
})
})
describe('#whitelistInvestor', async ()=>{
it('cannot by called by non-owner', async ()=> {
await presaleContract.whitelistInvestor(accounts[0], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('whitelists an investor', async ()=> {
'0'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
false.should.be.equal(
await presaleContract.whitelist(accounts[0])
)
await presaleContract.whitelistInvestor(accounts[0]);
true.should.be.equal(
await presaleContract.whitelist(accounts[0])
)
'1'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
})
})
describe('#whitelistInvestors', async ()=>{
it('cannot by called by non-owner', async ()=> {
await presaleContract.whitelistInvestors([accounts[0]], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('whitelists investors', async ()=> {
'0'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
false.should.be.equal(
await presaleContract.whitelist(accounts[0])
)
await presaleContract.whitelistInvestors([accounts[0], accounts[1], accounts[2]]);
true.should.be.equal(
await presaleContract.whitelist(accounts[2])
)
'3'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
})
})
describe('#blacklistInvestor', async ()=>{
it('cannot by called by non-owner', async ()=> {
await presaleContract.blacklistInvestor(accounts[0], {from: accounts[1]})
.should.be.rejectedWith(REVERT_MSG);
})
it('blacklist an investors', async ()=> {
'0'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
false.should.be.equal(
await presaleContract.whitelist(accounts[0])
)
await presaleContract.whitelistInvestors([accounts[0], accounts[1], accounts[2]]);
true.should.be.equal(
await presaleContract.whitelist(accounts[0])
)
'3'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
await presaleContract.blacklistInvestor(accounts[0]);
false.should.be.equal(
await presaleContract.whitelist(accounts[0])
)
'2'.should.be.bignumber.equal(
await presaleContract.investorsLength()
)
})
})
});