VolumeRestrictionTransferManager
Introduced in
3.0.0
Contract name
VolumeRestrictionTM.sol
Compatible Protocol Version
^3.0.0
Type
Transfer Manager Module
How it works
It is used to restrict the maximum volume of tokens being traded by any individual investor in a given period of time and it also restricts maximum transfers that should be across all the token holders associated. An issuer can also exempt any token holders by adding then into the exemption list to make them unaffected by this module.
Key functionalities (as defined in the Smart Contract)
Initialization
This module is initialized with no parameters. That means during the creation of this contract there’s no need to call any type of configure() function.
Using the module
Layout for the Individual restriction
Note - Below use-case only works when the Alice has only Individual restriction not Individual daily restriction (24 hrs rolling period).
UseCase: Issuer wants to restrict Alice’s transfers as per the volume of tokens. An issuer will do so with the following transaction.
Call the addIndividualRestriction() function with following data.
Now Alice starts trading with the following assumptions.
Day1: Alice tries to sell 1000 tokens
Day 2: Alice tries to sell 5000 tokens
Day 3: No trading
Day 4: No trading
Day 5: Alice tries to sell 6000 tokens
Day 6: Alice tries to sell 3000 tokens
Day 7: No trading
Day 8: Alice tries to sell 4000 tokens
Transfer Verification
If
_fromaddress is 0x0 or present in the exemption list orpausedvariable is true then transfers will be unaffected by this module.If
_fromaddress has any individual restriction, whetherIndividualorIndividual dailyor both.isDefaultwill be false in_restrictionCheck()function params. Otherwise, it will be true.4 cases related to
_fromaddress_from has Individual Restriction
_from has 24 hrs Individual daily restriction
_from has both individual restriction and individual daily restriction
_from doesn’t have any Individual restriction. It falls into the default restriction. Whatever the default restriction will active that time will apply, whether
defaultordefault dailyor both.
First Case :-
If
_fromhas Individual restriction only & transaction time is betweenstartTimeandendTimeof the restriction, then transaction will go through only when:_amountis less than or equal to the_allowedAmount - sumOfLastPeriod, where_allowedAmountis the fixed number of tokens (allowedTokens) allowed to transact in a given rolling period when restriction type isFixed. If not, thenallowedAmountwill be calculated at the tx processing time according to the current totalSupply of the ST. i.e_allowedAmount = (_restriction.allowedTokens.mul(ISecurityToken(securityToken).totalSupply())) / uint256(10) ** 18.sumOfLastPeriodwill be the sum of the volume traded by the_fromin last n days, where n is always less than or equal to therollingPeriod. (given n will always be calculated after thestartTimeof the individual restriction ).
Second Case :-
If
_fromaddress has individual daily restriction & transaction time is betweenstartTimeandendTimeof the restriction, then the transaction will go through only when:_amountis less than or equal to the_allowedAmount - txSumOfDay, where_allowedAmountwill be calculated the same as above but according to theindividual daily volume restriction. WhiletxSumOfDayis the amount traded till now within the 24 hrs span* . This amount is stored according to at the start time of 24 hrs i.edailyLastTradedDayTime.
Third Case :-
If
_fromaddress has (individual daily restriction + individual restriction) & transaction time is betweenstartTimeandendTimeof the restriction, then transaction will go through only when:_amountis less than or equal to the_allowedAmount - sumOfLastPeriod(First case)_amountis less than or equal to the_allowedAmount - txSumOfDay(Second Case)Both above condition should be true otherwise tx gets failed. #807.
Fourth Case :-
It works similar to any one of the first/second/third case. It depends upon which default restriction is active. The only difference between the above three and this is to use different storage variables to store the data.
Add Volume restriction
For Individual restriction for a given holder address.
Require checks
individualRestriction[_holder].endTime < nowit means if holder has no restriction or holder already has restriction but it is expired then it will allow the add new restriction otherwise tx get reverted._holdershould not be a present in the exemption list._restrictionTypecould be 0 or 1. No other value allowed._rollingPeriodInDaysalways between [1, 365]._restrictionType == 0then_allowedTokensalways greater then zero otherwise_allowedTokensshould be non zero and value lies between (0, 100 _10*_16 ].Difference of days between
_startTimeand_endTimeshould be >=_rollingPeriodInDaysIf
_startTimeis 0 then it will takes current block timestamp + 1 as the startTime.
For multiple _holders (Similar require checks are applied to it):
For Individual daily restriction:
Note: In Individual daily restriction _rollingPeriodInDays always hardcoded to 1.
Individual daily restriction for multiple holders:
For Global restriction(same require check applies):
For default daily restriction:
Note: Same require checks only one change that _rollingPeriodInDays values are by default 1.
Modify Volume Restrictions
For modifying the individual restriction **
Note: It follows the same require checks as addxxx.. functions have.
For modifying multiple individual restrictions:
For modifying the individual daily restriction
Modifying the Multiple daily restrictions
Modifying default restriction:
Modifying daily default restriction
Remove Volume Restriction
Similar to addition or modification contract has the removeXX() or removeXXMulti() functions that will use to remove the individual, individual daily default, default daily restriction.
Getters
Provide the Individual bucket details for a given address.
Provide the Default bucket details for a given address.
Use to get the volume of token that is traded at a particular day for a given address
Use to get the balance of the token holder for the given partition
getExemptAddress()use to return the list of exempted addresses.getIndividualRestriction(address _investor)use to return the individual restriction details for a given user.getIndividualDailyRestriction(address _investor)use to return the individual daily restriction details for a given user.getDefaultRestriction()use to return the default restriction details.getDefaultDailyRestriction()use to return the default daily restriction details.getRestrictionData()Provide the restriction details of all the restricted addresses
Other functions
Below function will be used to add/remove the wallet address from the exemption list.
Special considerations / notes
** modification only allowed when the former restriction startTime should be greater than the current timestamp.
24hrs span will not be always morning to midnight of a day. It can be the afternoon of the day to the afternoon of the other day. It always depends on the start time of the Daily restriction.
Below internal function is used to mitigate the subtle edge case where user restriction type changes from default to an individual or vice versa.
Know Issues/bugs
All batch functions will hit the block gas limits if the array length is greater than 80(approx.).
Last updated
Was this helpful?