/** * Source Code first verified at https://etherscan.io on Wednesday, March 20, 2019 (UTC) */ pragma solidity ^0.4.24; interface IBoot { /** * @notice This function returns the signature of configure function * @return bytes4 Configure function signature */ function getInitFunction() external pure returns(bytes4); } /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ interface IERC20 { function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address _owner) external view returns (uint256); function allowance(address _owner, address _spender) external view returns (uint256); function transfer(address _to, uint256 _value) external returns (bool); function transferFrom(address _from, address _to, uint256 _value) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool); function decreaseApproval(address _spender, uint _subtractedValue) external returns (bool); function increaseApproval(address _spender, uint _addedValue) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } /** * @title Contract used to store layout for the USDTieredSTO storage */ contract USDTieredSTOStorage { ///////////// // Storage // ///////////// struct Tier { // NB rates mentioned below are actually price and are used like price in the logic. // How many token units a buyer gets per USD in this tier (multiplied by 10**18) uint256 rate; // How many token units a buyer gets per USD in this tier (multiplied by 10**18) when investing in POLY up to tokensDiscountPoly uint256 rateDiscountPoly; // How many tokens are available in this tier (relative to totalSupply) uint256 tokenTotal; // How many token units are available in this tier (relative to totalSupply) at the ratePerTierDiscountPoly rate uint256 tokensDiscountPoly; // How many tokens have been minted in this tier (relative to totalSupply) uint256 mintedTotal; // How many tokens have been minted in this tier (relative to totalSupply) for each fund raise type mapping (uint8 => uint256) minted; // How many tokens have been minted in this tier (relative to totalSupply) at discounted POLY rate uint256 mintedDiscountPoly; } struct Investor { // Whether investor is accredited (0 = non-accredited, 1 = accredited) uint8 accredited; // Whether we have seen the investor before (already added to investors list) uint8 seen; // Overrides for default limit in USD for non-accredited investors multiplied by 10**18 (0 = no override) uint256 nonAccreditedLimitUSDOverride; } mapping (bytes32 => mapping (bytes32 => string)) oracleKeys; // Determine whether users can invest on behalf of a beneficiary bool public allowBeneficialInvestments = false; // Whether or not the STO has been finalized bool public isFinalized; // Address of issuer reserve wallet for unsold tokens address public reserveWallet; // List of stable coin addresses address[] public usdTokens; // Current tier uint256 public currentTier; // Amount of USD funds raised uint256 public fundsRaisedUSD; // Amount of stable coins raised mapping (address => uint256) public stableCoinsRaised; // Amount in USD invested by each address mapping (address => uint256) public investorInvestedUSD; // Amount in fund raise type invested by each investor mapping (address => mapping (uint8 => uint256)) public investorInvested; // Accredited & non-accredited investor data mapping (address => Investor) public investors; // List of active stable coin addresses mapping (address => bool) public usdTokenEnabled; // List of all addresses that have been added as accredited or non-accredited without // the default limit address[] public investorsList; // Default limit in USD for non-accredited investors multiplied by 10**18 uint256 public nonAccreditedLimitUSD; // Minimum investable amount in USD uint256 public minimumInvestmentUSD; // Final amount of tokens returned to issuer uint256 public finalAmountReturned; // Array of Tiers Tier[] public tiers; } /** * @title Proxy * @dev Gives the possibility to delegate any call to a foreign implementation. */ contract Proxy { /** * @dev Tells the address of the implementation where every call will be delegated. * @return address of the implementation to which it will be delegated */ function _implementation() internal view returns (address); /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function _fallback() internal { _delegate(_implementation()); } /** * @dev Fallback function allowing to perform a delegatecall to the given implementation. * This function will return whatever the implementation call returns */ function _delegate(address implementation) internal { /*solium-disable-next-line security/no-inline-assembly*/ assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } function () public payable { _fallback(); } } /** * @title OwnedProxy * @dev This contract combines an upgradeability proxy with basic authorization control functionalities */ contract OwnedProxy is Proxy { // Owner of the contract address private __owner; // Address of the current implementation address internal __implementation; /** * @dev Event to show ownership has been transferred * @param _previousOwner representing the address of the previous owner * @param _newOwner representing the address of the new owner */ event ProxyOwnershipTransferred(address _previousOwner, address _newOwner); /** * @dev Throws if called by any account other than the owner. */ modifier ifOwner() { if (msg.sender == _owner()) { _; } else { _fallback(); } } /** * @dev the constructor sets the original owner of the contract to the sender account. */ constructor() public { _setOwner(msg.sender); } /** * @dev Tells the address of the owner * @return the address of the owner */ function _owner() internal view returns (address) { return __owner; } /** * @dev Sets the address of the owner */ function _setOwner(address _newOwner) internal { require(_newOwner != address(0), "Address should not be 0x"); __owner = _newOwner; } /** * @notice Internal function to provide the address of the implementation contract */ function _implementation() internal view returns (address) { return __implementation; } /** * @dev Tells the address of the proxy owner * @return the address of the proxy owner */ function proxyOwner() external ifOwner returns (address) { return _owner(); } /** * @dev Tells the address of the current implementation * @return address of the current implementation */ function implementation() external ifOwner returns (address) { return _implementation(); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function transferProxyOwnership(address _newOwner) external ifOwner { require(_newOwner != address(0), "Address should not be 0x"); emit ProxyOwnershipTransferred(_owner(), _newOwner); _setOwner(_newOwner); } } /** * @title Utility contract to allow pausing and unpausing of certain functions */ contract Pausable { event Pause(uint256 _timestammp); event Unpause(uint256 _timestamp); bool public paused = false; /** * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!paused, "Contract is paused"); _; } /** * @notice Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(paused, "Contract is not paused"); _; } /** * @notice Called by the owner to pause, triggers stopped state */ function _pause() internal whenNotPaused { paused = true; /*solium-disable-next-line security/no-block-members*/ emit Pause(now); } /** * @notice Called by the owner to unpause, returns to normal state */ function _unpause() internal whenPaused { paused = false; /*solium-disable-next-line security/no-block-members*/ emit Unpause(now); } } /** * @title Helps contracts guard agains reentrancy attacks. * @author Remco Bloemen <[email protected]π.com> * @notice If you mark a function `nonReentrant`, you should also * mark it `external`. */ contract ReentrancyGuard { /** * @dev We use a single lock for the whole contract. */ bool private reentrancyLock = false; /** * @dev Prevents a contract from calling itself, directly or indirectly. * @notice If you mark a function `nonReentrant`, you should also * mark it `external`. Calling one nonReentrant function from * another is not supported. Instead, you can implement a * `private` function doing the actual work, and a `external` * wrapper marked as `nonReentrant`. */ modifier nonReentrant() { require(!reentrancyLock); reentrancyLock = true; _; reentrancyLock = false; } } /** * @title Storage layout for the STO contract */ contract STOStorage { mapping (uint8 => bool) public fundRaiseTypes; mapping (uint8 => uint256) public fundsRaised; // Start time of the STO uint256 public startTime; // End time of the STO uint256 public endTime; // Time STO was paused uint256 public pausedTime; // Number of individual investors uint256 public investorCount; // Address where ETH & POLY funds are delivered address public wallet; // Final amount of tokens sold uint256 public totalTokensSold; } /** * @title Storage for Module contract * @notice Contract is abstract */ contract ModuleStorage { /** * @notice Constructor * @param _securityToken Address of the security token * @param _polyAddress Address of the polytoken */ constructor (address _securityToken, address _polyAddress) public { securityToken = _securityToken; factory = msg.sender; polyToken = IERC20(_polyAddress); } address public factory; address public securityToken; bytes32 public constant FEE_ADMIN = "FEE_ADMIN"; IERC20 public polyToken; } /** * @title USDTiered STO module Proxy */ contract USDTieredSTOProxy is USDTieredSTOStorage, STOStorage, ModuleStorage, Pausable, ReentrancyGuard, OwnedProxy { /** * @notice Constructor * @param _securityToken Address of the security token * @param _polyAddress Address of the polytoken * @param _implementation representing the address of the new implementation to be set */ constructor (address _securityToken, address _polyAddress, address _implementation) public ModuleStorage(_securityToken, _polyAddress) { require( _implementation != address(0), "Implementation address should not be 0x" ); __implementation = _implementation; } } /** * @title Interface that every module factory contract should implement */ interface IModuleFactory { event ChangeFactorySetupFee(uint256 _oldSetupCost, uint256 _newSetupCost, address _moduleFactory); event ChangeFactoryUsageFee(uint256 _oldUsageCost, uint256 _newUsageCost, address _moduleFactory); event ChangeFactorySubscriptionFee(uint256 _oldSubscriptionCost, uint256 _newMonthlySubscriptionCost, address _moduleFactory); event GenerateModuleFromFactory( address _module, bytes32 indexed _moduleName, address indexed _moduleFactory, address _creator, uint256 _setupCost, uint256 _timestamp ); event ChangeSTVersionBound(string _boundType, uint8 _major, uint8 _minor, uint8 _patch); //Should create an instance of the Module, or throw function deploy(bytes _data) external returns(address); /** * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]); /** * @notice Get the name of the Module */ function getName() external view returns(bytes32); /** * @notice Returns the instructions associated with the module */ function getInstructions() external view returns (string); /** * @notice Get the tags related to the module factory */ function getTags() external view returns (bytes32[]); /** * @notice Used to change the setup fee * @param _newSetupCost New setup fee */ function changeFactorySetupFee(uint256 _newSetupCost) external; /** * @notice Used to change the usage fee * @param _newUsageCost New usage fee */ function changeFactoryUsageFee(uint256 _newUsageCost) external; /** * @notice Used to change the subscription fee * @param _newSubscriptionCost New subscription fee */ function changeFactorySubscriptionFee(uint256 _newSubscriptionCost) external; /** * @notice Function use to change the lower and upper bound of the compatible version st * @param _boundType Type of bound * @param _newVersion New version array */ function changeSTVersionBounds(string _boundType, uint8[] _newVersion) external; /** * @notice Get the setup cost of the module */ function getSetupCost() external view returns (uint256); /** * @notice Used to get the lower bound * @return Lower bound */ function getLowerSTVersionBounds() external view returns(uint8[]); /** * @notice Used to get the upper bound * @return Upper bound */ function getUpperSTVersionBounds() external view returns(uint8[]); } /** * @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. */ 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; } } /** * @title Helper library use to compare or validate the semantic versions */ library VersionUtils { /** * @notice This function is used to validate the version submitted * @param _current Array holds the present version of ST * @param _new Array holds the latest version of the ST * @return bool */ function isValidVersion(uint8[] _current, uint8[] _new) internal pure returns(bool) { bool[] memory _temp = new bool[](_current.length); uint8 counter = 0; for (uint8 i = 0; i < _current.length; i++) { if (_current[i] < _new[i]) _temp[i] = true; else _temp[i] = false; } for (i = 0; i < _current.length; i++) { if (i == 0) { if (_current[i] <= _new[i]) if(_temp[0]) { counter = counter + 3; break; } else counter++; else return false; } else { if (_temp[i-1]) counter++; else if (_current[i] <= _new[i]) counter++; else return false; } } if (counter == _current.length) return true; } /** * @notice Used to compare the lower bound with the latest version * @param _version1 Array holds the lower bound of the version * @param _version2 Array holds the latest version of the ST * @return bool */ function compareLowerBound(uint8[] _version1, uint8[] _version2) internal pure returns(bool) { require(_version1.length == _version2.length, "Input length mismatch"); uint counter = 0; for (uint8 j = 0; j < _version1.length; j++) { if (_version1[j] == 0) counter ++; } if (counter != _version1.length) { counter = 0; for (uint8 i = 0; i < _version1.length; i++) { if (_version2[i] > _version1[i]) return true; else if (_version2[i] < _version1[i]) return false; else counter++; } if (counter == _version1.length - 1) return true; else return false; } else return true; } /** * @notice Used to compare the upper bound with the latest version * @param _version1 Array holds the upper bound of the version * @param _version2 Array holds the latest version of the ST * @return bool */ function compareUpperBound(uint8[] _version1, uint8[] _version2) internal pure returns(bool) { require(_version1.length == _version2.length, "Input length mismatch"); uint counter = 0; for (uint8 j = 0; j < _version1.length; j++) { if (_version1[j] == 0) counter ++; } if (counter != _version1.length) { counter = 0; for (uint8 i = 0; i < _version1.length; i++) { if (_version1[i] > _version2[i]) return true; else if (_version1[i] < _version2[i]) return false; else counter++; } if (counter == _version1.length - 1) return true; else return false; } else return true; } /** * @notice Used to pack the uint8[] array data into uint24 value * @param _major Major version * @param _minor Minor version * @param _patch Patch version */ function pack(uint8 _major, uint8 _minor, uint8 _patch) internal pure returns(uint24) { return (uint24(_major) << 16) | (uint24(_minor) << 8) | uint24(_patch); } /** * @notice Used to convert packed data into uint8 array * @param _packedVersion Packed data */ function unpack(uint24 _packedVersion) internal pure returns (uint8[]) { uint8[] memory _unpackVersion = new uint8[](3); _unpackVersion[0] = uint8(_packedVersion >> 16); _unpackVersion[1] = uint8(_packedVersion >> 8); _unpackVersion[2] = uint8(_packedVersion); return _unpackVersion; } } /** * @title Interface that any module factory contract should implement * @notice Contract is abstract */ contract ModuleFactory is IModuleFactory, Ownable { IERC20 public polyToken; uint256 public usageCost; uint256 public monthlySubscriptionCost; uint256 public setupCost; string public description; string public version; bytes32 public name; string public title; // @notice Allow only two variables to be stored // 1. lowerBound // 2. upperBound // @dev (0.0.0 will act as the wildcard) // @dev uint24 consists packed value of uint8 _major, uint8 _minor, uint8 _patch mapping(string => uint24) compatibleSTVersionRange; /** * @notice Constructor * @param _polyAddress Address of the polytoken */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public { polyToken = IERC20(_polyAddress); setupCost = _setupCost; usageCost = _usageCost; monthlySubscriptionCost = _subscriptionCost; } /** * @notice Used to change the fee of the setup cost * @param _newSetupCost new setup cost */ function changeFactorySetupFee(uint256 _newSetupCost) public onlyOwner { emit ChangeFactorySetupFee(setupCost, _newSetupCost, address(this)); setupCost = _newSetupCost; } /** * @notice Used to change the fee of the usage cost * @param _newUsageCost new usage cost */ function changeFactoryUsageFee(uint256 _newUsageCost) public onlyOwner { emit ChangeFactoryUsageFee(usageCost, _newUsageCost, address(this)); usageCost = _newUsageCost; } /** * @notice Used to change the fee of the subscription cost * @param _newSubscriptionCost new subscription cost */ function changeFactorySubscriptionFee(uint256 _newSubscriptionCost) public onlyOwner { emit ChangeFactorySubscriptionFee(monthlySubscriptionCost, _newSubscriptionCost, address(this)); monthlySubscriptionCost = _newSubscriptionCost; } /** * @notice Updates the title of the ModuleFactory * @param _newTitle New Title that will replace the old one. */ function changeTitle(string _newTitle) public onlyOwner { require(bytes(_newTitle).length > 0, "Invalid title"); title = _newTitle; } /** * @notice Updates the description of the ModuleFactory * @param _newDesc New description that will replace the old one. */ function changeDescription(string _newDesc) public onlyOwner { require(bytes(_newDesc).length > 0, "Invalid description"); description = _newDesc; } /** * @notice Updates the name of the ModuleFactory * @param _newName New name that will replace the old one. */ function changeName(bytes32 _newName) public onlyOwner { require(_newName != bytes32(0),"Invalid name"); name = _newName; } /** * @notice Updates the version of the ModuleFactory * @param _newVersion New name that will replace the old one. */ function changeVersion(string _newVersion) public onlyOwner { require(bytes(_newVersion).length > 0, "Invalid version"); version = _newVersion; } /** * @notice Function use to change the lower and upper bound of the compatible version st * @param _boundType Type of bound * @param _newVersion new version array */ function changeSTVersionBounds(string _boundType, uint8[] _newVersion) external onlyOwner { require( keccak256(abi.encodePacked(_boundType)) == keccak256(abi.encodePacked("lowerBound")) || keccak256(abi.encodePacked(_boundType)) == keccak256(abi.encodePacked("upperBound")), "Must be a valid bound type" ); require(_newVersion.length == 3); if (compatibleSTVersionRange[_boundType] != uint24(0)) { uint8[] memory _currentVersion = VersionUtils.unpack(compatibleSTVersionRange[_boundType]); require(VersionUtils.isValidVersion(_currentVersion, _newVersion), "Failed because of in-valid version"); } compatibleSTVersionRange[_boundType] = VersionUtils.pack(_newVersion[0], _newVersion[1], _newVersion[2]); emit ChangeSTVersionBound(_boundType, _newVersion[0], _newVersion[1], _newVersion[2]); } /** * @notice Used to get the lower bound * @return lower bound */ function getLowerSTVersionBounds() external view returns(uint8[]) { return VersionUtils.unpack(compatibleSTVersionRange["lowerBound"]); } /** * @notice Used to get the upper bound * @return upper bound */ function getUpperSTVersionBounds() external view returns(uint8[]) { return VersionUtils.unpack(compatibleSTVersionRange["upperBound"]); } /** * @notice Get the setup cost of the module */ function getSetupCost() external view returns (uint256) { return setupCost; } /** * @notice Get the name of the Module */ function getName() public view returns(bytes32) { return name; } } /** * @title Utility contract for reusable code */ library Util { /** * @notice Changes a string to upper case * @param _base String to change */ function upper(string _base) internal pure returns (string) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { bytes1 b1 = _baseBytes[i]; if (b1 >= 0x61 && b1 <= 0x7A) { b1 = bytes1(uint8(b1)-32); } _baseBytes[i] = b1; } return string(_baseBytes); } /** * @notice Changes the string into bytes32 * @param _source String that need to convert into bytes32 */ /// Notice - Maximum Length for _source will be 32 chars otherwise returned bytes32 value will have lossy value. function stringToBytes32(string memory _source) internal pure returns (bytes32) { return bytesToBytes32(bytes(_source), 0); } /** * @notice Changes bytes into bytes32 * @param _b Bytes that need to convert into bytes32 * @param _offset Offset from which to begin conversion */ /// Notice - Maximum length for _source will be 32 chars otherwise returned bytes32 value will have lossy value. function bytesToBytes32(bytes _b, uint _offset) internal pure returns (bytes32) { bytes32 result; for (uint i = 0; i < _b.length; i++) { result |= bytes32(_b[_offset + i] & 0xFF) >> (i * 8); } return result; } /** * @notice Changes the bytes32 into string * @param _source that need to convert into string */ function bytes32ToString(bytes32 _source) internal pure returns (string result) { bytes memory bytesString = new bytes(32); uint charCount = 0; for (uint j = 0; j < 32; j++) { byte char = byte(bytes32(uint(_source) * 2 ** (8 * j))); if (char != 0) { bytesString[charCount] = char; charCount++; } } bytes memory bytesStringTrimmed = new bytes(charCount); for (j = 0; j < charCount; j++) { bytesStringTrimmed[j] = bytesString[j]; } return string(bytesStringTrimmed); } /** * @notice Gets function signature from _data * @param _data Passed data * @return bytes4 sig */ function getSig(bytes _data) internal pure returns (bytes4 sig) { uint len = _data.length < 4 ? _data.length : 4; for (uint i = 0; i < len; i++) { sig = bytes4(uint(sig) + uint(_data[i]) * (2 ** (8 * (len - 1 - i)))); } } } /** * @title Factory for deploying CappedSTO module */ contract USDTieredSTOFactory is ModuleFactory { address public logicContract; /** * @notice Constructor * @param _polyAddress Address of the polytoken */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { require(_logicContract != address(0), "0x address is not allowed"); logicContract = _logicContract; version = "2.1.0"; name = "USDTieredSTO"; title = "USD Tiered STO"; /*solium-disable-next-line max-len*/ description = "It allows both accredited and non-accredited investors to contribute into the STO. Non-accredited investors will be capped at a maximum investment limit (as a default or specific to their jurisdiction). Tokens will be sold according to tiers sequentially & each tier has its own price and volume of tokens to sell. Upon receipt of funds (ETH, POLY or DAI), security tokens will automatically transfer to investor’s wallet address"; compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); } /** * @notice Used to launch the Module with the help of factory * @return address Contract address of the Module */ function deploy(bytes _data) external returns(address) { if(setupCost > 0) require(polyToken.transferFrom(msg.sender, owner, setupCost), "Sufficent Allowance is not provided"); //Check valid bytes - can only call module init function address usdTieredSTO = new USDTieredSTOProxy(msg.sender, address(polyToken), logicContract); //Checks that _data is valid (not calling anything it shouldn't) require(Util.getSig(_data) == IBoot(usdTieredSTO).getInitFunction(), "Invalid data"); /*solium-disable-next-line security/no-low-level-calls*/ require(usdTieredSTO.call(_data), "Unsuccessfull call"); /*solium-disable-next-line security/no-block-members*/ emit GenerateModuleFromFactory(usdTieredSTO, getName(), address(this), msg.sender, setupCost, now); return usdTieredSTO; } /** * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { uint8[] memory res = new uint8[](1); res[0] = 3; return res; } /** * @notice Returns the instructions associated with the module */ function getInstructions() external view returns(string) { return "Initialises a USD tiered STO."; } /** * @notice Get the tags related to the module factory */ function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](4); availableTags[0] = "USD"; availableTags[1] = "Tiered"; availableTags[2] = "POLY"; availableTags[3] = "ETH"; return availableTags; } }