pragma solidity ^0.4.24;
/**
* @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 Interface that every module contract should implement
*/
interface IModule {
/**
* @notice This function returns the signature of configure function
*/
function getInitFunction() external pure returns (bytes4);
/**
* @notice Return the permission flags that are associated with a module
*/
function getPermissions() external view returns(bytes32[]);
/**
* @notice Used to withdraw the fee by the factory owner
*/
function takeFee(uint256 _amount) external returns(bool);
}
/**
* @title Interface for all security tokens
*/
interface ISecurityToken {
// Standard ERC20 interface
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);
//transfer, transferFrom must respect the result of verifyTransfer
function verifyTransfer(address _from, address _to, uint256 _value) external returns (bool success);
/**
* @notice Mints new tokens and assigns them to the target _investor.
* Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet)
* @param _investor Address the tokens will be minted to
* @param _value is the amount of tokens that will be minted to the investor
*/
function mint(address _investor, uint256 _value) external returns (bool success);
/**
* @notice Mints new tokens and assigns them to the target _investor.
* Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet)
* @param _investor Address the tokens will be minted to
* @param _value is The amount of tokens that will be minted to the investor
* @param _data Data to indicate validation
*/
function mintWithData(address _investor, uint256 _value, bytes _data) external returns (bool success);
/**
* @notice Used to burn the securityToken on behalf of someone else
* @param _from Address for whom to burn tokens
* @param _value No. of tokens to be burned
* @param _data Data to indicate validation
*/
function burnFromWithData(address _from, uint256 _value, bytes _data) external;
/**
* @notice Used to burn the securityToken
* @param _value No. of tokens to be burned
* @param _data Data to indicate validation
*/
function burnWithData(uint256 _value, bytes _data) external;
event Minted(address indexed _to, uint256 _value);
event Burnt(address indexed _burner, uint256 _value);
// Permissions this to a Permission module, which has a key of 1
// If no Permission return false - note that IModule withPerm will allow ST owner all permissions anyway
// this allows individual modules to override this logic if needed (to not allow ST owner all permissions)
function checkPermission(address _delegate, address _module, bytes32 _perm) external view returns (bool);
/**
* @notice Returns module list for a module type
* @param _module Address of the module
* @return bytes32 Name
* @return address Module address
* @return address Module factory address
* @return bool Module archived
* @return uint8 Module type
* @return uint256 Module index
* @return uint256 Name index
*/
function getModule(address _module) external view returns(bytes32, address, address, bool, uint8, uint256, uint256);
/**
* @notice Returns module list for a module name
* @param _name Name of the module
* @return address[] List of modules with this name
*/
function getModulesByName(bytes32 _name) external view returns (address[]);
/**
* @notice Returns module list for a module type
* @param _type Type of the module
* @return address[] List of modules with this type
*/
function getModulesByType(uint8 _type) external view returns (address[]);
/**
* @notice Queries totalSupply at a specified checkpoint
* @param _checkpointId Checkpoint ID to query as of
*/
function totalSupplyAt(uint256 _checkpointId) external view returns (uint256);
/**
* @notice Queries balance at a specified checkpoint
* @param _investor Investor to query balance for
* @param _checkpointId Checkpoint ID to query as of
*/
function balanceOfAt(address _investor, uint256 _checkpointId) external view returns (uint256);
/**
* @notice Creates a checkpoint that can be used to query historical balances / totalSuppy
*/
function createCheckpoint() external returns (uint256);
/**
* @notice Gets length of investors array
* NB - this length may differ from investorCount if the list has not been pruned of zero-balance investors
* @return Length
*/
function getInvestors() external view returns (address[]);
/**
* @notice returns an array of investors at a given checkpoint
* NB - this length may differ from investorCount as it contains all investors that ever held tokens
* @param _checkpointId Checkpoint id at which investor list is to be populated
* @return list of investors
*/
function getInvestorsAt(uint256 _checkpointId) external view returns(address[]);
/**
* @notice generates subset of investors
* NB - can be used in batches if investor list is large
* @param _start Position of investor to start iteration from
* @param _end Position of investor to stop iteration at
* @return list of investors
*/
function iterateInvestors(uint256 _start, uint256 _end) external view returns(address[]);
/**
* @notice Gets current checkpoint ID
* @return Id
*/
function currentCheckpointId() external view returns (uint256);
/**
* @notice Gets an investor at a particular index
* @param _index Index to return address from
* @return Investor address
*/
function investors(uint256 _index) external view returns (address);
/**
* @notice Allows the owner to withdraw unspent POLY stored by them on the ST or any ERC20 token.
* @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee.
* @param _tokenContract Address of the ERC20Basic compliance token
* @param _value Amount of POLY to withdraw
*/
function withdrawERC20(address _tokenContract, uint256 _value) external;
/**
* @notice Allows owner to approve more POLY to one of the modules
* @param _module Module address
* @param _budget New budget
*/
function changeModuleBudget(address _module, uint256 _budget) external;
/**
* @notice Changes the tokenDetails
* @param _newTokenDetails New token details
*/
function updateTokenDetails(string _newTokenDetails) external;
/**
* @notice Allows the owner to change token granularity
* @param _granularity Granularity level of the token
*/
function changeGranularity(uint256 _granularity) external;
/**
* @notice Removes addresses with zero balances from the investors list
* @param _start Index in investors list at which to start removing zero balances
* @param _iters Max number of iterations of the for loop
* NB - pruning this list will mean you may not be able to iterate over investors on-chain as of a historical checkpoint
*/
function pruneInvestors(uint256 _start, uint256 _iters) external;
/**
* @notice Freezes all the transfers
*/
function freezeTransfers() external;
/**
* @notice Un-freezes all the transfers
*/
function unfreezeTransfers() external;
/**
* @notice Ends token minting period permanently
*/
function freezeMinting() external;
/**
* @notice Mints new tokens and assigns them to the target investors.
* Can only be called by the STO attached to the token or by the Issuer (Security Token contract owner)
* @param _investors A list of addresses to whom the minted tokens will be delivered
* @param _values A list of the amount of tokens to mint to corresponding addresses from _investor[] list
* @return Success
*/
function mintMulti(address[] _investors, uint256[] _values) external returns (bool success);
/**
* @notice Function used to attach a module to the security token
* @dev E.G.: On deployment (through the STR) ST gets a TransferManager module attached to it
* @dev to control restrictions on transfers.
* @dev You are allowed to add a new moduleType if:
* @dev - there is no existing module of that type yet added
* @dev - the last member of the module list is replacable
* @param _moduleFactory is the address of the module factory to be added
* @param _data is data packed into bytes used to further configure the module (See STO usage)
* @param _maxCost max amount of POLY willing to pay to module. (WIP)
*/
function addModule(
address _moduleFactory,
bytes _data,
uint256 _maxCost,
uint256 _budget
) external;
/**
* @notice Archives a module attached to the SecurityToken
* @param _module address of module to archive
*/
function archiveModule(address _module) external;
/**
* @notice Unarchives a module attached to the SecurityToken
* @param _module address of module to unarchive
*/
function unarchiveModule(address _module) external;
/**
* @notice Removes a module attached to the SecurityToken
* @param _module address of module to archive
*/
function removeModule(address _module) external;
/**
* @notice Used by the issuer to set the controller addresses
* @param _controller address of the controller
*/
function setController(address _controller) external;
/**
* @notice Used by a controller to execute a forced transfer
* @param _from address from which to take tokens
* @param _to address where to send tokens
* @param _value amount of tokens to transfer
* @param _data data to indicate validation
* @param _log data attached to the transfer by controller to emit in event
*/
function forceTransfer(address _from, address _to, uint256 _value, bytes _data, bytes _log) external;
/**
* @notice Used by a controller to execute a foced burn
* @param _from address from which to take tokens
* @param _value amount of tokens to transfer
* @param _data data to indicate validation
* @param _log data attached to the transfer by controller to emit in event
*/
function forceBurn(address _from, uint256 _value, bytes _data, bytes _log) external;
/**
* @notice Used by the issuer to permanently disable controller functionality
* @dev enabled via feature switch "disableControllerAllowed"
*/
function disableController() external;
/**
* @notice Used to get the version of the securityToken
*/
function getVersion() external view returns(uint8[]);
/**
* @notice Gets the investor count
*/
function getInvestorCount() external view returns(uint256);
/**
* @notice Overloaded version of the transfer function
* @param _to receiver of transfer
* @param _value value of transfer
* @param _data data to indicate validation
* @return bool success
*/
function transferWithData(address _to, uint256 _value, bytes _data) external returns (bool success);
/**
* @notice Overloaded version of the transferFrom function
* @param _from sender of transfer
* @param _to receiver of transfer
* @param _value value of transfer
* @param _data data to indicate validation
* @return bool success
*/
function transferFromWithData(address _from, address _to, uint256 _value, bytes _data) external returns(bool);
/**
* @notice Provides the granularity of the token
* @return uint256
*/
function granularity() external view returns(uint256);
}
/**
* @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 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 Interface that any module contract should implement
* @notice Contract is abstract
*/
contract Module is IModule {
address public factory;
address public securityToken;
bytes32 public constant FEE_ADMIN = "FEE_ADMIN";
IERC20 public polyToken;
/**
* @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);
}
//Allows owner, factory or permissioned delegate
modifier withPerm(bytes32 _perm) {
bool isOwner = msg.sender == Ownable(securityToken).owner();
bool isFactory = msg.sender == factory;
require(isOwner||isFactory||ISecurityToken(securityToken).checkPermission(msg.sender, address(this), _perm), "Permission check failed");
_;
}
modifier onlyOwner {
require(msg.sender == Ownable(securityToken).owner(), "Sender is not owner");
_;
}
modifier onlyFactory {
require(msg.sender == factory, "Sender is not factory");
_;
}
modifier onlyFactoryOwner {
require(msg.sender == Ownable(factory).owner(), "Sender is not factory owner");
_;
}
modifier onlyFactoryOrOwner {
require((msg.sender == Ownable(securityToken).owner()) || (msg.sender == factory), "Sender is not factory or owner");
_;
}
/**
* @notice used to withdraw the fee by the factory owner
*/
function takeFee(uint256 _amount) public withPerm(FEE_ADMIN) returns(bool) {
require(polyToken.transferFrom(securityToken, Ownable(factory).owner(), _amount), "Unable to take fee");
return true;
}
}
/**
* @title Interface to be implemented by all Transfer Manager modules
* @dev abstract contract
*/
contract ITransferManager is Module, Pausable {
//If verifyTransfer returns:
// FORCE_VALID, the transaction will always be valid, regardless of other TM results
// INVALID, then the transfer should not be allowed regardless of other TM results
// VALID, then the transfer is valid for this TM
// NA, then the result from this TM is ignored
enum Result {INVALID, NA, VALID, FORCE_VALID}
function verifyTransfer(address _from, address _to, uint256 _amount, bytes _data, bool _isTransfer) public returns(Result);
function unpause() public onlyOwner {
super._unpause();
}
function pause() public onlyOwner {
super._pause();
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title Transfer Manager module for core transfer validation functionality
*/
contract GeneralTransferManager is ITransferManager {
using SafeMath for uint256;
//Address from which issuances come
address public issuanceAddress = address(0);
//Address which can sign whitelist changes
address public signingAddress = address(0);
bytes32 public constant WHITELIST = "WHITELIST";
bytes32 public constant FLAGS = "FLAGS";
//from and to timestamps that an investor can send / receive tokens respectively
struct TimeRestriction {
uint256 fromTime;
uint256 toTime;
uint256 expiryTime;
bool canBuyFromSTO;
}
// An address can only send / receive tokens once their corresponding uint256 > block.number
// (unless allowAllTransfers == true or allowAllWhitelistTransfers == true)
mapping (address => TimeRestriction) public whitelist;
// Map of used nonces by customer
mapping(address => mapping(uint256 => bool)) public nonceMap;
//If true, there are no transfer restrictions, for any addresses
bool public allowAllTransfers = false;
//If true, time lock is ignored for transfers (address must still be on whitelist)
bool public allowAllWhitelistTransfers = false;
//If true, time lock is ignored for issuances (address must still be on whitelist)
bool public allowAllWhitelistIssuances = true;
//If true, time lock is ignored for burn transactions
bool public allowAllBurnTransfers = false;
// Emit when Issuance address get changed
event ChangeIssuanceAddress(address _issuanceAddress);
// Emit when there is change in the flag variable called allowAllTransfers
event AllowAllTransfers(bool _allowAllTransfers);
// Emit when there is change in the flag variable called allowAllWhitelistTransfers
event AllowAllWhitelistTransfers(bool _allowAllWhitelistTransfers);
// Emit when there is change in the flag variable called allowAllWhitelistIssuances
event AllowAllWhitelistIssuances(bool _allowAllWhitelistIssuances);
// Emit when there is change in the flag variable called allowAllBurnTransfers
event AllowAllBurnTransfers(bool _allowAllBurnTransfers);
// Emit when there is change in the flag variable called signingAddress
event ChangeSigningAddress(address _signingAddress);
// Emit when investor details get modified related to their whitelisting
event ModifyWhitelist(
address _investor,
uint256 _dateAdded,
address _addedBy,
uint256 _fromTime,
uint256 _toTime,
uint256 _expiryTime,
bool _canBuyFromSTO
);
/**
* @notice Constructor
* @param _securityToken Address of the security token
* @param _polyAddress Address of the polytoken
*/
constructor (address _securityToken, address _polyAddress)
public
Module(_securityToken, _polyAddress)
{
}
/**
* @notice This function returns the signature of configure function
*/
function getInitFunction() public pure returns (bytes4) {
return bytes4(0);
}
/**
* @notice Used to change the Issuance Address
* @param _issuanceAddress new address for the issuance
*/
function changeIssuanceAddress(address _issuanceAddress) public withPerm(FLAGS) {
issuanceAddress = _issuanceAddress;
emit ChangeIssuanceAddress(_issuanceAddress);
}
/**
* @notice Used to change the Sigining Address
* @param _signingAddress new address for the signing
*/
function changeSigningAddress(address _signingAddress) public withPerm(FLAGS) {
signingAddress = _signingAddress;
emit ChangeSigningAddress(_signingAddress);
}
/**
* @notice Used to change the flag
true - It refers there are no transfer restrictions, for any addresses
false - It refers transfers are restricted for all addresses.
* @param _allowAllTransfers flag value
*/
function changeAllowAllTransfers(bool _allowAllTransfers) public withPerm(FLAGS) {
allowAllTransfers = _allowAllTransfers;
emit AllowAllTransfers(_allowAllTransfers);
}
/**
* @notice Used to change the flag
true - It refers that time lock is ignored for transfers (address must still be on whitelist)
false - It refers transfers are restricted for all addresses.
* @param _allowAllWhitelistTransfers flag value
*/
function changeAllowAllWhitelistTransfers(bool _allowAllWhitelistTransfers) public withPerm(FLAGS) {
allowAllWhitelistTransfers = _allowAllWhitelistTransfers;
emit AllowAllWhitelistTransfers(_allowAllWhitelistTransfers);
}
/**
* @notice Used to change the flag
true - It refers that time lock is ignored for issuances (address must still be on whitelist)
false - It refers transfers are restricted for all addresses.
* @param _allowAllWhitelistIssuances flag value
*/
function changeAllowAllWhitelistIssuances(bool _allowAllWhitelistIssuances) public withPerm(FLAGS) {
allowAllWhitelistIssuances = _allowAllWhitelistIssuances;
emit AllowAllWhitelistIssuances(_allowAllWhitelistIssuances);
}
/**
* @notice Used to change the flag
true - It allow to burn the tokens
false - It deactivate the burning mechanism.
* @param _allowAllBurnTransfers flag value
*/
function changeAllowAllBurnTransfers(bool _allowAllBurnTransfers) public withPerm(FLAGS) {
allowAllBurnTransfers = _allowAllBurnTransfers;
emit AllowAllBurnTransfers(_allowAllBurnTransfers);
}
/**
* @notice Default implementation of verifyTransfer used by SecurityToken
* If the transfer request comes from the STO, it only checks that the investor is in the whitelist
* If the transfer request comes from a token holder, it checks that:
* a) Both are on the whitelist
* b) Seller's sale lockup period is over
* c) Buyer's purchase lockup is over
* @param _from Address of the sender
* @param _to Address of the receiver
*/
function verifyTransfer(address _from, address _to, uint256 /*_amount*/, bytes /* _data */, bool /* _isTransfer */) public returns(Result) {
if (!paused) {
if (allowAllTransfers) {
//All transfers allowed, regardless of whitelist
return Result.VALID;
}
if (allowAllBurnTransfers && (_to == address(0))) {
return Result.VALID;
}
if (allowAllWhitelistTransfers) {
//Anyone on the whitelist can transfer, regardless of time
return (_onWhitelist(_to) && _onWhitelist(_from)) ? Result.VALID : Result.NA;
}
if (allowAllWhitelistIssuances && _from == issuanceAddress) {
if (!whitelist[_to].canBuyFromSTO && _isSTOAttached()) {
return Result.NA;
}
return _onWhitelist(_to) ? Result.VALID : Result.NA;
}
//Anyone on the whitelist can transfer provided the blocknumber is large enough
/*solium-disable-next-line security/no-block-members*/
return ((_onWhitelist(_from) && whitelist[_from].fromTime <= now) &&
(_onWhitelist(_to) && whitelist[_to].toTime <= now)) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/
}
return Result.NA;
}
/**
* @notice Adds or removes addresses from the whitelist.
* @param _investor is the address to whitelist
* @param _fromTime is the moment when the sale lockup period ends and the investor can freely sell his tokens
* @param _toTime is the moment when the purchase lockup period ends and the investor can freely purchase tokens from others
* @param _expiryTime is the moment till investors KYC will be validated. After that investor need to do re-KYC
* @param _canBuyFromSTO is used to know whether the investor is restricted investor or not.
*/
function modifyWhitelist(
address _investor,
uint256 _fromTime,
uint256 _toTime,
uint256 _expiryTime,
bool _canBuyFromSTO
)
public
withPerm(WHITELIST)
{
//Passing a _time == 0 into this function, is equivalent to removing the _investor from the whitelist
whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO);
/*solium-disable-next-line security/no-block-members*/
emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO);
}
/**
* @notice Adds or removes addresses from the whitelist.
* @param _investors List of the addresses to whitelist
* @param _fromTimes An array of the moment when the sale lockup period ends and the investor can freely sell his tokens
* @param _toTimes An array of the moment when the purchase lockup period ends and the investor can freely purchase tokens from others
* @param _expiryTimes An array of the moment till investors KYC will be validated. After that investor need to do re-KYC
* @param _canBuyFromSTO An array of boolean values
*/
function modifyWhitelistMulti(
address[] _investors,
uint256[] _fromTimes,
uint256[] _toTimes,
uint256[] _expiryTimes,
bool[] _canBuyFromSTO
) public withPerm(WHITELIST) {
require(_investors.length == _fromTimes.length, "Mismatched input lengths");
require(_fromTimes.length == _toTimes.length, "Mismatched input lengths");
require(_toTimes.length == _expiryTimes.length, "Mismatched input lengths");
require(_canBuyFromSTO.length == _toTimes.length, "Mismatched input length");
for (uint256 i = 0; i < _investors.length; i++) {
modifyWhitelist(_investors[i], _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]);
}
}
/**
* @notice Adds or removes addresses from the whitelist - can be called by anyone with a valid signature
* @param _investor is the address to whitelist
* @param _fromTime is the moment when the sale lockup period ends and the investor can freely sell his tokens
* @param _toTime is the moment when the purchase lockup period ends and the investor can freely purchase tokens from others
* @param _expiryTime is the moment till investors KYC will be validated. After that investor need to do re-KYC
* @param _canBuyFromSTO is used to know whether the investor is restricted investor or not.
* @param _validFrom is the time that this signature is valid from
* @param _validTo is the time that this signature is valid until
* @param _nonce nonce of signature (avoid replay attack)
* @param _v issuer signature
* @param _r issuer signature
* @param _s issuer signature
*/
function modifyWhitelistSigned(
address _investor,
uint256 _fromTime,
uint256 _toTime,
uint256 _expiryTime,
bool _canBuyFromSTO,
uint256 _validFrom,
uint256 _validTo,
uint256 _nonce,
uint8 _v,
bytes32 _r,
bytes32 _s
) public {
/*solium-disable-next-line security/no-block-members*/
require(_validFrom <= now, "ValidFrom is too early");
/*solium-disable-next-line security/no-block-members*/
require(_validTo >= now, "ValidTo is too late");
require(!nonceMap[_investor][_nonce], "Already used signature");
nonceMap[_investor][_nonce] = true;
bytes32 hash = keccak256(
abi.encodePacked(this, _investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _validFrom, _validTo, _nonce)
);
_checkSig(hash, _v, _r, _s);
//Passing a _time == 0 into this function, is equivalent to removing the _investor from the whitelist
whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO);
/*solium-disable-next-line security/no-block-members*/
emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO);
}
/**
* @notice Used to verify the signature
*/
function _checkSig(bytes32 _hash, uint8 _v, bytes32 _r, bytes32 _s) internal view {
//Check that the signature is valid
//sig should be signing - _investor, _fromTime, _toTime & _expiryTime and be signed by the issuer address
address signer = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)), _v, _r, _s);
require(signer == Ownable(securityToken).owner() || signer == signingAddress, "Incorrect signer");
}
/**
* @notice Internal function used to check whether the investor is in the whitelist or not
& also checks whether the KYC of investor get expired or not
* @param _investor Address of the investor
*/
function _onWhitelist(address _investor) internal view returns(bool) {
return (((whitelist[_investor].fromTime != 0) || (whitelist[_investor].toTime != 0)) &&
(whitelist[_investor].expiryTime >= now)); /*solium-disable-line security/no-block-members*/
}
/**
* @notice Internal function use to know whether the STO is attached or not
*/
function _isSTOAttached() internal view returns(bool) {
bool attached = ISecurityToken(securityToken).getModulesByType(3).length > 0;
return attached;
}
/**
* @notice Return the permissions flag that are associated with general trnasfer manager
*/
function getPermissions() public view returns(bytes32[]) {
bytes32[] memory allPermissions = new bytes32[](2);
allPermissions[0] = WHITELIST;
allPermissions[1] = FLAGS;
return allPermissions;
}
}
{
"compilationTarget": {
"GeneralTransferManager.sol": "GeneralTransferManager"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"_investors","type":"address[]"},{"name":"_fromTimes","type":"uint256[]"},{"name":"_toTimes","type":"uint256[]"},{"name":"_expiryTimes","type":"uint256[]"},{"name":"_canBuyFromSTO","type":"bool[]"}],"name":"modifyWhitelistMulti","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"allowAllBurnTransfers","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitFunction","outputs":[{"name":"","type":"bytes4"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"WHITELIST","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allowAllWhitelistTransfers","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_allowAllTransfers","type":"bool"}],"name":"changeAllowAllTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_signingAddress","type":"address"}],"name":"changeSigningAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"takeFee","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"polyToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_allowAllWhitelistIssuances","type":"bool"}],"name":"changeAllowAllWhitelistIssuances","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_allowAllWhitelistTransfers","type":"bool"}],"name":"changeAllowAllWhitelistTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"FLAGS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"whitelist","outputs":[{"name":"fromTime","type":"uint256"},{"name":"toTime","type":"uint256"},{"name":"expiryTime","type":"uint256"},{"name":"canBuyFromSTO","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"nonceMap","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allowAllTransfers","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"signingAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"issuanceAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"securityToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPermissions","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FEE_ADMIN","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_investor","type":"address"},{"name":"_fromTime","type":"uint256"},{"name":"_toTime","type":"uint256"},{"name":"_expiryTime","type":"uint256"},{"name":"_canBuyFromSTO","type":"bool"}],"name":"modifyWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"bytes"},{"name":"","type":"bool"}],"name":"verifyTransfer","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_issuanceAddress","type":"address"}],"name":"changeIssuanceAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"allowAllWhitelistIssuances","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_allowAllBurnTransfers","type":"bool"}],"name":"changeAllowAllBurnTransfers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_investor","type":"address"},{"name":"_fromTime","type":"uint256"},{"name":"_toTime","type":"uint256"},{"name":"_expiryTime","type":"uint256"},{"name":"_canBuyFromSTO","type":"bool"},{"name":"_validFrom","type":"uint256"},{"name":"_validTo","type":"uint256"},{"name":"_nonce","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"modifyWhitelistSigned","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_securityToken","type":"address"},{"name":"_polyAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_issuanceAddress","type":"address"}],"name":"ChangeIssuanceAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_allowAllTransfers","type":"bool"}],"name":"AllowAllTransfers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_allowAllWhitelistTransfers","type":"bool"}],"name":"AllowAllWhitelistTransfers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_allowAllWhitelistIssuances","type":"bool"}],"name":"AllowAllWhitelistIssuances","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_allowAllBurnTransfers","type":"bool"}],"name":"AllowAllBurnTransfers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_signingAddress","type":"address"}],"name":"ChangeSigningAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_investor","type":"address"},{"indexed":false,"name":"_dateAdded","type":"uint256"},{"indexed":false,"name":"_addedBy","type":"address"},{"indexed":false,"name":"_fromTime","type":"uint256"},{"indexed":false,"name":"_toTime","type":"uint256"},{"indexed":false,"name":"_expiryTime","type":"uint256"},{"indexed":false,"name":"_canBuyFromSTO","type":"bool"}],"name":"ModifyWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_timestammp","type":"uint256"}],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"Unpause","type":"event"}]