add whitelist
This commit is contained in:
parent
3bbd8f0887
commit
a8810b5619
101
README.md
101
README.md
|
@ -27,57 +27,99 @@ solidity_flattener --solc-paths=zeppelin-solidity=$(pwd)/node_modules/zeppelin-s
|
|||
Example:
|
||||
|
||||
"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. Let investors send money to contract's address OR to send to `buy` method (`0xa6f2ae3a`)
|
||||
4. Whitelist investors by calling `whitelistInvestors` with an array ['0x0039f22efb07a647557c7c5d17854cfd6d489ef3']
|
||||
5. Let whitelisted investors send money to contract's address OR to send to `buy` method (`0xa6f2ae3a`)
|
||||
|
||||
# How to whitelist a lot of addresses in batch
|
||||
1. `cd scripts`
|
||||
2. `npm install`
|
||||
3. open `.env` file and modify settings:
|
||||
```
|
||||
PRESALE_ADDRESS=0x6F3f79941f89E03D4aF9bDb8BE0623DC24F2bef0
|
||||
UNLOCKED_ADDRESS=0x0039f22efb07a647557c7c5d17854cfd6d489ef3
|
||||
RPC_PORT=8549
|
||||
GAS_PRICE=0.7
|
||||
```
|
||||
4. run parity with unlocked account from which the deployment will happen. It has to match with your .env UNLOCKED_ADDRESS:
|
||||
```
|
||||
parity --jsonrpc-port 8549 --chain kovan --unlock 0x0039F22efB07A647557C7C5d17854CFD6D489eF3 --password $HOME/FILE_PATH_TO_YOUR_PASSWORD_FILE
|
||||
```
|
||||
4. run `node whitelist.js`
|
||||
|
||||
# Test result and gas usage
|
||||
```
|
||||
|
||||
Contract: Presale
|
||||
✓ constructor should set owner
|
||||
✓ can not buy if not initialized (22623 gas)
|
||||
✓ can not buy if not initialized (21411 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)
|
||||
✓ rejects if not sent by owner (25424 gas)
|
||||
✓ sets values (131614 gas)
|
||||
✓ cannot initialize twice (157350 gas)
|
||||
✓ startTime cannot be 0 (25168 gas)
|
||||
✓ endTime cannot be 0 (25232 gas)
|
||||
✓ endTime cannot be less than startTime (25424 gas)
|
||||
✓ cap cannot be 0 (24976 gas)
|
||||
✓ vault cannot be 0x0 (24144 gas)
|
||||
✓ minimumContribution cannot be 0 (24976 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)
|
||||
✓ cannot buy if not whitelisted (21411 gas)
|
||||
✓ cannot buy if not value is 0 (63333 gas)
|
||||
✓ cannot buy if not value is less than minimum (63333 gas)
|
||||
✓ can not buy if time is not within startTime&endTime (111666 gas)
|
||||
✓ can not buy more than cap (63333 gas)
|
||||
✓ happy path (244544 gas)
|
||||
whitelisting capabilities
|
||||
#whitelistInvestor
|
||||
✓ cannot by called by non-owner (23450 gas)
|
||||
✓ whitelists an investor (64399 gas)
|
||||
#whitelistInvestors
|
||||
✓ cannot by called by non-owner (23666 gas)
|
||||
✓ whitelists investors (119844 gas)
|
||||
#blacklistInvestor
|
||||
✓ cannot by called by non-owner (23582 gas)
|
||||
✓ blacklist an investors (139579 gas)
|
||||
|
||||
·-----------------------------------------------------------------------|-----------------------------------·
|
||||
·------------------------------------------------------------------------|-----------------------------------·
|
||||
│ Gas · Block limit: 17592186044415 gas │
|
||||
·········································|······························|····································
|
||||
│ Methods · 1 gwei/gas · 297.51 usd/eth │
|
||||
···················|·····················|·········|··········|·········|················|···················
|
||||
··········································|······························|····································
|
||||
│ Methods · 1 gwei/gas · 307.55 usd/eth │
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ Contract · Method · Min · Max · Avg · # calls · usd (avg) │
|
||||
···················|·····················|·········|··········|·········|················|···················
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · blacklistInvestor · 19735 · 23582 · 21659 · 2 · 0.01 │
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · buy · - · - · - · 0 · - │
|
||||
···················|·····················|·········|··········|·········|················|···················
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · claimTokens · - · - · - · 0 · - │
|
||||
···················|·····················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · initialize · 24078 · 131519 · 46359 · 10 · 0.01 │
|
||||
···················|·····················|·········|··········|·········|················|···················
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · initialize · 24144 · 131614 · 46431 · 10 · 0.01 │
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · Presale · - · - · - · 0 · - │
|
||||
···················|·····················|·········|··········|·········|················|···················
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · transferOwnership · - · - · - · 0 · - │
|
||||
·------------------|---------------------|---------|----------|---------|----------------|------------------·
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · whitelistInvestor · 23450 · 64399 · 50749 · 3 · 0.02 │
|
||||
···················|······················|·········|··········|·········|················|···················
|
||||
│ PresaleOracles · whitelistInvestors · 23666 · 119844 · 87785 · 3 · 0.03 │
|
||||
·------------------|----------------------|---------|----------|---------|----------------|------------------·
|
||||
|
||||
16 passing (2m)
|
||||
23 passing (3m)
|
||||
```
|
||||
# Testnet deployment
|
||||
|
||||
=====
|
||||
## Latest Contract deployment
|
||||
https://kovan.etherscan.io/address/0x6f3f79941f89e03d4af9bdb8be0623dc24f2bef0
|
||||
=====
|
||||
|
||||
## Previous deployments with old source code:
|
||||
|
||||
Contract Deployment: https://kovan.etherscan.io/address/0xb9b49e21e77d2d89a9e4c7ef4f684ad2a4e99663#code
|
||||
|
||||
Called Initialize by Owner with params:
|
||||
|
@ -116,4 +158,3 @@ https://kovan.etherscan.io/address/0xec1afb89f87cb0ac296cad6e73dbeeab5b006050#re
|
|||
|
||||
Send 0.1 ether to get rejected:
|
||||
https://kovan.etherscan.io/tx/0xd859be5b5b58303a4cbc61902f8927efa9de96a3739ce39a18e1f6949a154c2b
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ contract PresaleOracles is Ownable {
|
|||
uint256 public totalInvestedInWei;
|
||||
uint256 public minimumContribution;
|
||||
mapping(address => uint256) public investorBalances;
|
||||
mapping(address => bool) public whitelist;
|
||||
uint256 public investorsLength;
|
||||
address public vault;
|
||||
bool public isInitialized = false;
|
||||
// TESTED by Roman Storm
|
||||
|
@ -46,6 +48,7 @@ contract PresaleOracles is Ownable {
|
|||
}
|
||||
//TESTED by Roman Storm
|
||||
function buy() public payable {
|
||||
require(whitelist[msg.sender]);
|
||||
require(isValidPurchase(msg.value));
|
||||
require(isInitialized);
|
||||
require(getTime() >= startTime && getTime() <= endTime);
|
||||
|
@ -81,4 +84,30 @@ contract PresaleOracles is Ownable {
|
|||
bool withinCap = totalInvestedInWei.add(_amount) <= cap;
|
||||
return hasMinimumAmount && withinCap && nonZero;
|
||||
}
|
||||
//TESTED by Roman Storm
|
||||
function whitelistInvestor(address _newInvestor) public onlyOwner {
|
||||
if(!whitelist[_newInvestor]) {
|
||||
whitelist[_newInvestor] = true;
|
||||
investorsLength++;
|
||||
}
|
||||
}
|
||||
//TESTED by Roman Storm
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -115,6 +115,8 @@ contract PresaleOracles is Ownable {
|
|||
uint256 public totalInvestedInWei;
|
||||
uint256 public minimumContribution;
|
||||
mapping(address => uint256) public investorBalances;
|
||||
mapping(address => bool) public whitelist;
|
||||
uint256 public investorsLength;
|
||||
address public vault;
|
||||
bool public isInitialized = false;
|
||||
// TESTED by Roman Storm
|
||||
|
@ -143,6 +145,7 @@ contract PresaleOracles is Ownable {
|
|||
}
|
||||
//TESTED by Roman Storm
|
||||
function buy() public payable {
|
||||
require(whitelist[msg.sender]);
|
||||
require(isValidPurchase(msg.value));
|
||||
require(isInitialized);
|
||||
require(getTime() >= startTime && getTime() <= endTime);
|
||||
|
@ -178,5 +181,31 @@ contract PresaleOracles is Ownable {
|
|||
bool withinCap = totalInvestedInWei.add(_amount) <= cap;
|
||||
return hasMinimumAmount && withinCap && nonZero;
|
||||
}
|
||||
//TESTED by Roman Storm
|
||||
function whitelistInvestor(address _newInvestor) public onlyOwner {
|
||||
if(!whitelist[_newInvestor]) {
|
||||
whitelist[_newInvestor] = true;
|
||||
investorsLength++;
|
||||
}
|
||||
}
|
||||
//TESTED by Roman Storm
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
PRESALE_ADDRESS=0x6F3f79941f89E03D4aF9bDb8BE0623DC24F2bef0
|
||||
UNLOCKED_ADDRESS=0x0039f22efb07a647557c7c5d17854cfd6d489ef3
|
||||
RPC_PORT=8549
|
||||
GAS_PRICE=0.7
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
|||
require('dotenv').config();
|
||||
const ContributionABI = require('../build/contracts/PresaleOracles.json').abi;
|
||||
|
||||
// const Web3 = require('web3');
|
||||
// // const MAINET_RPC_URL = 'https://mainnet.infura.io/metamask'
|
||||
// // const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask'
|
||||
// const local = `http://localhost:${process.env.RPC_PORT}`;
|
||||
// const provider = new Web3.providers.HttpProvider(local);
|
||||
// const web3 = new Web3(provider);
|
||||
// var myContract = new web3.eth.Contract(ContributionABI, '0x6F3f79941f89E03D4aF9bDb8BE0623DC24F2bef0');
|
||||
// const ARRAY_OF_ADDRESSES = require('./ARRAY_OF_ADDRESSES.json');
|
||||
// filterAddresses(ARRAY_OF_ADDRESSES).then(console.log)
|
||||
function setup({web3Param, contribAddress}){
|
||||
web3 = web3Param;
|
||||
CONTRIBUTION_ADDRESS = contribAddress
|
||||
myContract = new web3.eth.Contract(ContributionABI, CONTRIBUTION_ADDRESS);
|
||||
}
|
||||
|
||||
function readCap() {
|
||||
myContract.methods.cap().call().then((cap) => {
|
||||
console.log('cap', cap);
|
||||
})
|
||||
}
|
||||
function isWhitelisted(toCheckAddress) {
|
||||
readCap();
|
||||
var count = 0;
|
||||
var leftRun = toCheckAddress.length;
|
||||
let notWhitelisted = [];
|
||||
let promise = new Promise((res) => {
|
||||
if(toCheckAddress.length === 0 || !toCheckAddress) {
|
||||
rej('array is empty');
|
||||
}
|
||||
console.log(toCheckAddress.length)
|
||||
toCheckAddress.forEach((address, index) => {
|
||||
myContract.methods.whitelist(address).call().then((isWhitelisted) => {
|
||||
leftRun--;
|
||||
if (!isWhitelisted) {
|
||||
count++;
|
||||
notWhitelisted.push(address);
|
||||
}
|
||||
if (leftRun === 0) {
|
||||
console.log('FINISHED! notWhitelisted: ', notWhitelisted.length);
|
||||
res(notWhitelisted);
|
||||
}
|
||||
});
|
||||
})
|
||||
})
|
||||
return promise;
|
||||
}
|
||||
|
||||
function filterAddresses(arrayOfAddresses) {
|
||||
const date = Date.now();
|
||||
console.log(date, 'DATE NOW', arrayOfAddresses.length);
|
||||
return new Promise((res, rej) => {
|
||||
return isWhitelisted(arrayOfAddresses).then((whitelistedAddress) => {
|
||||
res(whitelistedAddress);
|
||||
}).catch(console.error);
|
||||
})
|
||||
}
|
||||
exports.filterAddresses = filterAddresses;
|
||||
exports.isWhitelisted = isWhitelisted;
|
||||
exports.setup = setup;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "scripts",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "whitelist.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Roman Storm",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dotenv": "^4.0.0",
|
||||
"web3": "^1.0.0-beta.24"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
require('dotenv').config();
|
||||
const ARRAY_OF_ADDRESSES = require('./ARRAY_OF_ADDRESSES.json');
|
||||
const RPC_PORT = process.env.RPC_PORT;
|
||||
const PRESALE_ADDRESS = process.env.PRESALE_ADDRESS;
|
||||
const UNLOCKED_ADDRESS = process.env.UNLOCKED_ADDRESS;
|
||||
|
||||
const ICO_ABI = require('../build/contracts/PresaleOracles.json').abi;
|
||||
const Web3 = require('web3');
|
||||
const provider = new Web3.providers.HttpProvider(`http://localhost:${RPC_PORT}`);
|
||||
const web3 = new Web3(provider);
|
||||
|
||||
const { filterAddresses, setup } = require('./filterAddresses');
|
||||
setup({ web3Param: web3, contribAddress: PRESALE_ADDRESS});
|
||||
filterAddresses(ARRAY_OF_ADDRESSES).then(async (toWhitelist) => {
|
||||
console.log(toWhitelist.length);
|
||||
const addPerTx = 160;
|
||||
const slices = Math.ceil(toWhitelist.length / addPerTx);
|
||||
var txcount = await web3.eth.getTransactionCount(UNLOCKED_ADDRESS);
|
||||
const nonce = web3.utils.toHex(txcount);
|
||||
console.log('STARTED', nonce);
|
||||
return sendTransactionToContribution({array: toWhitelist, slice: slices, addPerTx, nonce});
|
||||
}).then(console.log).catch(console.error);
|
||||
|
||||
const GAS_PRICE = web3.utils.toWei(process.env.GAS_PRICE, 'gwei');
|
||||
const GAS_LIMIT = '6700000';
|
||||
const myContract = new web3.eth.Contract(ICO_ABI, PRESALE_ADDRESS, {
|
||||
from: UNLOCKED_ADDRESS, // default from address
|
||||
gasPrice: GAS_PRICE,
|
||||
gas: GAS_LIMIT // default gas price in wei
|
||||
});
|
||||
|
||||
|
||||
async function sendTransactionToContribution({array, slice, addPerTx, nonce}) {
|
||||
if(array.length === 0){
|
||||
console.log('array doesnot have not whitelisted addresses');
|
||||
process.exit();
|
||||
}
|
||||
const start = (slice - 1) * addPerTx;
|
||||
const end = slice * addPerTx;
|
||||
const arrayToProcess = array.slice(start, end);
|
||||
let encodedData = myContract.methods.whitelistInvestors(arrayToProcess).encodeABI();
|
||||
|
||||
console.log('Processing array length', arrayToProcess.length, arrayToProcess[0], arrayToProcess[arrayToProcess.length - 1]);
|
||||
return new Promise((res) => {
|
||||
web3.eth.estimateGas({
|
||||
from: UNLOCKED_ADDRESS, to: PRESALE_ADDRESS, data: encodedData, gas: GAS_LIMIT, gasPrice: GAS_PRICE
|
||||
}).then((gasNeeded) => {
|
||||
console.log('gasNeeded', gasNeeded);
|
||||
web3.eth.sendTransaction({
|
||||
from: UNLOCKED_ADDRESS, to: PRESALE_ADDRESS, data: encodedData, gas: gasNeeded, gasPrice: GAS_PRICE, nonce
|
||||
}).on('transactionHash', function(hash){console.log('hash', hash)});
|
||||
slice--;
|
||||
if (slice > 0) {
|
||||
nonce = parseInt(nonce, 16);
|
||||
nonce++;
|
||||
nonce = web3.utils.toHex(nonce);
|
||||
sendTransactionToContribution({array, slice, addPerTx, nonce});
|
||||
} else {
|
||||
res({ result: 'completed' });
|
||||
// process.exit();
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
}
|
|
@ -112,6 +112,11 @@ contract('Presale', function(accounts) {
|
|||
PRESALE_END_DATE = moment('2017-12-18T16:00:00Z').unix();
|
||||
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 whitelisted', async () => {
|
||||
// require(whitelist[msg.sender]);
|
||||
await presaleContract.sendTransaction({amount: ETHER})
|
||||
.should.be.rejectedWith(REVERT_MSG);
|
||||
})
|
||||
it('cannot buy if not value is 0', async () => {
|
||||
// require(msg.value > 0);
|
||||
await presaleContract.setTime(PRESALE_START_DATE);
|
||||
|
@ -150,6 +155,7 @@ 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.mul(100)});
|
||||
ETHER.mul(100).should.be.bignumber.equal(
|
||||
await presaleContract.investorBalances(accounts[0])
|
||||
|
@ -177,5 +183,78 @@ contract('Presale', function(accounts) {
|
|||
})
|
||||
})
|
||||
|
||||
describe('whitelisting capabilities', async ()=> {
|
||||
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()
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
});
|
Loading…
Reference in New Issue