generated from PolymeshAssociation/typescript-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Requirements.ts
200 lines (175 loc) · 6.22 KB
/
Requirements.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import { QueryableStorageEntry } from '@polkadot/api/types';
import { Vec } from '@polkadot/types/codec';
import { AssetCompliance, AssetComplianceResult, IdentityId } from 'polymesh-types/types';
import { Identity, Namespace, SecurityToken } from '~/api/entities';
import {
setAssetRequirements,
SetAssetRequirementsParams,
togglePauseRequirements,
} from '~/api/procedures';
import { TransactionQueue } from '~/base';
import { Compliance, Requirement, SubCallback, UnsubCallback } from '~/types';
import {
assetComplianceResultToCompliance,
boolToBoolean,
complianceRequirementToRequirement,
identityIdToString,
signerToString,
stringToIdentityId,
stringToTicker,
} from '~/utils';
/**
* Handles all Security Token Compliance Requirements related functionality
*/
export class Requirements extends Namespace<SecurityToken> {
/**
* Configure asset compliance requirements for the Security Token. This operation will replace all existing requirements with a new requirement set
*
* This requires two transactions
*
* @param args.requirements - array of array of conditions. For a transfer to be successful, it must comply with all the conditions of at least one of the arrays. In other words, higher level arrays are *OR* between them,
* while conditions inside each array are *AND* between them
*
* @example Say A, B, C, D and E are requirements and we arrange them as `[[A, B], [C, D], [E]]`.
* For a transfer to succeed, it must either comply with A AND B, C AND D, OR E.
*/
public set(args: SetAssetRequirementsParams): Promise<TransactionQueue<SecurityToken>> {
const {
parent: { ticker },
context,
} = this;
return setAssetRequirements.prepare({ ticker, ...args }, context);
}
/**
* Retrieve all of the Security Token's requirements
*
* @note can be subscribed to
*/
public get(): Promise<Requirement[]>;
public get(callback: SubCallback<Requirement[]>): Promise<UnsubCallback>;
// eslint-disable-next-line require-jsdoc
public async get(callback?: SubCallback<Requirement[]>): Promise<Requirement[] | UnsubCallback> {
const {
parent: { ticker },
context: {
polymeshApi: {
query: { complianceManager },
queryMulti,
},
},
context,
} = this;
const rawTicker = stringToTicker(ticker, context);
const assembleResult = ([assetCompliance, claimIssuers]: [
AssetCompliance,
Vec<IdentityId>
]): Requirement[] => {
const defaultTrustedClaimIssuers = claimIssuers.map(identityIdToString);
return assetCompliance.requirements.map(complianceRequirement => {
const requirement = complianceRequirementToRequirement(complianceRequirement, context);
requirement.conditions.forEach(condition => {
if (!condition.trustedClaimIssuers || !condition.trustedClaimIssuers.length) {
condition.trustedClaimIssuers = defaultTrustedClaimIssuers;
}
});
return requirement;
});
};
if (callback) {
return queryMulti<[AssetCompliance, Vec<IdentityId>]>(
[
[complianceManager.assetCompliances as QueryableStorageEntry<'promise'>, rawTicker],
[complianceManager.trustedClaimIssuer as QueryableStorageEntry<'promise'>, rawTicker],
],
res => {
callback(assembleResult(res));
}
);
}
const result = await queryMulti<[AssetCompliance, Vec<IdentityId>]>([
[complianceManager.assetCompliances as QueryableStorageEntry<'promise'>, rawTicker],
[complianceManager.trustedClaimIssuer as QueryableStorageEntry<'promise'>, rawTicker],
]);
return assembleResult(result);
}
/**
* Detele all the current requirements for the Security Token.
*/
public reset(): Promise<TransactionQueue<SecurityToken>> {
const {
parent: { ticker },
context,
} = this;
return setAssetRequirements.prepare({ ticker, requirements: [] }, context);
}
/**
* Pause all the Security Token's requirements. This means that all transfers will be allowed until requirements are unpaused
*/
public pause(): Promise<TransactionQueue<SecurityToken>> {
const {
parent: { ticker },
context,
} = this;
return togglePauseRequirements.prepare({ ticker, pause: true }, context);
}
/**
* Un-pause all the Security Token's current requirements
*/
public unpause(): Promise<TransactionQueue<SecurityToken>> {
const {
parent: { ticker },
context,
} = this;
return togglePauseRequirements.prepare({ ticker, pause: false }, context);
}
/**
* Check whether the sender and receiver Identities in a transfer comply with all the requirements of this asset
*
* @note this does not take balances into account
*
* @param args.from - sender Identity (optional, defaults to the current Identity)
* @param args.to - receiver Identity
*/
public async checkSettle(args: {
from?: string | Identity;
to: string | Identity;
}): Promise<Compliance> {
const {
parent: { ticker },
context: {
polymeshApi: { rpc },
},
context,
parent,
} = this;
const { from = await this.context.getCurrentIdentity(), to } = args;
const fromDid = stringToIdentityId(signerToString(from), context);
const toDid = signerToString(to);
const { primaryIssuanceAgent } = await parent.details();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const res: AssetComplianceResult = await (rpc as any).compliance.canTransfer(
stringToTicker(ticker, context),
fromDid,
stringToIdentityId(toDid, context),
primaryIssuanceAgent ? stringToIdentityId(primaryIssuanceAgent.did, context) : null
);
return assetComplianceResultToCompliance(res, context);
}
/**
* Check whether asset compliance requirements are paused or not
*/
public async arePaused(): Promise<boolean> {
const {
parent: { ticker },
context: {
polymeshApi: {
query: { complianceManager },
},
},
context,
} = this;
const rawTicker = stringToTicker(ticker, context);
const { is_paused: isPaused } = await complianceManager.assetCompliances(rawTicker);
return boolToBoolean(isPaused);
}
}