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

fix #49 (Multiple KYC Providers) -> TBD in V2 #91

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions contracts/Compliance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ contract Compliance is ICompliance {
address[] usedBy;
}
mapping(address => Offering) offerings; // Mapping used for storing the Offering detials corresponds to offering contract address
mapping(address => address[]) public offeringProposals; // Security token contract proposals for a specific security token
mapping(address => address[]) public offeringProposals; // Security token offering contract proposals for a specific security token

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
Expand All @@ -61,7 +61,7 @@ contract Compliance is ICompliance {
* @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 _whiteListedKYC List of 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)
Expand All @@ -72,24 +72,25 @@ contract Compliance is ICompliance {
string _offeringType,
bytes32 _issuerJurisdiction,
bool _accredited,
address _KYC,
address[10] _whiteListedKYC,
bytes32 _details,
uint256 _expires,
uint256 _fee,
uint8 _quorum,
uint256 _vestingPeriod
) public
{
require(_KYC != address(0));
var (,, role, verified, expires) = PolyCustomers.getCustomer(_KYC, msg.sender);
require(_whiteListedKYC[0] != address(0));
// 0 index should be the provider addresss which verify the delegate or msg.sender
var (,, role, verified, expires) = PolyCustomers.getCustomer(_whiteListedKYC[0], msg.sender);
require(role == 2 && verified && expires > now);
require(_vestingPeriod >= MINIMUM_VESTING_PERIOD);
address _template = new Template(
msg.sender,
_offeringType,
_issuerJurisdiction,
_accredited,
_KYC,
_whiteListedKYC,
_details,
_expires,
_fee,
Expand Down Expand Up @@ -189,13 +190,18 @@ contract Compliance is ICompliance {
) public returns (bool success)
{
var (,,,,KYC) = ISecurityToken(_securityToken).getTokenDetails();
var (,,, verified, expires) = PolyCustomers.getCustomer(KYC, offerings[_stoContract].auditor);
require(offerings[_stoContract].auditor == msg.sender);
require(verified);
require(expires > now);
offeringProposals[_securityToken].push(_stoContract);
LogNewContractProposal(_securityToken, _stoContract, msg.sender);
return true;
for (uint16 i; i < KYC.length; i++) {
var (,,, verified, expires) = PolyCustomers.getCustomer(KYC[i], offerings[_stoContract].auditor);
if (expires != 0) {
require(offerings[_stoContract].auditor == msg.sender);
require(verified);
require(expires > now);
offeringProposals[_securityToken].push(_stoContract);
LogNewContractProposal(_securityToken, _stoContract, msg.sender);
return true;
}
}
return false;
}

/**
Expand All @@ -211,7 +217,7 @@ contract Compliance is ICompliance {
{
address proposedOffering = offeringProposals[_securityToken][_offeringProposalIndex];
require(offerings[proposedOffering].auditor == msg.sender);
var (,,,,chosenOffering) = ISecurityToken(_securityToken).getTokenDetails();
var (,,,chosenOffering,) = ISecurityToken(_securityToken).getTokenDetails();
require(chosenOffering != proposedOffering);
offeringProposals[_securityToken][_offeringProposalIndex] = address(0);
return true;
Expand Down
27 changes: 15 additions & 12 deletions contracts/SecurityToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ contract SecurityToken is IERC20 {
uint256 public tokensIssuedBySTO = 0; // Flag variable to track the security token issued by the offering contract

// Notifications
event LogTemplateSet(address indexed _delegateAddress, address _template, address indexed _KYC);
event LogTemplateSet(address indexed _delegateAddress, address _template);
event LogUpdatedComplianceProof(bytes32 _merkleRoot, bytes32 _complianceProofHash);
event LogSetSTOContract(address _STO, address indexed _STOtemplate, address indexed _auditor, uint256 _startTime, uint256 _endTime);
event LogNewWhitelistedAddress(address _KYC, address _shareholder, uint8 _role);
Expand Down Expand Up @@ -162,13 +162,12 @@ contract SecurityToken is IERC20 {
address _template = PolyCompliance.getTemplateByProposal(this, _templateIndex);
require(_template != address(0));
Template = ITemplate(_template);
var (_fee, _quorum, _vestingPeriod, _delegate, _KYC) = Template.getUsageDetails();
var (_fee, _quorum, _vestingPeriod, _delegate,) = Template.getUsageDetails();
require(POLY.balanceOf(this) >= _fee);
allocations[_delegate] = Allocation(_fee, _vestingPeriod, _quorum, 0, 0, false);
delegate = _delegate;
KYC = _KYC;
PolyCompliance.updateTemplateReputation(_template, _templateIndex);
LogTemplateSet(_delegate, _template, _KYC);
LogTemplateSet(_delegate, _template);
return true;
}

Expand Down Expand Up @@ -233,16 +232,19 @@ contract SecurityToken is IERC20 {
* The Issuer can add an address to the whitelist by themselves by
* creating their own KYC provider and using it to verify the accounts
* they want to add to the whitelist.
* @param _whitelistAddress Address attempting to join ST whitelist
* @param _whitelistAddress Address attempting to join ST whitelist
* @param _KYC Address to verify the investor
* @return bool success
*/
function addToWhitelist(address _whitelistAddress) public returns (bool success) {
require(KYC == msg.sender || owner == msg.sender);
var (jurisdiction, accredited, role, verified, expires) = PolyCustomers.getCustomer(KYC, _whitelistAddress);
function addToWhitelist(address _whitelistedAddress, address _KYC) public returns (bool success) {
require(owner == msg.sender);
require(_whitelistedAddress != address(0));
require(Template.validKYC(_KYC));
var (jurisdiction, accredited, role, verified, expires) = PolyCustomers.getCustomer(_KYC, _whitelistedAddress);
require(verified && expires > now);
require(Template.checkTemplateRequirements(jurisdiction, accredited, role));
shareholders[_whitelistAddress] = Shareholder(msg.sender, true, role);
LogNewWhitelistedAddress(msg.sender, _whitelistAddress, role);
shareholders[_whitelistedAddress] = Shareholder(_KYC, true, role);
LogNewWhitelistedAddress(_KYC, _whitelistedAddress, role);
return true;
}

Expand Down Expand Up @@ -319,8 +321,9 @@ contract SecurityToken is IERC20 {
}

// Get token details
function getTokenDetails() view public returns (address, address, bytes32, address, address) {
return (Template, delegate, merkleRoot, STO, KYC);
function getTokenDetails() view public returns (address, address, bytes32, address, address[10]) {
var (,,,,allowedKYC) = Template.getUsageDetails();
return (Template, delegate, merkleRoot, STO, allowedKYC);
}

/////////////////////////////////////////////// Customized ERC20 Functions ////////////////////////////////////////////////////////////
Expand Down
38 changes: 32 additions & 6 deletions contracts/Template.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ contract Template is ITemplate {
bytes32 public issuerJurisdiction; // Variable contains the jurisdiction of the issuer of the template
mapping(bytes32 => bool) public allowedJurisdictions; // Mapping that contains the allowed staus of Jurisdictions
mapping(uint8 => bool) public allowedRoles; // Mapping that contains the allowed status of Roles
mapping(address => bool) public allowedKYC; // Mapping that contains the status of the kyc providers for this template
address[10] public allowedKYCProviders; // An array of addresses to store the allowed KYC providers of the template
bool public accredited; // Variable that define the required level of accrediation for the investor
address public KYC; // Address of the KYC provider
bytes32 details; // Details of the offering requirements
Expand All @@ -39,15 +41,15 @@ contract Template is ITemplate {
string _offeringType,
bytes32 _issuerJurisdiction,
bool _accredited,
address _KYC,
address[10] _whiteListedKYC,
bytes32 _details,
uint256 _expires,
uint256 _fee,
uint8 _quorum,
uint256 _vestingPeriod
) public
{
require(_KYC != address(0) && _owner != address(0));
require(_whiteListedKYC[0] != address(0) && _owner != address(0));
require(_fee > 0);
require(_details.length > 0 && _expires > now && _issuerJurisdiction.length > 0);
require(_quorum > 0 && _quorum <= 100);
Expand All @@ -56,13 +58,28 @@ contract Template is ITemplate {
offeringType = _offeringType;
issuerJurisdiction = _issuerJurisdiction;
accredited = _accredited;
KYC = _KYC;
details = _details;
finalized = false;
expires = _expires;
fee = _fee;
quorum = _quorum;
vestingPeriod = _vestingPeriod;
require(addAllowedKYC(_whiteListedKYC));

}

/**
* @dev Internal function used to add whitelisted KYC providers in the template.
* @param _whiteListedKYC Array of permitted providers.
* @return bool
*/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are missing a function to allow the issuer to disable/reenable a KYC provider if they want to stop using one of them. If a KYC provider is disabled, then they can't be used to verify new investors.
We need to figure out what we would do with addresses already verified by a KYC provider if it gets disabled.

Copy link
Contributor Author

@satyamakgec satyamakgec Jan 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the particular template is used by one securitytoken only then we can add the functionality of adding more KYC providers and disable them in the Template contract. otherwise, we can maintain their allowedKYC mapping in the security token itself. But I think it doesn't have the sense to use the whitelistedKYC array in the first place(Template Constructor).

I am not sure whether the template is used by more than one securityToken or used by one only.
if we can confirm the above line then I can re-design accordingly

function addAllowedKYC(address[10] _whiteListedKYC) internal returns(bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would a new KYC provider be added later on?

for (uint16 i; i < _whiteListedKYC.length; i++) {
allowedKYC[_whiteListedKYC[i]] = true;
allowedKYCProviders[i] = _whiteListedKYC[i];
}
return true;
}

/**
Expand Down Expand Up @@ -138,6 +155,15 @@ contract Template is ITemplate {
return true;
}

/**
* @dev check the authentication of the KYC addresses
* @param _KYC address need to check
*/
function validKYC(address _KYC) public returns (bool) {
return allowedKYC[_KYC];
}


/**
* @dev getTemplateDetails is a constant function that gets template details
* @return bytes32 details, bool finalized
Expand All @@ -148,10 +174,10 @@ contract Template is ITemplate {
}

/**
* @dev `getUsageFees` is a function to get all the details on template usage fees
* @dev `getUsageDetails` is a function to get all the details on template usage fees
* @return uint256 fee, uint8 quorum, uint256 vestingPeriod, address owner, address KYC
*/
function getUsageDetails() view public returns (uint256, uint8, uint256, address, address) {
return (fee, quorum, vestingPeriod, owner, KYC);
function getUsageDetails() view public returns (uint256, uint8, uint256, address, address[10]) {
return (fee, quorum, vestingPeriod, owner, allowedKYCProviders);
}
}
4 changes: 2 additions & 2 deletions contracts/interfaces/ICompliance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface ICompliance {
* @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 _whiteListedKYC List of 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)
Expand All @@ -25,7 +25,7 @@ interface ICompliance {
string _offeringType,
bytes32 _issuerJurisdiction,
bool _accredited,
address _KYC,
address[10] _whiteListedKYC,
bytes32 _details,
uint256 _expires,
uint256 _fee,
Expand Down
10 changes: 7 additions & 3 deletions contracts/interfaces/ISecurityToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,14 @@

/**
* @dev Add a verified address to the Security Token whitelist
* @param _whitelistAddress Address attempting to join ST whitelist
* The Issuer can add an address to the whitelist by themselves by
* creating their own KYC provider and using it to verify the accounts
* they want to add to the whitelist.
* @param _whitelistAddress Address attempting to join ST whitelist
* @param _KYC Address to verify the investor
* @return bool success
*/
function addToWhitelist(uint8 KYCProviderIndex, address _whitelistAddress) public returns (bool success);
function addToWhitelist(address _whitelistedAddress, address _KYC) public returns (bool success);

/**
* @dev Allow POLY allocations to be withdrawn by owner, delegate, and the STO auditor at appropriate times
Expand All @@ -91,7 +95,7 @@
function issueSecurityTokens(address _contributor, uint256 _amountOfSecurityTokens, uint256 _polyContributed) public returns (bool success);

/// Get token details
function getTokenDetails() view public returns (address, address, bytes32, address, address);
function getTokenDetails() view public returns (address, address, bytes32, address, address[10]);

/**
* @dev Trasfer tokens from one address to another
Expand Down
8 changes: 7 additions & 1 deletion contracts/interfaces/ITemplate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ interface ITemplate {
uint8 _role
) public constant returns (bool allowed);

/**
* @dev check the authentication of the KYC addresses
* @param _KYC address need to check
*/
function validKYC(address _KYC) public returns (bool);

/**
* @dev getTemplateDetails is a constant function that gets template details
* @return bytes32 details, bool finalized
Expand All @@ -51,5 +57,5 @@ interface ITemplate {
* @dev `getUsageFees` is a function to get all the details on template usage fees
* @return uint256 fee, uint8 quorum, uint256 vestingPeriod, address owner, address KYC
*/
function getUsageDetails() view public returns (uint256, uint8, uint256, address, address);
function getUsageDetails() view public returns (uint256, uint8, uint256, address, address[10]);
}
7 changes: 5 additions & 2 deletions test/SecurityToken.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ contract('SecurityToken', accounts => {
const kyc = 0x2fe38f0b394b297bc0d86ed6b66286572f5235f9;
const details = 'going to launch on xx-xx-xx';
const fee = 1000;
let whiteListedKYC;

// STO
let mockStoContract = "0x81399dd18c7985a016eb2bb0a1f6aabf0745d667";
Expand Down Expand Up @@ -203,11 +204,13 @@ contract('SecurityToken', accounts => {
STAddress = await STRegistrar.getSecurityTokenAddress.call(ticker);
securityToken = await SecurityToken.at(STAddress);

whiteListedKYC = [provider0, provider1];

let templateCreated = await compliance.createTemplate(
offeringType,
issuerJurisdiction,
accredited,
provider0,
whiteListedKYC,
details,
expires,
1000,
Expand Down Expand Up @@ -437,7 +440,7 @@ describe("Compliance contracts functions", async()=> {
"Test",
issuerJurisdiction,
accredited,
provider0,
whiteListedKYC,
"This is for Test",
expires,
1000,
Expand Down
3 changes: 1 addition & 2 deletions test/Template.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract("Template",(accounts)=>{
let owner;

before(async()=>{
KYCAddress = accounts[0]; // Asigining the KYC address
KYCAddress = [accounts[0], accounts[2], accounts[3]]; // Asigining the KYC address
owner = accounts[1];
});

Expand All @@ -43,7 +43,6 @@ contract("Template",(accounts)=>{
assert.strictEqual(tempData[1].toNumber(), quorum);
assert.strictEqual(tempData[2].toNumber(), vestingPeriod);
assert.equal(tempData[3], owner);
assert.equal(tempData[4], KYCAddress);
});
});

Expand Down