This repository has been archived by the owner on Jul 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
/
Compliance.sol
350 lines (312 loc) · 15.9 KB
/
Compliance.sol
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
pragma solidity ^0.4.18;
/*
Polymath compliance protocol is intended to ensure regulatory compliance
in the jurisdictions that security tokens are being offered in. The compliance
protocol allows security tokens remain interoperable so that anyone can
build on top of the Polymath platform and extend it's functionality.
*/
import './SafeMath.sol';
import './interfaces/ICompliance.sol';
import './interfaces/IOfferingFactory.sol';
import './Customers.sol';
import './Template.sol';
import './interfaces/ISecurityToken.sol';
import './interfaces/ISecurityTokenRegistrar.sol';
/**
* @title Compilance
* @dev Regulatory details offered by the security token
*/
contract Compliance is ICompliance {
using SafeMath for uint256;
string public VERSION = "2";
ISecurityTokenRegistrar public STRegistrar;
//Structure used to hold reputation for template and offeringFactories
struct Reputation {
uint256 totalRaised; // Total amount raised by issuers that used the template / offeringFactory
address[] usedBy; // Array of security token addresses that used this particular template / offeringFactory
mapping (address => bool) usedBySecurityToken; // Mapping of STs using this Reputation
}
mapping(address => Reputation) public templates; // Mapping used for storing the template repuation
mapping(address => address[]) public templateProposals; // Template proposals for a specific security token
mapping(address => Reputation) public offeringFactories; // Mapping used for storing the offering factory reputation
mapping(address => address[]) public offeringFactoryProposals; // OfferingFactory proposals for a specific security token
mapping(address => mapping(address => bool)) public proposedTemplatesList; // Use to restrict the proposing the same templates again and again
mapping(address => mapping(address => bool)) public proposedOfferingFactoryList; // Use to restrict the proposing the same offeringFactory again and again
Customers public PolyCustomers; // Instance of the Compliance contract
uint256 public constant MINIMUM_VESTING_PERIOD = 60 * 60 * 24 * 100; // 100 Day minimum vesting period for POLY earned
// Notifications for templates
event LogTemplateCreated(address indexed _creator, address indexed _template, string _offeringType);
event LogNewTemplateProposal(address indexed _securityToken, address indexed _template, address indexed _delegate, uint _templateProposalIndex);
event LogCancelTemplateProposal(address indexed _securityToken, address indexed _template, uint _templateProposalIndex);
// Notifications for offering factories
event LogOfferingFactoryRegistered(address indexed _creator, address indexed _offeringFactory, bytes32 _description);
event LogNewOfferingFactoryProposal(address indexed _securityToken, address indexed _offeringFactory, address indexed _owner, uint _offeringFactoryProposalIndex);
event LogCancelOfferingFactoryProposal(address indexed _securityToken, address indexed _offeringFactory, uint _offeringFactoryProposalIndex);
/* @param _polyCustomersAddress The address of the Polymath Customers contract */
function Compliance(address _polyCustomersAddress) public {
PolyCustomers = Customers(_polyCustomersAddress);
}
/**
* @dev `setRegistrarAddress` This function set the SecurityTokenRegistrar contract address.
* Called just after the deployment of smart contracts.
* @param _STRegistrar It is the `this` reference of STR contract
* @return bool
*/
function setRegistrarAddress(address _STRegistrar) public returns (bool) {
require(_STRegistrar != address(0));
require(STRegistrar == address(0));
STRegistrar = ISecurityTokenRegistrar(_STRegistrar);
return true;
}
/**
* @dev `createTemplate` is a simple function to create a new compliance template
* @param _offeringType The name of the security being issued
* @param _issuerJurisdiction The jurisdiction id of the issuer
* @param _accredited Accreditation status required for investors
* @param _KYC KYC provider used by the template
* @param _details Details of the offering requirements
* @param _expires Timestamp of when the template will expire
* @param _fee Amount of POLY to use the template (held in escrow until issuance)
* @param _quorum Minimum percent of shareholders which need to vote to freeze
* @param _vestingPeriod Length of time to vest funds
*/
function createTemplate(
string _offeringType,
bytes32 _issuerJurisdiction,
bool _accredited,
address _KYC,
bytes32 _details,
uint256 _expires,
uint256 _fee,
uint8 _quorum,
uint256 _vestingPeriod
) public
{
require(_KYC != address(0));
require(_vestingPeriod >= MINIMUM_VESTING_PERIOD);
require(_quorum > 0 && _quorum <= 100);
address _template = new Template(
msg.sender,
_offeringType,
_issuerJurisdiction,
_accredited,
_KYC,
_details,
_expires,
_fee,
_quorum,
_vestingPeriod
);
templates[_template] = Reputation({
totalRaised: 0,
usedBy: new address[](0)
});
//Keep track of templates created through Compliance.sol
templates[_template].usedBySecurityToken[address(this)] = true;
LogTemplateCreated(msg.sender, _template, _offeringType);
}
/**
* @dev Propose a bid for a security token issuance
* @param _securityToken The security token being bid on
* @param _template The unique template address
* @return bool success
*/
function proposeTemplate(
address _securityToken,
address _template
) public returns (bool success)
{
require(templates[_template].usedBySecurityToken[address(this)]);
// Verifying that provided _securityToken is generated by securityTokenRegistrar only
var (,, securityTokenOwner,) = STRegistrar.getSecurityTokenData(_securityToken);
require(securityTokenOwner != address(0));
// Check whether the template is already proposed or not for the given securityToken
require(!proposedTemplatesList[_securityToken][_template]);
// Creating the instance of template to avail the function calling
ITemplate template = ITemplate(_template);
// This will fail if template is expired
var (,finalized) = template.getTemplateDetails();
var (,,, owner,) = template.getUsageDetails();
// Require that the caller is the template owner
// and that the template has been finalized
require(owner == msg.sender);
require(finalized);
//Get a reference of the template contract and add it to the templateProposals array
templateProposals[_securityToken].push(_template);
proposedTemplatesList[_securityToken][_template] = true;
LogNewTemplateProposal(_securityToken, _template, msg.sender, templateProposals[_securityToken].length - 1);
return true;
}
/**
* @dev Cancel a Template proposal if the bid hasn't been accepted
* @param _securityToken The security token being bid on
* @param _templateProposalIndex The template proposal array index
* @return bool success
*/
function cancelTemplateProposal(
address _securityToken,
uint256 _templateProposalIndex
) public returns (bool success)
{
address proposedTemplate = templateProposals[_securityToken][_templateProposalIndex];
ITemplate template = ITemplate(proposedTemplate);
var (,,, owner,) = template.getUsageDetails();
// Cancelation is only being performed by the owner of template.
require(owner == msg.sender);
var (chosenTemplate,,,,,) = ISecurityToken(_securityToken).getTokenDetails();
// Template shouldn't be choosed one.
require(chosenTemplate != proposedTemplate);
templateProposals[_securityToken][_templateProposalIndex] = address(0);
LogCancelTemplateProposal(_securityToken, proposedTemplate, _templateProposalIndex);
return true;
}
/**
* @dev Register the Offering factory by the developer.
* @param _factoryAddress address of the offering factory
* @return bool success
*/
function registerOfferingFactory(
address _factoryAddress
) public returns (bool success)
{
require(_factoryAddress != address(0));
// Restrict to update the reputation of already registered offeringFactory
require(!(offeringFactories[_factoryAddress].totalRaised > 0 || offeringFactories[_factoryAddress].usedBy.length > 0));
IOfferingFactory offeringFactory = IOfferingFactory(_factoryAddress);
var (, quorum, vestingPeriod, owner, description) = offeringFactory.getUsageDetails();
// Validate Offering Factory details
require(quorum > 0 && quorum <= 100);
require(vestingPeriod >= MINIMUM_VESTING_PERIOD);
require(owner != address(0));
// Add the factory in the available list of factory addresses
offeringFactories[_factoryAddress] = Reputation({
totalRaised: 0,
usedBy: new address[](0)
});
// Keep track of offering factories registered through Compliance.sol
offeringFactories[_factoryAddress].usedBySecurityToken[address(this)] = true;
LogOfferingFactoryRegistered(owner, _factoryAddress, description);
return true;
}
/**
* @dev Propose a Security Token Offering Factory for an issuance
* @param _securityToken The security token being bid on
* @param _factoryAddress The address of the offering factory
* @return bool success
*/
function proposeOfferingFactory(
address _securityToken,
address _factoryAddress
) public returns (bool success)
{
require(offeringFactories[_factoryAddress].usedBySecurityToken[address(this)]);
// Verifying that provided _securityToken is generated by securityTokenRegistrar only
var (,, securityTokenOwner,) = STRegistrar.getSecurityTokenData(_securityToken);
require(securityTokenOwner != address(0));
// Check whether the offeringFactory is already proposed or not for the given securityToken
require(!proposedOfferingFactoryList[_securityToken][_factoryAddress]);
IOfferingFactory offeringFactory = IOfferingFactory(_factoryAddress);
var (,,, owner,) = offeringFactory.getUsageDetails();
require(owner == msg.sender);
offeringFactoryProposals[_securityToken].push(_factoryAddress);
proposedOfferingFactoryList[_securityToken][_factoryAddress] = true;
LogNewOfferingFactoryProposal(_securityToken, _factoryAddress, owner, offeringFactoryProposals[_securityToken].length - 1);
return true;
}
/**
* @dev Cancel a Offering factory proposal if the bid hasn't been accepted
* @param _securityToken The security token being bid on
* @param _offeringFactoryProposalIndex The offeringFactory proposal array index
* @return bool success
*/
function cancelOfferingFactoryProposal(
address _securityToken,
uint256 _offeringFactoryProposalIndex
) public returns (bool success)
{
address proposedOfferingFactory = offeringFactoryProposals[_securityToken][_offeringFactoryProposalIndex];
IOfferingFactory offeringFactory = IOfferingFactory(proposedOfferingFactory);
var (,,, owner,) = offeringFactory.getUsageDetails();
// Cancelation is only being performed by the owner of template.
require(owner == msg.sender);
var (,,,,,chosenOfferingFactory) = ISecurityToken(_securityToken).getTokenDetails();
require(chosenOfferingFactory != proposedOfferingFactory);
offeringFactoryProposals[_securityToken][_offeringFactoryProposalIndex] = address(0);
LogCancelOfferingFactoryProposal(_securityToken, proposedOfferingFactory, _offeringFactoryProposalIndex);
return true;
}
/**
* @dev `updateTemplateReputation` is a function that updates the
history of a security token template usage to keep track of previous uses
* @param _template The unique template id
* @param _polyRaised The amount of poly raised
*/
function updateTemplateReputation(address _template, uint256 _polyRaised) external returns (bool success) {
// Check that the caller is a security token
var (,, securityTokenOwner,) = STRegistrar.getSecurityTokenData(msg.sender);
require(securityTokenOwner != address(0));
// If it is, then update reputation
if (!templates[_template].usedBySecurityToken[msg.sender]) {
templates[_template].usedBy.push(msg.sender);
templates[_template].usedBySecurityToken[msg.sender] = true;
}
templates[_template].totalRaised = templates[_template].totalRaised.add(_polyRaised);
return true;
}
/**
* @dev `updateOfferingReputation` is a function that updates the
history of a security token offeringFactory contract to keep track of previous uses
* @param _offeringFactory The address of the offering factory
* @param _polyRaised The amount of poly raised
*/
function updateOfferingFactoryReputation(address _offeringFactory, uint256 _polyRaised) external returns (bool success) {
// Check that the caller is a security token
var (,, securityTokenOwner,) = STRegistrar.getSecurityTokenData(msg.sender);
require(securityTokenOwner != address(0));
// If it is, then update reputation
if (!offeringFactories[_offeringFactory].usedBySecurityToken[msg.sender]) {
offeringFactories[_offeringFactory].usedBy.push(msg.sender);
offeringFactories[_offeringFactory].usedBySecurityToken[msg.sender] = true;
}
offeringFactories[_offeringFactory].totalRaised = offeringFactories[_offeringFactory].totalRaised.add(_polyRaised);
return true;
}
/**
* @dev Get template details by the proposal index
* @param _securityTokenAddress The security token ethereum address
* @param _templateIndex The array index of the template being checked
* @return Template struct
*/
function getTemplateByProposal(address _securityTokenAddress, uint8 _templateIndex) view public returns (
address _template
){
return templateProposals[_securityTokenAddress][_templateIndex];
}
/**
* @dev Get an array containing the address of all template proposals for a given ST
* @param _securityTokenAddress The security token address
* @return Template proposals array
*/
function getAllTemplateProposals(address _securityTokenAddress) view public returns (address[]) {
return templateProposals[_securityTokenAddress];
}
/**
* @dev Get security token offering smart contract details by the proposal index
* @param _securityTokenAddress The security token address
* @param _offeringFactoryProposalIndex The array index of the STO contract being checked
* @return Contract struct
*/
function getOfferingFactoryByProposal(address _securityTokenAddress, uint8 _offeringFactoryProposalIndex) view public returns (
address _offeringFactoryAddress
){
return offeringFactoryProposals[_securityTokenAddress][_offeringFactoryProposalIndex];
}
/**
* @dev Get an array containing the address of all offering proposals for a given ST
* @param _securityTokenAddress The security token address
* @return Offering proposals array
*/
function getAllOfferingFactoryProposals(address _securityTokenAddress) view public returns (address[]) {
return offeringFactoryProposals[_securityTokenAddress];
}
}