Skip to content
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

Single Trade Volume Restriction #262

Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a48ae40
Initial Setup
subramanianv Sep 18, 2018
90c9c54
deploy function
subramanianv Sep 18, 2018
62f4d6c
Implement VerfyTransfer Function and also Permissions
subramanianv Sep 18, 2018
b1e882a
Fix lookup errors
subramanianv Sep 18, 2018
f6b9c7a
Single Trade Volume Tests WIP
subramanianv Sep 25, 2018
c7f5012
Complete tests
subramanianv Sep 26, 2018
939d0c0
Update comments
subramanianv Sep 26, 2018
5f5f416
Merge branch 'development-1.5.0' of https://github.com/PolymathNetwor…
subramanianv Sep 26, 2018
4e1010f
change implementation according to development-1.5 branch
subramanianv Sep 26, 2018
c87b5c2
Tests refactored
subramanianv Sep 26, 2018
889db0e
Added multi functions
subramanianv Sep 27, 2018
f399728
added comments for singletradevolumeRestrictionFactory
subramanianv Sep 27, 2018
74fe6ed
Add token info script
adamdossa Sep 27, 2018
bb2d279
Merge pull request #282 from PolymathNetwork/token-info-script
pabloruiz55 Sep 27, 2018
a233e46
Added more tests
subramanianv Sep 27, 2018
2f2b19d
More tests
subramanianv Sep 27, 2018
6738b00
Changes from the review and more tests
subramanianv Sep 27, 2018
8aa2560
More tests
subramanianv Sep 27, 2018
47c82fd
More tests
subramanianv Sep 27, 2018
1814326
Merge branch 'development-1.5.0' of https://github.com/PolymathNetwor…
subramanianv Sep 27, 2018
d823228
Changes after the merge
subramanianv Sep 28, 2018
7a56664
Changes from the review
subramanianv Oct 1, 2018
1e46254
Merge https://github.com/PolymathNetwork/polymath-core into singleTra…
subramanianv Oct 1, 2018
8c344e3
Merge branch 'development-1.5.0' of https://github.com/PolymathNetwor…
subramanianv Oct 1, 2018
6b328dc
Add tests
subramanianv Oct 1, 2018
477a858
Merge branch 'development-1.5.0' of https://github.com/PolymathNetwor…
subramanianv Oct 3, 2018
09015da
Changes from the review
subramanianv Oct 3, 2018
c6722fd
Deleted tokeninfo.js
subramanianv Oct 3, 2018
b2c717d
Merge branch 'development-1.5.0' into singleTradeVolumeRestriction
adamdossa Oct 4, 2018
9da57ab
Update 2_deploy_contracts.js
adamdossa Oct 4, 2018
d30f0fb
Merge branch 'development-1.5.0' into singleTradeVolumeRestriction
pabloruiz55 Oct 4, 2018
77b3410
Update SingleTradeVolumeRestrictionManager.sol
adamdossa Oct 4, 2018
786d705
Update 2_deploy_contracts.js
adamdossa Oct 4, 2018
149f56d
Update w_single_trade_volume_restriction.js
adamdossa Oct 4, 2018
28c3315
minor fixes
SatyamSB Oct 5, 2018
61f268d
Merge branch 'development-1.5.0' into singleTradeVolumeRestriction
adamdossa Oct 5, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
pragma solidity ^0.4.24;
import "./ITransferManager.sol";

/////////////////////
// Module permissions
/////////////////////
// Owner ADMIN
// changeGlobalLimit X X
// addExemptWallet X X
// removeExemptWallet X X
// setTransferLimitForWallet X X
// removeTransferLimitForWallet X X

contract SingleTradeVolumeRestrictionManager is ITransferManager {
using SafeMath for uint256;

bool public globalTransferLimitInPercentage;

uint256 public globalTransferLimit;

mapping(address=>bool) public exemptWallets;

mapping(address => bool) public specialTransferLimitWallets;

mapping(address => uint) public specialTransferLimits;

bytes32 constant public ADMIN = "ADMIN";

constructor(address _securityToken, address _polyAddress) public
IModule(_securityToken, _polyAddress)
{

}

function verifyTransfer(address _from, address _to, uint256 _amount, bool /* _isTransfer */) public returns(Result) {
bool validTransfer;

if(paused) {
return Result.NA;
}

if(exemptWallets[_from]) return Result.NA;

if(specialTransferLimitWallets[_from]) {
if(globalTransferLimitInPercentage) {
validTransfer = (_amount.mul(100).div(ISecurityToken(securityToken).totalSupply())) <= specialTransferLimits[_from];
Copy link
Contributor

@satyamakgec satyamakgec Sep 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error in the calculation. You are giving the margin of 0.9 %. Suppose if the left size has the 15.7% and right side have the 15 % value then it still gets true instead of false.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@satyamakgec I don't fully understand your comment. Is your comment because of this warning from the solidity docs ? Division on integer literals used to truncate in earlier versions, but it will now convert into a rational number, i.e. 5 / 2 is not equal to 2, but to 2.5.

Copy link
Author

@subramanianv subramanianv Sep 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also From PercentageTransferManager
if(newBalance.mul(10**uint256(ISecurityToken(securityToken).decimals())).div(ISecurityToken(securityToken).totalSupply()) > maxHolderPercentage) { return Result.INVALID; }

Shouldn't newBalance be multipled by 10^18 explicitly instead of 10^decimals as maxHolderPercentage is multipled by (10^18/100) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so because by default securitytoken have 18 decimals so in case of PercentageTransferManager it always give you the value right percentage calculation.

   newBalance = x * 10^d
   totalSupply = y * 10^d
   maxHolderPercentage = z * 10^d
   so it looks like this -  (x* 10^d * 10^d) / y* 10^d > (z * 10^d)/100      ... where d = 18 
   After calculation you can easily compare ((x * 10^18)/y) > (z* 10^16)

But in your case you are doing this

   amount  = a* 10^d
   totalSupply = b* 10^d
   Limit= c* 10^d  (case 1)
   so it will look like this -  (a* 10^d * 100)/(b* 10^d) <= c* 10^d   .... where d = 18
   so your left hand side is always less than the right hand side.
   
   Limit = c (case 2)
   in this condition  - (155000 * 10^d * 100) / (1000000 * 10^d) <= 15   .... a= 155000, b = 1000000, c= 15 and d =18.
   After calculation it should be  15.5 <= 15  (and it will returns true as per my test on remix with 0.4.24 and 0.4.25 solidity version).

  and using case 2 you also can't cover the limits in decimal 

Copy link
Author

@subramanianv subramanianv Sep 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@satyamakgec Thanks for the reply. The first case, which I haven't implemented is missing a multiplication by 10^18. it should be (a* 10^d * 10^18)/(b* 10^d) <= c* 10^16. I will implement this formula/calculation.

In the PercentageTransferManager - the math should be (x* 10^d * 10^18) / y* 10^d > (z * 10^18)/100. The multiplication should be explicitly done by 10^18. I think this would work for security token of any decimals, not just tokens with 18 decimals

} else {
validTransfer = _amount <= specialTransferLimits[_from];
}
} else {
if(globalTransferLimitInPercentage) {
validTransfer = (_amount.mul(100).div(ISecurityToken(securityToken).totalSupply())) <= globalTransferLimit;
} else {
validTransfer = _amount <= globalTransferLimit;
}
}

if(validTransfer) return Result.NA;
return Result.INVALID;
}

function configure(bool _globalTransferLimitInPercentage, uint256 _globalTransferLimit) public onlyFactory {
globalTransferLimitInPercentage = _globalTransferLimitInPercentage;
changeGlobalLimit(_globalTransferLimit);
}

function changeGlobalLimit(uint256 _newGlobalTransferLimit) public withPerm(ADMIN) {
if(globalTransferLimitInPercentage) {
require(_newGlobalTransferLimit <= 100);
}
globalTransferLimit = _newGlobalTransferLimit;
}

function addExemptWallet(address _walletAddress) public withPerm(ADMIN) {
require(_walletAddress != address(0));
exemptWallets[_walletAddress] = true;
}

function removeExemptWallet(address _walletAddress) public withPerm(ADMIN) {
require(_walletAddress != address(0));
exemptWallets[_walletAddress] = false;
}

function setTransferLimitForWallet(address _walletAddress, uint _transferLimit) public withPerm(ADMIN) {
if(globalTransferLimitInPercentage) {
require(_transferLimit <= 100);
}
specialTransferLimitWallets[_walletAddress] = true;
specialTransferLimits[_walletAddress] = _transferLimit;
}

function removeTransferLimitForWallet(address _walletAddress) public withPerm(ADMIN) {
require(specialTransferLimitWallets[_walletAddress]);
specialTransferLimitWallets[_walletAddress] = false;
specialTransferLimits[_walletAddress] = 0;
}

/**
* @notice This function returns the signature of configure function
*/
function getInitFunction() public pure returns (bytes4) {
return bytes4(keccak256("configure(bool, uint256)"));
}

// TO IMPLEMENT
function getPermissions() public view returns(bytes32[]) {
bytes32[] memory allPermissions = new bytes32[](1);
allPermissions[0] = ADMIN;
return allPermissions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
pragma solidity ^0.4.24;

import "../../interfaces/IModuleFactory.sol";
import "./SingleTradeVolumeRestrictionManager.sol";
contract SingleTradeVolumeRestrictionFactory is IModuleFactory {

/**
* @notice Constructor
* @param _polyAddress Address of the polytoken
* @param _setupCost Setup cost of the module
* @param _usageCost Usage cost of the module
* @param _subscriptionCost Subscription cost of the module
*/
constructor(address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public
IModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost)
{

}

/**
* @notice used to launch the Module with the help of factory
* @return address Contract address of the Module
*/
function deploy(bytes _data) external returns(address) {
if (setupCost > 0)
require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom because of sufficent Allowance is not provided");
SingleTradeVolumeRestrictionManager singleTradeVolumeRestrictionManager = new SingleTradeVolumeRestrictionManager(msg.sender, address(polyToken));
require(getSig(_data) == singleTradeVolumeRestrictionManager.getInitFunction(), "Provided data is not valid");
require(address(singleTradeVolumeRestrictionManager).call(_data), "Un-successfull call");
emit LogGenerateModuleFromFactory(address(singleTradeVolumeRestrictionManager), getName(), address(this), msg.sender, now);
return address(singleTradeVolumeRestrictionManager);
}

/**
* @notice Type of the Module factory
*/
function getType() public view returns(uint8) {
return 2;
}

/**
* @notice Get the name of the Module
*/
function getName() public view returns(bytes32) {
return "SingleTradeVolumeRestriction";
}

/**
* @notice Get the description of the Module
*/
function getDescription() public view returns(string) {
return "Imposes volume restriction on a single trade";
}

/**
* @notice Get the title of the Module
*/
function getTitle() public view returns(string) {
return "Single Trade Volume Restriction";
}

/**
* @notice Get the Instructions that help to use the module
*/
function getInstructions() public view returns(string) {
return "Allows an issuer to impose volume restriction on a single trade";
}

/**
* @notice Get the tags related to the module factory
*/
function getTags() public view returns(bytes32[]) {
bytes32[] memory availableTags = new bytes32[](3);
availableTags[0] = "Single Trade";
availableTags[1] = "Transfer";
availableTags[2] = "Volume";
return availableTags;
}

}