EX-4.3 6 ff12019ex4-3_inxlimited.htm SMART CONTRACT

Exhibit 4.3

 

InxToken.sol  

 

pragma solidity ^0.4.24;

 

import “./openzeppelin-solidity/contracts/math/SafeMath.sol”;

 

/** 

* @title INX Ownable

* @dev Extanded version of ownable, but with multiple owners. The contract allow multiple owners

* to be set and checked.

*/

contract Ownable {

 

mapping ( address => uint) public owners;

 

event NewOwnerAdded(address _address);

 

/**

* @dev Throws if called by a none valid account.

*/

modifier onlyValidAddress(address _address) {

require(_address != address(0), “Address should be valid”);

_;

}

 

/**

* @dev Throws if called by any account other than the owner.

*/

modifier onlyOwner() {

require(isOwner(), “This operation requires an owner privilages”);

_;

}

 

/**

 

* @return true if ‘msg.sender’ is the owner of the contract.

*/

function isOwner() public view returns(bool) {

return owners[msg.sender] != 0;

}

 

/** 

* @dev Allows the current owner to add new oweners.

* @param newOwner The address to add as an owner.

*/

function addOwner(address newOwner) public onlyValidAddress(newOwner) onlyOwner() returns (bool)

{

owners[newOwner] = 1;

emit NewOwnerAdded(newOwner);

return true;

}

 

/** 

* @dev Allows the current owner to remove owner from the owners list control of the contract to a newOwner.

* @param ownerToRemoved The address of the owner that should be removed.

*/

function removeOwner(address ownerToRemoved) public

onlyValidAddress(ownerToRemoved) onlyOwner() returns (bool)

{

delete owners[ownerToRemoved];

return true;

}

}

 

/**

* @title INX Whitelisters

 

1

 

 

InxToken.sol  

 

* @dev A similar version of Ownable list, but that manages white lister - address that can only modify white listing.

*/

contract Whitelisters is Ownable{

 

mapping ( address => uint) public whitelisters;

 

event NewWhiteListerAdded(address _address);

event WhiteListerRemoved(address _address); 

 

/** 

* @dev Throws if called by a none valid account.

*/

modifier onlyValidAddress(address _address) {

require(_address != address(0), “Address should be valid”);

_;

}

 

/** 

* @dev Throws if called by any account other than a whitelister.

*/

modifier onlyWhitelister() {

require(isWhitelister(), “This operation requires whitelister

privilages”);

_;

}

 

/** 

* @return true if ‘msg.sender’ is a whitelister of the contract.

*/

function isWhitelister() public view returns(bool) {

return whitelisters[msg.sender] != 0;

}

 

/** 

* @dev Allows the current owner to add new whitelister.

* @param newWhitelister The address to add as a whitelister.

*/

function addWhitelister(address newWhitelister) public

onlyValidAddress(newWhitelister) onlyOwner() returns (bool) {

whitelisters[newWhitelister] = 1;

emit NewWhiteListerAdded(newWhitelister);

return true;

}

 

/** 

* @dev Allows the current owner to remove whitelister from the whitelister list .

* @param whitelisterToRemoved The address of the owner that should be removed.

*/

function removeWhitelister(address whitelisterToRemoved) public

onlyValidAddress(whitelisterToRemoved) onlyOwner() returns (bool) {

delete whitelisters[whitelisterToRemoved];

emit WhiteListerRemoved(whitelisterToRemoved);

return true;

}

}

 

contract Whitelisting is Ownable, Whitelisters {

 

event WhitelistUpdate(address _address,bool status,string data);

  

2

 

 

InxToken.sol  

 

struct whiteListItem {

 bool status;

string data;

}

 

// check for valid address 

modifier onlyValidAddress(address _address) {

require(_address != address(0), “Address should be valid”);

_;

}

 

// white list status 

mapping (address => whiteListItem) public whitelist;

 

/** 

* @dev Set a white list address

* @param to the address to be set

* @param status the whitelisting status (true for yes, false for no)

* @param data a string with data about the whitelisted address

*/

function setWhitelist(address to, bool status, string memory data) public

onlyValidAddress(to) onlyWhitelister returns(bool){

whitelist[to] = whiteListItem(status, data);

return true;

}

 

/** 

* @dev Check the status of the whitelist

* @param _address the address to be check

*/

function checkWhitelistStatus(address _address) public view returns(bool){

return whitelist[_address].status;

}

 

/** 

* @dev Get the data of and address in the whitelist

* @param _address the address to retrieve the data from

*/

function getWhitelistData(address _address) public view returns(string memory)

{

return whitelist[_address].data;

}

}

 

contract Timelock is Ownable {

 

using SafeMath for uint256;

 

struct lockupItem {

 

uint256 amount;

uint256 releaseTime;

}

 

mapping (address => lockupItem) lockups;

 

event AccountLock(address _address, uint256 amount, uint256 releaseTime);

event AccountRelease(address _address, uint256 amount);

 

/** 

* @dev lock address and amount and lock it, set the release time

* @param _address the address to lock

* @param amount the amount to lock

* @param releaseTime of the locked amount (in seconds since the epoch)

 

3

 

 

InxToken.sol  

 

*/ 

function lock( address _address, uint256 amount, uint256 releaseTime)

public onlyOwner returns(uint256) {

require(releaseTime > block.timestamp);

require(_address != address(0));

 

lockupItem memory _lockupItem = lockupItem(amount, releaseTime); 

lockups[_address] = _lockupItem;

emit AccountLock(_address, amount, releaseTime);

return block.timestamp;

}

 

/** 

* @dev release locked amount

* @param _address the address to retrieve the data from

* @param amountToRelease the amount to check

*/

function release( address _address, uint256 amountToRelease) public

onlyOwner returns(bool) {

require(_address != address(0));

 

uint256 _lockedAmount = lockups[_address].amount;

 

// nothing to release 

if(_lockedAmount == 0){

emit AccountRelease(_address, 0);

return;

}

 

// extract release time for re-locking 

uint256 _releaseTime = lockups[_address].releaseTime;

 

// delete the lock entry 

delete lockups[_address];

 

if(_lockedAmount >= amountToRelease){ 

uint256 newLockedAmount = _lockedAmount.sub(amountToRelease);

 

// re-lock the new locked balance 

lock(_address, newLockedAmount, _releaseTime);

emit AccountRelease(_address, amountToRelease);

} else {

emit AccountRelease(_address, 0);

}

 

//

 

}

 

/** 

* @dev check if the requested amount for transaction is free for transter

* @param _address the address to retrieve the data from

* @param amount the amount to check

*/

function checkNoneLockedAmount(address _address, uint256 amount, uint256 balance) public view returns(uint256)

 

{

 

// check if the address is listed in the lockups mapping 

if(lockups[_address].amount == 0) return amount;

 

// check if the lockup time has not passed (ie: 1555179440 

1893502800)

if(block.timestamp < lockups[_address].releaseTime){

 

4

 

 

InxToken.sol  

 

// check if the address balance is bigger than the locked amount 

if(balance > lockups[_address].amount) {

 

uint256 _noneLockedAvailableAmount = 0;

 

_noneLockedAvailableAmount = balance - 

lockups[_address].amount;

 

if( _noneLockedAvailableAmount >= amount) { 

return amount;

}

}

 

// the address balance is smaller than the locked amount, return 

0;

return 0;

}

 

return amount;

 

}

 

/** 

* @dev get address lockup info

* @param _address the address to retrieve the data from

* @return array of 2 uint256, release time (in seconds since the epoch) and amount (in INX)

*/

function checkLockup(address _address) public view returns(uint256,

uint256) {

 

// copy lockup data into memory 

lockupItem memory _lockupItem = lockups[_address];

 

return (_lockupItem.releaseTime, _lockupItem.amount);

 

}

}

 

import “./InxRegistry.sol”;

 

contract InxToken is Ownable, Whitelisters, Whitelisting, Timelock {

 

using SafeMath for uint256;

 

string public symbol; 

string public name;

uint8 public decimals;

uint256 private _totalSupply;

 

mapping (address => uint256) private _balances;

 

/** 

* @dev Total number of tokens in existence

*/

function totalSupply() public view returns (uint256) {

return _totalSupply;

}

 

/** 

* @dev Token decimals

*/

function tokenDecimals() public view returns (uint8) {

return decimals;

}

 

5

 

 

InxToken.sol  

 

/** 

* @dev Gets the balance of the specified address.

* @param owner The address to query the balance of.

* @return An uint256 representing the amount owned by the passed address.

*/

function balanceOf(address owner) public view returns (uint256) {

return _balances[owner];

}

 

// ERC20 private _allowed 

mapping (address => mapping (address => uint256)) private _allowed;

 

// service address 

address public serviceAddress;

 

InxRegistry private inxRegistery;

 

event InxServiceUpdate(address prevInxService, address InxService);

event LockedAmount(address _address, uint256 executed, uint256 requested, bool partialyExcuted);

event Approval(address indexed owner, address indexed spender, uint256 value);

event Transfer(address indexed from, address indexed to, uint256 value);

 

/** 

* @dev constructor

* @param registryService the address of the registry service (validation

contruct)

*/

constructor(address registryService) public {

symbol = “INX”;

name = “INX Token”;

decimals = 18;

_totalSupply = 200000000 * 10 ** uint(decimals);

_balances[msg.sender] = _totalSupply; 

 

owners[msg.sender] = 1; 

whitelisters[msg.sender] = 1;

 

serviceAddress = registryService;

 

// set the registery service instace 

inxRegistery = InxRegistry(serviceAddress);

}

 

/** 

* @dev Update the referece the address of the validator

*/

function updateInxService(address _serviceAddress) onlyOwner public {

address prevInxService = serviceAddress;

serviceAddress = _serviceAddress;

 

// set the registery service instace 

inxRegistery = InxRegistry(serviceAddress);

emit InxServiceUpdate(prevInxService, serviceAddress);

}

 

/**

 

* @dev Function to check the amount of tokens that an owner allowed to a spender.

* @param owner address The address which owns the funds.

* @param spender address The address which will spend the funds.

* @return A uint256 specifying the amount of tokens still available for the spender.

 

6

 

 

InxToken.sol  

 

*/ 

function allowance(

address owner,

address spender

)

public

view

returns (uint256)

{

return _allowed[owner][spender];

}

 

/** 

* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.

* @param spender The address which will spend the funds.

* @param value The amount of tokens to be spent.

*/

function approve(address spender, uint256 value) public returns (bool) {

require(spender != address(0));

 

uint8 reason = 99;

 

// get the whitelist status of the INX spender 

bool _spenderWhitelistStatus = whitelist[spender].status;

 

// get the whitelist status of the INX approver 

bool _approverWhitelistStatus = whitelist[msg.sender].status;

 

// get the ownership status 

bool _isOwner = owners[msg.sender] == 1;

 

// approve validation (proxy contract) 

reason = inxRegistery.validate(msg.sender, spender, 0,

_spenderWhitelistStatus, _approverWhitelistStatus, _isOwner,

“approve”);

 

if(reason == 0){ 

_allowed[msg.sender][spender] = value;

emit Approval(msg.sender, spender, value);

return true;

} else {

revert(“approval is not valid”);

return false;

}

}

 

/** 

* @dev Increase to the passed address the amount off tokens that are

allowed to be spended on behalf of msg.sender.

* @param spender The address which will spend the funds.

* @param addedValue The amount of tokens to add that can be spent.

*/

function increaseApproval(address spender, uint256 addedValue) public

returns(bool){

require(spender != address(0));

 

uint8 reason = 99;

 

// get the whitelist status of the INX spender 

bool _spenderWhitelistStatus = whitelist[spender].status;

 

// get the whitelist status of the INX approver 

bool _approverWhitelistStatus = whitelist[msg.sender].status;

 

7

 

 

InxToken.sol  

 

// get the ownership status 

bool _isOwner = owners[msg.sender] == 1;

 

// approve validation (proxy contract) 

reason = inxRegistery.validate(msg.sender, spender, 0,

_spenderWhitelistStatus, _approverWhitelistStatus, _isOwner,

“increaseApproval”);

 

if(reason == 0){ 

uint256 oldValue = _allowed[msg.sender][spender];

_allowed[msg.sender][spender] = oldValue.add(addedValue);

return true;

} else {

revert(“increase approval is not valid”);

return false;

}

}

 

/** 

* @dev Decrease to the passed address the amount off tokens that are allowed to be spended on behalf of msg.sender.

* @param spender The address which will spend the funds.

* @param substractedValue The amount of tokens to add that can be spent.

*/

function decreaseApproval(address spender, uint256 substractedValue)

public returns(bool){

require(spender != address(0));

 

uint8 reason = 99;

 

// get the whitelist status of the INX spender 

bool _spenderWhitelistStatus = whitelist[spender].status;

 

// get the whitelist status of the INX approver 

bool _approverWhitelistStatus = whitelist[msg.sender].status;

 

// get the ownership status 

bool _isOwner = owners[msg.sender] == 1;

 

// approve validation (proxy contract) 

reason = inxRegistery.validate(msg.sender, spender, 0,

_spenderWhitelistStatus, _approverWhitelistStatus, _isOwner,

“decreaseApproval”);

 

if(reason == 0){ 

uint256 oldValue = _allowed[msg.sender][spender];

 

if(substractedValue > oldValue){ 

_allowed[msg.sender][spender] = 0;

} else {

_allowed[msg.sender][spender] =

oldValue.sub(substractedValue);

}

return true;

 

} else { 

revert(“decrease approval is not valid”);

return false;

}

  

}

 

8

 

  

InxToken.sol  

  

/** 

* @dev Transfer tokens from one address to another

* @param from address The address which you want to send tokens from

* @param to address The address which you want to transfer to

* @param value uint256 the amount of tokens to be transferred

*/

function transferFrom(

address from,

address to,

uint256 value

)

public

returns (bool)

{

require(value <= _allowed[from][msg.sender], “not enogth allowance”);

 

uint8 reason = 99;

 

// get the whitelist status of the INX spender 

bool _spenderWhitelistStatus = whitelist[msg.sender].status;

 

// get the whitelist status of the INX approver 

bool _approverWhitelistStatus = whitelist[from].status;

 

// get the ownership status 

bool _isOwner = owners[msg.sender] == 1;

 

// approve validation (proxy contract), inorder to be consistant, we 

use the spender (msg.sender)

reason = inxRegistery.validate(from, msg.sender, 0,

_spenderWhitelistStatus, _approverWhitelistStatus, _isOwner,

“transferFrom”);

 

if(reason == 0){ 

// substract

_allowed[from][msg.sender] = _allowed[from]

[msg.sender].sub(value);

 

_transfer(from, to, value); 

return true;

 

} else {

 

revert(“transfer from is not valid”);

return false;

}

}

 

/** 

* @dev transfer

* @param to the address to transfer the funds to

* @param value the number of tokens to transfer

*/

function transfer(address to, uint256 value) public returns(bool) {

return _transfer(msg.sender, to, value);

}

 

/** 

* @dev _transfer

* @param to the address to transfer the funds to

* @param value the number of tokens to transfer

*/

function _transfer(address from, address to, uint256 value) internal

 

9

 

 

InxToken.sol  

 

returns(bool) {

require(value <= _balances[from]);

require(to != address(0));

 

uint8 reason = 99;

 

// get the whitelist status of the INX receiver 

bool _toWhitelistStatus = whitelist[to].status;

 

// get the whitelist status of the INX sender 

bool _fromWhitelistStatus = whitelist[from].status;

 

// get the ownership status 

bool _isOwner = owners[msg.sender] == 1;

 

// check lockups 

uint256 _noneLockedAmount = checkNoneLockedAmount(from, value,

_balances[from]);

 

// check if all amount is locked 

if(_noneLockedAmount == 0) {

emit LockedAmount(from,_noneLockedAmount, value, false);

revert(“amount is locked”);

}

 

// validate transaction (proxy contract) 

reason = inxRegistery.validate(from, to, _noneLockedAmount,

_toWhitelistStatus, _fromWhitelistStatus, _isOwner, “transfer”);

 

if(reason == 0){ 

_balances[from] = _balances[from].sub(_noneLockedAmount);

_balances[to] = _balances[to].add(_noneLockedAmount);

emit Transfer(from, to, _noneLockedAmount);

} else {

revert(“transaction is not valid”);

}

 

return reason == 0;

 

}

}

 

 

10