From de69a714a5ec97b68b88c89c1ec444d0e00c35c2 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 4 Oct 2018 19:10:20 +0100 Subject: [PATCH] Add additional transfer / mint / burn functions with _data parameter --- contracts/interfaces/ISecurityToken.sol | 84 ++++++++++++----- contracts/modules/Burn/TrackedRedemption.sol | 2 +- .../TransferManager/CountTransferManager.sol | 2 +- .../GeneralTransferManager.sol | 2 +- .../TransferManager/ITransferManager.sol | 2 +- .../ManualApprovalTransferManager.sol | 2 +- .../PercentageTransferManager.sol | 2 +- contracts/tokens/SecurityToken.sol | 89 ++++++++++++++----- test/c_checkpoints.js | 2 +- test/j_manual_approval_transfer_manager.js | 10 +-- test/o_security_token.js | 16 ++-- 11 files changed, 145 insertions(+), 68 deletions(-) diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index b0cbd22b1..20dcb72c8 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -30,17 +30,28 @@ interface ISecurityToken { function mint(address _investor, uint256 _value) external returns (bool success); /** - * @notice Burn function used to burn the securityToken - * @param _value No. of tokens that get burned + * @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 burn(uint256 _value) external; + function mintWithData(address _investor, uint256 _value, bytes _data) external returns (bool success); /** * @notice Burn function used to burn the securityToken on behalf of someone else * @param _from Address for whom to burn tokens * @param _value No. of token that get burned + * @param _data data to indicate validation */ - function burnFrom(address _from, uint256 _value) external; + function burnFromWithData(address _from, uint256 _value, bytes _data) external; + + /** + * @notice Burn function used to burn the securityToken + * @param _value No. of tokens that get 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); @@ -175,10 +186,22 @@ interface ISecurityToken { function mintMulti(address[] _investors, uint256[] _values) external returns (bool success); /** - * @notice Removes a module attached to the SecurityToken - * @param _module address of module to archive - */ - function removeModule(address _module) external; + * @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 @@ -193,18 +216,10 @@ interface ISecurityToken { function unarchiveModule(address _module) external; /** - * @notice Function used to attach the module in security token - * @param _moduleFactory Contract address of the module factory that needs to be attached - * @param _data Data used for the intialization of the module factory variables - * @param _maxCost Maximum cost of the Module factory - * @param _budget Budget of the Module factory - */ - function addModule( - address _moduleFactory, - bytes _data, - uint256 _maxCost, - uint256 _budget - ) external; + * @notice Removes a module attached to the SecurityToken + * @param _module address of module to archive + */ + function removeModule(address _module) external; /** * @notice Use by the issuer to set the controller addresses @@ -217,17 +232,19 @@ interface ISecurityToken { * @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 attached to the transfer by controller to emit in event + * @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) external; + function forceTransfer(address _from, address _to, uint256 _value, bytes _data, bytes _log) external; /** * @notice Use 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 attached to the transfer by controller to emit in event + * @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) external; + function forceBurn(address _from, uint256 _value, bytes _data, bytes _log) external; /** * @notice Use by the issuer to permanently disable controller functionality @@ -244,4 +261,23 @@ interface ISecurityToken { * @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); } diff --git a/contracts/modules/Burn/TrackedRedemption.sol b/contracts/modules/Burn/TrackedRedemption.sol index 44a0b1d0e..f6211a140 100644 --- a/contracts/modules/Burn/TrackedRedemption.sol +++ b/contracts/modules/Burn/TrackedRedemption.sol @@ -37,7 +37,7 @@ contract TrackedRedemption is IBurn, Module { * @param _value The number of tokens to redeem */ function redeemTokens(uint256 _value) public { - ISecurityToken(securityToken).burnFrom(msg.sender, _value); + ISecurityToken(securityToken).burnFromWithData(msg.sender, _value, ""); redeemedTokens[msg.sender] = redeemedTokens[msg.sender].add(_value); emit Redeemed(msg.sender, _value, now); } diff --git a/contracts/modules/TransferManager/CountTransferManager.sol b/contracts/modules/TransferManager/CountTransferManager.sol index 565a03033..32df49dd4 100644 --- a/contracts/modules/TransferManager/CountTransferManager.sol +++ b/contracts/modules/TransferManager/CountTransferManager.sol @@ -26,7 +26,7 @@ contract CountTransferManager is ITransferManager { } /// @notice Used to verify the transfer transaction according to the rule implemented in the trnasfer managers - function verifyTransfer(address /* _from */, address _to, uint256 /* _amount */, bool /* _isTransfer */) public returns(Result) { + function verifyTransfer(address /* _from */, address _to, uint256 /* _amount */, bytes /* _data */, bool /* _isTransfer */) public returns(Result) { if (!paused) { if (maxHolderCount < ISecurityToken(securityToken).getInvestorCount()) { // Allow transfers to existing maxHolders diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 3cd7e9152..707927b93 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -151,7 +151,7 @@ contract GeneralTransferManager is ITransferManager { * b) Seller's sale lockup period is over * c) Buyer's purchase lockup is over */ - function verifyTransfer(address _from, address _to, uint256 /*_amount*/, bool /* _isTransfer */) public returns(Result) { + 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 diff --git a/contracts/modules/TransferManager/ITransferManager.sol b/contracts/modules/TransferManager/ITransferManager.sol index 8279e68c5..3f736801c 100644 --- a/contracts/modules/TransferManager/ITransferManager.sol +++ b/contracts/modules/TransferManager/ITransferManager.sol @@ -16,7 +16,7 @@ contract ITransferManager is Module, Pausable { // NA, then the result from this TM is ignored enum Result {INVALID, NA, VALID, FORCE_VALID} - function verifyTransfer(address _from, address _to, uint256 _amount, bool _isTransfer) public returns(Result); + function verifyTransfer(address _from, address _to, uint256 _amount, bytes _data, bool _isTransfer) public returns(Result); function unpause() onlyOwner public { super._unpause(); diff --git a/contracts/modules/TransferManager/ManualApprovalTransferManager.sol b/contracts/modules/TransferManager/ManualApprovalTransferManager.sol index 04629995a..e4f5d35f0 100644 --- a/contracts/modules/TransferManager/ManualApprovalTransferManager.sol +++ b/contracts/modules/TransferManager/ManualApprovalTransferManager.sol @@ -87,7 +87,7 @@ contract ManualApprovalTransferManager is ITransferManager { * b) Seller's sale lockup period is over * c) Buyer's purchase lockup is over */ - function verifyTransfer(address _from, address _to, uint256 _amount, bool _isTransfer) public returns(Result) { + function verifyTransfer(address _from, address _to, uint256 _amount, bytes /* _data */, bool _isTransfer) public returns(Result) { // function must only be called by the associated security token if _isTransfer == true require(_isTransfer == false || msg.sender == securityToken, "Sender is not owner"); // manual blocking takes precidence over manual approval diff --git a/contracts/modules/TransferManager/PercentageTransferManager.sol b/contracts/modules/TransferManager/PercentageTransferManager.sol index 805d04557..0e67539af 100644 --- a/contracts/modules/TransferManager/PercentageTransferManager.sol +++ b/contracts/modules/TransferManager/PercentageTransferManager.sol @@ -38,7 +38,7 @@ contract PercentageTransferManager is ITransferManager { } /// @notice Used to verify the transfer transaction according to the rule implemented in the trnasfer managers - function verifyTransfer(address /* _from */, address _to, uint256 _amount, bool /* _isTransfer */) public returns(Result) { + function verifyTransfer(address /* _from */, address _to, uint256 _amount, bytes /* _data */, bool /* _isTransfer */) public returns(Result) { if (!paused) { // If an address is on the whitelist, it is allowed to hold more than maxHolderPercentage of the tokens. if (whitelist[_to]) { diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 83724284e..2b021c372 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -464,7 +464,18 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return bool success */ function transfer(address _to, uint256 _value) public returns (bool success) { - require(_updateTransfer(msg.sender, _to, _value), "Transfer not valid"); + return transferWithData(_to, _value, ""); + } + + /** + * @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) public returns (bool success) { + require(_updateTransfer(msg.sender, _to, _value, _data), "Transfer not valid"); require(super.transfer(_to, _value)); return true; } @@ -477,16 +488,28 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return bool success */ function transferFrom(address _from, address _to, uint256 _value) public returns(bool) { - require(_updateTransfer(_from, _to, _value), "Transfer not valid"); + return transferFromWithData(_from, _to, _value, ""); + } + + /** + * @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) public returns(bool) { + require(_updateTransfer(_from, _to, _value, _data), "Transfer not valid"); require(super.transferFrom(_from, _to, _value)); return true; } - function _updateTransfer(address _from, address _to, uint256 _value) internal returns(bool) { + function _updateTransfer(address _from, address _to, uint256 _value, bytes _data) internal returns(bool) { _adjustInvestorCount(_from, _to, _value); _adjustBalanceCheckpoints(_from); _adjustBalanceCheckpoints(_to); - return _verifyTransfer(_from, _to, _value, true); + return _verifyTransfer(_from, _to, _value, _data, true); } /** @@ -495,10 +518,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _from sender of transfer * @param _to receiver of transfer * @param _value value of transfer + * @param _data data to indicate validation * @param _isTransfer whether transfer is being executed * @return bool */ - function _verifyTransfer(address _from, address _to, uint256 _value, bool _isTransfer) internal checkGranularity(_value) returns (bool) { + function _verifyTransfer(address _from, address _to, uint256 _value, bytes _data, bool _isTransfer) internal checkGranularity(_value) returns (bool) { if (!transfersFrozen) { if (modules[TRANSFER_KEY].length == 0) { return true; @@ -512,7 +536,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr module = modules[TRANSFER_KEY][i]; if (!modulesToData[module].isArchived) { unarchived = true; - ITransferManager.Result valid = ITransferManager(module).verifyTransfer(_from, _to, _value, _isTransfer); + ITransferManager.Result valid = ITransferManager(module).verifyTransfer(_from, _to, _value, _data, _isTransfer); if (valid == ITransferManager.Result.INVALID) { isInvalid = true; } @@ -536,10 +560,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _from sender of transfer * @param _to receiver of transfer * @param _value value of transfer + * @param _data data to indicate validation * @return bool */ - function verifyTransfer(address _from, address _to, uint256 _value) public returns (bool) { - return _verifyTransfer(_from, _to, _value, false); + function verifyTransfer(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { + return _verifyTransfer(_from, _to, _value, _data, false); } /** @@ -558,9 +583,21 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value Number of tokens be minted * @return success */ - function mint(address _investor, uint256 _value) public onlyModuleOrOwner(MINT_KEY) checkGranularity(_value) isMintingAllowed() returns (bool success) { + function mint(address _investor, uint256 _value) public returns (bool success) { + return mintWithData(_investor, _value, ""); + } + + /** + * @notice mints new tokens and assigns them to the target _investor. + * @dev Can only be called by the issuer or STO attached to the token + * @param _investor Address where the minted tokens will be delivered + * @param _value Number of tokens be minted + * @param _data data to indicate validation + * @return success + */ + function mintWithData(address _investor, uint256 _value, bytes _data) public onlyModuleOrOwner(MINT_KEY) isMintingAllowed() returns (bool success) { require(_investor != address(0), "Investor is 0"); - require(_updateTransfer(address(0), _investor, _value), "Transfer not valid"); + require(_updateTransfer(address(0), _investor, _value, _data), "Transfer not valid"); _adjustTotalSupplyCheckpoints(); totalSupply_ = totalSupply_.add(_value); balances[_investor] = balances[_investor].add(_value); @@ -597,9 +634,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return TokenLib.checkPermission(modules[PERMISSION_KEY], _delegate, _module, _perm); } - function _burn(address _from, uint256 _value) internal returns(bool) { + function _burn(address _from, uint256 _value, bytes _data) internal returns(bool) { require(_value <= balances[_from], "Value too high"); - bool verified = _updateTransfer(_from, address(0), _value); + bool verified = _updateTransfer(_from, address(0), _value, _data); _adjustTotalSupplyCheckpoints(); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); @@ -611,20 +648,22 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr /** * @notice Burn function used to burn the securityToken * @param _value No. of tokens that get burned + * @param _data data to indicate validation */ - function burn(uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public { - require(_burn(msg.sender, _value), "Burn not valid"); + function burnWithData(uint256 _value, bytes _data) onlyModule(BURN_KEY) public { + require(_burn(msg.sender, _value, _data), "Burn not valid"); } /** * @notice Burn function used to burn the securityToken on behalf of someone else * @param _from Address for whom to burn tokens * @param _value No. of tokens that get burned + * @param _data data to indicate validation */ - function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public { + function burnFromWithData(address _from, uint256 _value, bytes _data) onlyModule(BURN_KEY) public { require(_value <= allowed[_from][msg.sender], "Value too high"); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - require(_burn(_from, _value), "Burn not valid"); + require(_burn(_from, _value, _data), "Burn not valid"); } /** @@ -693,15 +732,16 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @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 attached to the transfer by controller to emit in event + * @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) public onlyController { + function forceTransfer(address _from, address _to, uint256 _value, bytes _data, bytes _log) public onlyController { require(_to != address(0)); require(_value <= balances[_from]); - bool verified = _updateTransfer(_from, _to, _value); + bool verified = _updateTransfer(_from, _to, _value, _data); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); - emit ForceTransfer(msg.sender, _from, _to, _value, verified, _data); + emit ForceTransfer(msg.sender, _from, _to, _value, verified, _log); emit Transfer(_from, _to, _value); } @@ -709,11 +749,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice Use 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 attached to the transfer by controller to emit in event + * @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) public onlyController { - bool verified = _burn(_from, _value); - emit ForceBurn(msg.sender, _from, _value, verified, _data); + function forceBurn(address _from, uint256 _value, bytes _data, bytes _log) public onlyController { + bool verified = _burn(_from, _value, _data); + emit ForceBurn(msg.sender, _from, _value, verified, _log); } /** diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index d094a2dfc..f4ad15ee1 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -389,7 +389,7 @@ contract('Checkpoints', accounts => { } n = n.toFixed(0); console.log("Burning: " + n.toString() + " from: " + burner); - await I_SecurityToken.forceBurn(burner, n, "", { from: token_owner }); + await I_SecurityToken.forceBurn(burner, n, "", "", { from: token_owner }); } console.log("Checking Interim..."); for (let k = 0; k < cps.length; k++) { diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index cc6471e8a..064027246 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -371,7 +371,7 @@ contract('ManualApprovalTransferManager', accounts => { it("Cannot call verifyTransfer on the TM directly if _isTransfer == true", async() => { let errorThrown = false; try { - await I_ManualApprovalTransferManager.verifyTransfer(account_investor4, account_investor4, web3.utils.toWei('2', 'ether'), true, { from: token_owner }); + await I_ManualApprovalTransferManager.verifyTransfer(account_investor4, account_investor4, web3.utils.toWei('2', 'ether'), "", true, { from: token_owner }); } catch(error) { console.log(` tx revert -> invalid not from SecurityToken`.grey); ensureException(error); @@ -382,7 +382,7 @@ contract('ManualApprovalTransferManager', accounts => { }); it("Can call verifyTransfer on the TM directly if _isTransfer == false", async() => { - await I_ManualApprovalTransferManager.verifyTransfer(account_investor4, account_investor4, web3.utils.toWei('2', 'ether'), false, { from: token_owner }); + await I_ManualApprovalTransferManager.verifyTransfer(account_investor4, account_investor4, web3.utils.toWei('2', 'ether'), "", false, { from: token_owner }); }); it("Add a new token holder", async() => { @@ -503,14 +503,14 @@ contract('ManualApprovalTransferManager', accounts => { }); it("Check verifyTransfer without actually transferring", async() => { - let verified = await I_SecurityToken.verifyTransfer.call(account_investor1, account_investor4, web3.utils.toWei('1', 'ether')); + let verified = await I_SecurityToken.verifyTransfer.call(account_investor1, account_investor4, web3.utils.toWei('1', 'ether'), ""); console.log(JSON.stringify(verified)); assert.equal(verified, true); - verified = await I_SecurityToken.verifyTransfer.call(account_investor1, account_investor4, web3.utils.toWei('2', 'ether')); + verified = await I_SecurityToken.verifyTransfer.call(account_investor1, account_investor4, web3.utils.toWei('2', 'ether'), ""); assert.equal(verified, false); - verified = await I_SecurityToken.verifyTransfer.call(account_investor1, account_investor4, web3.utils.toWei('1', 'ether')); + verified = await I_SecurityToken.verifyTransfer.call(account_investor1, account_investor4, web3.utils.toWei('1', 'ether'), ""); assert.equal(verified, true); }); diff --git a/test/o_security_token.js b/test/o_security_token.js index b6abc9b20..de7e2b2ed 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -1157,7 +1157,7 @@ contract('SecurityToken', accounts => { let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); try { - let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance + web3.utils.toWei("500", "ether"), "", { from: account_controller }); + let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance + web3.utils.toWei("500", "ether"), "", "", { from: account_controller }); } catch(error) { console.log(` tx revert -> value is greater than its current balance`.grey); errorThrown = true; @@ -1171,7 +1171,7 @@ contract('SecurityToken', accounts => { let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); try { - let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", { from: token_owner }); + let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", "", { from: token_owner }); } catch(error) { console.log(` tx revert -> not owner`.grey); errorThrown = true; @@ -1184,7 +1184,7 @@ contract('SecurityToken', accounts => { let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); // console.log(currentInvestorCount.toString(), currentBalance.toString()); - let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", { from: account_controller }); + let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", "", { from: account_controller }); // console.log(tx.logs[0].args._value.toNumber(), currentBalance.toNumber()); assert.equal(tx.logs[0].args._value.toNumber(), currentBalance.toNumber()); let newInvestorCount = await I_SecurityToken.getInvestorCount.call(); @@ -1261,7 +1261,7 @@ contract('SecurityToken', accounts => { it("Should fail to forceTransfer because not approved controller", async() => { let errorThrown1 = false; try { - await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "reason", {from: account_investor1}); + await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "", "reason", {from: account_investor1}); } catch (error) { console.log(` tx revert -> not approved controller`.grey); errorThrown1 = true; @@ -1273,7 +1273,7 @@ contract('SecurityToken', accounts => { it("Should fail to forceTransfer because insufficient balance", async() => { let errorThrown = false; try { - await I_SecurityToken.forceTransfer(account_investor2, account_investor1, web3.utils.toWei("10", "ether"), "reason", {from: account_controller}); + await I_SecurityToken.forceTransfer(account_investor2, account_investor1, web3.utils.toWei("10", "ether"), "", "reason", {from: account_controller}); } catch (error) { console.log(` tx revert -> insufficient balance`.grey); errorThrown = true; @@ -1285,7 +1285,7 @@ contract('SecurityToken', accounts => { it("Should fail to forceTransfer because recipient is zero address", async() => { let errorThrown = false; try { - await I_SecurityToken.forceTransfer(account_investor1, address_zero, web3.utils.toWei("10", "ether"), "reason", {from: account_controller}); + await I_SecurityToken.forceTransfer(account_investor1, address_zero, web3.utils.toWei("10", "ether"), "", "reason", {from: account_controller}); } catch (error) { console.log(` tx revert -> recipient is zero address`.grey); errorThrown = true; @@ -1302,7 +1302,7 @@ contract('SecurityToken', accounts => { let start_balInv1 = await I_SecurityToken.balanceOf.call(account_investor1); let start_balInv2 = await I_SecurityToken.balanceOf.call(account_investor2); - let tx = await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "reason", {from: account_controller}); + let tx = await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "", "reason", {from: account_controller}); let end_investorCount = await I_SecurityToken.getInvestorCount.call(); let end_balInv1 = await I_SecurityToken.balanceOf.call(account_investor1); @@ -1391,7 +1391,7 @@ contract('SecurityToken', accounts => { it("Should fail to forceTransfer because controller functionality frozen", async() => { let errorThrown = false; try { - await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "reason", {from: account_controller}); + await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "", "reason", {from: account_controller}); } catch (error) { console.log(` tx revert -> recipient is zero address`.grey); errorThrown = true;