Skip to content

Commit

Permalink
Added test contract and solidity syntax highlight
Browse files Browse the repository at this point in the history
  • Loading branch information
s0b0lev committed Aug 10, 2018
1 parent b822b42 commit 7cb2362
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sol linguist-language=Solidity
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
*.pyc
*__pycache__/*
config/
*.sol
scanner/*.sol
firebase-*.json
.env
.vscode/
293 changes: 293 additions & 0 deletions tests/neureal_token_test.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
pragma solidity 0.4.24;

library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) return 0;
c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}

contract TESTToken {
using SafeMath for uint256;

/*** State Variables ***/

//TODO use this as a constant when LIVE so that the source code signature includes it and is unique
//TODO Set this to the Neureal multisig wallet that will take the ETH from the sale
// address private constant NEUREAL_ETH_WALLET = 0x0000000000000000000000000000000000000000;
address public NEUREAL_ETH_WALLET;

//TODO use this as a constant when LIVE so that the source code signature includes it and is unique
//TODO Set this to the address of the wallet that has authority to send the whitelisted Ethereum addresses
// address private constant WHITELIST_PROVIDER = 0x0000000000000000000000000000000000000000;
address public WHITELIST_PROVIDER;

//TODO Set this to the opening rate of token per ETH here based on https://www.coinbase.com/charts
//ex: $448 (per ETH) / $0.07 (opening price) = 6400 (works for wei as long as token decimals=18 because ETH=10^18 wei)
uint256 public constant OPENING_RATE = 6400;

//TODO change these values to the real values when going LIVE
uint256 public constant MAX_SALE = 700 * 10**18; //Maximum token that can be purchased in the sale (70000000)
uint256 public constant MIN_PURCHASE = 7 * 10**18; //Minumum token that can be purchased (150000)
uint256 public constant MAX_ALLOCATION = 50 * 10**18; //Maximum token that can be allocated by the owner (5000000)
uint256 public constant MAX_SUPPLY = MAX_SALE + MAX_ALLOCATION; //Maximum token that can be created
//Maximum value of ETH (in Wei) in the contract that can be withdrawn immediately after its sold. The rest can only be withdrawn after the sale has ended.
uint256 public constant MAX_WEI_WITHDRAWAL = (70 * 10**18) / OPENING_RATE; //Maximum ETH that can be withdrawn during the sale (7000000)

address private owner_; //Contract creator
function owner() external view returns (address) {
return owner_;
}

mapping(address => bool) private whitelist_; //List of addresses that can purchase token
function whitelisted(address _who) external view returns (bool) {
return whitelist_[_who];
}

uint256 private totalSale_ = 0; //Current total token sold (only for viewing)
function totalSale() external view returns (uint256) {
return totalSale_;
}
uint256 private totalSaleWei_ = 0; //Current total Wei recieved from sale (only for viewing)
function totalSaleWei() external view returns (uint256) {
return totalSaleWei_;
}
uint256 private totalAllocated_ = 0; //Current total token allocated (only for viewing)
function totalAllocated() external view returns (uint256) {
return totalAllocated_;
}

//TODO Make private when going LIVE ??
uint256 public weiWithdrawn_ = 0; //Current total Wei withdrawn to NEUREAL_ETH_WALLET
uint256 public totalRefunds_ = 0; //Current Wei locked up in refunds
mapping(address => uint256) public pendingRefunds_;

enum Phase {
BeforeSale,
Sale,
Finalized
}
Phase private phase_ = Phase.BeforeSale; //Current sale state
function phase() external view returns (Phase) {
return phase_;
}


/*** Events ***/
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event TokenPurchase(uint256 _totalTokenSold, uint256 _totalWei);
event Refund(address indexed _who, uint256 _weiValue);
event SaleStarted();
event SaleFinalized();


/*** ERC20 token standard ***/

string public constant name = "Neureal TGE Test";
string public constant symbol = "TEST";
uint8 public constant decimals = 18;

uint256 private totalSupply_ = 0;
function totalSupply() external view returns (uint256) {
return totalSupply_;
}

mapping(address => uint256) private balances_;
function balanceOf(address _who) external view returns (uint256) {
return balances_[_who];
}

function transfer(address _to, uint256 _value) external returns (bool) {
// Non transferable, revert so people don't loose as much ether
revert(); //uses some gas, around 23000, only like 3 instructions
// require(false); //uses some gas, around 23000, medium number of instructions
// assert(false); //uses full gas limit
// revert("NOT SUPPORTED"); //uses some gas, around 23000, lots of instructions
return false; //not needed?
}


/*** Non ERC20 Functions ***/

/* Initializes contract */
//TODO take parameters out when LIVE
constructor(address _NEUREAL_ETH_WALLET, address _WHITELIST_PROVIDER) public {
owner_ = msg.sender;
NEUREAL_ETH_WALLET = _NEUREAL_ETH_WALLET; //TODO take out when LIVE
WHITELIST_PROVIDER = _WHITELIST_PROVIDER; //TODO take out when LIVE
}


/** Purchase **/

/* KYC/AML/accredited auth whitelisting */
function whitelist(address _who) external {
require(phase_ != Phase.Finalized); //Only works before and during sale
require(msg.sender == WHITELIST_PROVIDER); //Only whitelist provider
whitelist_[_who] = true;
//DONT check blacklist (coinbase, exchange, etc) here, check in auth website
}
//TODO do we really need this?
function whitelistMany(address[] _who) external {
require(phase_ != Phase.Finalized); //Only works before and during sale
require(msg.sender == WHITELIST_PROVIDER); //Only whitelist provider
for (uint256 i = 0; i < _who.length; i++) {
whitelist_[_who[i]] = true;
}
}
//TODO do we really need this?
function whitelistRemove(address _who) external {
require(phase_ != Phase.Finalized); //Only works before and during sale
require(msg.sender == WHITELIST_PROVIDER); //Only whitelist provider
whitelist_[_who] = false;
}

/* Token purchase (called whenever someone tries to send ether to this contract) */
function() external payable {
require(phase_ == Phase.Sale); //Only sell during sale
require(msg.value != 0); //Stop spamming, contract only calls, etc
require(msg.sender != address(0)); //Prevent transfer to 0x0 address
require(msg.sender != address(this)); //Prevent calls from this.transfer(this)
require(whitelist_[msg.sender]); //Only whitelisted
// assert(address(this).balance >= msg.value); //this.balance gets updated with msg.value before this function starts

uint256 tokens = msg.value.mul(OPENING_RATE);

require(tokens >= MIN_PURCHASE); //must be above minimum

uint256 newTotalSale = totalSale_.add(tokens);
require(newTotalSale <= MAX_SALE); //Check if there is enough available in sale
uint256 newTotalSupply = totalSupply_.add(tokens);
require(newTotalSupply <= MAX_SUPPLY); //Check if there is enough available (should not happen)

balances_[msg.sender] = balances_[msg.sender].add(tokens);
totalSupply_ = newTotalSupply;
totalSale_ = newTotalSale;

totalSaleWei_ = totalSaleWei_.add(msg.value);
// NEUREAL_ETH_WALLET.transfer(msg.value); //This is not safe, use withdraw and revert methods

emit Transfer(address(0), msg.sender, tokens);
emit TokenPurchase(totalSale_, totalSaleWei_);
}

/* Withdraw current available ETH in contract */
function withdraw() external {
require(msg.sender == owner_); //Only owner
uint256 withdrawalValue = address(this).balance.sub(totalRefunds_);
if (phase_ != Phase.Finalized) {
uint256 newWeiWithdrawn = weiWithdrawn_.add(withdrawalValue);
if (newWeiWithdrawn > MAX_WEI_WITHDRAWAL) {
withdrawalValue = MAX_WEI_WITHDRAWAL.sub(weiWithdrawn_); //Withdraw up to the full amount left
require(withdrawalValue != 0); //Bail if already depleted
newWeiWithdrawn = MAX_WEI_WITHDRAWAL;
}
weiWithdrawn_ = newWeiWithdrawn;
}

NEUREAL_ETH_WALLET.transfer(withdrawalValue); //This works with our multisig (using 2300 gas stipend)
// require(NEUREAL_ETH_WALLET.call.value(withdrawalValue)()); //alternative to be able to send more gas
}


/** Revert **/

/* Revert token purchase, lock all ETH for refund, put all allocated token back in allocation pool */
function revertPurchase(address _who) external payable {
require(phase_ == Phase.Sale); //Only revert during sale, afterwords can revert using NEUREAL TGE
require(msg.sender == owner_); //Only owner
require(_who != address(0)); //Prevent refund to 0x0 address
require(balances_[_who] != 0); //Prevent if never purchased
require(pendingRefunds_[_who] == 0); //Prevent if already reverted

uint256 tokenValue = balances_[_who];
uint256 weiValue = tokenValue.div(OPENING_RATE);
assert(weiValue != 0); //We don't allow transfers, but if we did this might happen from rounding

require(address(this).balance >= weiValue); //Must have enough wei in contract after payable to lock up
totalRefunds_ = totalRefunds_.add(weiValue);
pendingRefunds_[_who] = weiValue;
totalSaleWei_ = totalSaleWei_.sub(weiValue);

totalSupply_ = totalSupply_.sub(tokenValue);
totalSale_ = totalSale_.sub(tokenValue);
balances_[_who] = 0;

emit Transfer(_who, address(0), tokenValue);
}
/* send allocated refund, anyone can call anytime */
function sendRefund(address _who) external {
require(pendingRefunds_[_who] != 0); //Limit reentrancy and execution if not needed

uint256 weiValue = pendingRefunds_[_who];
pendingRefunds_[_who] = 0;
totalRefunds_ = totalRefunds_.sub(weiValue);
emit Refund(_who, weiValue);

_who.transfer(weiValue);
// require(_who.call.value(weiValue)()); //TODO I think I need to use this alternative to send more gas than 2300 to be able to refund to contracts
}


/** Allocate **/

/* Owner allocation, create new token (under conditions) without costing ETH */
function allocate(address _to, uint256 _value) external {
require(phase_ != Phase.Finalized); //Only works before and during sale
require(msg.sender == owner_); //Only owner
require(_value != 0); //Allocate is not a transfer call from a wallet app, so this is ok
require(_to != address(0)); //Prevent transfer to 0x0 address
require(_to != address(this)); //Prevent transfer to this contract address

uint256 newTotalAllocated = totalAllocated_.add(_value);
require(newTotalAllocated <= MAX_ALLOCATION); //Check if there is enough available to allocate
uint256 newTotalSupply = totalSupply_.add(_value);
require(newTotalSupply <= MAX_SUPPLY); //Check if there is enough available (should not happen)

balances_[_to] = balances_[_to].add(_value);
totalSupply_ = newTotalSupply;
totalAllocated_ = newTotalAllocated;

emit Transfer(address(0), _to, _value);
}


/** Contract State **/

/* state transition */
function transition() external {
require(phase_ != Phase.Finalized); //Only works before and during sale
require(msg.sender == owner_); //Only owner

if (phase_ == Phase.BeforeSale) {
phase_ = Phase.Sale;
emit SaleStarted();
} else if (phase_ == Phase.Sale) {
phase_ = Phase.Finalized;
emit SaleFinalized();
}
}

}

/*
0x0000000000000000000000000000000000000000
TEST
18
JSON Interface:
[ ]
*/

0 comments on commit 7cb2362

Please sign in to comment.