contract TokenNetworkRegistry is Utils, Controllable {
    address public secret_registry_address;
    uint256 public settlement_timeout_min;
    uint256 public settlement_timeout_max;
    uint256 public max_token_networks;

    // Only for the limited Red Eyes release
    uint256 public token_network_created = 0;

    // Token address => TokenNetwork address
    mapping(address => address) public token_to_token_networks;

    event TokenNetworkCreated(address indexed token_address, address indexed token_network_address);

    modifier canCreateTokenNetwork() {
        require(token_network_created < max_token_networks, "TNR: registry full");
        _;
    }

    /// @param _secret_registry_address The address of SecretRegistry that's used by all
    /// TokenNetworks created by this contract
    /// @param _settlement_timeout_min The shortest settlement period (in number of blocks)
    /// that can be chosen at the channel opening
    /// @param _settlement_timeout_max The longest settlement period (in number of blocks)
    /// that can be chosen at the channel opening
    /// @param _max_token_networks the number of tokens that can be registered
    /// MAX_UINT256 means no limits
    constructor(
        address _secret_registry_address,
        uint256 _settlement_timeout_min,
        uint256 _settlement_timeout_max,
        uint256 _max_token_networks
    ) {
        require(_settlement_timeout_min > 0, "TNR: invalid settle timeout min");
        require(_settlement_timeout_max > 0, "TNR: invalid settle timeout max");
        require(_settlement_timeout_max > _settlement_timeout_min, "TNR: invalid settle timeouts");
        require(_secret_registry_address != address(0x0), "TNR: invalid SR address");
        require(contractExists(_secret_registry_address), "TNR: invalid SR");
        require(_max_token_networks > 0, "TNR: invalid TN limit");
        secret_registry_address = _secret_registry_address;
        settlement_timeout_min = _settlement_timeout_min;
        settlement_timeout_max = _settlement_timeout_max;
        max_token_networks = _max_token_networks;

        controller = msg.sender;
    }

    /// @notice Deploy a new TokenNetwork contract for the Token deployed at
    /// `_token_address`
    /// @param _token_address Ethereum address of an already deployed token, to
    /// be used in the new TokenNetwork contract
    function createERC20TokenNetwork(
        address _token_address,
        uint256 _channel_participant_deposit_limit,
        uint256 _token_network_deposit_limit
    )
        public
        canCreateTokenNetwork
        returns (address token_network_address)
    {
        // After the limits have been removed, new token networks must be created without limits
        // See https://github.com/raiden-network/raiden-contracts/issues/1416
        if (max_token_networks == MAX_SAFE_UINT256) {
            require(_channel_participant_deposit_limit == MAX_SAFE_UINT256, "TNR: limits must be set to MAX_INT");
            require(_token_network_deposit_limit == MAX_SAFE_UINT256, "TNR: limits must be set to MAX_INT");
        }

        require(token_to_token_networks[_token_address] == address(0x0), "TNR: token already registered");

        // We limit the number of token networks to 1 for the Bug Bounty release
        token_network_created = token_network_created + 1;

        TokenNetwork token_network;

        // Token contract checks are in the corresponding TokenNetwork contract
        token_network = new TokenNetwork(
            _token_address,
            secret_registry_address,
            settlement_timeout_min,
            settlement_timeout_max,
            controller,
            _channel_participant_deposit_limit,
            _token_network_deposit_limit
        );

        token_network_address = address(token_network);

        token_to_token_networks[_token_address] = token_network_address;
        emit TokenNetworkCreated(_token_address, token_network_address);

        return token_network_address;
    }

    function createERC20TokenNetworkWithoutLimits(
        address _token_address
    )
        external
        returns (address token_network_address)
    {
        return createERC20TokenNetwork(_token_address, MAX_SAFE_UINT256, MAX_SAFE_UINT256);
    }

    /// @notice Removes the limit on the number of token networks.
    /// Can only be called by the controller.
    function removeLimits()
        external
        onlyController
    {
        max_token_networks = MAX_SAFE_UINT256;
    }
}
/// @title TokenNetworkRegistry
/// @notice The TokenNetwork Registry deploys new TokenNetwork contracts for the
/// Raiden Network protocol.
function createERC20TokenNetwork(
    address _token_address,
    uint256 _channel_participant_deposit_limit,
    uint256 _token_network_deposit_limit
)
    public
    canCreateTokenNetwork
    returns (address token_network_address)
{
    // After the limits have been removed, new token networks must be created without limits
    // See https://github.com/raiden-network/raiden-contracts/issues/1416
    if (max_token_networks == MAX_SAFE_UINT256) {
        require(_channel_participant_deposit_limit == MAX_SAFE_UINT256, "TNR: limits must be set to MAX_INT");
        require(_token_network_deposit_limit == MAX_SAFE_UINT256, "TNR: limits must be set to MAX_INT");
    }

    require(token_to_token_networks[_token_address] == address(0x0), "TNR: token already registered");

    // We limit the number of token networks to 1 for the Bug Bounty release
    token_network_created = token_network_created + 1;

    TokenNetwork token_network;

    // Token contract checks are in the corresponding TokenNetwork contract
    token_network = new TokenNetwork(
        _token_address,
        secret_registry_address,
        settlement_timeout_min,
        settlement_timeout_max,
        controller,
        _channel_participant_deposit_limit,
        _token_network_deposit_limit
    );

    token_network_address = address(token_network);

    token_to_token_networks[_token_address] = token_network_address;
    emit TokenNetworkCreated(_token_address, token_network_address);

    return token_network_address;
}

/// @notice Deploy a new TokenNetwork contract for the Token deployed at
/// `_token_address`
/// @param _token_address Ethereum address of an already deployed token, to
/// be used in the new TokenNetwork contract