@@ -101,8 +101,29 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage
101101 uint256 _amount ,
102102 bytes calldata _data
103103 ) external returns (Result) {
104- (Result success ,) = verifyTransfer (_from, _to, _amount, _data);
105- return success;
104+ if (_data.length > 32 ) {
105+ address target;
106+ uint256 nonce;
107+ uint256 validFrom;
108+ uint256 validTo;
109+ bytes memory data;
110+ (target, nonce, validFrom, validTo, data) = abi.decode (_data, (address , uint256 , uint256 , uint256 , bytes ));
111+ if (target == address (this ))
112+ _processTransferSignature (nonce, validFrom, validTo, data);
113+ }
114+ (Result success ,) = verifyTransfer (_from, _to, _amount, _data);
115+ return success;
116+ }
117+
118+ function _processTransferSignature (uint256 _nonce , uint256 _validFrom , uint256 _validTo , bytes memory _data ) internal {
119+ address [] memory investor;
120+ uint256 [] memory fromTime;
121+ uint256 [] memory toTime;
122+ uint256 [] memory expiryTime;
123+ bytes memory signature;
124+ (investor, fromTime, toTime, expiryTime, signature) =
125+ abi.decode (_data, (address [], uint256 [], uint256 [], uint256 [], bytes ));
126+ _modifyKYCDataSignedMulti (investor, fromTime, toTime, expiryTime, _validFrom, _validTo, _nonce, signature);
106127 }
107128
108129 /**
@@ -376,28 +397,117 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage
376397 bytes memory _signature
377398 )
378399 public
400+ {
401+ require (
402+ _modifyKYCDataSigned (_investor, _fromTime, _toTime, _expiryTime, _validFrom, _validTo, _nonce, _signature),
403+ "Invalid signature or data "
404+ );
405+ }
406+
407+ function _modifyKYCDataSigned (
408+ address _investor ,
409+ uint256 _fromTime ,
410+ uint256 _toTime ,
411+ uint256 _expiryTime ,
412+ uint256 _validFrom ,
413+ uint256 _validTo ,
414+ uint256 _nonce ,
415+ bytes memory _signature
416+ )
417+ internal
418+ returns (bool )
379419 {
380420 /*solium-disable-next-line security/no-block-members*/
381- require (_validFrom <= now , "ValidFrom is too early " );
382- /*solium-disable-next-line security/no-block-members*/
383- require (_validTo >= now , "ValidTo is too late " );
384- require (! nonceMap[_investor][_nonce], "Already used signature " );
385- nonceMap[_investor][_nonce] = true ;
421+ if (_validFrom > now || _validTo < now || _investor == address (0 ))
422+ return false ;
386423 bytes32 hash = keccak256 (
387424 abi.encodePacked (this , _investor, _fromTime, _toTime, _expiryTime, _validFrom, _validTo, _nonce)
388425 );
389- _checkSig (hash, _signature);
390- _modifyKYCData (_investor, _fromTime, _toTime, _expiryTime);
426+ if (_checkSig (hash, _signature, _nonce)) {
427+ _modifyKYCData (_investor, _fromTime, _toTime, _expiryTime);
428+ return true ;
429+ }
430+ return false ;
431+ }
432+
433+ /**
434+ * @notice Adds or removes addresses from the whitelist - can be called by anyone with a valid signature
435+ * @param _investor is the address to whitelist
436+ * @param _fromTime is the moment when the sale lockup period ends and the investor can freely sell his tokens
437+ * @param _toTime is the moment when the purchase lockup period ends and the investor can freely purchase tokens from others
438+ * @param _expiryTime is the moment till investors KYC will be validated. After that investor need to do re-KYC
439+ * @param _validFrom is the time that this signature is valid from
440+ * @param _validTo is the time that this signature is valid until
441+ * @param _nonce nonce of signature (avoid replay attack)
442+ * @param _signature issuer signature
443+ */
444+ function modifyKYCDataSignedMulti (
445+ address [] memory _investor ,
446+ uint256 [] memory _fromTime ,
447+ uint256 [] memory _toTime ,
448+ uint256 [] memory _expiryTime ,
449+ uint256 _validFrom ,
450+ uint256 _validTo ,
451+ uint256 _nonce ,
452+ bytes memory _signature
453+ )
454+ public
455+ {
456+ require (
457+ _modifyKYCDataSignedMulti (_investor, _fromTime, _toTime, _expiryTime, _validFrom, _validTo, _nonce, _signature),
458+ "Invalid signature or data "
459+ );
460+ }
461+
462+ function _modifyKYCDataSignedMulti (
463+ address [] memory _investor ,
464+ uint256 [] memory _fromTime ,
465+ uint256 [] memory _toTime ,
466+ uint256 [] memory _expiryTime ,
467+ uint256 _validFrom ,
468+ uint256 _validTo ,
469+ uint256 _nonce ,
470+ bytes memory _signature
471+ )
472+ internal
473+ returns (bool )
474+ {
475+ if (_investor.length != _fromTime.length ||
476+ _fromTime.length != _toTime.length ||
477+ _toTime.length != _expiryTime.length
478+ ) {
479+ return false ;
480+ }
481+
482+ if (_validFrom > now || _validTo < now ) {
483+ return false ;
484+ }
485+
486+ bytes32 hash = keccak256 (
487+ abi.encodePacked (this , _investor, _fromTime, _toTime, _expiryTime, _validFrom, _validTo, _nonce)
488+ );
489+
490+ if (_checkSig (hash, _signature, _nonce)) {
491+ for (uint256 i = 0 ; i < _investor.length ; i++ ) {
492+ _modifyKYCData (_investor[i], _fromTime[i], _toTime[i], _expiryTime[i]);
493+ }
494+ return true ;
495+ }
496+ return false ;
391497 }
392498
393499 /**
394500 * @notice Used to verify the signature
395501 */
396- function _checkSig (bytes32 _hash , bytes memory _signature ) internal view {
502+ function _checkSig (bytes32 _hash , bytes memory _signature , uint256 _nonce ) internal returns ( bool ) {
397503 //Check that the signature is valid
398504 //sig should be signing - _investor, _fromTime, _toTime & _expiryTime and be signed by the issuer address
399505 address signer = _hash.toEthSignedMessageHash ().recover (_signature);
400- require (_checkPerm (OPERATOR, signer), "Incorrect signer " );
506+ if (nonceMap[signer][_nonce] || ! _checkPerm (OPERATOR, signer)) {
507+ return false ;
508+ }
509+ nonceMap[signer][_nonce] = true ;
510+ return true ;
401511 }
402512
403513 /**
0 commit comments