diff --git a/contracts/modules/TransferManager/CTM/CountTransferManager.sol b/contracts/modules/TransferManager/CTM/CountTransferManager.sol index 30e86850b..6cd8c738a 100644 --- a/contracts/modules/TransferManager/CTM/CountTransferManager.sol +++ b/contracts/modules/TransferManager/CTM/CountTransferManager.sol @@ -33,12 +33,16 @@ contract CountTransferManager is CountTransferManagerStorage, TransferManager { external returns(Result) { - (Result success, ) = _verifyTransfer(_from, _to, _amount); + (Result success, ) = _verifyTransfer(_from, _to, _amount, securityToken.holderCount()); return success; } /** * @notice Used to verify the transfer transaction and prevent a transfer if it passes the allowed amount of token holders + * @dev module.verifyTransfer is called by SecToken.canTransfer and does not receive the updated holderCount therefore + * verifyTransfer has to manually account for pot. tokenholder changes (by mimicking TokenLib.adjustInvestorCount). + * module.executeTransfer is called by SecToken.transfer|issue|others and receives an updated holderCount + * as sectoken calls TokenLib.adjustInvestorCount before executeTransfer. * @param _from Address of the sender * @param _to Address of the receiver * @param _amount Amount to send @@ -53,20 +57,33 @@ contract CountTransferManager is CountTransferManagerStorage, TransferManager { view returns(Result, bytes32) { - return _verifyTransfer(_from, _to, _amount); + uint256 holderCount = securityToken.holderCount(); + if (_amount != 0 && _from != _to) { + // Check whether receiver is a new token holder + if (_to != address(0) && securityToken.balanceOf(_to) == 0) { + holderCount++; + } + // Check whether sender is moving all of their tokens + if (_amount == securityToken.balanceOf(_from)) { + holderCount--; + } + } + + return _verifyTransfer(_from, _to, _amount, holderCount); } function _verifyTransfer( address _from, address _to, - uint256 _amount + uint256 _amount, + uint256 _holderCount ) internal view returns(Result, bytes32) { if (!paused) { - if (maxHolderCount < securityToken.holderCount()) { + if (maxHolderCount < _holderCount) { // Allow transfers to existing maxHolders if (securityToken.balanceOf(_to) != 0 || securityToken.balanceOf(_from) == _amount) { return (Result.NA, bytes32(0)); diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index ce75377a6..9654fbb67 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -311,6 +311,9 @@ contract("CountTransferManager", async (accounts) => { ); await catchRevert(I_SecurityToken.issue(account_investor3, new BN(web3.utils.toWei("3", "ether")), "0x0", { from: token_owner })); + await catchRevert(I_SecurityToken.transfer(account_investor3, new BN(web3.utils.toWei("1", "ether")), { from: account_investor2 })); + let canTransfer = await I_SecurityToken.canTransfer(account_investor3, new BN(web3.utils.toWei("1", "ether")), "0x0", { from: account_investor2 }); + assert.equal(canTransfer[0], "0x50"); //Transfer failure. }); it("Should still be able to add to original token holders", async () => {