Exhibit 4.3
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
* @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);
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)
*/
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){
// 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;
}
/**
* @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.
*/
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;
// 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;
}
}
/**
* @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
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