Permalink
Switch branches/tags
2.0.0-readme-update CLI-Permissions-Manager CLI-improvements CLI-minor-updates CLI-verifyTransfer-Bug CPSTL-contribute-md CPSTL-patch-1 CPSTL-patch-2 CPSTL-patch-3 CPSTL-patch-4 Cli-minor-updates EtherscanAPI-strMigrator MATM-Fix MATM-Issuance-Fix MATM-new-functions ModuleFactory-variables-visibility Optimise-GTM POLY-to-USD PercentageTM-admin-permission Permission-Manager-Changes Remove-redundant-getters ST_FIX_PR327 TravisCI-cron-jobs Vesting-Escrow-Wallet add-checkpoint-times anti-optimize-gtm audit_fix_iterate_investors bakii-travis-fix better-fees black capped-sto-fix cappedsto-price-fix change-cappedSTO-description cli-count-and-percentage-TM contracts-grammar-check-dev1.5.0 controller core-diagram count-TM-Audit-Change countTM-Audit-Change coveralls-fix create-checkpoint customModules dev-2.1.0-master dev-2.1.0 dev-3.0.0 development-1.5.0 disclaimer-ptm dividend-delegate divident-transfer docs-fix-master docs-script-improve docs-solc-fix document-getSTODetails event-upgradability faucet-fix fetch-PolyToken-from-PMRegistry fix-1 fix-3 fix-4 fix-10 fix-15 fix-coverage fix-deploy-address fix-investorCount fix-linter-errors fix-signing-issue-gtm fix_cli_for_max_modules_change force_transfer forced-transfer forcedTransfer fuzz-test-adding-removing-modules fuzz-test-permissions-manager-module general-fixes-st greenkeeper-fix greenkeeper/ganache-cli-6.2.0 greenkeeper/ganache-cli-6.2.1 greenkeeper/ganache-cli-6.2.2 greenkeeper/ganache-cli-6.2.3 greenkeeper/ganache-cli-pin-6.1.8 greenkeeper/solc-0.5.0 greenkeeper/solc-0.5.1 image-update improve-coverage improve-freezing improve-getter-mr improve-readme increase-coverage index-moduleAdded-params-ST indexed-matm interface-improve katipult_integration lockup-fix lockup-tm-fixes master-dev-2.1 master matm-fixes matm-to-master migration-scrit-to-2.0.0 mint-in-one module-label-changelog module-labeling monitoring-scripts more-info-transfer multi-identity multiple-controllers multiple-stable-coins multiple_types new_poly_oracle nonce-fix off-chain-validation optimize-dividend optimize-verifytransfer owner-fix-mr pr/262 precompute-hashes private/fede/cli/polymathRegistry private/fede/cli/stableCoin proxy-deplyoment-usdt reinvent-lockup release-2.0.0 remove-blocking-MATM remove-delegate remove-log-oracles rename-vrtm revert-329-voting-module-oct revert-433-Optimise-GTM safemath sample_modules signed-transfer-manager-fixed signing-fix single-use-migrator some_changes str-fix token-info-script token_owners_str tokeninfo-trycatch touches transfer-manager-with-signed-data unverify update-openZeppelin-and-oraclize-IERC20-workaround update-openZeppelin-and-oraclize update-tokenInfo-script upgradability upgrade-clean upgrade-in-constructor upgrade-keccak upgrade-mr upgrade-str usdtieredsto-desc usdtsto-changes usdtsto-migration volTM-module voting-module-oct-reopen voting-module-oct voting-module-test-refactor voting-module voting-pr-test warning windows-support withholding_tax_on_dividends withholding yarn
Nothing to show
Find file Copy path
315 lines (287 sloc) 13.7 KB
pragma solidity ^0.4.24;
import "./ITransferManager.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
/**
* @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;
}
}