diff --git a/.vscode/settings.json b/.vscode/settings.json
index ffc1f9486..de1aaf044 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,4 @@
{
- "editor.formatOnSave": true,
"prettier.eslintIntegration": true,
"search.exclude": {
"**/node_modules": true,
diff --git a/packages/polymath-issuer/package.json b/packages/polymath-issuer/package.json
index 155b79b94..4a21c528c 100644
--- a/packages/polymath-issuer/package.json
+++ b/packages/polymath-issuer/package.json
@@ -7,8 +7,8 @@
"node": ">=8.9"
},
"scripts": {
- "start:prod": "serve -s build",
"start": "node scripts/start.js",
+ "start:prod": "serve -s build",
"build": "node scripts/build.js",
"test": "node ./scripts/test.js --env=jsdom",
"typecheck": "flow --show-all-branches"
diff --git a/packages/polymath-issuer/src/actions/compliance.js b/packages/polymath-issuer/src/actions/compliance.js
index a6b494493..74a071f8e 100644
--- a/packages/polymath-issuer/src/actions/compliance.js
+++ b/packages/polymath-issuer/src/actions/compliance.js
@@ -14,6 +14,8 @@ import { formName as addInvestorFormName } from '../pages/compliance/components/
import { formName as editInvestorsFormName } from '../pages/compliance/components/EditInvestorsForm';
import { parseWhitelistCsv } from '../utils/parsers';
import { STAGE_OVERVIEW } from '../reducers/sto';
+import { PERM_TYPES } from '../constants';
+import Web3 from 'web3';
import type { Investor, Address } from '@polymathnetwork/js/types';
import type { GetState } from '../redux/reducer';
@@ -39,6 +41,31 @@ export const listLength = (listLength: number) => ({
listLength,
});
+export const LOAD_MANAGERS = 'compliance/LOAD_MANAGERS';
+export const loadManagers = managers => ({
+ type: LOAD_MANAGERS,
+ managers,
+});
+
+export const ADD_MANAGER = 'compliance/ADD_MANAGER';
+export const addManager = manager => ({
+ type: ADD_MANAGER,
+ manager,
+});
+
+export const REMOVE_MANAGER = 'compliance/REMOVE_MANAGER';
+export const removeManager = address => ({
+ type: REMOVE_MANAGER,
+ address,
+});
+
+export const TOGGLE_WHITELIST_MANAGEMENT =
+ 'compliance/TOGGLE_WHITELIST_MANAGEMENT';
+export const toggleWhitelistManagement = (isToggled: boolean) => ({
+ type: TOGGLE_WHITELIST_MANAGEMENT,
+ isToggled,
+});
+
export const RESET_UPLOADED = 'compliance/RESET_UPLOADED';
export const resetUploaded = () => ({ type: RESET_UPLOADED });
@@ -59,6 +86,210 @@ export type InvestorCSVRow = [
string,
];
+// make more functional and switch transfermanager to module
+async function getDelegateDetails(permissionManager, transferManager) {
+ const delegates = await permissionManager.getAllDelegates(
+ transferManager.address,
+ PERM_TYPES.ADMIN
+ );
+ let delegateDetails = [];
+ for (const delegate of delegates) {
+ let details = await permissionManager.getDelegateDetails(delegate);
+ delegateDetails.push({ id: delegate, address: delegate, details });
+ }
+ return delegateDetails;
+}
+
+export const fetchManagers = () => async (
+ dispatch: Function,
+ getState: GetState
+) => {
+ dispatch(ui.fetching());
+ // $FlowFixMe
+ try {
+ const st: SecurityToken = getState().token.token.contract;
+ const permissionManager = await st.getPermissionManager();
+ if (!permissionManager) {
+ return;
+ }
+ const moduleMetadata = await st.getModule(permissionManager.address);
+ if (permissionManager && !moduleMetadata.isArchived) {
+ const transferManager = await st.getTransferManager();
+ if (transferManager) {
+ const delegateDetails = await getDelegateDetails(
+ permissionManager,
+ transferManager
+ );
+ dispatch(loadManagers(delegateDetails));
+ }
+ dispatch(toggleWhitelistManagement(true));
+ } else {
+ dispatch(toggleWhitelistManagement(false));
+ }
+ dispatch(ui.fetched());
+ } catch (e) {
+ console.log(e);
+ }
+};
+
+export const addAddressToTransferManager = (
+ delegate: Address,
+ details: string
+) => async (dispatch: Function, getState: GetState) => {
+ const st: SecurityToken = getState().token.token.contract;
+ const permissionManager = await st.getPermissionManager();
+ const titles = ['Adding New Whitelist Manager', 'Setting Permissions'];
+ const isDelegate = await permissionManager.checkDelegate(delegate);
+ if (isDelegate) {
+ titles.shift();
+ }
+ dispatch(
+ ui.tx(
+ titles,
+ async () => {
+ if (permissionManager) {
+ const transferManager = await st.getTransferManager();
+ if (transferManager) {
+ if (!isDelegate) {
+ await permissionManager.addDelegate(delegate, details);
+ }
+ await permissionManager.changePermission(
+ delegate,
+ transferManager.address,
+ PERM_TYPES.ADMIN,
+ true
+ );
+ }
+ }
+ },
+ 'New Whistlist Manager Added',
+ () => {
+ dispatch(addManager({ address: delegate, details: details }));
+ },
+ undefined,
+ undefined,
+ undefined,
+ true
+ )
+ );
+};
+
+// TODO: Add confirm dialog box
+export const removeAddressFromTransferManager = (delegate: Address) => async (
+ dispatch: Function,
+ getState: GetState
+) => {
+ dispatch(
+ ui.confirm(
+
+
+ Once removed, the whitelist manager will no longer have permission to
+ update the whitelist. Consult your legal team before removing a wallet
+ from the list.
+
+
,
+ async () => {
+ dispatch(
+ ui.tx(
+ ['Removing Whitelist Manager'],
+ async () => {
+ const st: SecurityToken = getState().token.token.contract;
+ const permissionManager = await st.getPermissionManager();
+ if (permissionManager) {
+ const transferManager = await st.getTransferManager();
+ if (transferManager) {
+ await permissionManager.changePermission(
+ delegate,
+ transferManager.address,
+ PERM_TYPES.ADMIN,
+ false
+ );
+ }
+ }
+ },
+ 'Whitelist Manager Removed',
+ () => {
+ dispatch(removeManager(delegate));
+ },
+ undefined,
+ undefined,
+ undefined,
+ true
+ )
+ );
+ },
+ `Remove the Whitelist Manager from the Whitelist Managers List?`,
+ undefined,
+ 'pui-large-confirm-modal'
+ )
+ );
+};
+
+export const archiveGeneralPermissionModule = () => async (
+ dispatch: Function,
+ getState: GetState
+) => {
+ const st: SecurityToken = getState().token.token.contract;
+ dispatch(
+ ui.tx(
+ ['Disabling General Permissions Manager'],
+ async () => {
+ const permissionManager = await st.getPermissionManager();
+ await st.archiveModule(permissionManager.address);
+ },
+ 'General Permissions Manager Disabled',
+ () => {
+ dispatch(toggleWhitelistManagement(false));
+ dispatch(loadManagers([]));
+ },
+ undefined,
+ undefined,
+ undefined,
+ true
+ )
+ );
+};
+
+export const addGeneralPermissionModule = () => async (
+ dispatch: Function,
+ getState: GetState
+) => {
+ const st: SecurityToken = getState().token.token.contract;
+ const permissionManager = await st.getPermissionManager();
+ const transferManager = await st.getTransferManager();
+ let moduleMetadata = {};
+ let delegateDetails = [];
+
+ if (permissionManager)
+ moduleMetadata = await st.getModule(permissionManager.address);
+
+ dispatch(
+ ui.tx(
+ ['Enabling General Permissions Manager for General Transfer Manager'],
+ async () => {
+ if (moduleMetadata.isArchived) {
+ await st.unarchiveModule(permissionManager.address);
+ delegateDetails = await getDelegateDetails(
+ permissionManager,
+ transferManager
+ );
+ } else {
+ await st.setPermissionManager();
+ }
+ },
+ 'General Permissions Manager for General Transfer Manager Enabled',
+ () => {
+ dispatch(loadManagers(delegateDetails));
+ dispatch(toggleWhitelistManagement(true));
+ },
+ undefined,
+ undefined,
+ undefined,
+ true
+ )
+ );
+};
+
export const fetchWhitelist = () => async (
dispatch: Function,
getState: GetState
diff --git a/packages/polymath-issuer/src/constants.js b/packages/polymath-issuer/src/constants.js
index 95f63540c..c31153c6f 100644
--- a/packages/polymath-issuer/src/constants.js
+++ b/packages/polymath-issuer/src/constants.js
@@ -8,6 +8,10 @@ export const EVENT_TYPES = {
TOKEN_PURCHASE: 'TokenPurchase',
};
+export const PERM_TYPES = {
+ ADMIN: 'ADMIN',
+};
+
export const MODULE_TYPES = {
PERMISSION: 1,
TRANSFER: 2,
diff --git a/packages/polymath-issuer/src/pages/compliance/CompliancePage.js b/packages/polymath-issuer/src/pages/compliance/CompliancePage.js
index b62b77523..3b0ebf53c 100644
--- a/packages/polymath-issuer/src/pages/compliance/CompliancePage.js
+++ b/packages/polymath-issuer/src/pages/compliance/CompliancePage.js
@@ -1,64 +1,69 @@
// @flow
/* eslint-disable react/jsx-no-bind, react/no-unused-state */ // TODO @bshevchenko
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import { reset } from 'redux-form';
-import { BigNumber } from 'bignumber.js';
import {
- Page,
- etherscanAddress,
addressShortifier,
confirm,
+ etherscanAddress,
NotFoundPage,
+ Page,
+ Grid,
} from '@polymathnetwork/ui';
+import { BigNumber } from 'bignumber.js';
import {
Button,
DataTable,
- // PaginationV2,
- Modal,
// DatePicker,
// DatePickerInput,
Icon,
InlineNotification,
- Toggle,
- TextInput,
+ // PaginationV2,
+ Modal,
OverflowMenu,
OverflowMenuItem,
+ TextInput,
+ Toggle,
} from 'carbon-components-react';
-import type {
- Investor,
- Address,
- SecurityToken,
-} from '@polymathnetwork/js/types';
-
-import Progress from '../token/components/Progress';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { reset } from 'redux-form';
import {
- importWhitelist,
- exportWhitelist,
addInvestor,
+ disableOwnershipRestrictions,
+ editInvestors,
+ enableOwnershipRestrictions,
+ exportWhitelist,
fetchWhitelist,
+ importWhitelist,
listLength,
+ PERMANENT_LOCKUP_TS,
removeInvestors,
- editInvestors,
resetUploaded,
- disableOwnershipRestrictions,
- enableOwnershipRestrictions,
- updateOwnershipPercentage,
- PERMANENT_LOCKUP_TS,
toggleFreeze,
+ updateOwnershipPercentage,
+ fetchManagers,
+ toggleWhitelistManagement,
+ addGeneralPermissionModule,
+ archiveGeneralPermissionModule,
} from '../../actions/compliance';
+import Progress from '../token/components/Progress';
import AddInvestorForm, {
formName as addInvestorFormName,
} from './components/AddInvestorForm';
import { formName as editInvestorsFormName } from './components/EditInvestorsForm';
import ImportWhitelistModal from './components/ImportWhitelistModal';
+import WhitelistTable from './components/WhitelistTable';
+import WhitelistModal from './components/WhitelistModal';
+import './style.scss';
+import type {
+ Investor,
+ Address,
+ SecurityToken,
+} from '@polymathnetwork/js/types';
import type { RootState } from '../../redux/reducer';
import type { InvestorCSVRow } from '../../actions/compliance';
-import './style.scss';
-
const {
Table,
TableBody,
@@ -101,6 +106,8 @@ type DispatchProps = {|
enableOwnershipRestrictions: (percentage?: number) => any,
updateOwnershipPercentage: (percentage: number) => any,
toggleFreeze: () => any,
+ addGeneralPermissionModule: () => any,
+ archiveGeneralPermissionModule: () => any,
|};
const mapStateToProps = (state: RootState) => ({
@@ -112,6 +119,7 @@ const mapStateToProps = (state: RootState) => ({
isPercentagePaused: state.whitelist.percentageTM.isPaused,
percentage: state.whitelist.percentageTM.percentage,
isTokenFrozen: state.whitelist.freezeStatus,
+ isWhitelistToggled: state.whitelist.isToggled,
});
const mapDispatchToProps = {
@@ -129,6 +137,10 @@ const mapDispatchToProps = {
enableOwnershipRestrictions,
updateOwnershipPercentage,
toggleFreeze,
+ fetchManagers,
+ toggleWhitelistManagement,
+ addGeneralPermissionModule,
+ archiveGeneralPermissionModule,
};
type Props = StateProps & DispatchProps;
@@ -142,6 +154,8 @@ type State = {|
startDateAdded: ?Date,
endDateAdded: ?Date,
isPercentageToggled: boolean,
+ isWhitelistToggled: boolean,
+ isWhitelistModalOpen: boolean,
percentage: ?number,
|};
@@ -177,6 +191,7 @@ class CompliancePage extends Component {
if (this.props.percentage) {
this.setState({ percentage: this.props.percentage });
}
+ this.props.fetchManagers();
}
componentWillReceiveProps(nextProps) {
@@ -404,6 +419,14 @@ class CompliancePage extends Component {
this.props.removeInvestors(addresses);
};
+ handleToggleWhitelist = async (isToggled: boolean) => {
+ if (isToggled) {
+ await this.props.addGeneralPermissionModule();
+ } else {
+ await this.props.archiveGeneralPermissionModule();
+ }
+ };
+
handleTogglePercentage = (isToggled: boolean) => {
const { isPercentageEnabled, isPercentagePaused } = this.props;
if (!isPercentageEnabled) {
@@ -617,166 +640,173 @@ class CompliancePage extends Component {
// const paginatedRows = this.paginationRendering()
return (
-
-
-
Token Whitelist
-
- Whitelisted addresses may hold, buy, or sell the security token and
- may participate into the STO. Security token buy/sell
- operations may be subject to restrictions.
-
-
-
-
-
-
+
+
+
+ Token Whitelist
+
+ Whitelisted addresses may hold, buy, or sell the security token
+ and may participate into the STO. Security token buy/sell
+ operations may be subject to restrictions.
+
+
+
+
+ Import Whitelist
+
+
+
+
-
-
- {/*
-
- {}}
- onChange={() => {}}
- />
- {}}
- onChange={() => {}}
- />
-
- */}
-
-
-
- Enable Ownership Restrictions
-
- */}
+
+
+ Export Whitelist
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+ {/*
+
+ */}
+
Ownership Restrictions
+
+
+
+ Enable Ownership Restrictions
+
+
+
-
-
- Each Individual Investor Can
-
- Own Up To of Outstanding Tokens
-
-
-
-
- Apply
-
+ >
+
+ Each Individual Investor Can
+
+ Own Up To of Outstanding Tokens
+
+
+
+
+ Apply
+
+
+
+
+
-
-
-
- Import Whitelist
-
-
-
-
- Export Whitelist
-
-
-
+
+
+
+
+
+
Whitelist Management
+
+
+
+ Enable Third-Party Whitelist Management
+
+
+
- {/*
-
-
-
-
- Please enter the information below to edit the chosen investors.
-
-
-
-
- */}
-
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/packages/polymath-issuer/src/pages/compliance/components/WhitelistModal.js b/packages/polymath-issuer/src/pages/compliance/components/WhitelistModal.js
new file mode 100644
index 000000000..9553c2f1f
--- /dev/null
+++ b/packages/polymath-issuer/src/pages/compliance/components/WhitelistModal.js
@@ -0,0 +1,103 @@
+// @flow
+
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { Modal, Button } from '@polymathnetwork/ui';
+import { withFormik } from 'formik';
+import { Form } from 'carbon-components-react';
+import {
+ bull,
+ PageCentered,
+ ContentBox,
+ Heading,
+ FormItem,
+ TextInput,
+} from '@polymathnetwork/ui';
+import validator from '@polymathnetwork/ui/validator';
+import { addAddressToTransferManager } from '../../../actions/compliance';
+
+type Props = {
+ isOpen: boolean,
+ handleClose: () => any,
+};
+
+const formSchema = validator.object().shape({
+ address: validator
+ .string()
+ .isAddress('Invalid Address')
+ .isRequired('Required'),
+ details: validator.string().isRequired('Required'),
+});
+
+export const ConfirmEmailFormComponent = ({ handleSubmit, handleClose }) => (
+
+);
+
+const formikEnhancer = withFormik({
+ validationSchema: formSchema,
+ displayName: 'ConfirmEmailForm',
+ validateOnChange: false,
+ handleSubmit: (values, { setFieldError, props }) => {
+ const { dispatch, approvedManagers } = props;
+ const addressExists = approvedManagers.find(
+ i => i.address === values.address
+ );
+ if (addressExists) {
+ setFieldError('address', 'Address is already added to Whitelist Manager');
+ return;
+ }
+ props.handleClose();
+ dispatch(addAddressToTransferManager(values.address, values.details));
+ },
+});
+
+const mapStateToProps = state => ({
+ approvedManagers: state.whitelist.approvedManagers,
+});
+
+const FormikEnhancedForm = formikEnhancer(ConfirmEmailFormComponent);
+const ConnectedForm = connect(mapStateToProps)(FormikEnhancedForm);
+
+class WhitelistModal extends Component
{
+ render() {
+ const { isOpen, handleClose } = this.props;
+ return (
+
+ Add Whitelist Manager
+
+
+ Specify the whitelist manager address of the new whitelist manager.
+ Each manager will have permission to update the whitelist. Consult
+ with your legal team before adding a new wallet to the list.
+
+
+
+
+ );
+ }
+}
+
+export default WhitelistModal;
diff --git a/packages/polymath-issuer/src/pages/compliance/components/WhitelistTable.js b/packages/polymath-issuer/src/pages/compliance/components/WhitelistTable.js
new file mode 100644
index 000000000..1df4adf1e
--- /dev/null
+++ b/packages/polymath-issuer/src/pages/compliance/components/WhitelistTable.js
@@ -0,0 +1,140 @@
+// @flow
+
+import React, { Component } from 'react';
+import { DataTable, Icon } from 'carbon-components-react';
+import { Button } from '@polymathnetwork/ui';
+import WhitelistModal from './WhitelistModal';
+import { connect } from 'react-redux';
+import { removeAddressFromTransferManager } from '../../../actions/compliance';
+const {
+ TableContainer,
+ Table,
+ TableHead,
+ TableRow,
+ TableBody,
+ TableCell,
+ TableHeader,
+ TableToolbar,
+ TableToolbarContent,
+} = DataTable;
+
+const columns = [
+ {
+ header: 'Whitelist Manager Wallet Address',
+ key: 'address',
+ width: 250,
+ Cell: ({ value }) => value,
+ },
+ {
+ header: 'Manager Details',
+ key: 'details',
+ width: 250,
+ Cell: ({ value }) => value,
+ },
+];
+
+type State = {|
+ isWhitelistModalOpen: boolean,
+|};
+
+class WhitelistTable extends Component {
+ state = {
+ isWhitelistModalOpen: false,
+ };
+
+ handleOpen = () => {
+ this.setState({ isWhitelistModalOpen: true });
+ };
+
+ handleClose = () => {
+ this.setState({ isWhitelistModalOpen: false });
+ };
+
+ handleDelete = id => {
+ this.props.removeAddressFromTransferManager(id);
+ };
+
+ render() {
+ const { approvedManagers } = this.props;
+ return (
+
+
+
{
+ return (
+
+
+
+ {/* pass in `onInputChange` change here to make filtering work */}
+
+ Add new
+
+
+
+
+
+
+ {headers.map(header => (
+
+ {header.header}
+
+ ))}
+
+
+
+
+ {rows.map(row => (
+ console.log('test')}
+ >
+ {row.cells.map(cell => (
+ {cell.value}
+ ))}
+ {approvedManagers.length > 0 ? (
+ this.handleDelete(row.id)}
+ >
+
+
+ ) : (
+
+ )}
+
+ ))}
+
+
+
+ );
+ }}
+ />
+
+ );
+ }
+}
+
+const mapStateToProps = state => ({
+ approvedManagers: state.whitelist.approvedManagers,
+});
+
+const mapDispatchToProps = {
+ removeAddressFromTransferManager,
+};
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(WhitelistTable);
diff --git a/packages/polymath-issuer/src/pages/compliance/style.scss b/packages/polymath-issuer/src/pages/compliance/style.scss
index 3125165c8..5a6c919b3 100644
--- a/packages/polymath-issuer/src/pages/compliance/style.scss
+++ b/packages/polymath-issuer/src/pages/compliance/style.scss
@@ -1,20 +1,73 @@
+.delete-icon {
+ cursor: pointer;
+}
+
+.form-item-header {
+ margin-top: 12px;
+ margin-bottom: 5px;
+ font-size: 14px;
+}
+
.compliance-form {
- width: 60%;
+ width: 100%;
+
+ .whitelist-settings {
+ display: flex;
+ flex-direction: column;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ > .bx--form-item {
+ //&:first-child {
+ // max-width: 325px;
+ //}
+
+ &:last-child {
+ margin-bottom: 0 !important;
+ overflow: scroll;
+
+ .bx--form-item {
+ position: relative;
+ float: left;
+
+ input {
+ width: 84px;
+ min-width: 84px;
+
+ &::-webkit-outer-spin-button,
+ &::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+ }
+ }
+
+ &:after {
+ content: '%';
+ position: absolute;
+ top: 13px;
+ left: 55px;
+ color: #8c9ba5;
+ font-size: 14px;
+ }
+ }
+ }
+ }
+ }
.compliance-settings {
display: flex;
+ flex-direction: row;
margin-top: 20px;
margin-bottom: 20px;
> .bx--form-item {
- max-width: 220px;
+ max-width: 300px;
//&:first-child {
// max-width: 325px;
//}
&:last-child {
- margin-top: -22px;
+ margin-top: -24px;
margin-bottom: 0 !important;
height: 100px;
diff --git a/packages/polymath-issuer/src/reducers/compliance.js b/packages/polymath-issuer/src/reducers/compliance.js
index 2eb55749f..57a28da73 100644
--- a/packages/polymath-issuer/src/reducers/compliance.js
+++ b/packages/polymath-issuer/src/reducers/compliance.js
@@ -25,6 +25,7 @@ export type WhitelistState = {|
listLength: number,
freezeStatus: ?boolean,
isFrozenModalOpen: ?boolean,
+ approvedManagers: Array,
|};
const defaultState: WhitelistState = {
@@ -42,6 +43,8 @@ const defaultState: WhitelistState = {
listLength: 10,
freezeStatus: null,
isFrozenModalOpen: null,
+ approvedManagers: [],
+ isToggled: false,
};
// NOTE @RafaelVidaurre: WARNING For some reason this reducer is being renamed.
@@ -49,6 +52,35 @@ const defaultState: WhitelistState = {
// eslint-disable-next-line complexity
export default (state: WhitelistState = defaultState, action: Object) => {
switch (action.type) {
+ case a.TOGGLE_WHITELIST_MANAGEMENT:
+ return {
+ ...state,
+ isToggled: action.isToggled,
+ };
+ case a.REMOVE_MANAGER:
+ let index = state.approvedManagers.findIndex(
+ i => i.address === action.address
+ );
+ return {
+ ...state,
+ approvedManagers: [
+ ...state.approvedManagers.slice(0, index),
+ ...state.approvedManagers.slice(index + 1),
+ ],
+ };
+ case a.ADD_MANAGER:
+ return {
+ ...state,
+ approvedManagers: [
+ ...state.approvedManagers,
+ { ...action.manager, id: action.manager.address },
+ ],
+ };
+ case a.LOAD_MANAGERS:
+ return {
+ ...state,
+ approvedManagers: action.managers,
+ };
case a.TRANSFER_MANAGER:
return {
...state,
diff --git a/packages/polymath-js/src/contracts/PermissionManager.js b/packages/polymath-js/src/contracts/PermissionManager.js
index a79e37567..6d685ac63 100644
--- a/packages/polymath-js/src/contracts/PermissionManager.js
+++ b/packages/polymath-js/src/contracts/PermissionManager.js
@@ -18,4 +18,39 @@ export default class PermissionManager extends Contract {
}
version = version;
}
+
+ async addDelegate(at: Address, details: string) {
+ return this._tx(this._methods.addDelegate(at, this._toBytes(details)));
+ }
+
+ async checkDelegate(at: Address) {
+ return this._methods.checkDelegate(at).call();
+ }
+
+ async getDelegateDetails(delegate: Address) {
+ let details = await this._methods.delegateDetails(delegate).call();
+ return this._toAscii(details);
+ }
+
+ async getAllDelegates(moduleAddress: Address, permission: string) {
+ return this._methods
+ .getAllDelegatesWithPerm(moduleAddress, this._toBytes(permission))
+ .call();
+ }
+
+ async changePermission(
+ delegate: Address,
+ moduleAddress: Address,
+ permission: string,
+ valid: boolean
+ ) {
+ return this._tx(
+ this._methods.changePermission(
+ delegate,
+ moduleAddress,
+ this._toBytes(permission),
+ valid
+ )
+ );
+ }
}
diff --git a/packages/polymath-js/src/contracts/SecurityToken.js b/packages/polymath-js/src/contracts/SecurityToken.js
index afb47cb24..9a3e98af6 100644
--- a/packages/polymath-js/src/contracts/SecurityToken.js
+++ b/packages/polymath-js/src/contracts/SecurityToken.js
@@ -474,6 +474,21 @@ export default class SecurityToken extends Contract {
);
}
+ async setPermissionManager(): Promise {
+ const generalPermissionManagerFactory = await this.getModuleFactory(
+ 'GeneralPermissionManager',
+ MODULE_TYPES.PERMISSION
+ );
+ const setupCost = await generalPermissionManagerFactory.setupCost();
+ const data = this._toBytes('');
+ return this.addModule(
+ generalPermissionManagerFactory.address,
+ data,
+ PolyToken.addDecimals(setupCost),
+ 0
+ );
+ }
+
async setCountTM(count: number): Promise {
const countTransferManagerFactory = await this.getModuleFactory(
'CountTransferManager',
@@ -500,4 +515,16 @@ export default class SecurityToken extends Contract {
0
);
}
+
+ async getModule(at: Address): Promise {
+ return this._methods.getModule(at).call();
+ }
+
+ async arhiveModule(at: Address): Promise {
+ return this._tx(this._methods.archiveModule(at));
+ }
+
+ async unarchiveModule(at: Address): Promise {
+ return this._tx(this._methods.unarchiveModule(at));
+ }
}
diff --git a/packages/polymath-offchain/src/utils/emails.js b/packages/polymath-offchain/src/utils/emails.js
index 8e8e4b0be..1db5eeb7b 100644
--- a/packages/polymath-offchain/src/utils/emails.js
+++ b/packages/polymath-offchain/src/utils/emails.js
@@ -42,9 +42,6 @@ export const sendEmail = async (
from: { email: 'noreply@polymath.network', name: 'Polymath Network' },
replyTo,
to: { email, name },
- // @FIXME remon-nashid: requests to SendGrid fail when cc and receiver addresses are the same.
- // hardcoding CC email to my email to save the day.
- cc: 'remon@polymath.network',
subject,
html: body,
};