-
Notifications
You must be signed in to change notification settings - Fork 152
Support multiple module types #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
fc0bace
WIP
adamdossa a925a8c
Fixes
adamdossa 4838de7
Merge branch 'development-1.5.0' into support_multiple_module_types
adamdossa 59cb476
Size too big...
adamdossa ce06984
WIP
adamdossa ceed74e
WIP
adamdossa e7caf0d
Go back to in-lined internals
adamdossa f1c6aa4
Merge branch 'development-1.5.0' into support_multiple_module_types
adamdossa 0a00f95
Remove merge cruft
adamdossa 85a8ba6
More merge cruft
adamdossa f31a001
WIP fixes
adamdossa a37a776
Still too big
adamdossa 5c5dbd5
Working
adamdossa 80bfbb1
Remove commented lines
adamdossa 5a7657b
Fix test cases
adamdossa 5278696
More fixes
adamdossa 3b0f0be
Remove kludge
adamdossa b91c14e
Fix some more tests
adamdossa b37b605
move investors data and logic into the library
SatyamSB 11f6e60
minor naming fix
SatyamSB e7a290d
cleanup
SatyamSB 6fe5614
Merge branch 'support_multiple_module_types' into some-changes-adampr
SatyamSB 2b50c16
add some improvements
SatyamSB d5e0a7f
added a missing semi-colon
maxsam4 f4869dd
Fixes based on comments
adamdossa a810f91
Remove empty module
adamdossa 2952dc4
Add forceBurn to fuzz testing for checkpoints
adamdossa acbc3f5
resolve conflicts
SatyamSB 7e2859b
minor fix
SatyamSB 6d8bcee
remove investorCount
SatyamSB e4817d3
Merge pull request #314 from PolymathNetwork/some-changes-adampr
satyamakgec 1b4a549
Small update
adamdossa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,29 @@ | ||
| pragma solidity ^0.4.24; | ||
|
|
||
|
|
||
| library Encoder { | ||
|
|
||
| function getKey(string _key) internal pure returns (bytes32) { | ||
| return bytes32(keccak256(abi.encodePacked(_key))); | ||
| } | ||
|
|
||
| function getKey(string _key1, address _key2) internal pure returns (bytes32) { | ||
| return bytes32(keccak256(abi.encodePacked(_key1, _key2))); | ||
| } | ||
|
|
||
| function getKey(string _key1, string _key2) internal pure returns (bytes32) { | ||
| return bytes32(keccak256(abi.encodePacked(_key1, _key2))); | ||
| } | ||
|
|
||
| function getKey(string _key1, uint256 _key2) internal pure returns (bytes32) { | ||
| return bytes32(keccak256(abi.encodePacked(_key1, _key2))); | ||
| } | ||
|
|
||
| function getKey(string _key1, bytes32 _key2) internal pure returns (bytes32) { | ||
| return bytes32(keccak256(abi.encodePacked(_key1, _key2))); | ||
| } | ||
|
|
||
| function getKey(string _key1, bool _key2) internal pure returns (bytes32) { | ||
| return bytes32(keccak256(abi.encodePacked(_key1, _key2))); | ||
| } | ||
|
|
||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,193 @@ | ||
| pragma solidity ^0.4.24; | ||
|
|
||
| import "../modules/PermissionManager/IPermissionManager.sol"; | ||
| import "./KindMath.sol"; | ||
|
|
||
| library TokenLib { | ||
|
|
||
| using KindMath for uint256; | ||
|
|
||
| // Struct for module data | ||
| struct ModuleData { | ||
| bytes32 name; | ||
| address module; | ||
| address moduleFactory; | ||
| bool isArchived; | ||
| uint8[] moduleTypes; | ||
| uint256[] moduleIndexes; | ||
| uint256 nameIndex; | ||
| } | ||
|
|
||
| // Structures to maintain checkpoints of balances for governance / dividends | ||
| struct Checkpoint { | ||
| uint256 checkpointId; | ||
| uint256 value; | ||
| } | ||
|
|
||
| struct InvestorDataStorage { | ||
| // List of investors (may not be pruned to remove old investors with current zero balances) | ||
| mapping (address => bool) investorListed; | ||
| // List of token holders | ||
| address[] investors; | ||
| // Total number of non-zero token holders | ||
| uint256 investorCount; | ||
| } | ||
|
|
||
| // Emit when Module get archived from the securityToken | ||
| event ModuleArchived(uint8[] _types, address _module, uint256 _timestamp); | ||
| // Emit when Module get unarchived from the securityToken | ||
| event ModuleUnarchived(uint8[] _types, address _module, uint256 _timestamp); | ||
|
|
||
| /** | ||
| * @notice Archives a module attached to the SecurityToken | ||
| * @param _moduleData storage data | ||
| * @param _module address of module to archive | ||
| */ | ||
| function archiveModule(ModuleData storage _moduleData, address _module) public { | ||
| require(!_moduleData.isArchived, "Module archived"); | ||
| require(_moduleData.module != address(0), "Module missing"); | ||
| emit ModuleArchived(_moduleData.moduleTypes, _module, now); | ||
| _moduleData.isArchived = true; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Unarchives a module attached to the SecurityToken | ||
| * @param _moduleData storage data | ||
| * @param _module address of module to unarchive | ||
| */ | ||
| function unarchiveModule(ModuleData storage _moduleData, address _module) public { | ||
| require(_moduleData.isArchived, "Module unarchived"); | ||
| emit ModuleUnarchived(_moduleData.moduleTypes, _module, now); | ||
| _moduleData.isArchived = false; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Validate permissions with PermissionManager if it exists, If no Permission return false | ||
| * @dev Note that IModule withPerm will allow ST owner all permissions anyway | ||
| * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) | ||
| * @param _modules storage data | ||
| * @param _delegate address of delegate | ||
| * @param _module address of PermissionManager module | ||
| * @param _perm the permissions | ||
| * @return success | ||
| */ | ||
| function checkPermission(address[] storage _modules, address _delegate, address _module, bytes32 _perm) public view returns(bool) { | ||
| if (_modules.length == 0) { | ||
| return false; | ||
| } | ||
|
|
||
| for (uint8 i = 0; i < _modules.length; i++) { | ||
| if (IPermissionManager(_modules[i]).checkPermission(_delegate, _module, _perm)) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Queries value at a defined checkpoint | ||
| * @param _checkpoints is array of Checkpoint objects | ||
| * @param _checkpointId Checkpoint ID to query | ||
| * @param _currentValue Current value of checkpoint | ||
| * @return uint256 | ||
| */ | ||
| function getValueAt(Checkpoint[] storage _checkpoints, uint256 _checkpointId, uint256 _currentValue) public view returns(uint256) { | ||
| //Checkpoint id 0 is when the token is first created - everyone has a zero balance | ||
| if (_checkpointId == 0) { | ||
| return 0; | ||
| } | ||
| if (_checkpoints.length == 0) { | ||
| return _currentValue; | ||
| } | ||
| if (_checkpoints[0].checkpointId >= _checkpointId) { | ||
| return _checkpoints[0].value; | ||
| } | ||
| if (_checkpoints[_checkpoints.length - 1].checkpointId < _checkpointId) { | ||
| return _currentValue; | ||
| } | ||
| if (_checkpoints[_checkpoints.length - 1].checkpointId == _checkpointId) { | ||
| return _checkpoints[_checkpoints.length - 1].value; | ||
| } | ||
| uint256 min = 0; | ||
| uint256 max = _checkpoints.length - 1; | ||
| while (max > min) { | ||
| uint256 mid = (max + min) / 2; | ||
| if (_checkpoints[mid].checkpointId == _checkpointId) { | ||
| max = mid; | ||
| break; | ||
| } | ||
| if (_checkpoints[mid].checkpointId < _checkpointId) { | ||
| min = mid + 1; | ||
| } else { | ||
| max = mid; | ||
| } | ||
| } | ||
| return _checkpoints[max].value; | ||
| } | ||
|
|
||
| /** | ||
| * @notice store the changes to the checkpoint objects | ||
| * @param _checkpoints the affected checkpoint object array | ||
| * @param _newValue the new value that needs to be stored | ||
| */ | ||
| function adjustCheckpoints(TokenLib.Checkpoint[] storage _checkpoints, uint256 _newValue, uint256 _currentCheckpointId) public { | ||
| //No checkpoints set yet | ||
| if (_currentCheckpointId == 0) { | ||
| return; | ||
| } | ||
| //No new checkpoints since last update | ||
| if ((_checkpoints.length > 0) && (_checkpoints[_checkpoints.length - 1].checkpointId == _currentCheckpointId)) { | ||
| return; | ||
| } | ||
| //New checkpoint, so record balance | ||
| _checkpoints.push( | ||
| TokenLib.Checkpoint({ | ||
| checkpointId: _currentCheckpointId, | ||
| value: _newValue | ||
| }) | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * @notice keeps track of the number of non-zero token holders | ||
| * @param _investorData Date releated to investor metrics | ||
| * @param _from sender of transfer | ||
| * @param _to receiver of transfer | ||
| * @param _value value of transfer | ||
| * @param _balanceTo balance of the _to address | ||
| * @param _balanceFrom balance of the _from address | ||
| */ | ||
| function adjustInvestorCount(InvestorDataStorage storage _investorData, address _from, address _to, uint256 _value, uint256 _balanceTo, uint256 _balanceFrom) public { | ||
| if ((_value == 0) || (_from == _to)) { | ||
| return; | ||
| } | ||
| // Check whether receiver is a new token holder | ||
| if ((_balanceTo == 0) && (_to != address(0))) { | ||
| _investorData.investorCount = (_investorData.investorCount).add(1); | ||
| } | ||
| // Check whether sender is moving all of their tokens | ||
| if (_value == _balanceFrom) { | ||
| _investorData.investorCount = (_investorData.investorCount).sub(1); | ||
| } | ||
| //Also adjust investor list | ||
| if (!_investorData.investorListed[_to] && (_to != address(0))) { | ||
| _investorData.investors.push(_to); | ||
| _investorData.investorListed[_to] = true; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| /** | ||
| * @notice removes addresses with zero balances from the investors list | ||
| * @param _investorData Date releated to investor metrics | ||
| * @param _index Index in investor list | ||
| * NB - pruning this list will mean you may not be able to iterate over investors on-chain as of a historical checkpoint | ||
| */ | ||
| function pruneInvestors(InvestorDataStorage storage _investorData, uint256 _index) public { | ||
| _investorData.investorListed[_investorData.investors[_index]] = false; | ||
| _investorData.investors[_index] = _investorData.investors[_investorData.investors.length - 1]; | ||
| _investorData.investors.length--; | ||
| } | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.