adapt to proxi-finalize

This commit is contained in:
dennis00010011b 2018-07-11 02:38:57 -07:00
parent ed791a47c5
commit d76ed654d9
23 changed files with 2986 additions and 95 deletions

675
contracts/DutchProxy.abi Normal file
View File

@ -0,0 +1,675 @@
[
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "provider",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "proxy_admin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleInfo",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleWhitelist",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleStartAndEndTimes",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_calldata",
"type": "bytes"
}
],
"name": "exec",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "registry_exec_id",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleStatus",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "decreaseApproval",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_name",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAdmin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_storage",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "buy",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "bool"
}
],
"name": "init",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "isCrowdsaleFull",
"outputs": [
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "increaseApproval",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_exec_id",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_buyer",
"type": "address"
}
],
"name": "getWhitelistStatus",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_index",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_version",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getTokensSold",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_storage",
"type": "address"
},
{
"name": "_registry_exec_id",
"type": "bytes32"
},
{
"name": "_provider",
"type": "address"
},
{
"name": "_app_name",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"payable": true,
"stateMutability": "payable",
"type": "fallback"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "execution_id",
"type": "bytes32"
},
{
"indexed": false,
"name": "message",
"type": "string"
}
],
"name": "StorageException",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "amt",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "owner",
"type": "address"
},
{
"indexed": true,
"name": "spender",
"type": "address"
},
{
"indexed": false,
"name": "amt",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
]

1
contracts/DutchProxy.bin Normal file

File diff suppressed because one or more lines are too long

376
contracts/DutchProxy.sol Normal file
View File

@ -0,0 +1,376 @@
pragma solidity ^0.4.23;
// File: contracts/classes/admin/IAdmin.sol
interface IAdmin {
function getAdmin() external view returns (address);
function getCrowdsaleInfo() external view returns (uint, address, uint, bool, bool, bool);
function isCrowdsaleFull() external view returns (bool, uint);
function getCrowdsaleStartAndEndTimes() external view returns (uint, uint);
function getCrowdsaleStatus() external view returns (uint, uint, uint, uint, uint, uint, bool);
function getTokensSold() external view returns (uint);
function getCrowdsaleWhitelist() external view returns (uint, address[]);
function getWhitelistStatus(address) external view returns (uint, uint);
}
interface AdminIdx {
function getAdmin(address, bytes32) external view returns (address);
function getCrowdsaleInfo(address, bytes32) external view returns (uint, address, uint, bool, bool, bool);
function isCrowdsaleFull(address, bytes32) external view returns (bool, uint);
function getCrowdsaleStartAndEndTimes(address, bytes32) external view returns (uint, uint);
function getCrowdsaleStatus(address, bytes32) external view returns (uint, uint, uint, uint, uint, uint, bool);
function getTokensSold(address, bytes32) external view returns (uint);
function getCrowdsaleWhitelist(address, bytes32) external view returns (uint, address[]);
function getWhitelistStatus(address, bytes32, address) external view returns (uint, uint);
}
// File: contracts/classes/sale/ISale.sol
interface ISale {
function buy() external payable;
}
// File: contracts/classes/token/IToken.sol
interface IToken {
function name() external view returns (string);
function symbol() external view returns (string);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address) external view returns (uint);
function allowance(address, address) external view returns (uint);
function transfer(address, uint) external returns (bool);
function transferFrom(address, address, uint) external returns (bool);
function approve(address, uint) external returns (bool);
function increaseApproval(address, uint) external returns (bool);
function decreaseApproval(address, uint) external returns (bool);
event Transfer(address indexed from, address indexed to, uint amt);
event Approval(address indexed owner, address indexed spender, uint amt);
}
interface TokenIdx {
function name(address, bytes32) external view returns (bytes32);
function symbol(address, bytes32) external view returns (bytes32);
function decimals(address, bytes32) external view returns (uint8);
function totalSupply(address, bytes32) external view returns (uint);
function balanceOf(address, bytes32, address) external view returns (uint);
function allowance(address, bytes32, address, address) external view returns (uint);
}
// File: contracts/IDutchCrowdsale.sol
interface IDutchCrowdsale {
function init(address, uint, uint, uint, uint, uint, uint, bool, address, bool) external;
}
// File: authos-solidity/contracts/interfaces/StorageInterface.sol
interface StorageInterface {
function getTarget(bytes32 exec_id, bytes4 selector)
external view returns (address implementation);
function getIndex(bytes32 exec_id) external view returns (address index);
function createInstance(address sender, bytes32 app_name, address provider, bytes32 registry_exec_id, bytes calldata)
external payable returns (bytes32 instance_exec_id, bytes32 version);
function createRegistry(address index, address implementation) external returns (bytes32 exec_id);
function exec(address sender, bytes32 exec_id, bytes calldata)
external payable returns (uint emitted, uint paid, uint stored);
}
// File: authos-solidity/contracts/core/Proxy.sol
contract Proxy {
// Registry storage
address public proxy_admin;
StorageInterface public app_storage;
bytes32 public registry_exec_id;
address public provider;
bytes32 public app_name;
// App storage
bytes32 public app_version;
bytes32 public app_exec_id;
address public app_index;
// Function selector for storage 'exec' function
bytes4 internal constant EXEC_SEL = bytes4(keccak256('exec(address,bytes32,bytes)'));
// Event emitted in case of a revert from storage
event StorageException(bytes32 indexed execution_id, string message);
// For storage refunds
function () external payable { }
// Constructor - sets proxy admin, as well as initial variables
constructor (address _storage, bytes32 _registry_exec_id, address _provider, bytes32 _app_name) public {
proxy_admin = msg.sender;
app_storage = StorageInterface(_storage);
registry_exec_id = _registry_exec_id;
provider = _provider;
app_name = _app_name;
}
// Declare abstract execution function -
function exec(bytes _calldata) external payable returns (bool);
// Checks to see if an error message was returned with the failed call, and emits it if so -
function checkErrors() internal {
// If the returned data begins with selector 'Error(string)', get the contained message -
string memory message;
bytes4 err_sel = bytes4(keccak256('Error(string)'));
assembly {
// Get pointer to free memory, place returned data at pointer, and update free memory pointer
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
mstore(0x40, add(ptr, returndatasize))
// Check value at pointer for equality with Error selector -
if eq(mload(ptr), and(err_sel, 0xffffffff00000000000000000000000000000000000000000000000000000000)) {
message := add(0x24, ptr)
}
}
// If no returned message exists, emit a default error message. Otherwise, emit the error message
if (bytes(message).length == 0)
emit StorageException(app_exec_id, "No error recieved");
else
emit StorageException(app_exec_id, message);
}
}
// File: authos-solidity/contracts/lib/StringUtils.sol
library StringUtils {
function toStr(bytes32 _val) internal pure returns (string memory str) {
assembly {
str := mload(0x40)
mstore(str, 0x20)
mstore(add(0x20, str), _val)
mstore(0x40, add(0x40, str))
}
}
}
// File: contracts/DutchProxy.sol
contract SaleProxy is ISale, Proxy {
// Allows a sender to purchase tokens from the active sale
function buy() external payable {
if (address(app_storage).call.value(msg.value)(abi.encodeWithSelector(
EXEC_SEL, msg.sender, app_exec_id, msg.data
)) == false) checkErrors(); // Call failed - emit errors
// Return unspent wei to sender
address(msg.sender).transfer(address(this).balance);
}
}
contract AdminProxy is IAdmin, SaleProxy {
/*
Returns the admin address for the crowdsale
@return address: The admin of the crowdsale
*/
function getAdmin() external view returns (address) {
return AdminIdx(app_index).getAdmin(app_storage, app_exec_id);
}
/*
Returns information about the ongoing sale -
@return uint: The total number of wei raised during the sale
@return address: The team funds wallet
@return uint: The minimum number of tokens a purchaser must buy
@return bool: Whether the sale is finished configuring
@return bool: Whether the sale has completed
@return bool: Whether the unsold tokens at the end of the sale are burnt (if false, they are sent to the team wallet)
*/
function getCrowdsaleInfo() external view returns (uint, address, uint, bool, bool, bool) {
return AdminIdx(app_index).getCrowdsaleInfo(app_storage, app_exec_id);
}
/*
Returns whether or not the sale is full, as well as the maximum number of sellable tokens
If the current rate is such that no more tokens can be purchased, returns true
@return bool: Whether or not the sale is sold out
@return uint: The total number of tokens for sale
*/
function isCrowdsaleFull() external view returns (bool, uint) {
return AdminIdx(app_index).isCrowdsaleFull(app_storage, app_exec_id);
}
/*
Returns the start and end times of the sale
@return uint: The time at which the sale will begin
@return uint: The time at which the sale will end
*/
function getCrowdsaleStartAndEndTimes() external view returns (uint, uint) {
return AdminIdx(app_index).getCrowdsaleStartAndEndTimes(app_storage, app_exec_id);
}
/*
Returns information about the current sale tier
@return uint: The price of 1 token (10^decimals) in wei at the start of the sale
@return uint: The price of 1 token (10^decimals) in wei at the end of the sale
@return uint: The price of 1 token (10^decimals) currently
@return uint: The total duration of the sale
@return uint: The amount of time remaining in the sale (factors in time till sale starts)
@return uint: The amount of tokens still available to be sold
@return bool: Whether the sale is whitelisted or not
*/
function getCrowdsaleStatus() external view returns (uint, uint, uint, uint, uint, uint, bool) {
return AdminIdx(app_index).getCrowdsaleStatus(app_storage, app_exec_id);
}
/*
Returns the number of tokens sold during the sale, so far
@return uint: The number of tokens sold during the sale up to this point
*/
function getTokensSold() external view returns (uint) {
return AdminIdx(app_index).getTokensSold(app_storage, app_exec_id);
}
/*
Returns the whitelist set by the admin
@return uint: The length of the whitelist
@return address[]: The list of addresses in the whitelist
*/
function getCrowdsaleWhitelist() external view returns (uint, address[]) {
return AdminIdx(app_index).getCrowdsaleWhitelist(app_storage, app_exec_id);
}
/*
Returns whitelist information for a buyer
@param _buyer: The address about which the whitelist information will be retrieved
@return uint: The minimum number of tokens the buyer must make during the sale
@return uint: The maximum amount of tokens allowed to be purchased by the buyer
*/
function getWhitelistStatus(address _buyer) external view returns (uint, uint) {
return AdminIdx(app_index).getWhitelistStatus(app_storage, app_exec_id, _buyer);
}
}
contract TokenProxy is IToken, AdminProxy {
using StringUtils for bytes32;
// Returns the name of the token
function name() external view returns (string) {
return TokenIdx(app_index).name(app_storage, app_exec_id).toStr();
}
// Returns the symbol of the token
function symbol() external view returns (string) {
return TokenIdx(app_index).symbol(app_storage, app_exec_id).toStr();
}
// Returns the number of decimals the token has
function decimals() external view returns (uint8) {
return TokenIdx(app_index).decimals(app_storage, app_exec_id);
}
// Returns the total supply of the token
function totalSupply() external view returns (uint) {
return TokenIdx(app_index).totalSupply(app_storage, app_exec_id);
}
// Returns the token balance of the owner
function balanceOf(address _owner) external view returns (uint) {
return TokenIdx(app_index).balanceOf(app_storage, app_exec_id, _owner);
}
// Returns the number of tokens allowed by the owner to be spent by the spender
function allowance(address _owner, address _spender) external view returns (uint) {
return TokenIdx(app_index).allowance(app_storage, app_exec_id, _owner, _spender);
}
// Executes a transfer, sending tokens to the recipient
function transfer(address _to, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Transfer(msg.sender, _to, _amt);
return true;
}
// Executes a transferFrom, transferring tokens from the _from account by using an allowed amount
function transferFrom(address _from, address _to, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Transfer(_from, _to, _amt);
return true;
}
// Approve a spender for a given amount
function approve(address _spender, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Approval(msg.sender, _spender, _amt);
return true;
}
// Increase the amount approved for the spender
function increaseApproval(address _spender, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Approval(msg.sender, _spender, _amt);
return true;
}
// Decrease the amount approved for the spender, to a minimum of 0
function decreaseApproval(address _spender, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Approval(msg.sender, _spender, _amt);
return true;
}
}
contract DutchProxy is IDutchCrowdsale, TokenProxy {
// Constructor - sets storage address, registry id, provider, and app name
constructor (address _storage, bytes32 _registry_exec_id, address _provider, bytes32 _app_name) public
Proxy(_storage, _registry_exec_id, _provider, _app_name) { }
// Constructor - creates a new instance of the application in storage, and sets this proxy's exec id
function init(address, uint, uint, uint, uint, uint, uint, bool, address, bool) external {
require(msg.sender == proxy_admin && app_exec_id == 0 && app_name != 0);
(app_exec_id, app_version) = app_storage.createInstance(
msg.sender, app_name, provider, registry_exec_id, msg.data
);
app_index = app_storage.getIndex(app_exec_id);
}
// Executes an arbitrary function in this application
function exec(bytes _calldata) external payable returns (bool success) {
require(app_exec_id != 0 && _calldata.length >= 4);
// Call 'exec' in AbstractStorage, passing in the sender's address, the app exec id, and the calldata to forward -
app_storage.exec.value(msg.value)(msg.sender, app_exec_id, _calldata);
// Get returned data
success = checkReturn();
// If execution failed, emit errors -
if (!success) checkErrors();
// Transfer any returned wei back to the sender
msg.sender.transfer(address(this).balance);
}
// Checks data returned by an application and returns whether or not the execution changed state
function checkReturn() internal pure returns (bool success) {
success = false;
assembly {
// returndata size must be 0x60 bytes
if eq(returndatasize, 0x60) {
// Copy returned data to pointer and check that at least one value is nonzero
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
if iszero(iszero(mload(ptr))) { success := 1 }
if iszero(iszero(mload(add(0x20, ptr)))) { success := 1 }
if iszero(iszero(mload(add(0x40, ptr)))) { success := 1 }
}
}
return success;
}
}

View File

@ -0,0 +1,841 @@
[
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "provider",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleMaxRaise",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "proxy_admin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleInfo",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_tier",
"type": "uint256"
},
{
"name": "_buyer",
"type": "address"
}
],
"name": "getWhitelistStatus",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleTierList",
"outputs": [
{
"name": "",
"type": "bytes32[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleStartAndEndTimes",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_calldata",
"type": "bytes"
}
],
"name": "exec",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "registry_exec_id",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "decreaseApproval",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_name",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAdmin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getReservedTokenDestinationList",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_storage",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_idx",
"type": "uint256"
}
],
"name": "getTierStartAndEndDates",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "buy",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_idx",
"type": "uint256"
}
],
"name": "getCrowdsaleTier",
"outputs": [
{
"name": "",
"type": "bytes32"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_destination",
"type": "address"
}
],
"name": "getReservedDestinationInfo",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "isCrowdsaleFull",
"outputs": [
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_amt",
"type": "uint256"
}
],
"name": "increaseApproval",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_exec_id",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_index",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "app_version",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getTokensSold",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCurrentTierInfo",
"outputs": [
{
"name": "",
"type": "bytes32"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_tier_idx",
"type": "uint256"
}
],
"name": "getTierWhitelist",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bytes32"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "bool"
},
{
"name": "",
"type": "address"
}
],
"name": "init",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCrowdsaleUniqueBuyers",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_storage",
"type": "address"
},
{
"name": "_registry_exec_id",
"type": "bytes32"
},
{
"name": "_provider",
"type": "address"
},
{
"name": "_app_name",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"payable": true,
"stateMutability": "payable",
"type": "fallback"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "execution_id",
"type": "bytes32"
},
{
"indexed": false,
"name": "message",
"type": "string"
}
],
"name": "StorageException",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "amt",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "owner",
"type": "address"
},
{
"indexed": true,
"name": "spender",
"type": "address"
},
{
"indexed": false,
"name": "amt",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
]

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,479 @@
pragma solidity ^0.4.23;
// File: contracts/classes/sale/ISale.sol
interface ISale {
function buy() external payable;
}
// File: contracts/classes/sale_manager/ISaleManager.sol
interface ISaleManager {
function getAdmin() external view returns (address);
function getCrowdsaleInfo() external view returns (uint, address, bool, bool);
function isCrowdsaleFull() external view returns (bool, uint);
function getCrowdsaleStartAndEndTimes() external view returns (uint, uint);
function getCurrentTierInfo() external view returns (bytes32, uint, uint, uint, uint, uint, bool, bool);
function getCrowdsaleTier(uint) external view returns (bytes32, uint, uint, uint, uint, bool, bool);
function getTierWhitelist(uint) external view returns (uint, address[]);
function getCrowdsaleMaxRaise() external view returns (uint, uint);
function getCrowdsaleTierList() external view returns (bytes32[]);
function getCrowdsaleUniqueBuyers() external view returns (uint);
function getTierStartAndEndDates(uint) external view returns (uint, uint);
function getTokensSold() external view returns (uint);
function getWhitelistStatus(uint, address) external view returns (uint, uint);
}
interface SaleManagerIdx {
function getAdmin(address, bytes32) external view returns (address);
function getCrowdsaleInfo(address, bytes32) external view returns (uint, address, bool, bool);
function isCrowdsaleFull(address, bytes32) external view returns (bool, uint);
function getCrowdsaleStartAndEndTimes(address, bytes32) external view returns (uint, uint);
function getCurrentTierInfo(address, bytes32) external view returns (bytes32, uint, uint, uint, uint, uint, bool, bool);
function getCrowdsaleTier(address, bytes32, uint) external view returns (bytes32, uint, uint, uint, uint, bool, bool);
function getTierWhitelist(address, bytes32, uint) external view returns (uint, address[]);
function getCrowdsaleMaxRaise(address, bytes32) external view returns (uint, uint);
function getCrowdsaleTierList(address, bytes32) external view returns (bytes32[]);
function getCrowdsaleUniqueBuyers(address, bytes32) external view returns (uint);
function getTierStartAndEndDates(address, bytes32, uint) external view returns (uint, uint);
function getTokensSold(address, bytes32) external view returns (uint);
function getWhitelistStatus(address, bytes32, uint, address) external view returns (uint, uint);
}
// File: contracts/classes/token/IToken.sol
interface IToken {
function name() external view returns (string);
function symbol() external view returns (string);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address) external view returns (uint);
function allowance(address, address) external view returns (uint);
function transfer(address, uint) external returns (bool);
function transferFrom(address, address, uint) external returns (bool);
function approve(address, uint) external returns (bool);
function increaseApproval(address, uint) external returns (bool);
function decreaseApproval(address, uint) external returns (bool);
event Transfer(address indexed from, address indexed to, uint amt);
event Approval(address indexed owner, address indexed spender, uint amt);
}
interface TokenIdx {
function name(address, bytes32) external view returns (bytes32);
function symbol(address, bytes32) external view returns (bytes32);
function decimals(address, bytes32) external view returns (uint8);
function totalSupply(address, bytes32) external view returns (uint);
function balanceOf(address, bytes32, address) external view returns (uint);
function allowance(address, bytes32, address, address) external view returns (uint);
}
// File: contracts/classes/token_manager/ITokenManager.sol
interface ITokenManager {
function getReservedTokenDestinationList() external view returns (uint, address[]);
function getReservedDestinationInfo(address) external view returns (uint, uint, uint, uint);
}
interface TokenManagerIdx {
function getReservedTokenDestinationList(address, bytes32) external view returns (uint, address[]);
function getReservedDestinationInfo(address, bytes32, address) external view returns (uint, uint, uint, uint);
}
// File: contracts/IMintedCapped.sol
interface IMintedCapped {
function init(address, uint, bytes32, uint, uint, uint, uint, bool, bool, address) external;
}
// File: authos-solidity/contracts/interfaces/StorageInterface.sol
interface StorageInterface {
function getTarget(bytes32 exec_id, bytes4 selector)
external view returns (address implementation);
function getIndex(bytes32 exec_id) external view returns (address index);
function createInstance(address sender, bytes32 app_name, address provider, bytes32 registry_exec_id, bytes calldata)
external payable returns (bytes32 instance_exec_id, bytes32 version);
function createRegistry(address index, address implementation) external returns (bytes32 exec_id);
function exec(address sender, bytes32 exec_id, bytes calldata)
external payable returns (uint emitted, uint paid, uint stored);
}
// File: authos-solidity/contracts/core/Proxy.sol
contract Proxy {
// Registry storage
address public proxy_admin;
StorageInterface public app_storage;
bytes32 public registry_exec_id;
address public provider;
bytes32 public app_name;
// App storage
bytes32 public app_version;
bytes32 public app_exec_id;
address public app_index;
// Function selector for storage 'exec' function
bytes4 internal constant EXEC_SEL = bytes4(keccak256('exec(address,bytes32,bytes)'));
// Event emitted in case of a revert from storage
event StorageException(bytes32 indexed execution_id, string message);
// For storage refunds
function () external payable { }
// Constructor - sets proxy admin, as well as initial variables
constructor (address _storage, bytes32 _registry_exec_id, address _provider, bytes32 _app_name) public {
proxy_admin = msg.sender;
app_storage = StorageInterface(_storage);
registry_exec_id = _registry_exec_id;
provider = _provider;
app_name = _app_name;
}
// Declare abstract execution function -
function exec(bytes _calldata) external payable returns (bool);
// Checks to see if an error message was returned with the failed call, and emits it if so -
function checkErrors() internal {
// If the returned data begins with selector 'Error(string)', get the contained message -
string memory message;
bytes4 err_sel = bytes4(keccak256('Error(string)'));
assembly {
// Get pointer to free memory, place returned data at pointer, and update free memory pointer
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
mstore(0x40, add(ptr, returndatasize))
// Check value at pointer for equality with Error selector -
if eq(mload(ptr), and(err_sel, 0xffffffff00000000000000000000000000000000000000000000000000000000)) {
message := add(0x24, ptr)
}
}
// If no returned message exists, emit a default error message. Otherwise, emit the error message
if (bytes(message).length == 0)
emit StorageException(app_exec_id, "No error recieved");
else
emit StorageException(app_exec_id, message);
}
}
// File: authos-solidity/contracts/lib/StringUtils.sol
library StringUtils {
function toStr(bytes32 _val) internal pure returns (string memory str) {
assembly {
str := mload(0x40)
mstore(str, 0x20)
mstore(add(0x20, str), _val)
mstore(0x40, add(0x40, str))
}
}
}
// File: contracts/MintedCappedProxy.sol
contract SaleProxy is ISale, Proxy {
// Allows a sender to purchase tokens from the active sale
function buy() external payable {
if (address(app_storage).call.value(msg.value)(abi.encodeWithSelector(
EXEC_SEL, msg.sender, app_exec_id, msg.data
)) == false) checkErrors(); // Call failed - emit errors
// Return unspent wei to sender
address(msg.sender).transfer(address(this).balance);
}
}
contract SaleManagerProxy is ISaleManager, SaleProxy {
/*
Returns the admin address for the crowdsale
@return address: The admin of the crowdsale
*/
function getAdmin() external view returns (address) {
return SaleManagerIdx(app_index).getAdmin(app_storage, app_exec_id);
}
/*
Returns information about the ongoing sale -
@return uint: The total number of wei raised during the sale
@return address: The team funds wallet
@return bool: Whether the sale is finished configuring
@return bool: Whether the sale has completed
*/
function getCrowdsaleInfo() external view returns (uint, address, bool, bool) {
return SaleManagerIdx(app_index).getCrowdsaleInfo(app_storage, app_exec_id);
}
/*
Returns whether or not the sale is full, as well as the maximum number of sellable tokens
@return bool: Whether or not the sale is sold out
@return uint: The total number of tokens for sale
*/
function isCrowdsaleFull() external view returns (bool, uint) {
return SaleManagerIdx(app_index).isCrowdsaleFull(app_storage, app_exec_id);
}
/*
Returns the start and end times of the sale
@return uint: The time at which the sale will begin
@return uint: The time at which the sale will end
*/
function getCrowdsaleStartAndEndTimes() external view returns (uint, uint) {
return SaleManagerIdx(app_index).getCrowdsaleStartAndEndTimes(app_storage, app_exec_id);
}
/*
Returns information about the current sale tier
@return bytes32: The tier's name
@return uint: The index of the tier
@return uint: The time at which the tier will end
@return uint: The number of tokens remaining for sale during this tier
@return uint: The price of 1 token (10^decimals units) in wei
@return uint: The minimum amount of tokens that must be purchased during this tier
@return bool: Whether the tier's duration can be modified by the sale admin, prior to it beginning
@return bool: Whether the tier is whitelisted
*/
function getCurrentTierInfo() external view returns (bytes32, uint, uint, uint, uint, uint, bool, bool) {
return SaleManagerIdx(app_index).getCurrentTierInfo(app_storage, app_exec_id);
}
/*
Returns information about the tier represented by the given index
@param _idx: The index of the tier about which information will be returned
@return bytes32: The tier's name
@return uint: The number of tokens available for sale during this tier, in total
@return uint: The price of 1 token (10^decimals units) in wei
@return uint: The duration the tier lasts
@return uint: The minimum amount of tokens that must be purchased during this tier
@return bool: Whether the tier's duration can be modified by the sale admin, prior to it beginning
@return bool: Whether the tier is whitelisted
*/
function getCrowdsaleTier(uint _idx) external view returns (bytes32, uint, uint, uint, uint, bool, bool) {
return SaleManagerIdx(app_index).getCrowdsaleTier(app_storage, app_exec_id, _idx);
}
/*
Returns the whitelist associated with the given tier
@param _tier_idx: The index of the tier about which information will be returned
@return uint: The length of the whitelist
@return address[]: The list of addresses whitelisted
*/
function getTierWhitelist(uint _tier_idx) external view returns (uint, address[]) {
return SaleManagerIdx(app_index).getTierWhitelist(app_storage, app_exec_id, _tier_idx);
}
/*
Returns the maximum amount of wei that can be raised, as well as the total number of tokens that can be sold
@return uint: The maximum amount of wei that can be raised
@return uint: The total number of tokens that can be sold
*/
function getCrowdsaleMaxRaise() external view returns (uint, uint) {
return SaleManagerIdx(app_index).getCrowdsaleMaxRaise(app_storage, app_exec_id);
}
/*
Returns a list of the sale's tier names
@return bytes32[]: A list of the names of each of the tiers of the sale (names may not be unique)
*/
function getCrowdsaleTierList() external view returns (bytes32[]) {
return SaleManagerIdx(app_index).getCrowdsaleTierList(app_storage, app_exec_id);
}
/*
Returns the number of unique contributors to the sale
@return uint: The number of unique contributors to the sale
*/
function getCrowdsaleUniqueBuyers() external view returns (uint) {
return SaleManagerIdx(app_index).getCrowdsaleUniqueBuyers(app_storage, app_exec_id);
}
/*
Returns the start and end time of the given tier
@param _idx: The index of the tier about which information will be returned
@return uint: The time at which the tier will begin
@return uint: The time at which the tier will end
*/
function getTierStartAndEndDates(uint _idx) external view returns (uint, uint) {
return SaleManagerIdx(app_index).getTierStartAndEndDates(app_storage, app_exec_id, _idx);
}
/*
Returns the total number of tokens sold during the sale
@return uint: The total number of tokens sold during the sale
*/
function getTokensSold() external view returns (uint) {
return SaleManagerIdx(app_index).getTokensSold(app_storage, app_exec_id);
}
/*
Returns whitelist information for a buyer during a given tier
@param _tier: The index of the tier whose whitelist will be queried
@param _buyer: The address about which the whitelist information will be retrieved
@return uint: The minimum number of tokens the buyer must make during the sale
@return uint: The maximum amount of tokens able to be purchased by the buyer this tier
*/
function getWhitelistStatus(uint _tier, address _buyer) external view returns (uint, uint) {
return SaleManagerIdx(app_index).getWhitelistStatus(app_storage, app_exec_id, _tier, _buyer);
}
}
contract TokenManagerProxy is ITokenManager, SaleManagerProxy {
/*
Returns the list of addresses for which tokens have been reserved
@return uint: The length of the list
@return address[]: The list of destinations
*/
function getReservedTokenDestinationList() external view returns (uint, address[]) {
return TokenManagerIdx(app_index).getReservedTokenDestinationList(app_storage, app_exec_id);
}
/*
Returns information about a reserved token destination
@param _destination: The address whose reservation information will be queried
@return uint: The index of the address in the reservation list
@return uint: The number of tokens that will be minted for the destination when the sale is completed
@return uint: The percent of tokens sold that will be minted for the destination when the sale is completed
@return uint: The number of decimals in the above percent figure
*/
function getReservedDestinationInfo(address _destination) external view returns (uint, uint, uint, uint) {
return TokenManagerIdx(app_index).getReservedDestinationInfo(app_storage, app_exec_id, _destination);
}
}
contract TokenProxy is IToken, TokenManagerProxy {
using StringUtils for bytes32;
// Returns the name of the token
function name() external view returns (string) {
return TokenIdx(app_index).name(app_storage, app_exec_id).toStr();
}
// Returns the symbol of the token
function symbol() external view returns (string) {
return TokenIdx(app_index).symbol(app_storage, app_exec_id).toStr();
}
// Returns the number of decimals the token has
function decimals() external view returns (uint8) {
return TokenIdx(app_index).decimals(app_storage, app_exec_id);
}
// Returns the total supply of the token
function totalSupply() external view returns (uint) {
return TokenIdx(app_index).totalSupply(app_storage, app_exec_id);
}
// Returns the token balance of the owner
function balanceOf(address _owner) external view returns (uint) {
return TokenIdx(app_index).balanceOf(app_storage, app_exec_id, _owner);
}
// Returns the number of tokens allowed by the owner to be spent by the spender
function allowance(address _owner, address _spender) external view returns (uint) {
return TokenIdx(app_index).allowance(app_storage, app_exec_id, _owner, _spender);
}
// Executes a transfer, sending tokens to the recipient
function transfer(address _to, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Transfer(msg.sender, _to, _amt);
return true;
}
// Executes a transferFrom, transferring tokens from the _from account by using an allowed amount
function transferFrom(address _from, address _to, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Transfer(_from, _to, _amt);
return true;
}
// Approve a spender for a given amount
function approve(address _spender, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Approval(msg.sender, _spender, _amt);
return true;
}
// Increase the amount approved for the spender
function increaseApproval(address _spender, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Approval(msg.sender, _spender, _amt);
return true;
}
// Decrease the amount approved for the spender, to a minimum of 0
function decreaseApproval(address _spender, uint _amt) external returns (bool) {
app_storage.exec(msg.sender, app_exec_id, msg.data);
emit Approval(msg.sender, _spender, _amt);
return true;
}
}
contract MintedCappedProxy is IMintedCapped, TokenProxy {
// Constructor - sets storage address, registry id, provider, and app name
constructor (address _storage, bytes32 _registry_exec_id, address _provider, bytes32 _app_name) public
Proxy(_storage, _registry_exec_id, _provider, _app_name) { }
// Constructor - creates a new instance of the application in storage, and sets this proxy's exec id
function init(address, uint, bytes32, uint, uint, uint, uint, bool, bool, address) external {
require(msg.sender == proxy_admin && app_exec_id == 0 && app_name != 0);
(app_exec_id, app_version) = app_storage.createInstance(
msg.sender, app_name, provider, registry_exec_id, msg.data
);
app_index = app_storage.getIndex(app_exec_id);
}
// Executes an arbitrary function in this application
function exec(bytes _calldata) external payable returns (bool success) {
require(app_exec_id != 0 && _calldata.length >= 4);
// Call 'exec' in AbstractStorage, passing in the sender's address, the app exec id, and the calldata to forward -
app_storage.exec.value(msg.value)(msg.sender, app_exec_id, _calldata);
// Get returned data
success = checkReturn();
// If execution failed, emit errors -
if (!success) checkErrors();
// Transfer any returned wei back to the sender
msg.sender.transfer(address(this).balance);
}
// Checks data returned by an application and returns whether or not the execution changed state
function checkReturn() internal pure returns (bool success) {
success = false;
assembly {
// returndata size must be 0x60 bytes
if eq(returndatasize, 0x60) {
// Copy returned data to pointer and check that at least one value is nonzero
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
if iszero(iszero(mload(ptr))) { success := 1 }
if iszero(iszero(mload(add(0x20, ptr)))) { success := 1 }
if iszero(iszero(mload(add(0x40, ptr)))) { success := 1 }
}
}
return success;
}
}

1
contracts/Proxies.abi Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
[{"constant":true,"inputs":[],"name":"abstractStorageAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"deployer","type":"address"}],"name":"getCrowdsalesForUser","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"deployer","type":"address"}],"name":"countCrowdsalesForUser","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"proxyAddress","type":"address"}],"name":"getADminFromDutchProxy","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newMintedCappedIdxAddr","type":"address"}],"name":"changeMintedCappedIdx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"proxyAddress","type":"address"}],"name":"getProxyExecID","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newDutchIdxAddr","type":"address"}],"name":"changeDutchIdxAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dutchIdxAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"proxyAddress","type":"address"}],"name":"getAdminFromMintedCappedProxy","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mintedCappedIdxAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newAbstractStorageAddr","type":"address"}],"name":"changeAbstractStorage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"proxyAddress","type":"address"}],"name":"trackCrowdsale","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_abstractStorage","type":"address"},{"name":"_mintedCappedIdx","type":"address"},{"name":"_dutchIdx","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"proxyAddress","type":"address"},{"indexed":false,"name":"appExecID","type":"bytes32"}],"name":"Added","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,145 @@
pragma solidity ^0.4.24;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @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) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
contract AbstractProxy {
bytes32 public app_exec_id;
function getAdmin() external view returns (address);
}
contract MintedCappedIdx {
function getAdmin(address, bytes32) external view returns (address);
}
contract DutchIdx {
function getAdmin(address, bytes32) external view returns (address);
}
/**
* Registry of contracts deployed from Token Wizard 2.0.
*/
contract TokenWizardProxiesRegistry is Ownable {
address public abstractStorageAddr;
address public mintedCappedIdxAddr;
address public dutchIdxAddr;
mapping (address => Crowdsale[]) private deployedCrowdsalesByUser;
event Added(address indexed sender, address indexed proxyAddress, bytes32 appExecID);
struct Crowdsale {
address proxyAddress;
bytes32 execID;
}
constructor (
address _abstractStorage,
address _mintedCappedIdx,
address _dutchIdx
) public {
require(_abstractStorage != address(0));
require(_mintedCappedIdx != address(0));
require(_dutchIdx != address(0));
require(_abstractStorage != _mintedCappedIdx && _abstractStorage != _dutchIdx && _mintedCappedIdx != _dutchIdx);
abstractStorageAddr = _abstractStorage;
mintedCappedIdxAddr = _mintedCappedIdx;
dutchIdxAddr = _dutchIdx;
}
function changeAbstractStorage(address newAbstractStorageAddr) public onlyOwner {
abstractStorageAddr = newAbstractStorageAddr;
}
function changeMintedCappedIdx(address newMintedCappedIdxAddr) public onlyOwner {
mintedCappedIdxAddr = newMintedCappedIdxAddr;
}
function changeDutchIdxAddr(address newDutchIdxAddr) public onlyOwner {
dutchIdxAddr = newDutchIdxAddr;
}
function trackCrowdsale(address proxyAddress) public {
AbstractProxy proxy = AbstractProxy(proxyAddress);
require(proxyAddress != address(0));
require(msg.sender == proxy.getAdmin());
bytes32 appExecID = proxy.app_exec_id();
require(mintedCappedIdx.getAdmin(abstractStorageAddr, appExecID) != address(0) || dutchIdx.getAdmin(abstractStorageAddr, appExecID) != address(0));
MintedCappedIdx mintedCappedIdx = MintedCappedIdx(mintedCappedIdxAddr);
DutchIdx dutchIdx = DutchIdx(dutchIdxAddr);
for (uint i = 0; i < deployedCrowdsalesByUser[msg.sender].length; i++) {
require(deployedCrowdsalesByUser[msg.sender][i].proxyAddress != proxyAddress);
require(deployedCrowdsalesByUser[msg.sender][i].execID != appExecID);
}
deployedCrowdsalesByUser[msg.sender].push(Crowdsale({proxyAddress: proxyAddress, execID: appExecID}));
emit Added(msg.sender, proxyAddress, appExecID);
}
function countCrowdsalesForUser(address deployer) public view returns (uint) {
return deployedCrowdsalesByUser[deployer].length;
}
function getCrowdsalesForUser(address deployer) public view returns (address[]) {
address[] storage proxies;
for (uint k = 0; k < deployedCrowdsalesByUser[deployer].length; k++) {
proxies.push(deployedCrowdsalesByUser[deployer][k].proxyAddress);
}
return proxies;
}
}

View File

@ -12,7 +12,6 @@ class Crowdsale {
this.reservedTokens = [];
this.gasPrice;
this.tiers = [];
this.tokenAddress;
this.contractAddress;
@ -21,6 +20,7 @@ class Crowdsale {
this.executionID;
this.networkID;
this.sort;
this.proxyAddress;
}
async parser(fileName) {

View File

@ -40,9 +40,9 @@ class User {
logger.info("getTokenBalance");
try {
const web3 = await Utils.getWeb3Instance(crowdsale.networkID);
let contractAddress = await Utils.getContractAddressInitCrowdsale(crowdsale);
let contractAddress = await Utils.getContractAddressIdx(crowdsale);
logger.info("contractAddress" + contractAddress);
let addressRegistryStorage = await Utils.getEnvAddressAbstractStorage();
let addressRegistryStorage = await Utils.getFromEnvAbstractStorageAddress();
logger.info("addressRegistryStorage" + addressRegistryStorage);
let abi = await Utils.getContractABIInitCrowdsale(crowdsale);
let myContract = new web3.eth.Contract(abi, contractAddress);
@ -82,7 +82,7 @@ class User {
logger.info("Open manage page")
const startURL = Utils.getStartURL();
let mngPage = new ManagePage(this.driver);
mngPage.URL = startURL + "manage/" + crowdsale.executionID;
mngPage.URL = startURL + "manage/" + crowdsale.proxyAddress;
return await mngPage.open()
&& await mngPage.waitUntilLoaderGone()
&& !await mngPage.isDisplayedButtonOK();
@ -370,7 +370,8 @@ class User {
await wizardStep4.waitUntilDisplayedButtonContinue() &&
await wizardStep4.clickButtonContinue() &&
await wizardStep4.waitUntilLoaderGone();
crowdsale.executionID = await crowdsalePage.getExecutionID();
crowdsale.proxyAddress = await crowdsalePage.getProxyAddress();
counter = 200;
do {
await this.driver.sleep(300);
@ -388,10 +389,14 @@ class User {
crowdsale.url = await investPage.getURL();
logger.info("Final invest page link: " + crowdsale.url);
logger.info("token address: " + crowdsale.executionID);
logger.info("proxyAddress " + crowdsale.proxyAddress);
crowdsale.networkID = this.networkID;
crowdsale.sort = 'minted';
return result && crowdsale.executionID !== "";
crowdsale.executionID = await Utils.getProxyExecID(crowdsale);
logger.info("executionID " + crowdsale.executionID);
return result && crowdsale.proxyAddress !== "";
}
async createDutchAuctionCrowdsale(crowdsale) {
@ -451,7 +456,7 @@ class User {
await wizardStep4.clickButtonContinue() &&
await wizardStep4.waitUntilLoaderGone();
if (!result) return false;
crowdsale.executionID = await crowdsalePage.getExecutionID();
crowdsale.proxyAddress = await crowdsalePage.getProxyAddress();
counter = 200;
do {
@ -470,12 +475,14 @@ class User {
crowdsale.url = await investPage.getURL();
logger.info("Final invest page link: " + crowdsale.url);
logger.info("token address: " + crowdsale.executionID);
logger.info("proxyAddress: " + crowdsale.proxyAddress);
crowdsale.networkID = this.networkID;
logger.info("crowdsale.networkID " + crowdsale.networkID);
crowdsale.networkID = this.networkID;
crowdsale.sort = 'dutch';
return result && crowdsale.executionID !== "";
crowdsale.executionID = await Utils.getProxyExecID(crowdsale);
logger.info("executionID " + crowdsale.executionID);
return result && crowdsale.proxyAddress !== "";
}
async changeMinCapFromManagePage(tier, value) {

View File

@ -10,7 +10,8 @@
"margo": "node ./test/margo.js",
"e2eMintedRopsten": "mocha ./test/e2eMintedRopsten.js",
"e2eDutchRopsten": "mocha ./test/e2eDutchRopsten.js",
"tr": "mocha -b ./test/funcDutchRateTime.js"
"tr": "mocha -b ./test/funcDutchRateTime.js",
"testDecimals":"mocha -b ./test/testDecimals.js"
},
"dependencies": {
"chromedriver": "^2.35.0",

View File

@ -22,8 +22,8 @@ class CrowdsalePage extends Page {
return await super.clickWithWait(buttonInvest);
}
async getExecutionID() {
logger.info(this.name + "getExecutionID");
async getProxyAddress() {
logger.info(this.name + "getProxyAddress");
return await super.getTextForElement(fieldExecID);
}

View File

@ -111,7 +111,7 @@ class MetaMask extends Page {
}
}
async signTransaction(refreshCount,tier) {
async signTransaction(refreshCount, tier) {
logger.info(this.name + "signTransaction ");
await this.switchToNextPage();
let counter = 5;
@ -121,8 +121,9 @@ class MetaMask extends Page {
await super.waitUntilLocated(iconChangeAccount);
if (await this.isElementDisplayed(buttonSubmit)) {
return await this.fillGasLimit( 6600000)
&& await this.clickButtonSubmitTransaction()
return await this.fillGasLimit(4600000)
&& await this.waitUntilDisplayed(buttonSubmit)
&& await this.clickButtonSubmitTransaction()
&& await this.switchToNextPage();
}
await this.driver.sleep(3000);

View File

@ -0,0 +1,26 @@
{
"name": "DutchDecimalsWhitelist.json",
"ticker": "test",
"decimals": 0,
"totalSupply":100,
"walletAddress":"0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b",
"gasprice":50,
"burnExcess":false,
"tiers":[
{
"isWhitelisted":true,
"startDate": "180000",
"startTime": "180000",
"endDate":"72000000",
"endTime":"72000000",
"minCap":11,
"minRate":1000,
"maxRate":10000,
"supply": 100,
"whitelist":[{
"address": "0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b",
"min": 50,
"max": 150
} ]
}]
}

View File

@ -1,25 +1,28 @@
{
"name": "scenarioDutchRopsten.json",
"ticker": "test",
"decimals": 10,
"totalSupply":100,
"walletAddress":"0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b",
"gasprice":300,
"gasprice":150,
"burnExcess":false,
"tiers":[
{
"isWhitelisted":false,
"startDate": "600000",
"startTime": "600000",
"endDate":"700000",
"endTime":"700000",
"isWhitelisted":true,
"startDate": "240000",
"startTime": "240000",
"endDate":"360000",
"endTime":"360000",
"minCap":11,
"minRate":1000,
"maxRate":10000,
"supply": 100,
"whitelist":[
{
"address": "0xF16AB2EA0a7F7B28C267cbA3Ed211Ea5c6e27411",
"min": 50,
"max": 150
}
]
}]

View File

@ -0,0 +1,34 @@
{
"name": "MintedDecimalsWhitelist",
"ticker": "test",
"decimals": 0,
"reservedTokens":[
],
"walletAddress":"0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b",
"gasprice": 1,
"tiers":[
{
"name":"###1",
"allowModify": true,
"isWhitelisted":true,
"startDate": "120000",
"startTime": "120000",
"endDate":"23/02/2050",
"endTime":"12:34",
"minCap":11,
"rate":200,
"supply": 250,
"whitelist":[
{
"address": "0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b",
"min": 50,
"max": 150
}
]
}
]
}

View File

@ -2,49 +2,41 @@
"name": "scenarioE2eMintedRopsten.json",
"ticker": "test",
"decimals": 18,
"decimals": 10,
"reservedTokens":[
],
"walletAddress":"0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b",
"gasprice":300,
"gasprice":150,
"tiers":[
{
"name":"###1",
"allowModify": true,
"isWhitelisted":true,
"isWhitelisted":false,
"startDate": "600000",
"startTime": "600000",
"endDate":"800000",
"endTime":"800000",
"minCap":13,
"rate":1000,
"endDate":"720000",
"endTime":"720000",
"minCap":11,
"rate":2000,
"supply": 100,
"whitelist":[{
"address": "0xF16AB2EA0a7F7B28C267cbA3Ed211Ea5c6e27411",
"min": 10,
"max": 150
}]
"whitelist":[
]
},
{
"name":"###2",
"allowModify": true,
"isWhitelisted":true,
"isWhitelisted":false,
"startDate": "",
"startTime": "",
"endDate":"",
"endTime":"",
"minCap":16,
"rate":1000,
"supply": 200,
"minCap":12,
"rate":2000,
"supply": 100,
"whitelist":[
{
"address": "0xF16AB2EA0a7F7B28C267cbA3Ed211Ea5c6e27411",
"min": 10,
"max": 150
}
]
}

View File

@ -471,7 +471,7 @@ test.describe('e2e test for TokenWizard2.0/DutchAuctionCrowdsale. v2.7.5 ', asyn
test.it('Crowdsale starts as scheduled',
async function () {
let startTime;
let counter = 180;
do {
startTime = await Utils.getDutchCrowdsaleStartTime(e2eWhitelist);
@ -622,18 +622,18 @@ test.describe('e2e test for TokenWizard2.0/DutchAuctionCrowdsale. v2.7.5 ', asyn
test.it('Crowdsale has finished as scheduled',
async function () {
let endTime;
let endT;
let counter = 180;
do {
endTime = await Utils.getDutchCrowdsaleEndTime(e2eWhitelist);
endT = await Utils.getDutchCrowdsaleEndTime(e2eWhitelist);
logger.info("wait " + Date.now());
logger.info("wait " + endTime);
logger.info("wait " + endT);
//console.log("Date.now() = " + Date.now());
//console.log("endTime = " + endTime);
//console.log("endTime = " + endT);
//console.log("counter"+counter);
await driver.sleep(1000);
}
while (counter-- > 0 && (Date.now() / 1000 <= endTime));
while (counter-- > 0 && (Date.now() / 1000 <= endT));
return await assert.equal(counter > 0, true, 'Test FAILED. Crowdsale has not finished in time ');
});
@ -806,6 +806,7 @@ test.describe('e2e test for TokenWizard2.0/DutchAuctionCrowdsale. v2.7.5 ', asyn
async function () {
let counter = 180;
let startTime;
do {
startTime = await Utils.getDutchCrowdsaleStartTime(e2eMinCap);
logger.info("wait " + Date.now());

View File

@ -24,7 +24,7 @@ const endDateForTestEarlier = "01/07/2049";
const endTimeForTestLater = "420000";
const endDateForTestLater = "420000";
test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', async function () {
test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.8.0 ', async function () {
this.timeout(2400000);//40 min
this.slow(1800000);
@ -66,8 +66,13 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
/////////////////////////////////////////////////////////////////////////
test.before(async function () {
await Utils.copyEnvFromWizard();
//await Utils.deployTWProxiesRegistry(8545,'./contracts/ProxiesRegistry');
//await Utils.deployTWProxiesRegistryToRopsten(3,'./contracts/ProxiesRegistry');
//await Utils.copyEnvToWizard();
//throw ("Stop");
const scenarioE2eMintedMinCap = './scenarios/scenarioE2eMintedMinCap.json';
const scenarioE2eMintedWhitelist = './scenarios/scenarioE2eMintedWhitelist.json';
const scenarioForUItests = './scenarios/scenarioUItests.json';
@ -137,7 +142,7 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
test.after(async function () {
// Utils.killProcess(ganache);
await Utils.sendEmail(tempOutputFile);
//await Utils.sendEmail(tempOutputFile);
let outputPath = Utils.getOutputPath();
outputPath = outputPath + "/result" + Utils.getDate();
await fs.ensureDirSync(outputPath);
@ -494,6 +499,7 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
let owner = Owner;
assert.equal(await owner.setMetaMaskAccount(), true, "Can not set Metamask account");
let result = await owner.createMintedCappedCrowdsale(e2eWhitelist);
logger.info("e2eWhitelist.proxyAddress " + e2eWhitelist.proxyAddress);
logger.info("e2eWhitelist.executionID " + e2eWhitelist.executionID);
logger.info("e2eWhitelist.networkID " + e2eWhitelist.networkID);
logger.info("e2eWhitelist.sort " + e2eWhitelist.sort);
@ -824,7 +830,7 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
let result = await investor.contribute(contribution);
let soldTokensAfter = await Utils.getTokensSold(e2eWhitelist);
if (result) investor.tokenBalance = (soldTokensAfter - soldTokensBefore)/1e18 + investor.tokenBalance;
if (result) investor.tokenBalance = (soldTokensAfter - soldTokensBefore) / 1e18 + investor.tokenBalance;
let shouldBe = e2eWhitelist.tiers[0].whitelist[0].max;
let balance = await investor.getBalanceFromInvestPage(e2eWhitelist);
@ -904,16 +910,17 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
async function () {
let tierNumber = 1;
let counter = 180;
let endT;
do {
endTime = await Utils.getTiersEndTimeMintedCrowdsale(e2eWhitelist, tierNumber);
logger.info("wait " + Date.now());
logger.info("wait " + startTime);
endT = await Utils.getTiersEndTimeMintedCrowdsale(e2eWhitelist, tierNumber);
//logger.info("wait " + Date.now());
//logger.info("wait " + endT);
//console.log("Date.now() = " + Date.now());
//console.log("startTime = " + endTime);
await driver.sleep(1000);
}
while (counter-- > 0 && (Date.now() / 1000 <= endTime));
while (counter-- > 0 && (Date.now() / 1000 <= endT));
return await assert.equal(counter > 0, true, 'Test FAILED. Tier #1 has not finished as scheduled');
});
///// TIER #2 Whitelist
@ -952,14 +959,14 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
}
console.log(result);
console.log(contribution);
// await driver.sleep(20000000000);
// await driver.sleep(20000000000);
return await assert.equal(result, false, "Test FAILED.Whitelisting is inherited");
});
test.it("Contribution page: minContribution field contains correct minCap value for whitelisted investor",
async function () {
let investor = Investor1;
//assert.equal(await investor.setMetaMaskAccount(), true, "Can not set Metamask account");
//assert.equal(await inve stor.setMetaMaskAccount(), true, "Can not set Metamask account");
assert.equal(await investor.openInvestPage(e2eWhitelist), true, 'Investor can not open Invest page');
assert.equal(await investPage.waitUntilLoaderGone(), true, 'Loader displayed too long time');
let result = await investPage.getMinContribution();
@ -1014,7 +1021,7 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
let contribution = investor.maxCap;
let result = await investor.contribute(contribution);
let soldTokensAfter = await Utils.getTokensSold(e2eWhitelist);
investor.tokenBalance = (soldTokensAfter - soldTokensBefore)/1e18 + investor.tokenBalance;
investor.tokenBalance = (soldTokensAfter - soldTokensBefore) / 1e18 + investor.tokenBalance;
return await assert.equal(result, true, "Test FAILED.Investor can not buy maxCap in first transaction");
});
@ -1360,16 +1367,17 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
async function () {
let tierNumber = 1;
let counter = 180;
let endT;
do {
endTime = await Utils.getTiersEndTimeMintedCrowdsale(e2eMinCap, tierNumber);
logger.info("wait " + Date.now());
logger.info("wait " + startTime);
endT = await Utils.getTiersEndTimeMintedCrowdsale(e2eMinCap, tierNumber);
//logger.info("wait " + Date.now());
//logger.info("wait " + endT);
//console.log("Date.now() = " + Date.now());
//console.log("startTime = " + startTime);
await driver.sleep(1000);
}
while (counter-- > 0 && (Date.now() / 1000 <= endTime));
while (counter-- > 0 && (Date.now() / 1000 <= endT));
return await assert.equal(counter > 0, true, 'Test FAILED. Tier #1 has not finished as scheduled');
});
@ -1394,7 +1402,7 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
return await assert.equal(result, true, 'Test FAILED. Countdown timer has incorrect status ');
});
test.it('Should be individual minCap for each tier: if investor has bought in tier# then he is not able to buy less than minCap in first transaction in tier#2',
test.it.skip('Should be individual minCap for each tier: if investor has bought in tier# then he is not able to buy less than minCap in first transaction in tier#2',
async function () {
let investor = Investor1;
assert.equal(await investor.setMetaMaskAccount(), true, "Can not set Metamask account");
@ -1544,16 +1552,17 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
async function () {
let tierNumber = 2;
let counter = 180;
let endT;
do {
endTime = await Utils.getTiersEndTimeMintedCrowdsale(e2eMinCap, tierNumber);
endT = await Utils.getTiersEndTimeMintedCrowdsale(e2eMinCap, tierNumber);
logger.info("wait " + Date.now());
logger.info("wait " + endTime);
logger.info("wait " + endT);
//console.log("Date.now() = " + Date.now());
//console.log("startTime = " + startTime);
await driver.sleep(1000);
}
while (counter-- > 0 && (Date.now() / 1000 <= endTime));
while (counter-- > 0 && (Date.now() / 1000 <= endT));
return await assert.equal(counter > 0, true, 'Test FAILED. Tier #2 has not finished as scheduled');
});
//////// TIER#3 ///////////
@ -1622,16 +1631,17 @@ test.describe('e2e test for TokenWizard2.0/MintedCappedCrowdsale. v2.7.5 ', asyn
async function () {
let tierNumber = 3;
let counter = 180;
let endT;
do {
endTime = await Utils.getTiersEndTimeMintedCrowdsale(e2eMinCap, tierNumber);
endT = await Utils.getTiersEndTimeMintedCrowdsale(e2eMinCap, tierNumber);
logger.info("wait " + Date.now());
logger.info("wait " + endTime);
logger.info("wait " + endT);
//console.log("Date.now() = " + Date.now());
//console.log("startTime = " + startTime);
await driver.sleep(1000);
}
while (counter-- > 0 && (Date.now() / 1000 <= endTime));
while (counter-- > 0 && (Date.now() / 1000 <= endT));
return await assert.equal(counter > 0, true, 'Test FAILED. Tier #3 has not finished as scheduled');
});
///// AFTER END //////

164
test/testDecimals.js Normal file
View File

@ -0,0 +1,164 @@
let test = require('selenium-webdriver/testing');
let assert = require('assert');
const fs = require('fs-extra');
///////////////////////////////////////////////////////
const WizardWelcome = require('../pages/WizardWelcome.js').WizardWelcome;
const WizardStep1 = require('../pages/WizardStep1.js').WizardStep1;
const WizardStep2 = require('../pages/WizardStep2.js').WizardStep2;
const WizardStep3 = require('../pages/WizardStep3.js').WizardStep3;
const WizardStep4 = require('../pages/WizardStep4.js').WizardStep4;
const TierPage = require('../pages/TierPage.js').TierPage;
const ReservedTokensPage = require('../pages/ReservedTokensPage.js').ReservedTokensPage;
const CrowdsalePage = require('../pages/CrowdsalePage.js').CrowdsalePage;
const InvestPage = require('../pages/ContributionPage.js').InvestPage;
const ManagePage = require('../pages/ManagePage.js').ManagePage;
const logger = require('../entity/Logger.js').logger;
const tempOutputPath = require('../entity/Logger.js').tempOutputPath;
const Utils = require('../utils/Utils.js').Utils;
const MetaMask = require('../pages/MetaMask.js').MetaMask;
const User = require("../entity/User.js").User;
const Crowdsale = require('../entity/Crowdsale.js').Crowdsale;
const smallAmount = 0.1;
const endTimeForTestEarlier = "01:23";
const endDateForTestEarlier = "01/07/2049";
const endTimeForTestLater = "420000";
const endDateForTestLater = "420000";
test.describe('POA token-wizard. Test MintedCappedCrowdsale', async function () {
this.timeout(2400000);//40 min
this.slow(1800000);
const user3_56B2File ='./users/user3_56B2.json';
const user8545_56B2File = './users/user8545_56B2.json';//Owner
const user8545_F16AFile = './users/user8545_F16A.json';//Investor1 - whitelisted for Tier#1 before deployment
const user8545_f5aAFile = './users/user8545_f5aA.json';//Investor2 - added from manage page before start
const user8545_ecDFFile = './users/user8545_ecDF.json';//Reserved address, also wh investor that added after start time
const user8545_dDdCFile = './users/user8545_dDdC.json';//Investor3 - whitelisted for Tier#2 before deployment
let driver;
let Owner;
let Investor1;
let Investor2;
let Investor3;
let ReservedAddress;
let metaMask;
let welcomePage;
let wizardStep1;
let wizardStep2;
let wizardStep3;
let wizardStep4;
let tierPage;
let reservedTokensPage;
let investPage;
let startURL;
let crowdsaleForUItests;
let e2eMinCap;
let e2eWhitelist;
let e2eMultitier;
let mngPage;
let balance;
let endTime;
let endDate;
let MintedDecimalsWhitelist;
let DutchDecimalsWhitelist;
/////////////////////////////////////////////////////////////////////////
test.before(async function () {
logger.info("test decimals ");
await Utils.copyEnvFromWizard();
const scenarioDutchDecimalsWhitelist = './scenarios/scenarioDutchDecimalsWhitelist.json';
const scenarioMintedDecimalsWhitelist = './scenarios/scenarioMintedDecimalsWhitelist.json'
//DutchDecimalsWhitelist = await Utils.getDutchCrowdsaleInstance(scenarioDutchDecimalsWhitelist);
MintedDecimalsWhitelist = await Utils.getMintedCrowdsaleInstance(scenarioMintedDecimalsWhitelist);
startURL = await Utils.getStartURL();
driver = await Utils.startBrowserWithMetamask();
Owner = new User(driver, user8545_56B2File);
await Utils.receiveEth(Owner, 20);
logger.info("Owner = " + Owner.account);
logger.info("Owner's balance = " + await Utils.getBalance(Owner) / 1e18 + " Eth");
metaMask = new MetaMask(driver);
await metaMask.activate();//return activated Metamask and empty page
await Owner.setMetaMaskAccount();
welcomePage = new WizardWelcome(driver, startURL);
wizardStep1 = new WizardStep1(driver);
wizardStep2 = new WizardStep2(driver);
wizardStep3 = new WizardStep3(driver);
wizardStep4 = new WizardStep4(driver);
investPage = new InvestPage(driver);
reservedTokensPage = new ReservedTokensPage(driver);
mngPage = new ManagePage(driver);
//tierPage = new TierPage(driver, e2eRopsten.tiers[0]);
});
test.after(async function () {
// Utils.killProcess(ganache);
//await Utils.sendEmail(tempOutputFile);
let outputPath = Utils.getOutputPath();
outputPath = outputPath + "/result" + Utils.getDate();
await fs.ensureDirSync(outputPath);
await fs.copySync(tempOutputPath, outputPath);
//await fs.remove(tempOutputPath);
//await driver.quit();
});
//////////////////////// Test SUITE #1 /////////////////////////////
test.it('Owner can create crowdsale:Minted,whitelist',
async function () {
let owner = Owner;
assert.equal(await owner.setMetaMaskAccount(), true, "Can not set Metamask account");
MintedDecimalsWhitelist.decimals = 0;
console.log("Decimals = "+ MintedDecimalsWhitelist.decimals);
let result = await owner.createMintedCappedCrowdsale(MintedDecimalsWhitelist);
return await assert.equal(result, true, 'Test FAILED. Crowdsale has not created ');
});
test.it('Crowdsale starts as scheduled',
async function () {
let startTime;
let counter = 180;
do {
startTime = await Utils.getMintedCrowdsaleStartTime(MintedDecimalsWhitelist);
logger.info("wait " + Date.now());
logger.info("wait " + startTime);
//console.log("Date.now() = " + Date.now());
//console.log("startTime = " + startTime);
//console.log("counter"+counter);
await driver.sleep(1000);
}
while (counter-- > 0 && (Date.now() / 1000 <= startTime));
return await assert.equal(counter > 0, true, 'Test FAILED. Tier has not start in time ');
});
test.it('Investor is able to buy amount equal minCap',
async function () {
let investor = Owner;
//assert.equal(await investor.setMetaMaskAccount(), true, "Can not set Metamask account");
let contribution = MintedDecimalsWhitelist.tiers[0].whitelist[0].min;
investor.tokenBalance += contribution;
let result = await investor.openInvestPage(MintedDecimalsWhitelist)
&& await investor.contribute(contribution);
return await assert.equal(result, true, 'Test FAILED. Investor can not buy ');
});
test.it('Investors balance is properly changed after purchase ',
async function () {
let investor = Owner;
let balance= await investor.getTokenBalance(MintedDecimalsWhitelist);
console.log("Balance in wei = "+balance);
let balanceTokens = balance/Math.pow(10,MintedDecimalsWhitelist.decimals);
console.log("Balance in tokens = "+balanceTokens);
console.log("ShouldBe = " + MintedDecimalsWhitelist.tiers[0].whitelist[0].min);
let result = (balanceTokens === MintedDecimalsWhitelist.tiers[0].whitelist[0].min)
return await assert.equal(result, true, "Test FAILED. Investor can buy but balance did not changed");
});
//////////////////////////////////////
});

View File

@ -325,41 +325,41 @@ class Utils {
return (Math.abs(balanceShouldBe - balanceEthOwnerAfter / 1e18) < delta);
}
static async getEnvAddressMintedIDXAddress() {
static async getFromEnvMintedIDXAddress() {
logger.info("Utils:getEnvAddressMintedInitCrowdsale");
require('dotenv').config();
return Object.values(JSON.parse(process.env.REACT_APP_MINTED_CAPPED_IDX_ADDRESS))[0];
}
static async getEnvAddressDutchIDXAddress() {
static async getFromEnvDutchIDXAddress() {
logger.info("Utils:getEnvAddressDutchInitCrowdsale");
require('dotenv').config();
return Object.values(JSON.parse(process.env.REACT_APP_DUTCH_IDX_ADDRESS))[0];
}
static async getEnvAddressAbstractStorage() {
static async getFromEnvAbstractStorageAddress() {
logger.info("Utils:getEnvAddressRegistryStorage");
require('dotenv').config();
return Object.values(JSON.parse(process.env.REACT_APP_ABSTRACT_STORAGE_ADDRESS))[0];
}
static async getEnvNetworkId() {
static async getFromEnvNetworkId() {
logger.info("Utils:getEnvNetworkId");
require('dotenv').config();
return Object.keys(JSON.parse(process.env.REACT_APP_REGISTRY_STORAGE_ADDRESS))[0];
}
static async getContractAddressInitCrowdsale(crowdsale) {
logger.info("Utils:getContractAddressInitCrowdsale");
static async getContractAddressIdx(crowdsale) {
logger.info("Utils:getContractAddressIdx");
switch (crowdsale.sort) {
case 'minted':
return Utils.getEnvAddressMintedIDXAddress();
return Utils.getFromEnvMintedIDXAddress();
break;
case 'dutch':
return Utils.getEnvAddressDutchIDXAddress();
return Utils.getFromEnvDutchIDXAddress();
break;
default:
return Utils.getEnvAddressMintedIDXAddress();
return Utils.getFromEnvMintedIDXAddress();
}
}
@ -382,6 +382,7 @@ class Utils {
}
static async copyEnvFromWizard() {
logger.info("Utils:copyEnvFromWizard")
try {
fs.copySync('../../.env', './.env', {overwrite: true});
return true;
@ -393,6 +394,18 @@ class Utils {
}
}
static async copyEnvToWizard() {
try {
fs.copySync('./.env', '../../.env', {overwrite: true});
return true;
}
catch (err) {
logger.info("! Can't find .env file in e2e directory !");
logger.info(err);
return false;
}
}
static async sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
@ -447,8 +460,8 @@ class Utils {
if (crowdsale.sort === _minted) return false;
let web3 = Utils.getWeb3Instance(crowdsale.networkID);
const abi = await Utils.getContractABIInitCrowdsale(crowdsale);
let myContract = new web3.eth.Contract(abi, await Utils.getEnvAddressDutchIDXAddress());
let result = await myContract.methods.getCrowdsaleStartAndEndTimes(await Utils.getEnvAddressAbstractStorage(), crowdsale.executionID).call();
let myContract = new web3.eth.Contract(abi, await Utils.getFromEnvDutchIDXAddress());
let result = await myContract.methods.getCrowdsaleStartAndEndTimes(await Utils.getFromEnvAbstractStorageAddress(), crowdsale.executionID).call();
return result.start_time;
}
@ -457,8 +470,8 @@ class Utils {
if (crowdsale.sort === _minted) return false;
let web3 = Utils.getWeb3Instance(crowdsale.networkID);
const abi = await Utils.getContractABIInitCrowdsale(crowdsale);
let myContract = new web3.eth.Contract(abi, await Utils.getEnvAddressDutchIDXAddress());
let result = await myContract.methods.getCrowdsaleStartAndEndTimes(await Utils.getEnvAddressAbstractStorage(), crowdsale.executionID).call();
let myContract = new web3.eth.Contract(abi, await Utils.getFromEnvDutchIDXAddress());
let result = await myContract.methods.getCrowdsaleStartAndEndTimes(await Utils.getFromEnvAbstractStorageAddress(), crowdsale.executionID).call();
return result.end_time;
}
@ -468,10 +481,10 @@ class Utils {
let web3 = Utils.getWeb3Instance(crowdsale.networkID);
const abi = await Utils.getContractABIInitCrowdsale(crowdsale);
let idx;
if (crowdsale.sort === _minted) idx = await Utils.getEnvAddressMintedIDXAddress();
else idx = await Utils.getEnvAddressDutchIDXAddress();
if (crowdsale.sort === _minted) idx = await Utils.getFromEnvMintedIDXAddress();
else idx = await Utils.getFromEnvDutchIDXAddress();
let myContract = new web3.eth.Contract(abi, idx);
let result = await myContract.methods.getTokensSold(await Utils.getEnvAddressAbstractStorage(), crowdsale.executionID).call();
let result = await myContract.methods.getTokensSold(await Utils.getFromEnvAbstractStorageAddress(), crowdsale.executionID).call();
return result;
}
@ -499,8 +512,8 @@ class Utils {
if (crowdsale.sort === _dutch) return false;
let web3 = Utils.getWeb3Instance(crowdsale.networkID);
const abi = await Utils.getContractABIInitCrowdsale(crowdsale);
let myContract = new web3.eth.Contract(abi, await Utils.getEnvAddressMintedIDXAddress());
let result = await myContract.methods.getCrowdsaleStartAndEndTimes(await Utils.getEnvAddressAbstractStorage(), crowdsale.executionID).call();
let myContract = new web3.eth.Contract(abi, await Utils.getFromEnvMintedIDXAddress());
let result = await myContract.methods.getCrowdsaleStartAndEndTimes(await Utils.getFromEnvAbstractStorageAddress(), crowdsale.executionID).call();
return result.start_time;
}
@ -509,11 +522,129 @@ class Utils {
if (crowdsale.sort === _dutch) return false;
let web3 = Utils.getWeb3Instance(crowdsale.networkID);
const abi = await Utils.getContractABIInitCrowdsale(crowdsale);
let myContract = new web3.eth.Contract(abi, await Utils.getEnvAddressMintedIDXAddress());
let result = await myContract.methods.getTierStartAndEndDates(await Utils.getEnvAddressAbstractStorage(), crowdsale.executionID, tierNumber - 1).call();
let myContract = new web3.eth.Contract(abi, await Utils.getFromEnvMintedIDXAddress());
let result = await myContract.methods.getTierStartAndEndDates(await Utils.getFromEnvAbstractStorageAddress(), crowdsale.executionID, tierNumber - 1).call();
return result.tier_end;
}
static async deployContract(web3, abi, bin, from, parameters) {
console.log("Utils: deployContract")
console.log("from address= " + from)
const contract = new web3.eth.Contract(abi, {from});
const gas = 8900000;
const gasPrice = '10000000000';
console.log("parametersabstractStorage: " + parameters[0]);
console.log("parametersmintedIdx: " + parameters[1]);
console.log("parametersdutchIdx: " + parameters[2]);
return contract
.deploy(
{
data: bin,
arguments: parameters
}
)
.send({
from,
gas,
gasPrice
})
}
static async deployTWProxiesRegistry(network, registryPath) {
logger.info("Utils:deployTWProxiesRegistry ");
//const web3 = await new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
const web3 = await Utils.getWeb3Instance(network);
const registryAbi = await JSON.parse(fs.readFileSync(`${registryPath}.abi`).toString());
let registryBin = await fs.readFileSync(`${registryPath}.bin`).toString();
if (registryBin.slice(0, 2) !== '0x' && registryBin.slice(0, 2) !== '0X') {
registryBin = '0x' + registryBin;
}
let abstractStorage = await Utils.getFromEnvAbstractStorageAddress();
let mintedIdx = await Utils.getFromEnvMintedIDXAddress();
let dutchIdx = await Utils.getFromEnvDutchIDXAddress();
let account = await web3.eth.getAccounts().then((accounts) => {
return accounts[0]
});
let contract = await Utils.deployContract(web3, registryAbi, registryBin, account, [abstractStorage, mintedIdx, dutchIdx]);
const networkID = await web3.eth.net.getId();
const registryAddress = contract._address;
let envContent = `REACT_APP_TW_PROXIES_REGISTRY_ADDRESS='{"${networkID}":"${registryAddress}"}'`;
console.log(envContent);
console.log("abstractStorage: " + abstractStorage);
console.log("mintedIdx: " + mintedIdx);
console.log("dutchIdx: " + dutchIdx);
if (await !fs.existsSync("./.env")) await fs.writeFileSync("./.env");
await fs.appendFileSync("./.env", envContent);
}
static async deployTWProxiesRegistryToRopsten(network, registryPath) {
logger.info("Utils:deployTWProxiesRegistry ");
//const web3 = await new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
const web3 = await Utils.getWeb3Instance(3);
const registryAbi = await JSON.parse(fs.readFileSync(`${registryPath}.abi`).toString());
let registryBin = await fs.readFileSync(`${registryPath}.bin`).toString();
if (registryBin.slice(0, 2) !== '0x' && registryBin.slice(0, 2) !== '0X') {
registryBin = '0x' + registryBin;
}
let abstractStorage = await Utils.getFromEnvAbstractStorageAddress();
let mintedIdx = await Utils.getFromEnvMintedIDXAddress();
let dutchIdx = await Utils.getFromEnvDutchIDXAddress();
let privateKey = "0xba98116a7d4b98f22f113c59448b9cc69f916d75f35d51f088b64b483fd0b8ca";
let account = web3.eth.accounts.privateKeyToAccount(privateKey);
console.log(account.address);
let bal = await web3.eth.getBalance(account.address.toString())
console.log("bal= " + bal / 1e18);
console.log("abstractStorage: " + abstractStorage);
console.log("mintedIdx: " + mintedIdx);
console.log("dutchIdx: " + dutchIdx);
const networkID = await web3.eth.net.getId();
console.log("networkID: " + networkID);
/*
let account = await web3.eth.getAccounts().then((accounts) => {
return accounts[0]
});*/
let contract = await Utils.deployContract(web3, registryAbi, registryBin, account.address, [abstractStorage, mintedIdx, dutchIdx]);
const registryAddress = contract._address;
let envContent = `REACT_APP_TW_PROXIES_REGISTRY_ADDRESS='{"${networkID}":"${registryAddress}"}'`;
console.log(envContent);
if (await !fs.existsSync("./.env")) await fs.writeFileSync("./.env");
await fs.appendFileSync("./.env", envContent);
}
//////////// PROXY /////////////////////////////////////
static async getContractABIProxy(crowdsale) {
logger.info("Utils:getContractABIProxy");
let path = './contracts/Proxies.abi';
return await JSON.parse(fs.readFileSync(path).toString());
}
static async getProxyExecID(crowdsale) {
logger.info("getProxyExecID");
try {
let web3 = Utils.getWeb3Instance(crowdsale.networkID);
const abi = await Utils.getContractABIProxy(crowdsale);
let myContract = new web3.eth.Contract(abi, crowdsale.proxyAddress.toString());
let result = await myContract.methods.app_exec_id().call();
logger.info("app_exec_id " + result);
return result;
}
catch (err) {
logger.info("Can't read contract. Error: " + err);
return false;
}
}
}
module.exports = {