Skip to content

Commit e65daca

Browse files
committed
feat: add the features namespace to the SecurityToken entity
This namespace handles enabling features and querying their status. Individual `enable` functions in other namespaces have been removed BREAKING CHANGE: Remove `permissions.enable` and `dividends.enable`
1 parent 8550bd3 commit e65daca

File tree

4 files changed

+228
-22
lines changed

4 files changed

+228
-22
lines changed

src/entities/SecurityToken/Dividends.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,6 @@ interface GetManager {
2323
}
2424

2525
export class Dividends extends SubModule {
26-
/**
27-
* Enable dividend functionalities (ERC20, ETH or both)
28-
*
29-
* @param storageWalletAddress wallet that will receive reclaimed dividends and withheld taxes
30-
* @param types array containing the types of dividends to enable (will enable both if not present)
31-
*/
32-
public enable = async (args: { storageWalletAddress: string; types?: DividendType[] }) => {
33-
const { symbol } = this.securityToken;
34-
const procedure = new EnableDividendManagers(
35-
{
36-
symbol,
37-
...args,
38-
},
39-
this.context
40-
);
41-
return procedure.prepare();
42-
};
43-
4426
/**
4527
* Distribute dividends in POLY
4628
*
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import { ModuleName } from '@polymathnetwork/contract-wrappers';
2+
import { SubModule } from './SubModule';
3+
import { EnableGeneralPermissionManager, EnableDividendManagers } from '../../procedures';
4+
import {
5+
Feature,
6+
ErrorCode,
7+
EnableGeneralPermissionManagerProcedureArgs,
8+
EnableDividendManagersProcedureArgs,
9+
DividendType,
10+
} from '../../types';
11+
import { PolymathError } from '../../PolymathError';
12+
import { TransactionQueue } from '../TransactionQueue';
13+
14+
export interface FeatureStatuses {
15+
[Feature.Permissions]: boolean;
16+
[Feature.Shareholders]: boolean;
17+
[Feature.Erc20Dividends]: boolean;
18+
[Feature.EtherDividends]: boolean;
19+
}
20+
21+
type EnableOpts =
22+
| EnablePermissionsOpts
23+
| EnableShareholdersOpts
24+
| EnableErc20DividendsOpts
25+
| EnableEtherDividendsOpts;
26+
27+
export interface EnablePermissionsOpts {}
28+
29+
export interface EnableShareholdersOpts {}
30+
31+
export interface EnableErc20DividendsOpts {
32+
storageWalletAddress: string;
33+
}
34+
35+
export interface EnableEtherDividendsOpts {
36+
storageWalletAddress: string;
37+
}
38+
39+
export interface Enable {
40+
(args: { feature: Feature.Permissions }, opts: EnablePermissionsOpts): Promise<
41+
TransactionQueue<EnableGeneralPermissionManagerProcedureArgs>
42+
>;
43+
(args: { feature: Feature.Shareholders }, opts: EnableShareholdersOpts): Promise<
44+
TransactionQueue
45+
>; // poorly typed because the corresponding procedure doesn't exist yet
46+
(args: { feature: Feature.Erc20Dividends }, opts: EnableErc20DividendsOpts): Promise<
47+
TransactionQueue<EnableDividendManagersProcedureArgs>
48+
>;
49+
(args: { feature: Feature.EtherDividends }, opts: EnableEtherDividendsOpts): Promise<
50+
TransactionQueue<EnableDividendManagersProcedureArgs>
51+
>;
52+
}
53+
54+
export class Features extends SubModule {
55+
/**
56+
* List of all existing features
57+
*/
58+
public list: Feature[] = [
59+
Feature.Permissions,
60+
Feature.Shareholders,
61+
Feature.Erc20Dividends,
62+
Feature.EtherDividends,
63+
];
64+
65+
/**
66+
* Returns whether a particular feature has been enabled or not
67+
*
68+
* @param feature feature for which to query status
69+
*/
70+
public isEnabled = async (args: { feature: Feature }) => {
71+
const { feature } = args;
72+
const {
73+
context: { contractWrappers },
74+
securityToken: { symbol },
75+
} = this;
76+
let attachedModule;
77+
switch (feature) {
78+
case Feature.Permissions: {
79+
attachedModule = (await contractWrappers.getAttachedModules(
80+
{ symbol, moduleName: ModuleName.GeneralPermissionManager },
81+
{ unarchived: true }
82+
))[0];
83+
break;
84+
}
85+
case Feature.Shareholders: {
86+
attachedModule = (await contractWrappers.getAttachedModules(
87+
{ symbol, moduleName: ModuleName.GeneralTransferManager },
88+
{ unarchived: true }
89+
))[0];
90+
break;
91+
}
92+
case Feature.Erc20Dividends: {
93+
attachedModule = (await contractWrappers.getAttachedModules(
94+
{ symbol, moduleName: ModuleName.ERC20DividendCheckpoint },
95+
{ unarchived: true }
96+
))[0];
97+
break;
98+
}
99+
case Feature.EtherDividends: {
100+
attachedModule = (await contractWrappers.getAttachedModules(
101+
{ symbol, moduleName: ModuleName.EtherDividendCheckpoint },
102+
{ unarchived: true }
103+
))[0];
104+
break;
105+
}
106+
default: {
107+
throw new PolymathError({
108+
code: ErrorCode.FetcherValidationError,
109+
message: `Feature '${feature}' is not supported`,
110+
});
111+
}
112+
}
113+
114+
return !!attachedModule;
115+
};
116+
117+
/**
118+
* Gets the status on all Security Token features (true = enabled, false = not enabled/disabled)
119+
*/
120+
public getStatus = async () => {
121+
const { list } = this;
122+
123+
const [
124+
permissionsEnabled,
125+
shareholdersEnabled,
126+
erc20DividendsEnabled,
127+
etherDividendsEnabled,
128+
] = await Promise.all(list.map(feature => this.isEnabled({ feature })));
129+
130+
const result: FeatureStatuses = {
131+
[Feature.Permissions]: permissionsEnabled,
132+
[Feature.Shareholders]: shareholdersEnabled,
133+
[Feature.Erc20Dividends]: erc20DividendsEnabled,
134+
[Feature.EtherDividends]: etherDividendsEnabled,
135+
};
136+
};
137+
138+
/**
139+
* Enable a feature
140+
*
141+
* @param feature feature to enable
142+
* @param opts feature options
143+
*/
144+
public enable: Enable = async (
145+
args: { feature: Feature },
146+
opts: EnableOpts
147+
): Promise<TransactionQueue> => {
148+
const { feature } = args;
149+
150+
const alreadyEnabled = await this.isEnabled({ feature });
151+
152+
if (alreadyEnabled) {
153+
throw new PolymathError({
154+
code: ErrorCode.FatalError,
155+
message: `Feature '${feature}' already enabled`,
156+
});
157+
}
158+
159+
const { symbol } = this.securityToken;
160+
let procedure;
161+
switch (feature) {
162+
case Feature.Permissions: {
163+
procedure = new EnableGeneralPermissionManager(
164+
{
165+
symbol,
166+
...opts,
167+
},
168+
this.context
169+
);
170+
break;
171+
}
172+
case Feature.Shareholders: {
173+
// TODO @monitz87: add logic here when the GTM attaching procedure is implemented
174+
throw new PolymathError({
175+
code: ErrorCode.FatalError,
176+
message: 'Cannot enable/disable the Shareholders feature',
177+
});
178+
// break;
179+
}
180+
case Feature.Erc20Dividends: {
181+
procedure = new EnableDividendManagers(
182+
{ symbol, ...(opts as EnableErc20DividendsOpts), types: [DividendType.Erc20] },
183+
this.context
184+
);
185+
break;
186+
}
187+
case Feature.EtherDividends: {
188+
procedure = new EnableDividendManagers(
189+
{ symbol, ...(opts as EnableEtherDividendsOpts), types: [DividendType.Eth] },
190+
this.context
191+
);
192+
break;
193+
}
194+
default: {
195+
throw new PolymathError({
196+
code: ErrorCode.FetcherValidationError,
197+
message: `Feature '${feature}' is not supported`,
198+
});
199+
}
200+
}
201+
202+
return procedure.prepare();
203+
};
204+
}

src/entities/SecurityToken/SecurityToken.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Context } from '../../Context';
22
import { Entity } from '../Entity';
33
import { serialize, unserialize as unserializeUtil } from '../../utils';
4+
import { Features } from './Features';
45
import { Shareholders } from './Shareholders';
56
import { Dividends } from './Dividends';
67
import { Offerings } from './Offerings';
@@ -57,6 +58,8 @@ export class SecurityToken extends Entity<Params> {
5758

5859
public address: string;
5960

61+
public features: Features;
62+
6063
public shareholders: Shareholders;
6164

6265
public dividends: Dividends;
@@ -77,6 +80,7 @@ export class SecurityToken extends Entity<Params> {
7780
this.owner = owner;
7881
this.address = address;
7982
this.uid = SecurityToken.generateId({ symbol });
83+
this.features = new Features(this, context);
8084
this.shareholders = new Shareholders(this, context);
8185
this.dividends = new Dividends(this, context);
8286
this.offerings = new Offerings(this, context);

src/types/index.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,24 @@ export function isPojo(pojo: any): pojo is Pojo {
436436
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
437437

438438
export enum TransactionSpeed {
439-
Slow = 'slow',
440-
Medium = 'medium',
441-
Fast = 'fast',
442-
Fastest = 'fastest',
439+
Slow = 'Slow',
440+
Medium = 'Medium',
441+
Fast = 'Fast',
442+
Fastest = 'Fastest',
443+
}
444+
445+
export enum Feature {
446+
Permissions = 'Permissions',
447+
Shareholders = 'Shareholders',
448+
Erc20Dividends = 'Erc20Dividends',
449+
EtherDividends = 'EtherDividends',
450+
}
451+
452+
export enum Roles {
453+
PermissionsAdministrator = 'PermissionsAdministrator',
454+
Erc20DividendsOperator = 'Erc20DividendsOperator',
455+
Erc20DividendsAdministrator = 'Erc20DividendsAdministrator',
456+
EtherDividendsOperator = 'EtherDividendsOperator',
457+
EtherDividendsAdministrator = 'EtherDividendsAdministrator',
458+
ShareholdersAdministrator = 'ShareholdersAdministrator',
443459
}

0 commit comments

Comments
 (0)