Skip to content
This repository has been archived by the owner on Jul 6, 2022. It is now read-only.

Commit

Permalink
Merge 8c75805 into 2788061
Browse files Browse the repository at this point in the history
  • Loading branch information
shuffledex committed May 6, 2019
2 parents 2788061 + 8c75805 commit c98c853
Show file tree
Hide file tree
Showing 28 changed files with 2,061 additions and 387 deletions.
1 change: 1 addition & 0 deletions src/PolymathAPI.ts
Expand Up @@ -121,6 +121,7 @@ export class PolymathAPI {
providerUtils.standardizeOrThrow(params.provider);
if (params.polymathRegistryAddress !== undefined) {
assert.isETHAddressHex('polymathRegistryAddress', params.polymathRegistryAddress);
assert.isAddressNotZero(params.polymathRegistryAddress);
}

this.web3Wrapper = new Web3Wrapper(params.provider, {
Expand Down
5 changes: 5 additions & 0 deletions src/contract_wrappers/contract_wrapper.ts
Expand Up @@ -9,6 +9,7 @@ import {
RawLog,
LogEntry,
LogWithDecodedArgs,
TxData,
} from 'ethereum-types';
import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
import * as _ from 'lodash';
Expand Down Expand Up @@ -247,4 +248,8 @@ export default abstract class ContractWrapper {
const addresses = await this.web3Wrapper.getAvailableAddressesAsync();
return addresses[0];
};

protected getCallerAddress = async (txData: Partial<TxData> | undefined): Promise<string> => {
return txData === undefined || txData.from === undefined ? this.getDefaultFromAddress() : txData.from;
};
}
Expand Up @@ -4,6 +4,8 @@ import assert from '../../../utils/assert';
import { TxParams, DividendCheckpointBaseContract } from '../../../types';
import { numberToBigNumber, dateToBigNumber, bigNumberToDate, bytes32ToString } from '../../../utils/convert';

const EXCLUDED_ADDRESS_LIMIT = 150;

interface DividendIndexParams {
dividendIndex: number;
}
Expand Down Expand Up @@ -158,6 +160,10 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
return (await this.contract).wallet.callAsync();
};

public paused = async () => {
return (await this.contract).paused.callAsync();
};

public dividends = async (params: DividendIndexParams) => {
const result = await (await this.contract).dividends.callAsync(numberToBigNumber(params.dividendIndex));
const typedResult: Dividend = {
Expand Down Expand Up @@ -186,14 +192,22 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public pause = async (params: TxParams) => {
assert.assert(!(await this.paused()), 'Contract currently paused');
assert.assert(await this.isCallerTheSecurityTokenOwner(params.txData), 'The caller must be the ST owner');
return (await this.contract).pause.sendTransactionAsync(params.txData, params.safetyFactor);
};

public unpause = async (params: TxParams) => {
assert.assert((await this.paused()), 'Contract currently not paused');
assert.assert(await this.isCallerTheSecurityTokenOwner(params.txData), 'The caller must be the ST owner');
return (await this.contract).unpause.sendTransactionAsync(params.txData, params.safetyFactor);
};

public reclaimERC20 = async (params: ReclaimERC20Params) => {
assert.assert(await this.isCallerTheSecurityTokenOwner(params.txData), 'The caller must be the ST owner');
assert.isETHAddressHex('tokenContract', params.tokenContract);
assert.isAddressNotZero(params.tokenContract);
// require(token.transfer(msg.sender, balance), "Transfer failed");
return (await this.contract).reclaimERC20.sendTransactionAsync(
params.tokenContract,
params.txData,
Expand All @@ -202,10 +216,14 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public reclaimETH = async (params: TxParams) => {
assert.assert(await this.isCallerTheSecurityTokenOwner(params.txData), 'The caller must be the ST owner');
return (await this.contract).reclaimETH.sendTransactionAsync(params.txData, params.safetyFactor);
};

public changeWallet = async (params: ChangeWalletParams) => {
assert.assert(await this.isCallerTheSecurityTokenOwner(params.txData), 'The caller must be the ST owner');
assert.isETHAddressHex('wallet', params.wallet);
assert.isAddressNotZero(params.wallet);
return (await this.contract).changeWallet.sendTransactionAsync(params.wallet, params.txData, params.safetyFactor);
};

Expand All @@ -218,6 +236,10 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public setDefaultExcluded = async (params: SetDefaultExcludedParams) => {
assert.assert(params.excluded.length <= EXCLUDED_ADDRESS_LIMIT, 'Too many excluded addresses');
assert.isETHAddressHexArray('excluded', params.excluded);
assert.isAddressArrayNotZero(params.excluded);
assert.checkDuplicateAddresses(params.excluded);
return (await this.contract).setDefaultExcluded.sendTransactionAsync(
params.excluded,
params.txData,
Expand All @@ -226,6 +248,8 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public setWithholding = async (params: SetWithholdingParams) => {
assert.assert(params.investors.length === params.withholding.length, 'Mismatched input lengths');
assert.checkWithholdingArrayTax(params.withholding);
return (await this.contract).setWithholding.sendTransactionAsync(
params.investors,
params.withholding,
Expand All @@ -235,6 +259,7 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public setWithholdingFixed = async (params: SetWithholdingFixedParams) => {
assert.checkWithholdingTax(params.withholding);
return (await this.contract).setWithholdingFixed.sendTransactionAsync(
params.investors,
params.withholding,
Expand All @@ -244,6 +269,8 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public pushDividendPaymentToAddresses = async (params: PushDividendPaymentToAddressesParams) => {
assert.isETHAddressHexArray('payees', params.payees);
await this.checkValidDividendIndex(params.dividendIndex);
return (await this.contract).pushDividendPaymentToAddresses.sendTransactionAsync(
numberToBigNumber(params.dividendIndex),
params.payees,
Expand All @@ -253,6 +280,7 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public pushDividendPayment = async (params: PushDividendPaymentParams) => {
await this.checkValidDividendIndex(params.dividendIndex);
return (await this.contract).pushDividendPayment.sendTransactionAsync(
numberToBigNumber(params.dividendIndex),
dateToBigNumber(params.start),
Expand All @@ -263,6 +291,19 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public pullDividendPayment = async (params: DividendIndexTxParams) => {
await this.checkValidDividendIndex(params.dividendIndex);
assert.assert(!(await this.paused()), 'Contract currently paused');
const address = (await this.web3Wrapper.getAvailableAddressesAsync())[0];
const isClaimed = await this.isClaimed({
investor: address,
dividendIndex: params.dividendIndex,
});
const isExcluded = await this.isExcluded({
investor: address,
dividendIndex: params.dividendIndex,
});
assert.assert(!isClaimed, 'Dividend already claimed');
assert.assert(!isExcluded, `${address} is excluded from Dividend`);
return (await this.contract).pullDividendPayment.sendTransactionAsync(
numberToBigNumber(params.dividendIndex),
params.txData,
Expand All @@ -271,6 +312,11 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public reclaimDividend = async (params: DividendIndexTxParams) => {
const dividends = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividends[0].length, 'Incorrect dividend index');
const dividend = await this.dividends(params);
assert.assert(new Date() >= dividend.expiry, 'Dividend expiry is in the future');
assert.assert(!dividend.reclaimed, 'Dividend is already claimed');
return (await this.contract).reclaimDividend.sendTransactionAsync(
numberToBigNumber(params.dividendIndex),
params.txData,
Expand All @@ -279,6 +325,8 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public calculateDividend = async (params: CalculateDividendParams) => {
const dividendsData = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividendsData[0].length, 'Invalid dividend');
const result = await (await this.contract).calculateDividend.callAsync(
numberToBigNumber(params.dividendIndex),
params.payee,
Expand All @@ -295,6 +343,8 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public withdrawWithholding = async (params: DividendIndexTxParams) => {
const dividends = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividends[0].length, 'Incorrect dividend index');
return (await this.contract).reclaimDividend.sendTransactionAsync(
numberToBigNumber(params.dividendIndex),
params.txData,
Expand All @@ -303,6 +353,10 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public updateDividendDates = async (params: UpdateDividendDatesParams) => {
assert.assert(await this.isCallerTheSecurityTokenOwner(params.txData), 'The caller must be the ST owner');
const dividendsData = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividendsData[0].length, 'Invalid dividend');
assert.assert(params.expiry > params.maturity, 'Expiry before maturity');
return (await this.contract).updateDividendDates.sendTransactionAsync(
numberToBigNumber(params.dividendIndex),
dateToBigNumber(params.maturity),
Expand Down Expand Up @@ -343,6 +397,8 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public getDividendProgress = async (params: DividendIndexParams) => {
const dividendsData = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividendsData[0].length, 'Invalid dividend');
const result = await (await this.contract).getDividendProgress.callAsync(numberToBigNumber(params.dividendIndex));
const typedResult: DividendProgress[] = [];
for (let i = 0; i < result[0].length; i += 1) {
Expand All @@ -360,6 +416,9 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {
};

public getCheckpointData = async (params: CheckpointIdParams) => {
const st = await this.securityTokenContract();
const currentCheckpointId = await st.currentCheckpointId.callAsync();
assert.assert(new BigNumber(params.checkpointId).lte(currentCheckpointId), 'Invalid checkpoint');
const result = await (await this.contract).getCheckpointData.callAsync(numberToBigNumber(params.checkpointId));
const typedResult: CheckpointData[] = [];
for (let i = 0; i < result[0].length; i += 1) {
Expand All @@ -375,11 +434,25 @@ export default abstract class DividendCheckpointWrapper extends ModuleWrapper {

public isClaimed = async (params: InvestorStatus) => {
assert.isETHAddressHex('investor', params.investor);
const dividendsData = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividendsData[0].length, 'Invalid dividend');
return (await this.contract).isClaimed.callAsync(params.investor, numberToBigNumber(params.dividendIndex));
};

public isExcluded = async (params: InvestorStatus) => {
assert.isETHAddressHex('investor', params.investor);
const dividendsData = await (await this.contract).getDividendsData.callAsync();
assert.assert(params.dividendIndex < dividendsData[0].length, 'Invalid dividend');
return (await this.contract).isExcluded.callAsync(params.investor, numberToBigNumber(params.dividendIndex));
};

private checkValidDividendIndex = async(dividendIndex: number) => {
const dividends = await this.getDividendsData();
assert.assert(dividends.length > dividendIndex, 'Invalid dividend');
const dividend = await this.getDividendData({dividendIndex});
// Reclaimed
assert.assert(!dividend.claimedAmount.isGreaterThan(0), 'Dividend claimed amount greater than 0, dividend reclaimed');
assert.assert(dividend.maturity <= new Date(), 'Dividend maturity in future');
assert.assert(dividend.expiry > new Date(), 'Dividend expiry in past');
}
}
Expand Up @@ -21,6 +21,8 @@ import ContractFactory from '../../../factories/contractFactory';
import { TxParams, GetLogsAsyncParams, SubscribeAsyncParams, EventCallback, Subscribe, GetLogs } from '../../../types';
import { numberToBigNumber, dateToBigNumber, stringToBytes32 } from '../../../utils/convert';

const EXCLUDED_ADDRESS_LIMIT = 150;

interface ERC20DividendDepositedSubscribeAsyncParams extends SubscribeAsyncParams {
eventName: ERC20DividendCheckpointEvents.ERC20DividendDeposited;
callback: EventCallback<ERC20DividendCheckpointERC20DividendDepositedEventArgs>;
Expand Down Expand Up @@ -170,7 +172,7 @@ export default class ERC20DividendCheckpointWrapper extends DividendCheckpointWr
};

public createDividend = async (params: CreateDividendParams) => {
assert.isETHAddressHex('token', params.token);
await this.sharedAsserts(params.expiry, params.maturity, params.amount, params.token, params.name);
return (await this.contract).createDividend.sendTransactionAsync(
dateToBigNumber(params.maturity),
dateToBigNumber(params.expiry),
Expand All @@ -183,7 +185,7 @@ export default class ERC20DividendCheckpointWrapper extends DividendCheckpointWr
};

public createDividendWithCheckpoint = async (params: CreateDividendWithCheckpointParams) => {
assert.isETHAddressHex('token', params.token);
await this.sharedAsserts(params.expiry, params.maturity, params.amount, params.token, params.name);
return (await this.contract).createDividendWithCheckpoint.sendTransactionAsync(
dateToBigNumber(params.maturity),
dateToBigNumber(params.expiry),
Expand All @@ -197,8 +199,7 @@ export default class ERC20DividendCheckpointWrapper extends DividendCheckpointWr
};

public createDividendWithExclusions = async (params: CreateDividendWithExclusionsParams) => {
assert.isETHAddressHex('token', params.token);
assert.isETHAddressHexArray('excluded', params.excluded);
await this.sharedAsserts(params.expiry, params.maturity, params.amount, params.token, params.name, params.excluded);
return (await this.contract).createDividendWithExclusions.sendTransactionAsync(
dateToBigNumber(params.maturity),
dateToBigNumber(params.expiry),
Expand All @@ -214,8 +215,7 @@ export default class ERC20DividendCheckpointWrapper extends DividendCheckpointWr
public createDividendWithCheckpointAndExclusions = async (
params: CreateDividendWithCheckpointAndExclusionsParams,
) => {
assert.isETHAddressHex('token', params.token);
assert.isETHAddressHexArray('excluded', params.excluded);
await this.sharedAsserts(params.expiry, params.maturity, params.amount, params.token, params.name, params.excluded);
return (await this.contract).createDividendWithCheckpointAndExclusions.sendTransactionAsync(
dateToBigNumber(params.maturity),
dateToBigNumber(params.expiry),
Expand All @@ -229,6 +229,30 @@ export default class ERC20DividendCheckpointWrapper extends DividendCheckpointWr
);
};

private sharedAsserts = async (
expiry: Date,
maturity: Date,
amount: BigNumber,
token: string,
name: string,
excluded?: string[],
) => {
let auxExcluded = excluded;
if (auxExcluded === undefined) {
auxExcluded = await this.getDefaultExcluded();
assert.isETHAddressHexArray('excluded', auxExcluded);
assert.isAddressArrayNotZero(auxExcluded);
// we need to simulate push to verify the `duped exclude address` assert
}
assert.assert(auxExcluded.length <= EXCLUDED_ADDRESS_LIMIT, 'Too many addresses excluded');
assert.assert(expiry > maturity, 'Expiry before maturity');
assert.assert(expiry > new Date(), 'Expiry in past');
assert.assert(amount.gt(new BigNumber(0)), 'No dividend sent');
assert.isETHAddressHex('token', token);
assert.isAddressNotZero(token);
assert.assert(name.length > 0, 'The name can not be empty');
};

/**
* Subscribe to an event type emitted by the contract.
* @return Subscription token used later to unsubscribe
Expand Down

0 comments on commit c98c853

Please sign in to comment.