Skip to content

Commit af7bd20

Browse files
committed
Merge dev-3.0
2 parents e424d24 + cd4a7f9 commit af7bd20

File tree

3 files changed

+144
-99
lines changed

3 files changed

+144
-99
lines changed

contracts/libraries/TokenLib.sol

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pragma solidity ^0.5.0;
22

33
import "../modules/PermissionManager/IPermissionManager.sol";
44
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
5+
import "../interfaces/IPoly.sol";
56

67
library TokenLib {
78
using SafeMath for uint256;
@@ -37,6 +38,10 @@ library TokenLib {
3738
event ModuleArchived(uint8[] _types, address _module, uint256 _timestamp);
3839
// Emit when Module is unarchived from the SecurityToken
3940
event ModuleUnarchived(uint8[] _types, address _module, uint256 _timestamp);
41+
// Emit when Module get removed from the securityToken
42+
event ModuleRemoved(uint8[] _types, address _module, uint256 _timestamp);
43+
// Emit when the budget allocated to a module is changed
44+
event ModuleBudgetChanged(uint8[] _moduleTypes, address _module, uint256 _oldBudget, uint256 _budget);
4045

4146
/**
4247
* @notice Archives a module attached to the SecurityToken
@@ -63,6 +68,95 @@ library TokenLib {
6368
_moduleData.isArchived = false;
6469
}
6570

71+
/**
72+
* @notice Removes a module attached to the SecurityToken
73+
* @param _module address of module to unarchive
74+
*/
75+
function removeModule(
76+
address _module,
77+
mapping(uint8 => address[]) storage _modules,
78+
mapping(address => ModuleData) storage _modulesToData,
79+
mapping(bytes32 => address[]) storage _names
80+
)
81+
public
82+
{
83+
require(_modulesToData[_module].isArchived, "Not archived");
84+
require(_modulesToData[_module].module != address(0), "Module missing");
85+
/*solium-disable-next-line security/no-block-members*/
86+
emit ModuleRemoved(_modulesToData[_module].moduleTypes, _module, now);
87+
// Remove from module type list
88+
uint8[] memory moduleTypes = _modulesToData[_module].moduleTypes;
89+
for (uint256 i = 0; i < moduleTypes.length; i++) {
90+
_removeModuleWithIndex(moduleTypes[i], _modulesToData[_module].moduleIndexes[i], _modules, _modulesToData);
91+
/* modulesToData[_module].moduleType[moduleTypes[i]] = false; */
92+
}
93+
// Remove from module names list
94+
uint256 index = _modulesToData[_module].nameIndex;
95+
bytes32 name = _modulesToData[_module].name;
96+
uint256 length = _names[name].length;
97+
_names[name][index] = _names[name][length - 1];
98+
_names[name].length = length - 1;
99+
if ((length - 1) != index) {
100+
_modulesToData[_names[name][index]].nameIndex = index;
101+
}
102+
// Remove from modulesToData
103+
delete _modulesToData[_module];
104+
}
105+
106+
/**
107+
* @notice Internal - Removes a module attached to the SecurityToken by index
108+
*/
109+
function _removeModuleWithIndex(
110+
uint8 _type,
111+
uint256 _index,
112+
mapping(uint8 => address[]) storage _modules,
113+
mapping(address => ModuleData) storage _modulesToData
114+
)
115+
internal
116+
{
117+
uint256 length = _modules[_type].length;
118+
_modules[_type][_index] = _modules[_type][length - 1];
119+
_modules[_type].length = length - 1;
120+
121+
if ((length - 1) != _index) {
122+
//Need to find index of _type in moduleTypes of module we are moving
123+
uint8[] memory newTypes = _modulesToData[_modules[_type][_index]].moduleTypes;
124+
for (uint256 i = 0; i < newTypes.length; i++) {
125+
if (newTypes[i] == _type) {
126+
_modulesToData[_modules[_type][_index]].moduleIndexes[i] = _index;
127+
}
128+
}
129+
}
130+
}
131+
132+
/**
133+
* @notice allows owner to increase/decrease POLY approval of one of the modules
134+
* @param _module module address
135+
* @param _change change in allowance
136+
* @param _increase true if budget has to be increased, false if decrease
137+
*/
138+
function changeModuleBudget(
139+
address _module,
140+
uint256 _change,
141+
bool _increase,
142+
address _polyToken,
143+
mapping(address => ModuleData) storage _modulesToData
144+
)
145+
public
146+
{
147+
require(_modulesToData[_module].module != address(0), "Module missing");
148+
uint256 currentAllowance = IPoly(_polyToken).allowance(address(this), _module);
149+
uint256 newAllowance;
150+
if (_increase) {
151+
require(IPoly(_polyToken).increaseApproval(_module, _change), "IncreaseApproval fail");
152+
newAllowance = currentAllowance.add(_change);
153+
} else {
154+
require(IPoly(_polyToken).decreaseApproval(_module, _change), "Insufficient allowance");
155+
newAllowance = currentAllowance.sub(_change);
156+
}
157+
emit ModuleBudgetChanged(_modulesToData[_module].moduleTypes, _module, currentAllowance, newAllowance);
158+
}
159+
66160
/**
67161
* @notice Validates permissions with PermissionManager if it exists. If there's no permission return false
68162
* @dev Note that IModule withPerm will allow ST owner all permissions by default

contracts/tokens/SecurityToken.sol

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -292,46 +292,7 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater
292292
* @param _module address of module to unarchive
293293
*/
294294
function removeModule(address _module) external onlyOwner {
295-
// require(modulesToData[_module].isArchived, "Not archived");
296-
// require(modulesToData[_module].module != address(0), "Module missing");
297-
// /*solium-disable-next-line security/no-block-members*/
298-
// emit ModuleRemoved(modulesToData[_module].moduleTypes, _module, now);
299-
// // Remove from module type list
300-
// uint8[] memory moduleTypes = modulesToData[_module].moduleTypes;
301-
// for (uint256 i = 0; i < moduleTypes.length; i++) {
302-
// _removeModuleWithIndex(moduleTypes[i], modulesToData[_module].moduleIndexes[i]);
303-
// /* modulesToData[_module].moduleType[moduleTypes[i]] = false; */
304-
// }
305-
// // Remove from module names list
306-
// uint256 index = modulesToData[_module].nameIndex;
307-
// bytes32 name = modulesToData[_module].name;
308-
// uint256 length = names[name].length;
309-
// names[name][index] = names[name][length - 1];
310-
// names[name].length = length - 1;
311-
// if ((length - 1) != index) {
312-
// modulesToData[names[name][index]].nameIndex = index;
313-
// }
314-
// // Remove from modulesToData
315-
// delete modulesToData[_module];
316-
}
317-
318-
/**
319-
* @notice Internal - Removes a module attached to the SecurityToken by index
320-
*/
321-
function _removeModuleWithIndex(uint8 _type, uint256 _index) internal {
322-
uint256 length = modules[_type].length;
323-
modules[_type][_index] = modules[_type][length - 1];
324-
modules[_type].length = length - 1;
325-
326-
if ((length - 1) != _index) {
327-
//Need to find index of _type in moduleTypes of module we are moving
328-
uint8[] memory newTypes = modulesToData[modules[_type][_index]].moduleTypes;
329-
for (uint256 i = 0; i < newTypes.length; i++) {
330-
if (newTypes[i] == _type) {
331-
modulesToData[modules[_type][_index]].moduleIndexes[i] = _index;
332-
}
333-
}
334-
}
295+
TokenLib.removeModule(_module, modules, modulesToData, names);
335296
}
336297

337298
/**
@@ -385,17 +346,7 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater
385346
* @param _increase true if budget has to be increased, false if decrease
386347
*/
387348
function changeModuleBudget(address _module, uint256 _change, bool _increase) external onlyOwner {
388-
require(modulesToData[_module].module != address(0), "Module missing");
389-
uint256 currentAllowance = IPoly(polyToken).allowance(address(this), _module);
390-
uint256 newAllowance;
391-
if (_increase) {
392-
require(IPoly(polyToken).increaseApproval(_module, _change), "IncreaseApproval fail");
393-
newAllowance = currentAllowance.add(_change);
394-
} else {
395-
require(IPoly(polyToken).decreaseApproval(_module, _change), "Insufficient allowance");
396-
newAllowance = currentAllowance.sub(_change);
397-
}
398-
emit ModuleBudgetChanged(modulesToData[_module].moduleTypes, _module, currentAllowance, newAllowance);
349+
TokenLib.changeModuleBudget(_module, _change, _increase, polyToken, modulesToData);
399350
}
400351

401352
/**

test/o_security_token.js

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -395,54 +395,54 @@ contract("SecurityToken", async (accounts) => {
395395
assert.equal(log.logs[0].args._newDetails, "new token details");
396396
});
397397

398-
// it("Should successfully remove the general transfer manager module from the securityToken -- fails msg.sender should be Owner", async () => {
399-
// await catchRevert(I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: account_delegate }));
400-
// });
401-
402-
// it("Should fail to remove the module - module not archived", async () => {
403-
// await catchRevert(I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: account_temp }));
404-
// });
405-
406-
// it("Should fail to remove the module - incorrect address", async () => {
407-
// await catchRevert(I_SecurityToken.removeModule(address_zero, { from: token_owner }));
408-
// });
409-
410-
// it("Should successfully remove the general transfer manager module from the securityToken", async () => {
411-
// let key = await takeSnapshot();
412-
// await I_SecurityToken.archiveModule(I_GeneralTransferManager.address, { from: token_owner });
413-
// let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: token_owner });
414-
// assert.equal(tx.logs[0].args._types[0], transferManagerKey);
415-
// assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address);
416-
// await I_SecurityToken.mint(account_investor1, new BN(web3.utils.toWei("500")), { from: token_owner });
417-
// await I_SecurityToken.transfer(account_investor2, new BN(web3.utils.toWei("200")), { from: account_investor1 });
418-
// assert.equal((await I_SecurityToken.balanceOf(account_investor2)).div(new BN(10).pow(new BN(18))).toNumber(), 200);
419-
// await revertToSnapshot(key);
420-
// });
421-
422-
// it("Should successfully remove the module from the middle of the names mapping", async () => {
423-
// let snap_Id = await takeSnapshot();
424-
// let D_GPM, D_GPM_1, D_GPM_2;
425-
// let FactoryInstances;
426-
// let GPMAddress = new Array();
427-
428-
// [D_GPM] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, 0);
429-
// [D_GPM_1] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, 0);
430-
// [D_GPM_2] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, 0);
431-
// FactoryInstances = [D_GPM, D_GPM_1, D_GPM_2];
432-
// // Adding module in the ST
433-
// for (let i = 0; i < FactoryInstances.length; i++) {
434-
// let tx = await I_SecurityToken.addModule(FactoryInstances[i].address, "0x0", new BN(0), new BN(0), { from: token_owner });
435-
// assert.equal(tx.logs[2].args._types[0], permissionManagerKey, "fail in adding the GPM");
436-
// GPMAddress.push(tx.logs[2].args._module);
437-
// }
438-
// // Archive the one of the module
439-
// await I_SecurityToken.archiveModule(GPMAddress[0], { from: token_owner });
440-
// // Remove the module
441-
// let tx = await I_SecurityToken.removeModule(GPMAddress[0], { from: token_owner });
442-
// assert.equal(tx.logs[0].args._types[0], permissionManagerKey);
443-
// assert.equal(tx.logs[0].args._module, GPMAddress[0]);
444-
// await revertToSnapshot(snap_Id);
445-
// });
398+
it("Should successfully remove the general transfer manager module from the securityToken -- fails msg.sender should be Owner", async () => {
399+
await catchRevert(I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: account_delegate }));
400+
});
401+
402+
it("Should fail to remove the module - module not archived", async () => {
403+
await catchRevert(I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: account_temp }));
404+
});
405+
406+
it("Should fail to remove the module - incorrect address", async () => {
407+
await catchRevert(I_SecurityToken.removeModule(address_zero, { from: token_owner }));
408+
});
409+
410+
it("Should successfully remove the general transfer manager module from the securityToken", async () => {
411+
let key = await takeSnapshot();
412+
await I_SecurityToken.archiveModule(I_GeneralTransferManager.address, { from: token_owner });
413+
let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: token_owner });
414+
assert.equal(tx.logs[0].args._types[0], transferManagerKey);
415+
assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address);
416+
await I_SecurityToken.mint(account_investor1, new BN(web3.utils.toWei("500")), { from: token_owner });
417+
await I_SecurityToken.transfer(account_investor2, new BN(web3.utils.toWei("200")), { from: account_investor1 });
418+
assert.equal((await I_SecurityToken.balanceOf(account_investor2)).div(new BN(10).pow(new BN(18))).toNumber(), 200);
419+
await revertToSnapshot(key);
420+
});
421+
422+
it("Should successfully remove the module from the middle of the names mapping", async () => {
423+
let snap_Id = await takeSnapshot();
424+
let D_GPM, D_GPM_1, D_GPM_2;
425+
let FactoryInstances;
426+
let GPMAddress = new Array();
427+
428+
[D_GPM] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, 0);
429+
[D_GPM_1] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, 0);
430+
[D_GPM_2] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, 0);
431+
FactoryInstances = [D_GPM, D_GPM_1, D_GPM_2];
432+
// Adding module in the ST
433+
for (let i = 0; i < FactoryInstances.length; i++) {
434+
let tx = await I_SecurityToken.addModule(FactoryInstances[i].address, "0x0", new BN(0), new BN(0), { from: token_owner });
435+
assert.equal(tx.logs[2].args._types[0], permissionManagerKey, "fail in adding the GPM");
436+
GPMAddress.push(tx.logs[2].args._module);
437+
}
438+
// Archive the one of the module
439+
await I_SecurityToken.archiveModule(GPMAddress[0], { from: token_owner });
440+
// Remove the module
441+
let tx = await I_SecurityToken.removeModule(GPMAddress[0], { from: token_owner });
442+
assert.equal(tx.logs[0].args._types[0], permissionManagerKey);
443+
assert.equal(tx.logs[0].args._module, GPMAddress[0]);
444+
await revertToSnapshot(snap_Id);
445+
});
446446

447447
it("Should successfully archive the module first and fail during achiving the module again", async () => {
448448
let key = await takeSnapshot();

0 commit comments

Comments
 (0)