Skip to content

Commit 0ecdf79

Browse files
Merge branch 'dev-2.1.0' into Vesting-Escrow-Wallet
2 parents 3b78ff7 + c85c599 commit 0ecdf79

File tree

8 files changed

+947
-478
lines changed

8 files changed

+947
-478
lines changed

CLI/commands/dividends_manager.js

Lines changed: 720 additions & 459 deletions
Large diffs are not rendered by default.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,0.5
2+
0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,1
3+
0xac297053173b02b02a737d47f7b4a718e5b170ef,2
4+
0x49fc0b78238dab644698a90fa351b4c749e123d2,10
5+
0x10223927009b8add0960359dd90d1449415b7ca9,15
6+
0x3c65cfe3de848cf38e9d76e9c3e57a2f1140b399,50
7+
0xabf60de3265b3017db7a1be66fc8b364ec1dbb98,0
8+
0xb841fe5a89da1bbef2d0805fbd7ffcbbb2fca5e3,23
9+
0x56be93088141b16ebaa9416122fd1d928da25ecf,45
10+
0xbb276b6f68f0a41d54b7e0a608fe8eb1ebdee7b0,67

contracts/modules/Checkpoint/DividendCheckpoint.sol

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
142142
validDividendIndex(_dividendIndex)
143143
{
144144
Dividend storage dividend = dividends[_dividendIndex];
145-
address[] memory investors = ISecurityToken(securityToken).getInvestors();
145+
uint256 checkpointId = dividend.checkpointId;
146+
address[] memory investors = ISecurityToken(securityToken).getInvestorsAt(checkpointId);
146147
uint256 numberInvestors = Math.min256(investors.length, _start.add(_iterations));
147148
for (uint256 i = _start; i < numberInvestors; i++) {
148149
address payee = investors[i];
@@ -226,6 +227,136 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
226227
*/
227228
function withdrawWithholding(uint256 _dividendIndex) external;
228229

230+
/**
231+
* @notice Get static dividend data
232+
* @return uint256[] timestamp of dividends creation
233+
* @return uint256[] timestamp of dividends maturity
234+
* @return uint256[] timestamp of dividends expiry
235+
* @return uint256[] amount of dividends
236+
* @return uint256[] claimed amount of dividends
237+
* @return bytes32[] name of dividends
238+
*/
239+
function getDividendsData() external view returns (
240+
uint256[] memory createds,
241+
uint256[] memory maturitys,
242+
uint256[] memory expirys,
243+
uint256[] memory amounts,
244+
uint256[] memory claimedAmounts,
245+
bytes32[] memory names)
246+
{
247+
createds = new uint256[](dividends.length);
248+
maturitys = new uint256[](dividends.length);
249+
expirys = new uint256[](dividends.length);
250+
amounts = new uint256[](dividends.length);
251+
claimedAmounts = new uint256[](dividends.length);
252+
names = new bytes32[](dividends.length);
253+
for (uint256 i = 0; i < dividends.length; i++) {
254+
(createds[i], maturitys[i], expirys[i], amounts[i], claimedAmounts[i], names[i]) = getDividendData(i);
255+
}
256+
}
257+
258+
/**
259+
* @notice Get static dividend data
260+
* @return uint256 timestamp of dividend creation
261+
* @return uint256 timestamp of dividend maturity
262+
* @return uint256 timestamp of dividend expiry
263+
* @return uint256 amount of dividend
264+
* @return uint256 claimed amount of dividend
265+
* @return bytes32 name of dividend
266+
*/
267+
function getDividendData(uint256 _dividendIndex) public view returns (
268+
uint256 created,
269+
uint256 maturity,
270+
uint256 expiry,
271+
uint256 amount,
272+
uint256 claimedAmount,
273+
bytes32 name)
274+
{
275+
created = dividends[_dividendIndex].created;
276+
maturity = dividends[_dividendIndex].maturity;
277+
expiry = dividends[_dividendIndex].expiry;
278+
amount = dividends[_dividendIndex].amount;
279+
claimedAmount = dividends[_dividendIndex].claimedAmount;
280+
name = dividends[_dividendIndex].name;
281+
}
282+
283+
/**
284+
* @notice Retrieves list of investors, their claim status and whether they are excluded
285+
* @param _dividendIndex Dividend to withdraw from
286+
* @return address[] list of investors
287+
* @return bool[] whether investor has claimed
288+
* @return bool[] whether investor is excluded
289+
* @return uint256[] amount of withheld tax
290+
* @return uint256[] investor balance
291+
* @return uint256[] amount to be claimed including withheld tax
292+
*/
293+
function getDividendProgress(uint256 _dividendIndex) external view returns (
294+
address[] memory investors,
295+
bool[] memory resultClaimed,
296+
bool[] memory resultExcluded,
297+
uint256[] memory resultWithheld,
298+
uint256[] memory resultBalance,
299+
uint256[] memory resultAmount)
300+
{
301+
require(_dividendIndex < dividends.length, "Invalid dividend");
302+
//Get list of Investors
303+
Dividend storage dividend = dividends[_dividendIndex];
304+
uint256 checkpointId = dividend.checkpointId;
305+
investors = ISecurityToken(securityToken).getInvestorsAt(checkpointId);
306+
resultClaimed = new bool[](investors.length);
307+
resultExcluded = new bool[](investors.length);
308+
resultWithheld = new uint256[](investors.length);
309+
resultBalance = new uint256[](investors.length);
310+
resultAmount = new uint256[](investors.length);
311+
for (uint256 i; i < investors.length; i++) {
312+
resultClaimed[i] = dividend.claimed[investors[i]];
313+
resultExcluded[i] = dividend.dividendExcluded[investors[i]];
314+
resultBalance[i] = ISecurityToken(securityToken).balanceOfAt(investors[i], dividend.checkpointId);
315+
if (!resultExcluded[i]) {
316+
resultWithheld[i] = dividend.withheld[investors[i]];
317+
resultAmount[i] = resultBalance[i].mul(dividend.amount).div(dividend.totalSupply);
318+
}
319+
}
320+
}
321+
322+
/**
323+
* @notice Retrieves list of investors, their balances, and their current withholding tax percentage
324+
* @param _checkpointId Checkpoint Id to query for
325+
* @return address[] list of investors
326+
* @return uint256[] investor balances
327+
* @return uint256[] investor withheld percentages
328+
*/
329+
function getCheckpointData(uint256 _checkpointId) external view returns (address[] memory investors, uint256[] memory balances, uint256[] memory withholdings) {
330+
require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint");
331+
investors = ISecurityToken(securityToken).getInvestorsAt(_checkpointId);
332+
balances = new uint256[](investors.length);
333+
withholdings = new uint256[](investors.length);
334+
for (uint256 i; i < investors.length; i++) {
335+
balances[i] = ISecurityToken(securityToken).balanceOfAt(investors[i], _checkpointId);
336+
withholdings[i] = withholdingTax[investors[i]];
337+
}
338+
}
339+
340+
/**
341+
* @notice Checks whether an address is excluded from claiming a dividend
342+
* @param _dividendIndex Dividend to withdraw from
343+
* @return bool whether the address is excluded
344+
*/
345+
function isExcluded(address _investor, uint256 _dividendIndex) external view returns (bool) {
346+
require(_dividendIndex < dividends.length, "Invalid dividend");
347+
return dividends[_dividendIndex].dividendExcluded[_investor];
348+
}
349+
350+
/**
351+
* @notice Checks whether an address has claimed a dividend
352+
* @param _dividendIndex Dividend to withdraw from
353+
* @return bool whether the address has claimed
354+
*/
355+
function isClaimed(address _investor, uint256 _dividendIndex) external view returns (bool) {
356+
require(_dividendIndex < dividends.length, "Invalid dividend");
357+
return dividends[_dividendIndex].claimed[_investor];
358+
}
359+
229360
/**
230361
* @notice Return the permissions flag that are associated with this module
231362
* @return bytes32 array

contracts/modules/Checkpoint/DividendCheckpointStorage.sol

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pragma solidity ^0.4.24;
66
*/
77
contract DividendCheckpointStorage {
88

9-
uint256 public EXCLUDED_ADDRESS_LIMIT = 50;
9+
uint256 public EXCLUDED_ADDRESS_LIMIT = 150;
1010
bytes32 public constant DISTRIBUTE = "DISTRIBUTE";
1111
bytes32 public constant MANAGE = "MANAGE";
1212
bytes32 public constant CHECKPOINT = "CHECKPOINT";
@@ -21,10 +21,11 @@ contract DividendCheckpointStorage {
2121
uint256 claimedAmount; // Amount of dividend claimed so far
2222
uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this)
2323
bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend
24-
uint256 dividendWithheld;
25-
uint256 dividendWithheldReclaimed;
24+
uint256 totalWithheld;
25+
uint256 totalWithheldWithdrawn;
2626
mapping (address => bool) claimed; // List of addresses which have claimed dividend
2727
mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends
28+
mapping (address => uint256) withheld; // Amount of tax withheld from claim
2829
bytes32 name; // Name/title - used for identification
2930
}
3031

@@ -37,7 +38,4 @@ contract DividendCheckpointStorage {
3738
// Mapping from address to withholding tax as a percentage * 10**16
3839
mapping (address => uint256) public withholdingTax;
3940

40-
// Total amount of ETH withheld per investor
41-
mapping (address => uint256) public investorWithheld;
42-
4341
}

contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,10 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
241241
uint256 claimAfterWithheld = claim.sub(withheld);
242242
if (claimAfterWithheld > 0) {
243243
require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "transfer failed");
244-
_dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld);
245-
investorWithheld[_payee] = investorWithheld[_payee].add(withheld);
244+
if (withheld > 0) {
245+
_dividend.totalWithheld = _dividend.totalWithheld.add(withheld);
246+
_dividend.withheld[_payee] = withheld;
247+
}
246248
emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld);
247249
}
248250
}
@@ -271,8 +273,8 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
271273
function withdrawWithholding(uint256 _dividendIndex) external withPerm(MANAGE) {
272274
require(_dividendIndex < dividends.length, "Invalid dividend");
273275
Dividend storage dividend = dividends[_dividendIndex];
274-
uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed);
275-
dividend.dividendWithheldReclaimed = dividend.dividendWithheld;
276+
uint256 remainingWithheld = dividend.totalWithheld.sub(dividend.totalWithheldWithdrawn);
277+
dividend.totalWithheldWithdrawn = dividend.totalWithheld;
276278
address owner = IOwnable(securityToken).owner();
277279
require(IERC20(dividendTokens[_dividendIndex]).transfer(owner, remainingWithheld), "transfer failed");
278280
emit ERC20DividendWithholdingWithdrawn(owner, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld);

contracts/modules/Checkpoint/EtherDividendCheckpoint.sol

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import "../../interfaces/IOwnable.sol";
88
*/
99
contract EtherDividendCheckpoint is DividendCheckpoint {
1010
using SafeMath for uint256;
11-
11+
1212
event EtherDividendDeposited(
1313
address indexed _depositor,
1414
uint256 _checkpointId,
@@ -176,8 +176,10 @@ contract EtherDividendCheckpoint is DividendCheckpoint {
176176
/*solium-disable-next-line security/no-send*/
177177
if (_payee.send(claimAfterWithheld)) {
178178
_dividend.claimedAmount = _dividend.claimedAmount.add(claim);
179-
_dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld);
180-
investorWithheld[_payee] = investorWithheld[_payee].add(withheld);
179+
if (withheld > 0) {
180+
_dividend.totalWithheld = _dividend.totalWithheld.add(withheld);
181+
_dividend.withheld[_payee] = withheld;
182+
}
181183
emit EtherDividendClaimed(_payee, _dividendIndex, claim, withheld);
182184
} else {
183185
_dividend.claimed[_payee] = false;
@@ -210,8 +212,8 @@ contract EtherDividendCheckpoint is DividendCheckpoint {
210212
function withdrawWithholding(uint256 _dividendIndex) external withPerm(MANAGE) {
211213
require(_dividendIndex < dividends.length, "Incorrect dividend index");
212214
Dividend storage dividend = dividends[_dividendIndex];
213-
uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed);
214-
dividend.dividendWithheldReclaimed = dividend.dividendWithheld;
215+
uint256 remainingWithheld = dividend.totalWithheld.sub(dividend.totalWithheldWithdrawn);
216+
dividend.totalWithheldWithdrawn = dividend.totalWithheld;
215217
address owner = IOwnable(securityToken).owner();
216218
owner.transfer(remainingWithheld);
217219
emit EtherDividendWithholdingWithdrawn(owner, _dividendIndex, remainingWithheld);

0 commit comments

Comments
 (0)