Skip to content
Merged
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
30 changes: 26 additions & 4 deletions contracts/modules/STO/USDTieredSTO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ contract USDTieredSTO is ISTO, ReentrancyGuard {
// List of accredited investors
mapping (address => bool) public accredited;

// Limit in USD for non-accredited investors multiplied by 10**18
// Default limit in USD for non-accredited investors multiplied by 10**18
uint256 public nonAccreditedLimitUSD;

// Overrides for default limit in USD for non-accredited investors multiplied by 10**18
mapping (address => uint256) public nonAccreditedLimitUSDOverride;

// Minimum investable amount in USD
uint256 public minimumInvestmentUSD;

Expand All @@ -102,6 +105,8 @@ contract USDTieredSTO is ISTO, ReentrancyGuard {
////////////

event SetAllowBeneficialInvestments(bool _allowed);
event SetNonAccreditedLimit(address _investor, uint256 _limit);
event SetAccredited(address _investor, bool _accredited);
event TokenPurchase(address indexed _purchaser, address indexed _beneficiary, uint256 _tokens, uint256 _usdAmount, uint256 _tierPrice, uint8 _tier);
event FundsReceivedETH(address indexed _purchaser, address indexed _beneficiary, uint256 _usdAmount, uint256 _receivedValue, uint256 _spentValue, uint256 _rate);
event FundsReceivedPOLY(address indexed _purchaser, address indexed _beneficiary, uint256 _usdAmount, uint256 _receivedValue, uint256 _spentValue, uint256 _rate);
Expand Down Expand Up @@ -331,6 +336,22 @@ contract USDTieredSTO is ISTO, ReentrancyGuard {
require(_investors.length == _accredited.length);
for (uint256 i = 0; i < _investors.length; i++) {
accredited[_investors[i]] = _accredited[i];
emit SetAccredited(_investors[i], _accredited[i]);
}
}

/**
* @notice Modify the list of overrides for non-accredited limits in USD
* @param _investors Array of investor addresses to modify
* @param _nonAccreditedLimit Array of uints specifying non-accredited limits
*/
function changeNonAccreditedLimit(address[] _investors, uint256[] _nonAccreditedLimit) public onlyOwner {
//nonAccreditedLimitUSDOverride
require(_investors.length == _nonAccreditedLimit.length);
for (uint256 i = 0; i < _investors.length; i++) {
require(_nonAccreditedLimit[i] > 0, "Limit cannot be 0");
nonAccreditedLimitUSDOverride[_investors[i]] = _nonAccreditedLimit[i];
emit SetNonAccreditedLimit(_investors[i], _nonAccreditedLimit[i]);
}
}

Expand Down Expand Up @@ -409,9 +430,10 @@ contract USDTieredSTO is ISTO, ReentrancyGuard {

// Check for non-accredited cap
if (!accredited[_beneficiary]) {
require(investorInvestedUSD[_beneficiary] < nonAccreditedLimitUSD, "Non-accredited investor has already reached nonAccreditedLimitUSD");
if (investedUSD.add(investorInvestedUSD[_beneficiary]) > nonAccreditedLimitUSD)
investedUSD = nonAccreditedLimitUSD.sub(investorInvestedUSD[_beneficiary]);
uint256 investorLimitUSD = (nonAccreditedLimitUSDOverride[_beneficiary] == 0) ? nonAccreditedLimitUSD : nonAccreditedLimitUSDOverride[_beneficiary];
require(investorInvestedUSD[_beneficiary] < investorLimitUSD, "Non-accredited investor has already reached nonAccreditedLimitUSD");
if (investedUSD.add(investorInvestedUSD[_beneficiary]) > investorLimitUSD)
investedUSD = investorLimitUSD.sub(investorInvestedUSD[_beneficiary]);
}

uint256 spentUSD;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ contract ManualApprovalTransferManager is ITransferManager {
* @param _expiryTime is the time until which the transfer is allowed
*/
function addManualApproval(address _from, address _to, uint256 _allowance, uint256 _expiryTime) public withPerm(TRANSFER_APPROVAL) {
//Passing a _expiryTime == 0 into this function, is equivalent to removing the manual approval.
require(_from != address(0), "Invalid from address");
require(_to != address(0), "Invalid to address");
require(_expiryTime > now, "Invalid expiry time");
require(manualApprovals[_from][_to].allowance == 0, "Approval already exists");
manualApprovals[_from][_to] = ManualApproval(_allowance, _expiryTime);
emit LogAddManualApproval(_from, _to, _allowance, _expiryTime, msg.sender);
}
Expand All @@ -137,10 +137,10 @@ contract ManualApprovalTransferManager is ITransferManager {
* @param _expiryTime is the time until which the transfer is blocked
*/
function addManualBlocking(address _from, address _to, uint256 _expiryTime) public withPerm(TRANSFER_APPROVAL) {
//Passing a _expiryTime == 0 into this function, is equivalent to removing the manual blocking.
require(_from != address(0), "Invalid from address");
require(_to != address(0), "Invalid to address");
require(_expiryTime > now, "Invalid expiry time");
require(manualApprovals[_from][_to].expiryTime == 0, "Blocking already exists");
manualBlockings[_from][_to] = ManualBlocking(_expiryTime);
emit LogAddManualBlocking(_from, _to, _expiryTime, msg.sender);
}
Expand Down
12 changes: 11 additions & 1 deletion test/q_usd_tiered_sto.js
Original file line number Diff line number Diff line change
Expand Up @@ -1563,11 +1563,19 @@ contract('USDTieredSTO', accounts => {
assert.equal((await I_USDTieredSTO_Array[stoId].investorInvestedPOLY.call(ACCREDITED1)).toNumber(), init_investorInvestedPOLY.add(investment_POLY).toNumber(), "investorInvestedPOLY not changed as expected");
});

it("should successfully modify NONACCREDITED cap for NONACCREDITED1", async() => {
let stoId = 0;
let tierId = 0;
console.log("Current investment: " + (await I_USDTieredSTO_Array[stoId].investorInvestedUSD.call(NONACCREDITED1)).toNumber());
await I_USDTieredSTO_Array[stoId].changeNonAccreditedLimit([NONACCREDITED1], [_nonAccreditedLimitUSD[stoId].div(2)], {from: ISSUER});
console.log("Current limit: " + (await I_USDTieredSTO_Array[stoId].nonAccreditedLimitUSDOverride(NONACCREDITED1)).toNumber());
});

it("should successfully buy a partial amount and refund balance when reaching NONACCREDITED cap", async() => {
let stoId = 0;
let tierId = 0;

let investment_USD = _nonAccreditedLimitUSD[stoId];
let investment_USD = (await I_USDTieredSTO_Array[stoId].nonAccreditedLimitUSDOverride(NONACCREDITED1));//_nonAccreditedLimitUSD[stoId];
let investment_Token = await convert(stoId, tierId, false, "USD", "TOKEN", investment_USD);
let investment_ETH = await convert(stoId, tierId, false, "USD", "ETH", investment_USD);
let investment_POLY = await convert(stoId, tierId, false, "USD", "POLY", investment_USD);
Expand All @@ -1577,6 +1585,8 @@ contract('USDTieredSTO', accounts => {
let refund_ETH = await convert(stoId, tierId, false, "USD", "ETH", refund_USD);
let refund_POLY = await convert(stoId, tierId, false, "USD", "POLY", refund_USD);

console.log("Expected refund in tokens: " + refund_Token.toNumber());

let snap = await takeSnapshot();

let init_TokenSupply = await I_SecurityToken.totalSupply();
Expand Down