Skip to content

Commit

Permalink
Optimise GTM (#443)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* Fixes

* Update config

* Log gas for 50 txs

* WIP

* update

* Fix tests

* Fix typo

* Change onWhitelist logic

* Update changelog

* Update all test cases

* Add whitelist optimization

* Make Dividend modules proxies

* Updates

* minor cleanup

* make script dynamic

* Keep ABI constant

* Fixes

* Update change log

* Updates

* add require statement in factory constructors

* remove the test cases for the STVRTM

* Return investor data in getAllInvestorsData

* CLI changes according GTM optimizations

* Bump versions

* version changes

* Update CHANGELOG.md
  • Loading branch information
adamdossa authored Dec 5, 2018
1 parent 4fc9f24 commit 3dba7bd
Show file tree
Hide file tree
Showing 38 changed files with 1,067 additions and 1,368 deletions.
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,26 @@ All notable changes to this project will be documented in this file.
* Added `getTokensSoldByTier` to return sold (not minted during finalisation) tokens in each tier to USDTSTO.
* Removed individual mappings for tier data removed in UDSTSTO.

## GeneralTransferManager
* `getInvestors`, `getAllInvestorsData`, `getInvestorsData` added to GTM to allow easy data queries.
* `modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime)` added which sets a default timestamp used when `fromTime` or `toTime` are 0
* Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`).
* General Transfer Manager: Fix for when `allowAllWhitelistIssuances` is FALSE
* General Transfer Manager: Make GTM a Proxy based implementation to reduce deployment gas costs
* Changed the version of `GeneralTransferManagerFactory` from `1.0.0` to `2.1.0`.

## Manual Approval TransferManager
* 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.
* Changed the version of `ManualApprovalTransferManagerFactory` from `1.0.0` to `2.0.1`.
* Changed the version of `ManualApprovalTransferManagerFactory` from `1.0.0` to `2.1.0`.
* Deployed 2.0.1 `ManualApprovalTransferManagerFactory` to address 0x6af2afad53cb334e62b90ddbdcf3a086f654c298

## Dividends
* Changed the version of `ERC20DividendCheckpointFactory` & `EtherDividendCheckpointFactory` from `1.0.0` to `2.1.0`.
* Applied proxy pattern to Dividends modules

## Changed
* `getAllModulesAndPermsFromTypes()` does not take securityToken address as a parameter anymore.


# v1.5.0 - Release Candidate

Expand Down
68 changes: 55 additions & 13 deletions CLI/commands/transfer_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const contracts = require('./helpers/contract_addresses');
const abis = require('./helpers/contract_abis');
const gbl = require('./common/global');
const csvParse = require('./helpers/csv');
const { table } = require('table')

///////////////////
// Constants
Expand Down Expand Up @@ -328,17 +329,28 @@ async function generalTransferManager() {
let displayAllowAllWhitelistTransfers = await currentTransferManager.methods.allowAllWhitelistTransfers().call();
let displayAllowAllWhitelistIssuances = await currentTransferManager.methods.allowAllWhitelistIssuances().call();
let displayAllowAllBurnTransfers = await currentTransferManager.methods.allowAllBurnTransfers().call();
let displayDefaults = await currentTransferManager.methods.defaults().call();
let displayInvestors = await currentTransferManager.methods.getInvestors().call();

console.log(`- Issuance address: ${displayIssuanceAddress}`);
console.log(`- Signing address: ${displaySigningAddress}`);
console.log(`- Allow all transfers: ${displayAllowAllTransfers ? `YES` : `NO`}`);
console.log(`- Allow all whitelist transfers: ${displayAllowAllWhitelistTransfers ? `YES` : `NO`}`);
console.log(`- Allow all whitelist issuances: ${displayAllowAllWhitelistIssuances ? `YES` : `NO`}`);
console.log(`- Allow all burn transfers: ${displayAllowAllBurnTransfers ? `YES` : `NO`}`);
console.log(`- Default times:`);
console.log(` - From time: ${displayDefaults.fromTime} (${moment.unix(displayDefaults.fromTime).format('MMMM Do YYYY, HH:mm:ss')})`);
console.log(` - To time: ${displayDefaults.toTime} (${moment.unix(displayDefaults.toTime).format('MMMM Do YYYY, HH:mm:ss')})`);
console.log(`- Investors: ${displayInvestors.length}`);
// ------------------

let options = ['Check whitelist', 'Modify whitelist', 'Modify whitelist from CSV', /*'Modify Whitelist Signed',*/
`Change issuance address`, 'Change signing address'];
let options = [];
if (displayInvestors.length > 0) {
options.push(`Show investors`, `Show whitelist data`);
}
options.push('Modify whitelist', 'Modify whitelist from CSV', /*'Modify Whitelist Signed',*/
'Change the default times used when they are zero', `Change issuance address`, 'Change signing address');

if (displayAllowAllTransfers) {
options.push('Disallow all transfers');
} else {
Expand All @@ -364,18 +376,33 @@ async function generalTransferManager() {
let optionSelected = options[index];
console.log('Selected:', index != -1 ? optionSelected : 'Return', '\n');
switch (optionSelected) {
case 'Check whitelist':
let investorToCheck = readlineSync.question('Enter the address you want to check: ', {
case `Show investors`:
console.log('***** List of investors on whitelist *****');
displayInvestors.map(i => console.log(i));
break;
case `Show whitelist data`:
let investorsToShow = readlineSync.question(`Enter the addresses of the investors you want to show (i.e: addr1,addr2,addr3) or leave empty to show them all: `, {
limit: function (input) {
return web3.utils.isAddress(input);
return input === '' || input.split(",").every(a => web3.utils.isAddress(a));
},
limitMessage: "Must be a valid address"
limitMessage: `All addresses must be valid`
});
let timeRestriction = await currentTransferManager.methods.whitelist(investorToCheck).call();
console.log(`Sale lockup: ${moment.unix(timeRestriction.fromTime).format('MMMM Do YYYY, HH:mm:ss')}`);
console.log(`Buy lockup: ${moment.unix(timeRestriction.toTime).format('MMMM Do YYYY, HH:mm:ss')}`);
console.log(`KYC expiry time: ${moment.unix(timeRestriction.expiryTime).format('MMMM Do YYYY, HH:mm:ss')}`);
console.log(`Restricted investor: ${timeRestriction.canBuyFromSTO ? 'YES' : 'NO'} `);
if (investorsToShow === '') {
let whitelistData = await currentTransferManager.methods.getAllInvestorsData().call();
showWhitelistTable(whitelistData[0], whitelistData[1], whitelistData[2], whitelistData[3], whitelistData[4]);
} else {
let investorsArray = investorsToShow.split(',');
let whitelistData = await currentTransferManager.methods.getInvestorsData(investorsArray).call();
showWhitelistTable(investorsArray, whitelistData[0], whitelistData[1], whitelistData[2], whitelistData[3]);
}
break;
case 'Change the default times used when they are zero':
let fromTimeDefault = readlineSync.questionInt(`Enter the default time (Unix Epoch time) used when fromTime is zero: `);
let toTimeDefault = readlineSync.questionInt(`Enter the default time (Unix Epoch time) used when fromTime is zero: `);
let changeDefaultsAction = currentTransferManager.methods.changeDefaults(fromTimeDefault, toTimeDefault);
let changeDefaultsReceipt = await common.sendTransaction(changeDefaultsAction);
let changeDefaultsEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, changeDefaultsReceipt.logs, 'ChangeDefaults');
console.log(chalk.green(`Default times have been updated successfully!`));
break;
case 'Modify whitelist':
let investor = readlineSync.question('Enter the address to whitelist: ', {
Expand Down Expand Up @@ -490,6 +517,21 @@ async function generalTransferManager() {
}
}

function showWhitelistTable(investorsArray, fromTimeArray, toTimeArray, expiryTimeArray, canBuyFromSTOArray) {
let dataTable = [['Investor', 'From time', 'To time', 'KYC expiry date', 'Restricted']];
for (let i = 0; i < investorsArray.length; i++) {
dataTable.push([
investorsArray[i],
moment.unix(fromTimeArray[i]).format('MM/DD/YYYY HH:mm'),
moment.unix(toTimeArray[i]).format('MM/DD/YYYY HH:mm'),
moment.unix(expiryTimeArray[i]).format('MM/DD/YYYY HH:mm'),
canBuyFromSTOArray[i] ? 'YES' : 'NO'
]);
}
console.log();
console.log(table(dataTable));
}

async function modifyWhitelistInBatch() {
let csvFilePath = readlineSync.question(`Enter the path for csv data file (${WHITELIST_DATA_CSV}): `, {
defaultInput: WHITELIST_DATA_CSV
Expand Down Expand Up @@ -553,8 +595,8 @@ async function manualApprovalTransferManager() {
let manualApproval = await getManualApproval(from, to);
if (manualApproval) {
console.log(`Manual approval found!`);
console.log(`Allowance: ${web3.utils.fromWei(manualApproval.allowance)} `);
console.log(`Expiry time: ${moment.unix(manualApproval.expiryTime).format('MMMM Do YYYY, HH:mm:ss')}; `)
console.log(`Allowance: ${web3.utils.fromWei(manualApproval.allowance)}`);
console.log(`Expiry time: ${moment.unix(manualApproval.expiryTime).format('MMMM Do YYYY, HH:mm:ss')}`);
} else {
console.log(chalk.yellow(`There are no manual approvals from ${from} to ${to}.`));
}
Expand Down
1 change: 1 addition & 0 deletions CLI/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"readline-sync": "^1.4.9",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"table": "^5.1.1",
"web3": "1.0.0-beta.35"
}
}
85 changes: 83 additions & 2 deletions CLI/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,22 @@ ajv@^5.3.0:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"

ansi-styles@^3.2.1:
ajv@^6.6.1:
version "6.6.1"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.1.tgz#6360f5ed0d80f232cc2b294c362d5dc2e538dd61"
integrity sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"

ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=

ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
Expand Down Expand Up @@ -68,6 +83,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=

astral-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==

async-limiter@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
Expand Down Expand Up @@ -741,6 +761,11 @@ fast-deep-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=

fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=

fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
Expand Down Expand Up @@ -1042,6 +1067,11 @@ is-callable@^1.1.3:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==

is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=

is-function@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
Expand Down Expand Up @@ -1120,6 +1150,11 @@ json-schema-traverse@^0.3.0:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=

json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==

json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
Expand Down Expand Up @@ -1155,7 +1190,7 @@ keccakjs@^0.2.1:
browserify-sha3 "^0.0.1"
sha3 "^1.1.0"

lodash@^4.13.1:
lodash@^4.13.1, lodash@^4.17.11:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
Expand Down Expand Up @@ -1496,6 +1531,11 @@ punycode@^1.4.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=

punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==

qs@6.5.2, qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
Expand Down Expand Up @@ -1749,6 +1789,15 @@ simple-get@^2.7.0:
once "^1.3.1"
simple-concat "^1.0.0"

slice-ansi@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7"
integrity sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==
dependencies:
ansi-styles "^3.2.0"
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"

sshpk@^1.7.0:
version "1.15.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2"
Expand Down Expand Up @@ -1784,13 +1833,28 @@ strict-uri-encode@^1.0.0:
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=

string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"

string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"

strip-ansi@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
dependencies:
ansi-regex "^3.0.0"

strip-dirs@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5"
Expand Down Expand Up @@ -1831,6 +1895,16 @@ swarm-js@0.1.37:
tar.gz "^1.0.5"
xhr-request-promise "^0.1.2"

table@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/table/-/table-5.1.1.tgz#92030192f1b7b51b6eeab23ed416862e47b70837"
integrity sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==
dependencies:
ajv "^6.6.1"
lodash "^4.17.11"
slice-ansi "2.0.0"
string-width "^2.1.1"

tar-stream@^1.5.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
Expand Down Expand Up @@ -1956,6 +2030,13 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=

uri-js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
dependencies:
punycode "^2.1.0"

url-parse-lax@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
Expand Down
37 changes: 2 additions & 35 deletions contracts/modules/Checkpoint/DividendCheckpoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
pragma solidity ^0.4.24;

import "./ICheckpoint.sol";
import "./DividendCheckpointStorage.sol";
import "../Module.sol";
import "../../interfaces/ISecurityToken.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
Expand All @@ -17,43 +18,9 @@ import "openzeppelin-solidity/contracts/math/Math.sol";
* @title Checkpoint module for issuing ether dividends
* @dev abstract contract
*/
contract DividendCheckpoint is ICheckpoint, Module {
contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
using SafeMath for uint256;

uint256 public EXCLUDED_ADDRESS_LIMIT = 50;
bytes32 public constant DISTRIBUTE = "DISTRIBUTE";
bytes32 public constant MANAGE = "MANAGE";
bytes32 public constant CHECKPOINT = "CHECKPOINT";

struct Dividend {
uint256 checkpointId;
uint256 created; // Time at which the dividend was created
uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass
uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer -
// set to very high value to bypass
uint256 amount; // Dividend amount in WEI
uint256 claimedAmount; // Amount of dividend claimed so far
uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this)
bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend
uint256 dividendWithheld;
uint256 dividendWithheldReclaimed;
mapping (address => bool) claimed; // List of addresses which have claimed dividend
mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends
bytes32 name; // Name/title - used for identification
}

// List of all dividends
Dividend[] public dividends;

// List of addresses which cannot claim dividends
address[] public excluded;

// Mapping from address to withholding tax as a percentage * 10**16
mapping (address => uint256) public withholdingTax;

// Total amount of ETH withheld per investor
mapping (address => uint256) public investorWithheld;

event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp);
event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp);
event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp);
Expand Down
Loading

0 comments on commit 3dba7bd

Please sign in to comment.