Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getTokensByOwner to STR #280

Merged
merged 8 commits into from
Sep 26, 2018
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
[__1.5.0__](https://www.npmjs.com/package/polymath-core?activeTab=readme) __15-08-18__

## Added
* Added `getTokensByOwner` to STR
* Generalised MakerDAO oracle to allow different instances referencing different currencies
* Added DAI as a fundraising currency to USDTieredSTO
* `transferTickerOwnership()` function is introduced in `TickerRegistry` to transfer the ticker ownership after the registeration #191.
Expand Down
59 changes: 57 additions & 2 deletions contracts/SecurityTokenRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity ^0.4.24;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./interfaces/IOwner.sol";
import "./interfaces/IOwnable.sol";
import "./interfaces/ISTFactory.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/ISecurityTokenRegistry.sol";
Expand All @@ -25,6 +25,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage {
address public owner;
address public polymathRegistry;

address[] public activeUsers;
mapping(address => bool) public seenUsers;

mapping(address => bytes32[]) userToTickers;
mapping(string => address) tickerToSecurityToken;
mapping(string => uint) tickerIndex;
Expand Down Expand Up @@ -143,6 +146,11 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage {
require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("tickerRegFee"))), "Sufficent allowance is not provided");
string memory ticker = Util.upper(_ticker);
require(_tickerAvailable(ticker), "Ticker is already reserved");
// Check whether ticker was previously registered (and expired)
address previousOwner = getAddress(Encoder.getKey("registeredTickers_owner", _ticker));
if (previousOwner != address(0)) {
_deleteTickerOwnership(previousOwner, _ticker);
}
_addTicker(_owner, ticker, _tokenName, now, now.add(getUint(Encoder.getKey("expiryLimit"))), false, false);
}

Expand Down Expand Up @@ -232,6 +240,10 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage {
uint256 length = uint256(getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length);
pushArray(Encoder.getKey("userToTickers", _owner), Util.stringToBytes32(_ticker));
set(Encoder.getKey("tickerIndex", _ticker), length);
if (!getBool(Encoder.getKey("seenUsers", _owner))) {
pushArray(Encoder.getKey("activeUsers"), _owner);
set(Encoder.getKey("seenUsers", _owner), true);
}
}

/**
Expand Down Expand Up @@ -280,6 +292,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage {
*/
function _deleteTickerOwnership(address _owner, string _ticker) internal {
uint256 _index = uint256(getUint(Encoder.getKey("tickerIndex", _ticker)));
assert(_index < getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length);
// deleting the _index from the data strucutre userToTickers[_oldowner][_index];
deleteArrayBytes32(Encoder.getKey("userToTickers", _owner), _index);

Expand Down Expand Up @@ -318,6 +331,48 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage {
return tempList;
}

/**
* @notice Returns the list of tokens owned by the selected address
* @param _owner is the address which owns the list of tickers
* @dev Intention is that this is called off-chain so block gas limit is not relevant
*/
function getTokensByOwner(address _owner) external view returns(address[]) {
// Loop over all active users, then all associated tickers of those users
// This ensures we find tokens, even if their owner has been modified
address[] memory activeUsers = getArrayAddress(Encoder.getKey("activeUsers"));
bytes32[] memory tickers;
address token;
uint256 count = 0;
uint256 i = 0;
uint256 j = 0;
for (i = 0; i < activeUsers.length; i++) {
tickers = getArrayBytes32(Encoder.getKey("userToTickers", activeUsers[i]));
for (j = 0; j < tickers.length; j++) {
token = getAddress(Encoder.getKey("tickerToSecurityToken", Util.bytes32ToString(tickers[j])));
if (token != address(0)) {
if (IOwnable(token).owner() == _owner) {
count = count + 1;
}
}
}
}
uint256 index = 0;
address[] memory result = new address[](count);
for (i = 0; i < activeUsers.length; i++) {
tickers = getArrayBytes32(Encoder.getKey("userToTickers", activeUsers[i]));
for (j = 0; j < tickers.length; j++) {
token = getAddress(Encoder.getKey("tickerToSecurityToken", Util.bytes32ToString(tickers[j])));
if (token != address(0)) {
if (IOwnable(token).owner() == _owner) {
result[index] = token;
index = index + 1;
}
}
}
}
return result;
}

/**
* @notice Returns the owner and timestamp for a given ticker
* @param _ticker is the ticker symbol
Expand Down Expand Up @@ -442,7 +497,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage {
function getSecurityTokenData(address _securityToken) external view returns (string, address, string, uint256) {
return (
getString(Encoder.getKey("securityTokens_ticker", _securityToken)),
IOwner(_securityToken).owner(),
IOwnable(_securityToken).owner(),
getString(Encoder.getKey("securityTokens_tokenDetails", _securityToken)),
getUint(Encoder.getKey("securityTokens_deployedAt", _securityToken))
);
Expand Down
26 changes: 26 additions & 0 deletions contracts/interfaces/IOwnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
pragma solidity ^0.4.24;


/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
interface IOwnable {
/**
* @dev Returns owner
*/
function owner() external returns (address);

/**
* @dev Allows the current owner to relinquish control of the contract.
*/
function renounceOwnership() external;

/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) external;

}
5 changes: 0 additions & 5 deletions contracts/interfaces/IOwner.sol

This file was deleted.

9 changes: 8 additions & 1 deletion contracts/interfaces/ISecurityTokenRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ interface ISecurityTokenRegistry {
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) external;
function transferOwnership(address _newOwner) external;

/**
* @notice Get security token address by ticker name
Expand Down Expand Up @@ -85,6 +85,13 @@ interface ISecurityTokenRegistry {
*/
function getTickersByOwner(address _owner) external view returns(bytes32[]);

/**
* @notice Returns the list of tokens owned by the selected address
* @param _owner is the address which owns the list of tickers
* @dev Intention is that this is called off-chain so block gas limit is not relevant
*/
function getTokensByOwner(address _owner) external view returns(address[]);

/**
* @notice Returns the owner and timestamp for a given ticker
* @param _ticker ticker
Expand Down
5 changes: 4 additions & 1 deletion test/n_security_token_registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,9 @@ contract('SecurityTokenRegistry', accounts => {
assert.equal(tx.logs[1].args._ticker, symbol2, "SecurityToken doesn't get deployed");

I_SecurityToken002 = SecurityToken.at(tx.logs[1].args._securityTokenAddress);
let tokens = await I_STRProxied.getTokensByOwner.call(token_owner);
assert.equal(tokens[0], I_SecurityToken.address);
assert.equal(tokens[1], I_SecurityToken002.address);

const log = await promisifyLogWatch(I_SecurityToken002.LogModuleAdded({from: _blockNo}), 1);
// Verify that GeneralTransferManager module get added successfully or not
Expand Down Expand Up @@ -1084,7 +1087,7 @@ contract('SecurityTokenRegistry', accounts => {
let tickersList = await I_STRProxied.getTickersByOwner.call(token_owner);
assert.equal(tickersList.length, 4);
let tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp);
assert.equal(tickersListArray.length, 3);
assert.equal(tickersListArray.length, 2);
});

});
Expand Down
1 change: 0 additions & 1 deletion test/o_security_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ contract('SecurityToken', accounts => {
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
let _blockNo = latestBlock();
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 });

// Verify the successful generation of the security token
assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed");

Expand Down