// File: /Users/Elena/Source/argent-contracts/contracts/infrastructure/base/Owned.sol



// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;

/**
 * @title Owned
 * @notice Basic contract to define an owner.
 * @author Julien Niset - <julien@argent.xyz>
 */
contract Owned {

    // The owner
    address public owner;

    event OwnerChanged(address indexed _newOwner);

    /**
     * @notice Throws if the sender is not the owner.
     */
    modifier onlyOwner {
        require(msg.sender == owner, "Must be owner");
        _;
    }

    constructor() public {
        owner = msg.sender;
    }

    /**
     * @notice Lets the owner transfer ownership of the contract to a new owner.
     * @param _newOwner The new owner.
     */
    function changeOwner(address _newOwner) external onlyOwner {
        require(_newOwner != address(0), "Address must not be null");
        owner = _newOwner;
        emit OwnerChanged(_newOwner);
    }
}
// File: /Users/Elena/Source/argent-contracts/contracts/infrastructure_0.5/MakerRegistry.sol



pragma solidity ^0.5.4;
import "../infrastructure/base/Owned.sol";
import "../../lib/maker/MakerInterfaces.sol";

/**
 * @title MakerRegistry
 * @notice Simple registry containing a mapping between token collaterals and their corresponding Maker Join adapters.
 * @author Olivier VDB - <olivier@argent.xyz>
 */
contract MakerRegistry is Owned {

    VatLike public vat;
    address[] public tokens;
    mapping (address => Collateral) public collaterals;
    mapping (bytes32 => address) public collateralTokensByIlks;

    struct Collateral {
        bool exists;
        uint128 index;
        JoinLike join;
        bytes32 ilk;
    }

    event CollateralAdded(address indexed _token);
    event CollateralRemoved(address indexed _token);

    constructor(VatLike _vat) public {
        vat = _vat;
    }

    /**
     * @notice Adds a new token as possible CDP collateral.
     * @param _joinAdapter The Join Adapter for the token.
     */
    function addCollateral(JoinLike _joinAdapter) external onlyOwner {
        require(vat.wards(address(_joinAdapter)) == 1, "MR: _joinAdapter not authorised in vat");
        address token = address(_joinAdapter.gem());
        require(!collaterals[token].exists, "MR: collateral already added");
        collaterals[token].exists = true;
        collaterals[token].index = uint128(tokens.push(token) - 1);
        collaterals[token].join = _joinAdapter;
        bytes32 ilk = _joinAdapter.ilk();
        collaterals[token].ilk = ilk;
        collateralTokensByIlks[ilk] = token;
        emit CollateralAdded(token);
    }

    /**
     * @notice Removes a token as possible CDP collateral.
     * @param _token The token to remove as collateral.
     */
    function removeCollateral(address _token) external onlyOwner {
        require(collaterals[_token].exists, "MR: collateral does not exist");
        delete collateralTokensByIlks[collaterals[_token].ilk];

        address last = tokens[tokens.length - 1];
        if (_token != last) {
            uint128 targetIndex = collaterals[_token].index;
            tokens[targetIndex] = last;
            collaterals[last].index = targetIndex;
        }
        tokens.length --;
        delete collaterals[_token];
        emit CollateralRemoved(_token);
    }

    /**
    * @notice Gets the list of supported collaterals.
    */
    function getCollateralTokens() external view returns (address[] memory _tokens) {
        _tokens = new address[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            _tokens[i] = tokens[i];
        }
        return _tokens;
    }

    /**
     * @notice Gets the ilk for a given token collateral.
     * @param _token The token collateral.
     */
    function getIlk(address _token) external view returns (bytes32 _ilk) {
        _ilk = collaterals[_token].ilk;
    }

    /**
    * @notice Gets the join adapter and collateral token for a given ilk.
    */
    function getCollateral(bytes32 _ilk) external view returns (JoinLike _join, GemLike _token) {
        _token = GemLike(collateralTokensByIlks[_ilk]);
        _join = collaterals[address(_token)].join;
    }
}
// File: /Users/Elena/Source/argent-contracts/lib/maker/MakerInterfaces.sol



pragma solidity >=0.5.4 <0.7.0;

interface GemLike {
    function balanceOf(address) external view returns (uint);
    function transferFrom(address, address, uint) external returns (bool);
    function approve(address, uint) external returns (bool success);
    function decimals() external view returns (uint);
    function transfer(address,uint) external returns (bool);
}

interface DSTokenLike {
    function mint(address,uint) external;
    function burn(address,uint) external;
}

interface VatLike {
    function can(address, address) external view returns (uint);
    function dai(address) external view returns (uint);
    function hope(address) external;
    function wards(address) external view returns (uint);
    function ilks(bytes32) external view returns (uint Art, uint rate, uint spot, uint line, uint dust);
    function urns(bytes32, address) external view returns (uint ink, uint art);
    function frob(bytes32, address, address, address, int, int) external;
    function slip(bytes32,address,int) external;
    function move(address,address,uint) external;
    function fold(bytes32,address,int) external;
    function suck(address,address,uint256) external;
    function flux(bytes32, address, address, uint) external;
    function fork(bytes32, address, address, int, int) external;
}

interface JoinLike {
    function ilk() external view returns (bytes32);
    function gem() external view returns (GemLike);
    function dai() external view returns (GemLike);
    function join(address, uint) external;
    function exit(address, uint) external;
    function vat() external returns (VatLike);
    function live() external returns (uint);
}

interface ManagerLike {
    function vat() external view returns (address);
    function urns(uint) external view returns (address);
    function open(bytes32, address) external returns (uint);
    function frob(uint, int, int) external;
    function give(uint, address) external;
    function move(uint, address, uint) external;
    function flux(uint, address, uint) external;
    function shift(uint, uint) external;
    function ilks(uint) external view returns (bytes32);
    function owns(uint) external view returns (address);
}

interface ScdMcdMigrationLike {
    function swapSaiToDai(uint) external;
    function swapDaiToSai(uint) external;
    function migrate(bytes32) external returns (uint);
    function saiJoin() external returns (JoinLike);
    function wethJoin() external returns (JoinLike);
    function daiJoin() external returns (JoinLike);
    function cdpManager() external returns (ManagerLike);
    function tub() external returns (SaiTubLike);
}

interface ValueLike {
    function peek() external returns (uint, bool);
}

interface SaiTubLike {
    function skr() external view returns (GemLike);
    function gem() external view returns (GemLike);
    function gov() external view returns (GemLike);
    function sai() external view returns (GemLike);
    function pep() external view returns (ValueLike);
    function bid(uint) external view returns (uint);
    function ink(bytes32) external view returns (uint);
    function tab(bytes32) external returns (uint);
    function rap(bytes32) external returns (uint);
    function shut(bytes32) external;
    function exit(uint) external;
}

interface VoxLike {
    function par() external returns (uint);
}

interface JugLike {
    function drip(bytes32) external;
}

interface PotLike {
    function chi() external view returns (uint);
    function pie(address) external view returns (uint);
    function drip() external;
}