Skip to content

Commit fd15cb8

Browse files
committed
Merge branch 'dev-2.1.0' into dev-2.2.0
2 parents 40d4789 + fcc2fc6 commit fd15cb8

File tree

73 files changed

+5868
-2376
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+5868
-2376
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ jobs:
3939
path: ./test-results/mocha/results.xml
4040
coverage:
4141
docker:
42-
- image: circleci/node:8
42+
- image: maxsam4/solidity-kit:0.4.24
4343
steps:
4444
- checkout
4545
- restore_cache:
4646
key: dependency-cache-{{ checksum "package.json" }}
4747
- run: yarn install
48-
- run: sudo npm i truffle -g
4948
- run: node --version
5049
- run: truffle version
50+
- run: node_modules/.bin/truffle version
5151
- run:
52-
command: npm run coverage
52+
command: scripts/coverage.sh
5353
no_output_timeout: 1h
5454
- save_cache:
5555
key: dependency-cache-{{ checksum "package.json" }}

CHANGELOG.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,59 @@ All notable changes to this project will be documented in this file.
2121
* Removed individual mappings for tier data removed in UDSTSTO.
2222
* Removed the old Proxy deployment method of USDTieredSTO and adopt the new inherited proxy deployment approach.
2323
* Bump the version to `2.1.0`
24+
* Added `getAccreditedData` to return accredited & non-accredited investor data.
25+
* Event `TokenPurchase` has uint256 tier instead of uint8 tier.
26+
* Event `SetAddresses` has non-indexed array of address of `_usdTokens` rather than single indexed address.
27+
* Added `getUsdTokens()` function that returns array of accepted stable coin (usd token) addresses.
28+
* Pass an array of `_usdToken` address in `configure` function instead of singleton address. This will require changes in bytes data generation when deploying a usdtsto through factory.
2429

2530
## GeneralTransferManager
2631
* `getInvestors`, `getAllInvestorsData`, `getInvestorsData` added to GTM to allow easy data queries.
27-
* `modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime)` added which sets a default timestamp used when `fromTime` or `toTime` are 0
32+
* `changeDefaults(uint64 _defaultFromTime, uint64 _defaultToTime)` added which sets a default timestamp used when `fromTime` or `toTime` are 0.
2833
* Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`).
29-
* General Transfer Manager: Fix for when `allowAllWhitelistIssuances` is FALSE
30-
* General Transfer Manager: Make GTM a Proxy based implementation to reduce deployment gas costs
34+
* Fix for when `allowAllWhitelistIssuances` is FALSE
35+
* Make GTM a Proxy based implementation to reduce deployment gas costs
3136
* Changed the version of `GeneralTransferManagerFactory` from `1.0.0` to `2.1.0`.
37+
* `_investor` and `_addedBy` is now indexed in the `ModifyWhitelist` event.
38+
* Add public variable `defaults` to get the offset timing.
3239

3340
## Manual Approval TransferManager
34-
* Removed `0x0` check for the `_from` address to `ManualApprovalTransferManager`. This allows for the Issuer/Transfer Agent to approve a one-off mint of tokens that otherwise would not be possible.
41+
* Removed `0x0` check for the `_from` address to `ManualApprovalTransferManager`. This allows for the Issuer/Transfer Agent to approve a one-off mint of tokens that otherwise would not be possible.
3542
* Changed the version of `ManualApprovalTransferManagerFactory` from `1.0.0` to `2.1.0`.
3643
* Deployed 2.0.1 `ManualApprovalTransferManagerFactory` to address 0x6af2afad53cb334e62b90ddbdcf3a086f654c298
3744
* Add `getActiveApprovalsToUser()` function to access all the active approvals for a user whether user is in the `from` or in `to`.
3845
* Add `getApprovalDetails()` to get the details of the approval corresponds to `_from` and `_to` address.
3946
* Add feature to modify the details of the active approval using `modifyApproval()` & `modifyApprovalMulti()`.
4047
* Add `addManualApprovalMulti()` and `revokeManualApprovalMulti()` batch function for adding and revoking the manual approval respectively.
48+
* Add `_description` parameter during the `addManualApproval()` function call. It will be a `bytes32` variable which depicts the cause of manual approval.
49+
* Remove `addManualBlocking()` , `revokeManualBlocking()` functions.
50+
* Add `getTotalApprovalsLength()` to get the number of active approvals.
51+
* Add `getAllApprovals()` to get the details of all approvals.
4152

4253
## Dividends
4354
* Changed the version of `ERC20DividendCheckpointFactory` & `EtherDividendCheckpointFactory` from `1.0.0` to `2.1.0`.
44-
* Applied proxy pattern to Dividends modules
55+
* Applied proxy pattern to Dividends modules.
56+
* During the launch of dividend module issuer need to pass the reclaimed wallet that receive the left over funds from the module.
57+
i.e pass `_wallet` in `configure()` function of dividend module. It emits `SetWallet` event for the confirmation of the same.
58+
* Add `changeWallet()` function to change the reclaimed wallet address (only be called by the owner).
59+
* Add `getDividendsData()` getter to receive the details about all the dividend.
60+
* Add `getDividendData()` getter to receive the details about the particular dividend by passing a corresponding dividend index.
61+
* Add `getDividendProgress()` getter to retrieves the list of investors and their details corresponds to particular dividend.
62+
* Add `getCheckpointData()` use to retrieves list of investors, their balances, and their current withholding tax percentage corresponds to checkpointId.
63+
* `isExcluded()` a view function added to check whether an address is excluded from claming a dividend or not.
64+
* `isClaimed()` a view function added to checks whether an address has claimed a dividend or not.
65+
* DividendIndex is indexed in the events `ERC20DividendClaimed`, `ERC20DividendReclaimed`, `ERC20DividendWithholdingWithdrawn`. Similarly for the Ether dividend module `EtherDividendClaimed`, `EtherDividendReclaimed`, `EtherDividendClaimFailed`, `EtherDividendWithholdingWithdrawn`.
66+
* `EXCLUDED_ADDRESS_LIMIT` changed from 50 to 150.
4567

4668
## Experimental modules
4769
* Remove the `SingleTradeVolumeRestrictionTMFactory.sol` and its corresponding module `SingleTradeVolumeRestrictionTM.sol`.
70+
* Add the new TM called `BlacklistTransferManager.sol` and its corresponding factory `BlacklistTransferManagerFactory.sol`.
71+
* Chnage the name of module from `LockupVolumeRestrictionTM.sol` to `LockUpTransferManager.sol`, similarly factory become `LockUpTransferManagerFactory.sol`.
72+
* Add new module called `VestingEscrowWallet.sol` and its corresponding factory `VestingEscrowWalletFactory.sol`.
73+
74+
## STR & MR
75+
* `getArrayAddress(), getArrayBytes32(), getArrayUint()` are now public getters.
76+
* `getUintValues(), getBoolValues(), getStringValues(), getAddressValues(), getBytes32Values(), getBytesValues()` rename to `getUintValue(), getBoolValue(), getStringValue(), getAddressValue(), getBytes32Value(), getBytesValue()`. #488
4877

4978
## Added
5079
* Add new module called `VolumeRestrictionTM.sol` under the TransferManager modules list. It will be used to restrict the token
@@ -97,7 +126,7 @@ volume traded in a given rolling period.
97126
* Removed investors list pruning
98127
* Remove `swarmHash` from the `registerTicker(), addCustomTicker(), generateSecurityToken(), addCustomSecurityToken()` functions of TickerRegistry.sol and SecurityTokenRegistry.sol. #230
99128
* Remove `Log` prefix from all the event present in the ecosystem.
100-
* Removed `addTagByModuleType` & `removeTagsByModuleType` from MR.
129+
* Removed `addTagByModuleType` & `removeTagsByModuleType` from MR.
101130

102131
======
103132

CLI/commands/ST20Generator.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,13 @@ async function selectTicker() {
187187

188188
async function approvePoly(spender, fee) {
189189
polyBalance = await polyToken.methods.balanceOf(Issuer.address).call();
190-
let requiredAmount = web3.utils.toWei(fee.toString(), "ether");
190+
let requiredAmount = web3.utils.toWei(fee.toString());
191191
if (parseInt(polyBalance) >= parseInt(requiredAmount)) {
192-
let allowance = await polyToken.methods.allowance(spender, Issuer.address).call();
193-
if (allowance == web3.utils.toWei(fee.toString(), "ether")) {
192+
let allowance = await polyToken.methods.allowance(Issuer.address, spender).call();
193+
if (parseInt(allowance) >= parseInt(requiredAmount)) {
194194
return true;
195195
} else {
196-
let approveAction = polyToken.methods.approve(spender, web3.utils.toWei(fee.toString(), "ether"));
196+
let approveAction = polyToken.methods.approve(spender, requiredAmount);
197197
await common.sendTransaction(approveAction);
198198
}
199199
} else {

CLI/commands/common/common_functions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ module.exports = {
158158
},
159159
splitIntoBatches: function (data, batchSize) {
160160
let allBatches = [];
161-
for (let index = 0; index < data.length; index += batchSize) {
162-
allBatches.push(data.slice(index, index + batchSize));
161+
for (let index = 0; index < data.length; index += parseInt(batchSize)) {
162+
allBatches.push(data.slice(index, index + parseInt(batchSize)));
163163
}
164164
return allBatches;
165165
},

CLI/commands/common/permissions_list.js

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,30 +68,54 @@ function getPermissionList() {
6868
setAllowPrimaryIssuance: "ADMIN",
6969
changeHolderPercentage: "ADMIN"
7070
},
71-
LockupVolumeRestrictionTM: {
72-
addLockup: "ADMIN",
73-
addLockUpMulti: "ADMIN",
74-
removeLockUp: "ADMIN",
75-
modifyLockUp: "ADMIN"
71+
VolumeRestrictionTM: {
72+
changeExemptWalletList: "ADMIN",
73+
addIndividualRestriction: "ADMIN",
74+
addIndividualRestrictionMulti: "ADMIN",
75+
addGlobalRestriction: "ADMIN",
76+
addDailyGlobalRestriction: "ADMIN",
77+
removeIndividualRestriction: "ADMIN",
78+
removeIndividualRestrictionMulti: "ADMIN",
79+
removeGlobalRestriction: "ADMIN",
80+
removeDailyGlobalRestriction: "ADMIN",
81+
modifyIndividualRestriction: "ADMIN",
82+
modifyIndividualRestrictionMulti: "ADMIN",
83+
modifyGlobalRestriction: "ADMIN",
84+
modifyDailyGlobalRestriction: "ADMIN"
7685
},
77-
SingleTradeVolumeRestrictionTM: {
78-
setAllowPrimaryIssuance: "ADMIN",
79-
changeTransferLimitToPercentage: "ADMIN",
80-
changeTransferLimitToTokens: "ADMIN",
81-
changeGlobalLimitInTokens: "ADMIN",
82-
changeGlobalLimitInPercentage: "ADMIN",
83-
addExemptWallet: "ADMIN",
84-
removeExemptWallet: "ADMIN",
85-
addExemptWalletMulti: "ADMIN",
86-
removeExemptWalletMulti: "ADMIN",
87-
setTransferLimitInTokens: "ADMIN",
88-
setTransferLimitInPercentage: "ADMIN",
89-
removeTransferLimitInPercentage: "ADMIN",
90-
removeTransferLimitInTokens: "ADMIN",
91-
setTransferLimitInTokensMulti: "ADMIN",
92-
setTransferLimitInPercentageMulti: "ADMIN",
93-
removeTransferLimitInTokensMulti: "ADMIN",
94-
removeTransferLimitInPercentageMulti: "ADMIN"
86+
BlacklistTransferManager: {
87+
addBlacklistType: "ADMIN",
88+
addBlacklistTypeMulti: "ADMIN",
89+
modifyBlacklistType: "ADMIN",
90+
modifyBlacklistTypeMulti: "ADMIN",
91+
deleteBlacklistType: "ADMIN",
92+
deleteBlacklistTypeMulti: "ADMIN",
93+
addInvestorToBlacklist: "ADMIN",
94+
addInvestorToBlacklistMulti: "ADMIN",
95+
addMultiInvestorToBlacklistMulti: "ADMIN",
96+
addInvestorToNewBlacklist: "ADMIN",
97+
deleteInvestorFromAllBlacklist: "ADMIN",
98+
deleteInvestorFromAllBlacklistMulti: "ADMIN",
99+
deleteInvestorFromBlacklist: "ADMIN",
100+
deleteMultiInvestorsFromBlacklistMulti: "ADMIN",
101+
},
102+
VestingEscrowWallet: {
103+
changeTreasuryWallet: "ONLY_OWNER",
104+
depositTokens: "ADMIN",
105+
sendToTreasury: "ADMIN",
106+
pushAvailableTokens: "ADMIN",
107+
addTemplate: "ADMIN",
108+
removeTemplate: "ADMIN",
109+
addSchedule: "ADMIN",
110+
addScheduleFromTemplate: "ADMIN",
111+
modifySchedule: "ADMIN",
112+
revokeSchedule: "ADMIN",
113+
revokeAllSchedules: "ADMIN",
114+
pushAvailableTokensMulti: "ADMIN",
115+
addScheduleMulti: "ADMIN",
116+
addScheduleFromTemplateMulti: "ADMIN",
117+
revokeSchedulesMulti: "ADMIN",
118+
modifyScheduleMulti: "ADMIN"
95119
}
96120
}
97121
}

CLI/commands/dividends_manager.js

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,16 @@ async function configExistingModules(dividendModules) {
123123
async function dividendsManager() {
124124
console.log(chalk.blue(`Dividends module at ${currentDividendsModule.options.address}`), '\n');
125125

126+
let wallet = await currentDividendsModule.methods.wallet().call();
126127
let currentDividends = await getDividends();
127128
let defaultExcluded = await currentDividendsModule.methods.getDefaultExcluded().call();
128129
let currentCheckpointId = await securityToken.methods.currentCheckpointId().call();
129130

131+
console.log(`- Wallet: ${wallet}`);
130132
console.log(`- Current dividends: ${currentDividends.length}`);
131133
console.log(`- Default exclusions: ${defaultExcluded.length}`);
132134

133-
let options = ['Create checkpoint'];
135+
let options = ['Change wallet', 'Create checkpoint'];
134136
if (currentCheckpointId > 0) {
135137
options.push('Explore checkpoint');
136138
}
@@ -150,6 +152,9 @@ async function dividendsManager() {
150152
let selected = index != -1 ? options[index] : 'RETURN';
151153
console.log('Selected:', selected, '\n');
152154
switch (selected) {
155+
case 'Change wallet':
156+
await changeWallet();
157+
break;
153158
case 'Create checkpoint':
154159
await createCheckpointFromDividendModule();
155160
break;
@@ -180,6 +185,19 @@ async function dividendsManager() {
180185
await dividendsManager();
181186
}
182187

188+
async function changeWallet() {
189+
let newWallet = readlineSync.question('Enter the new account address to receive reclaimed dividends and tax: ', {
190+
limit: function (input) {
191+
return web3.utils.isAddress(input);
192+
},
193+
limitMessage: "Must be a valid address",
194+
});
195+
let action = currentDividendsModule.methods.changeWallet(newWallet);
196+
let receipt = await common.sendTransaction(action);
197+
let event = common.getEventFromLogs(currentDividendsModule._jsonInterface, receipt.logs, 'SetWallet');
198+
console.log(chalk.green(`The wallet has been changed successfully!`));
199+
}
200+
183201
async function createCheckpointFromDividendModule() {
184202
let createCheckpointAction = securityToken.methods.createCheckpoint();
185203
await common.sendTransaction(createCheckpointAction);
@@ -230,8 +248,19 @@ async function manageExistingDividend(dividendIndex) {
230248
let claimedArray = progress[1];
231249
let excludedArray = progress[2];
232250
let withheldArray = progress[3];
233-
let balanceArray = progress[4];
234-
let amountArray = progress[5];
251+
let amountArray = progress[4];
252+
let balanceArray = progress[5];
253+
254+
// function for adding two numbers. Easy!
255+
const add = (a, b) => {
256+
const bnA = new web3.utils.BN(a);
257+
const bnB = new web3.utils.BN(b);
258+
return bnA.add(bnB).toString();
259+
};
260+
// use reduce to sum our array
261+
let taxesToWithHeld = withheldArray.reduce(add, 0);
262+
let claimedInvestors = claimedArray.filter(c => c).length;
263+
let excludedInvestors = excludedArray.filter(e => e).length;
235264

236265
console.log(`- Name: ${web3.utils.hexToUtf8(dividend.name)}`);
237266
console.log(`- Created: ${moment.unix(dividend.created).format('MMMM Do YYYY, HH:mm:ss')}`);
@@ -240,11 +269,13 @@ async function manageExistingDividend(dividendIndex) {
240269
console.log(`- At checkpoint: ${dividend.checkpointId}`);
241270
console.log(`- Amount: ${web3.utils.fromWei(dividend.amount)} ${dividendTokenSymbol}`);
242271
console.log(`- Claimed amount: ${web3.utils.fromWei(dividend.claimedAmount)} ${dividendTokenSymbol}`);
243-
console.log(`- Withheld: ${web3.utils.fromWei(dividend.totalWithheld)} ${dividendTokenSymbol}`);
244-
console.log(`- Withheld claimed: ${web3.utils.fromWei(dividend.totalWithheldWithdrawn)} ${dividendTokenSymbol}`);
272+
console.log(`- Taxes:`);
273+
console.log(` To withhold: ${web3.utils.fromWei(taxesToWithHeld)} ${dividendTokenSymbol}`);
274+
console.log(` Withheld to-date: ${web3.utils.fromWei(dividend.totalWithheld)} ${dividendTokenSymbol}`);
275+
console.log(` Withdrawn to-date: ${web3.utils.fromWei(dividend.totalWithheldWithdrawn)} ${dividendTokenSymbol}`);
245276
console.log(`- Total investors: ${investorArray.length}`);
246-
console.log(` Have already claimed: ${claimedArray.filter(c => c).length}`);
247-
console.log(` Excluded: ${excludedArray.filter(e => e).length} `);
277+
console.log(` Have already claimed: ${claimedInvestors} (${investorArray.length - excludedInvestors !== 0 ? claimedInvestors / (investorArray.length - excludedInvestors) * 100 : 0}%)`);
278+
console.log(` Excluded: ${excludedInvestors} `);
248279
// ------------------
249280

250281

@@ -454,10 +485,10 @@ function showReport(_name, _tokenSymbol, _amount, _witthheld, _claimed, _investo
454485
let investor = _investorArray[i];
455486
let excluded = _excludedArray[i];
456487
let withdrawn = _claimedArray[i] ? 'YES' : 'NO';
457-
let amount = !excluded ? web3.utils.fromWei(_amountArray[i]) : 0;
458-
let withheld = (!excluded && _claimedArray[i]) ? web3.utils.fromWei(_withheldArray[i]) : 'NA';
459-
let withheldPercentage = (!excluded && _claimedArray[i]) ? (withheld !== '0' ? parseFloat(withheld) / parseFloat(amount) * 100 : 0) : 'NA';
460-
let received = (!excluded && _claimedArray[i]) ? web3.utils.fromWei(web3.utils.toBN(_amountArray[i]).sub(web3.utils.toBN(_withheldArray[i]))) : 0;
488+
let amount = !excluded ? web3.utils.fromWei(web3.utils.toBN(_amountArray[i]).add(web3.utils.toBN(_withheldArray[i]))) : 0;
489+
let withheld = !excluded ? web3.utils.fromWei(_withheldArray[i]) : 'NA';
490+
let withheldPercentage = (!excluded) ? (withheld !== '0' ? parseFloat(withheld) / parseFloat(amount) * 100 : 0) : 'NA';
491+
let received = !excluded ? web3.utils.fromWei(_amountArray[i]) : 0;
461492
dataTable.push([
462493
investor,
463494
amount,
@@ -476,6 +507,8 @@ function showReport(_name, _tokenSymbol, _amount, _witthheld, _claimed, _investo
476507
console.log(`- Total amount of investors: ${_investorArray.length} `);
477508
console.log();
478509
console.log(table(dataTable));
510+
console.log();
511+
console.log(chalk.yellow(`NOTE: If investor has not claimed the dividend yet, TAX and AMOUNT are calculated with the current values set and they might change.`));
479512
console.log(chalk.yellow(`-----------------------------------------------------------------------------------------------------------------------------------------------------------`));
480513
console.log();
481514
}
@@ -561,7 +594,14 @@ async function addDividendsModule() {
561594

562595
let index = readlineSync.keyInSelect(options, 'Which dividends module do you want to add? ', { cancel: 'Return' });
563596
if (index != -1 && readlineSync.keyInYNStrict(`Are you sure you want to add ${options[index]} module? `)) {
564-
let bytes = web3.utils.fromAscii('', 16);
597+
let wallet = readlineSync.question('Enter the account address to receive reclaimed dividends and tax: ', {
598+
limit: function (input) {
599+
return web3.utils.isAddress(input);
600+
},
601+
limitMessage: "Must be a valid address",
602+
});
603+
let configureFunction = abis.erc20DividendCheckpoint().find(o => o.name === 'configure' && o.type === 'function');
604+
let bytes = web3.eth.abi.encodeFunctionCall(configureFunction, [wallet]);
565605

566606
let selectedDividendFactoryAddress = await contracts.getModuleFactoryAddressByName(securityToken.options.address, gbl.constants.MODULES_TYPES.DIVIDENDS, options[index]);
567607
let addModuleAction = securityToken.methods.addModule(selectedDividendFactoryAddress, bytes, 0, 0);
@@ -655,11 +695,11 @@ async function selectDividend(dividends) {
655695
let result = null;
656696
let options = dividends.map(function (d) {
657697
return `${d.name}
658-
Amount: ${ web3.utils.fromWei(d.amount)} ${dividendsType}
659-
Status: ${ isExpiredDividend(d) ? 'Expired' : hasRemaining(d) ? 'In progress' : 'Completed'}
660-
Token: ${ d.tokenSymbol}
661-
Created: ${ moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')}
662-
Expiry: ${ moment.unix(d.expiry).format('MMMM Do YYYY, HH:mm:ss')} `
698+
Amount: ${web3.utils.fromWei(d.amount)} ${d.tokenSymbol}
699+
Status: ${isExpiredDividend(d) ? 'Expired' : hasRemaining(d) ? 'In progress' : 'Completed'}
700+
Token: ${d.tokenSymbol}
701+
Created: ${moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')}
702+
Expiry: ${moment.unix(d.expiry).format('MMMM Do YYYY, HH:mm:ss')} `
663703
});
664704

665705
let index = readlineSync.keyInSelect(options, 'Select a dividend:', { cancel: 'RETURN' });

0 commit comments

Comments
 (0)