ETH Price: $3,205.96 (+1.53%)

Contract

0x689359561355Ef829bB6D30a9c5b0E98c544CB11

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
Value
0x60c06040631092612023-02-21 13:33:41508 days ago1676986421IN
 Create: CreditLineController
0 ETH0.002198980.1

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To Value
719278022023-03-20 23:18:39481 days ago1679354319
0x68935956...8c544CB11
0 ETH
719278022023-03-20 23:18:39481 days ago1679354319
0x68935956...8c544CB11
0 ETH
719278022023-03-20 23:18:39481 days ago1679354319
0x68935956...8c544CB11
0 ETH
719278022023-03-20 23:18:39481 days ago1679354319
0x68935956...8c544CB11
0 ETH
718546412023-03-20 18:08:22481 days ago1679335702
0x68935956...8c544CB11
0 ETH
718546412023-03-20 18:08:22481 days ago1679335702
0x68935956...8c544CB11
0 ETH
718546412023-03-20 18:08:22481 days ago1679335702
0x68935956...8c544CB11
0 ETH
718546412023-03-20 18:08:22481 days ago1679335702
0x68935956...8c544CB11
0 ETH
718543562023-03-20 18:07:10481 days ago1679335630
0x68935956...8c544CB11
0 ETH
718543562023-03-20 18:07:10481 days ago1679335630
0x68935956...8c544CB11
0 ETH
718543562023-03-20 18:07:10481 days ago1679335630
0x68935956...8c544CB11
0 ETH
718543562023-03-20 18:07:10481 days ago1679335630
0x68935956...8c544CB11
0 ETH
718535592023-03-20 18:03:55481 days ago1679335435
0x68935956...8c544CB11
0 ETH
718535592023-03-20 18:03:55481 days ago1679335435
0x68935956...8c544CB11
0 ETH
718535592023-03-20 18:03:55481 days ago1679335435
0x68935956...8c544CB11
0 ETH
718535592023-03-20 18:03:55481 days ago1679335435
0x68935956...8c544CB11
0 ETH
717298892023-03-20 9:35:23482 days ago1679304923
0x68935956...8c544CB11
0 ETH
716095792023-03-20 1:09:18482 days ago1679274558
0x68935956...8c544CB11
0 ETH
716095792023-03-20 1:09:18482 days ago1679274558
0x68935956...8c544CB11
0 ETH
716095792023-03-20 1:09:18482 days ago1679274558
0x68935956...8c544CB11
0 ETH
716095792023-03-20 1:09:18482 days ago1679274558
0x68935956...8c544CB11
0 ETH
716058372023-03-20 0:53:27482 days ago1679273607
0x68935956...8c544CB11
0 ETH
716058372023-03-20 0:53:27482 days ago1679273607
0x68935956...8c544CB11
0 ETH
716058372023-03-20 0:53:27482 days ago1679273607
0x68935956...8c544CB11
0 ETH
716058372023-03-20 0:53:27482 days ago1679273607
0x68935956...8c544CB11
0 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CreditLineController

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 28 : CreditLineController.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.9;

import {ISynthereumFinder} from '../../core/interfaces/IFinder.sol';
import {ICreditLineController} from './interfaces/ICreditLineController.sol';
import {
  ISynthereumRegistry
} from '../../core/registries/interfaces/IRegistry.sol';
import {ICreditLine} from './interfaces/ICreditLine.sol';
import {
  ISynthereumFactoryVersioning
} from '../../core/interfaces/IFactoryVersioning.sol';
import {ICreditLineStorage} from './interfaces/ICreditLineStorage.sol';
import {
  SynthereumInterfaces,
  FactoryInterfaces
} from '../../core/Constants.sol';
import {
  FixedPoint
} from '../../../@uma/core/contracts/common/implementation/FixedPoint.sol';
import {
  ReentrancyGuard
} from '../../../@openzeppelin/contracts/security/ReentrancyGuard.sol';
import {
  AccessControlEnumerable
} from '../../../@openzeppelin/contracts/access/AccessControlEnumerable.sol';

/**
 * @title SelfMintingController
 * Set capMintAmount, and fee recipient, proportions and percentage of each self-minting derivative
 */

contract CreditLineController is
  ICreditLineController,
  ReentrancyGuard,
  AccessControlEnumerable
{
  using FixedPoint for FixedPoint.Unsigned;

  bytes32 public constant MAINTAINER_ROLE = keccak256('Maintainer');

  //Describe role structure
  struct Roles {
    address admin;
    address maintainer;
  }

  //----------------------------------------
  // Storage
  //----------------------------------------

  ISynthereumFinder public immutable synthereumFinder;

  uint8 public immutable selfMintingVersion;

  mapping(address => uint256) private capMint;

  mapping(address => uint256) private liquidationReward;

  mapping(address => uint256) private collateralRequirement;

  mapping(address => ICreditLineStorage.Fee) private fee;

  //----------------------------------------
  // Events
  //----------------------------------------

  event SetCapMintAmount(
    address indexed selfMintingDerivative,
    uint256 capMintAmount
  );

  event SetFeePercentage(
    address indexed selfMintingDerivative,
    uint256 feePercentage
  );

  event SetFeeRecipients(
    address indexed selfMintingDerivative,
    address[] feeRecipient,
    uint32[] feeProportions
  );

  event SetLiquidationReward(
    address indexed selfMintingDerivative,
    uint256 liquidationReward
  );

  event SetCollateralRequirement(
    address indexed selfMintingDerivative,
    uint256 collateralRequirement
  );

  //----------------------------------------
  // Modifiers
  //----------------------------------------
  modifier onlyMaintainerOrSelfMintingFactory() {
    if (hasRole(MAINTAINER_ROLE, msg.sender)) {
      _;
    } else {
      require(
        _isSelfMintingFactory(),
        'Sender must be the maintainer or a self-minting factory'
      );
      _;
    }
  }

  modifier onlySelfMintingFactory() {
    require(_isSelfMintingFactory(), 'Sender must be the self-minting factory');
    _;
  }

  //----------------------------------------
  // Constructor
  //----------------------------------------

  /**
   * @notice Constructs the SynthereumManager contract
   * @param _synthereumFinder Synthereum finder contract
   * @param roles Admin and maintainer roles
   * @param version Version of self-minting contracts on which this controller has setting grants
   */
  constructor(
    ISynthereumFinder _synthereumFinder,
    Roles memory roles,
    uint8 version
  ) {
    synthereumFinder = _synthereumFinder;
    selfMintingVersion = version;
    _setRoleAdmin(DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE);
    _setRoleAdmin(MAINTAINER_ROLE, DEFAULT_ADMIN_ROLE);
    _setupRole(DEFAULT_ADMIN_ROLE, roles.admin);
    _setupRole(MAINTAINER_ROLE, roles.maintainer);
  }

  //----------------------------------------
  // External functions
  //----------------------------------------
  function setCollateralRequirement(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata collateralRequirements
  ) external override onlySelfMintingFactory nonReentrant {
    require(
      selfMintingDerivatives.length > 0,
      'No self-minting derivatives passed'
    );
    require(
      selfMintingDerivatives.length == collateralRequirements.length,
      'Number of derivatives and overcollaterals must be the same'
    );
    bool isMaintainer = hasRole(MAINTAINER_ROLE, msg.sender);
    for (uint256 j; j < selfMintingDerivatives.length; j++) {
      ICreditLine creditLineDerivative = ICreditLine(selfMintingDerivatives[j]);
      uint8 version = creditLineDerivative.version();
      require(version == selfMintingVersion, 'Wrong self-minting version');
      if (isMaintainer) {
        checkSelfMintingDerivativeRegistration(creditLineDerivative, version);
      }
      _setCollateralRequirement(
        address(creditLineDerivative),
        collateralRequirements[j]
      );
    }
  }

  function setCapMintAmount(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata capMintAmounts
  ) external override onlyMaintainerOrSelfMintingFactory nonReentrant {
    require(
      selfMintingDerivatives.length > 0,
      'No self-minting derivatives passed'
    );
    require(
      selfMintingDerivatives.length == capMintAmounts.length,
      'Number of derivatives and mint cap amounts must be the same'
    );
    bool isMaintainer = hasRole(MAINTAINER_ROLE, msg.sender);
    for (uint256 j; j < selfMintingDerivatives.length; j++) {
      ICreditLine creditLineDerivative = ICreditLine(selfMintingDerivatives[j]);
      uint8 version = creditLineDerivative.version();
      require(version == selfMintingVersion, 'Wrong self-minting version');
      if (isMaintainer) {
        checkSelfMintingDerivativeRegistration(creditLineDerivative, version);
      }
      _setCapMintAmount(address(creditLineDerivative), capMintAmounts[j]);
    }
  }

  function setFeePercentage(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata feePercentages
  ) external override onlyMaintainerOrSelfMintingFactory nonReentrant {
    uint256 selfMintingDerCount = selfMintingDerivatives.length;
    require(selfMintingDerCount > 0, 'No self-minting derivatives passed');
    require(
      selfMintingDerCount == feePercentages.length,
      'Number of derivatives and fee percentages must be the same'
    );
    bool isMaintainer = hasRole(MAINTAINER_ROLE, msg.sender);
    for (uint256 j; j < selfMintingDerCount; j++) {
      ICreditLine creditLineDerivative = ICreditLine(selfMintingDerivatives[j]);
      uint8 version = creditLineDerivative.version();
      require(version == selfMintingVersion, 'Wrong self-minting version');
      if (isMaintainer) {
        checkSelfMintingDerivativeRegistration(creditLineDerivative, version);
      }
      _setFeePercentage(address(creditLineDerivative), feePercentages[j]);
    }
  }

  function setFeeRecipients(
    address[] calldata selfMintingDerivatives,
    address[][] calldata feeRecipients,
    uint32[][] calldata feeProportions
  ) external override onlyMaintainerOrSelfMintingFactory nonReentrant {
    uint256 selfMintingDerCount = selfMintingDerivatives.length;
    require(selfMintingDerCount > 0, 'No self-minting derivatives passed');
    require(
      selfMintingDerCount == feeRecipients.length,
      'Mismatch between derivatives to update and fee recipients'
    );
    require(
      selfMintingDerCount == feeProportions.length,
      'Mismatch between derivatives to update and fee proportions'
    );
    bool isMaintainer = hasRole(MAINTAINER_ROLE, msg.sender);
    // update each derivative fee parameters
    for (uint256 j; j < selfMintingDerCount; j++) {
      ICreditLine creditLineDerivative = ICreditLine(selfMintingDerivatives[j]);
      uint8 version = creditLineDerivative.version();
      require(version == selfMintingVersion, 'Wrong self-minting version');
      if (isMaintainer) {
        checkSelfMintingDerivativeRegistration(creditLineDerivative, version);
      }
      _setFeeRecipients(
        address(creditLineDerivative),
        feeRecipients[j],
        feeProportions[j]
      );
    }
  }

  function setLiquidationRewardPercentage(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata _liquidationRewards
  ) external override onlyMaintainerOrSelfMintingFactory nonReentrant {
    uint256 selfMintingDerCount = selfMintingDerivatives.length;
    require(selfMintingDerCount > 0, 'No self-minting derivatives passed');
    require(
      selfMintingDerCount == _liquidationRewards.length,
      'Mismatch between derivatives to update and liquidation rewards'
    );

    bool isMaintainer = hasRole(MAINTAINER_ROLE, msg.sender);
    for (uint256 j; j < selfMintingDerCount; j++) {
      ICreditLine creditLineDerivative = ICreditLine(selfMintingDerivatives[j]);
      uint8 version = creditLineDerivative.version();
      require(version == selfMintingVersion, 'Wrong self-minting version');
      if (isMaintainer) {
        checkSelfMintingDerivativeRegistration(creditLineDerivative, version);
      }
      _setLiquidationReward(selfMintingDerivatives[j], _liquidationRewards[j]);
    }
  }

  function getCollateralRequirement(address selfMintingDerivative)
    external
    view
    override
    returns (uint256)
  {
    return collateralRequirement[selfMintingDerivative];
  }

  function getLiquidationRewardPercentage(address selfMintingDerivative)
    external
    view
    override
    returns (uint256)
  {
    return liquidationReward[selfMintingDerivative];
  }

  function getFeeInfo(address selfMintingDerivative)
    external
    view
    override
    returns (ICreditLineStorage.Fee memory)
  {
    return fee[selfMintingDerivative];
  }

  function feePercentage(address selfMintingDerivative)
    external
    view
    override
    returns (uint256)
  {
    return fee[selfMintingDerivative].feePercentage;
  }

  function feeRecipientsInfo(address selfMintingDerivative)
    external
    view
    override
    returns (
      address[] memory,
      uint32[] memory,
      uint256
    )
  {
    ICreditLineStorage.Fee storage _feeData = fee[selfMintingDerivative];
    return (
      _feeData.feeRecipients,
      _feeData.feeProportions,
      _feeData.totalFeeProportions
    );
  }

  function getCapMintAmount(address selfMintingDerivative)
    external
    view
    override
    returns (uint256 capMintAmount)
  {
    return capMint[selfMintingDerivative];
  }

  //----------------------------------------
  // Internal functions
  //----------------------------------------

  function _setLiquidationReward(
    address selfMintingDerivative,
    uint256 liqReward
  ) internal {
    require(
      liquidationReward[selfMintingDerivative] != liqReward,
      'Liquidation reward is the same'
    );
    require(
      liqReward > 0 && liqReward < 10**18,
      'Liquidation reward must be between 0 and 100%'
    );
    liquidationReward[selfMintingDerivative] = liqReward;
    emit SetLiquidationReward(selfMintingDerivative, liqReward);
  }

  function _setCollateralRequirement(
    address selfMintingDerivative,
    uint256 percentage
  ) internal {
    require(
      collateralRequirement[selfMintingDerivative] != percentage,
      'Collateral requirement is the same'
    );
    require(
      percentage > 10**18,
      'Overcollateralisation must be bigger than 100%'
    );
    collateralRequirement[selfMintingDerivative] = percentage;
    emit SetCollateralRequirement(selfMintingDerivative, percentage);
  }

  function _setFeeRecipients(
    address selfMintingDerivative,
    address[] calldata feeRecipients,
    uint32[] calldata feeProportions
  ) internal {
    uint256 totalActualFeeProportions = 0;

    // Store the sum of all proportions
    for (uint256 i = 0; i < feeProportions.length; i++) {
      totalActualFeeProportions += feeProportions[i];

      fee[selfMintingDerivative].feeRecipients = feeRecipients;
      fee[selfMintingDerivative].feeProportions = feeProportions;
      fee[selfMintingDerivative]
        .totalFeeProportions = totalActualFeeProportions;

      emit SetFeeRecipients(
        selfMintingDerivative,
        feeRecipients,
        feeProportions
      );
    }
  }

  function _setFeePercentage(
    address selfMintingDerivative,
    uint256 _feePercentage
  ) internal {
    require(
      fee[selfMintingDerivative].feePercentage != _feePercentage,
      'Fee percentage is the same'
    );
    require(_feePercentage <= 10**18, 'Fee percentage must be less than 100%');
    fee[selfMintingDerivative].feePercentage = _feePercentage;
    emit SetFeePercentage(selfMintingDerivative, _feePercentage);
  }

  function _setCapMintAmount(
    address selfMintingDerivative,
    uint256 capMintAmount
  ) internal {
    require(
      capMint[selfMintingDerivative] != capMintAmount,
      'Cap mint amount is the same'
    );
    capMint[selfMintingDerivative] = capMintAmount;
    emit SetCapMintAmount(selfMintingDerivative, capMintAmount);
  }

  /**
   * @notice Check if a self-minting derivative is registered with the SelfMintingRegistry
   * @param selfMintingDerivative Self-minting derivative contract
   * @param version version of self-mintinting derivative
   */
  function checkSelfMintingDerivativeRegistration(
    ICreditLine selfMintingDerivative,
    uint8 version
  ) internal view {
    ISynthereumRegistry selfMintingRegistry =
      ISynthereumRegistry(
        synthereumFinder.getImplementationAddress(
          SynthereumInterfaces.SelfMintingRegistry
        )
      );
    require(
      selfMintingRegistry.isDeployed(
        selfMintingDerivative.syntheticTokenSymbol(),
        selfMintingDerivative.collateralToken(),
        version,
        address(selfMintingDerivative)
      ),
      'Self-minting derivative not registred'
    );
  }

  function _isSelfMintingFactory() internal view returns (bool) {
    ISynthereumFactoryVersioning factoryVersioning =
      ISynthereumFactoryVersioning(
        synthereumFinder.getImplementationAddress(
          SynthereumInterfaces.FactoryVersioning
        )
      );
    uint256 numberOfFactories =
      factoryVersioning.numberOfFactoryVersions(
        FactoryInterfaces.SelfMintingFactory
      );
    uint256 counter = 0;
    for (uint8 i = 0; counter < numberOfFactories; i++) {
      try
        factoryVersioning.getFactoryVersion(
          FactoryInterfaces.SelfMintingFactory,
          i
        )
      returns (address factory) {
        if (msg.sender == factory) {
          return true;
        } else {
          counter++;
        }
      } catch {}
    }
    if (numberOfFactories == counter) {
      return false;
    }
  }
}

File 2 of 28 : AccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    function _grantRole(bytes32 role, address account) private {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 3 of 28 : IAccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 4 of 28 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 5 of 28 : Strings.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 6 of 28 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 7 of 28 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 8 of 28 : AccessControlEnumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {grantRole} to track enumerable memberships
     */
    function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
        super.grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {revokeRole} to track enumerable memberships
     */
    function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
        super.revokeRole(role, account);
        _roleMembers[role].remove(account);
    }

    /**
     * @dev Overload {renounceRole} to track enumerable memberships
     */
    function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
        super.renounceRole(role, account);
        _roleMembers[role].remove(account);
    }

    /**
     * @dev Overload {_setupRole} to track enumerable memberships
     */
    function _setupRole(bytes32 role, address account) internal virtual override {
        super._setupRole(role, account);
        _roleMembers[role].add(account);
    }
}

File 9 of 28 : IAccessControlEnumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

File 10 of 28 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastvalue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastvalue;
                // Update the index for the moved value
                set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly {
            result := store
        }

        return result;
    }
}

File 11 of 28 : IFinder.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/**
 * @title Provides addresses of the contracts implementing certain interfaces.
 */
interface ISynthereumFinder {
  /**
   * @notice Updates the address of the contract that implements `interfaceName`.
   * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.
   * @param implementationAddress address of the deployed contract that implements the interface.
   */
  function changeImplementationAddress(
    bytes32 interfaceName,
    address implementationAddress
  ) external;

  /**
   * @notice Gets the address of the contract that implements the given `interfaceName`.
   * @param interfaceName queried interface.
   * @return implementationAddress Address of the deployed contract that implements the interface.
   */
  function getImplementationAddress(bytes32 interfaceName)
    external
    view
    returns (address);
}

File 12 of 28 : ICreditLineController.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {IERC20} from '../../../../@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {ICreditLineStorage} from './ICreditLineStorage.sol';
import {
  FixedPoint
} from '../../../../@uma/core/contracts/common/implementation/FixedPoint.sol';

/** @title Interface for interacting with the SelfMintingController
 */
interface ICreditLineController {
  /**
   * @notice Allow to set collateralRequirement percentage on a list of registered self-minting derivatives
   * @param selfMintingDerivatives Self-minting derivatives
   * @param collateralRequirements Over collateralization percentage for self-minting derivatives
   */
  function setCollateralRequirement(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata collateralRequirements
  ) external;

  /**
   * @notice Allow to set capMintAmount on a list of registered self-minting derivatives
   * @param selfMintingDerivatives Self-minting derivatives
   * @param capMintAmounts Mint cap amounts for self-minting derivatives
   */
  function setCapMintAmount(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata capMintAmounts
  ) external;

  /**
   * @notice Allow to set fee percentages on a list of registered self-minting derivatives
   * @param selfMintingDerivatives Self-minting derivatives
   * @param feePercentages fee percentages for self-minting derivatives
   */
  function setFeePercentage(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata feePercentages
  ) external;

  /**
   * @notice Update the addresses and weight of recipients for generated fees
   * @param selfMintingDerivatives Derivatives to update
   * @param feeRecipients A two-dimension array containing for each derivative the addresses of fee recipients
   * @param feeProportions An array of the proportions of fees generated each recipient will receive
   */
  function setFeeRecipients(
    address[] calldata selfMintingDerivatives,
    address[][] calldata feeRecipients,
    uint32[][] calldata feeProportions
  ) external;

  /**
   * @notice Update the liquidation reward percentage
   * @param selfMintingDerivatives Derivatives to update
   * @param _liquidationRewards Percentage of reward for correct liquidation by a liquidator
   */
  function setLiquidationRewardPercentage(
    address[] calldata selfMintingDerivatives,
    uint256[] calldata _liquidationRewards
  ) external;

  /**
   * @notice Gets the over collateralization percentage of a self-minting derivative
   * @param selfMintingDerivative Derivative to read value of
   * @return the collateralRequirement percentage
   */
  function getCollateralRequirement(address selfMintingDerivative)
    external
    view
    returns (uint256);

  /**
   * @notice Gets the set liquidtion reward percentage of a self-minting derivative
   * @param selfMintingDerivative Self-minting derivative
   * @return liquidation Reward percentage
   */
  function getLiquidationRewardPercentage(address selfMintingDerivative)
    external
    view
    returns (uint256);

  /**
   * @notice Gets the set CapMintAmount of a self-minting derivative
   * @param selfMintingDerivative Self-minting derivative
   * @return capMintAmount Limit amount for minting
   */
  function getCapMintAmount(address selfMintingDerivative)
    external
    view
    returns (uint256 capMintAmount);

  /**
   * @notice Gets the fee params of a self-minting derivative
   * @param selfMintingDerivative Self-minting derivative
   * @return fee fee info (percent + recipient + proportions)
   */
  function getFeeInfo(address selfMintingDerivative)
    external
    view
    returns (ICreditLineStorage.Fee memory fee);

  /**
   * @notice Gets the fee percentage of a self-minting derivative
   * @param selfMintingDerivative Self-minting derivative
   * @return feePercentage value
   */
  function feePercentage(address selfMintingDerivative)
    external
    view
    returns (uint256);

  /**
   * @notice Returns fee recipients info
   * @return Addresses, weigths and total of weigtht
   */
  function feeRecipientsInfo(address selfMintingDerivative)
    external
    view
    returns (
      address[] memory,
      uint32[] memory,
      uint256
    );
}

File 13 of 28 : IRegistry.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {IERC20} from '../../../../@openzeppelin/contracts/token/ERC20/IERC20.sol';

/**
 * @title Provides interface with functions of SynthereumRegistry
 */

interface ISynthereumRegistry {
  /**
   * @notice Allow the deployer to register an element
   * @param syntheticTokenSymbol Symbol of the syntheticToken of the element to register
   * @param collateralToken Collateral ERC20 token of the element to register
   * @param version Version of the element to register
   * @param element Address of the element to register
   */
  function register(
    string calldata syntheticTokenSymbol,
    IERC20 collateralToken,
    uint8 version,
    address element
  ) external;

  /**
   * @notice Allow the deployer to unregister an element
   * @param syntheticTokenSymbol Symbol of the syntheticToken of the element to unregister
   * @param collateralToken Collateral ERC20 token of the element to unregister
   * @param version Version of the element  to unregister
   * @param element Address of the element  to unregister
   */
  function unregister(
    string calldata syntheticTokenSymbol,
    IERC20 collateralToken,
    uint8 version,
    address element
  ) external;

  /**
   * @notice Returns if a particular element exists or not
   * @param syntheticTokenSymbol Synthetic token symbol of the element
   * @param collateralToken ERC20 contract of collateral currency
   * @param version Version of the element
   * @param element Contract of the element to check
   * @return isElementDeployed Returns true if a particular element exists, otherwise false
   */
  function isDeployed(
    string calldata syntheticTokenSymbol,
    IERC20 collateralToken,
    uint8 version,
    address element
  ) external view returns (bool isElementDeployed);

  /**
   * @notice Returns all the elements with partcular symbol, collateral and version
   * @param syntheticTokenSymbol Synthetic token symbol of the element
   * @param collateralToken ERC20 contract of collateral currency
   * @param version Version of the element
   * @return List of all elements
   */
  function getElements(
    string calldata syntheticTokenSymbol,
    IERC20 collateralToken,
    uint8 version
  ) external view returns (address[] memory);

  /**
   * @notice Returns all the synthetic token symbol used
   * @return List of all synthetic token symbol
   */
  function getSyntheticTokens() external view returns (string[] memory);

  /**
   * @notice Returns all the versions used
   * @return List of all versions
   */
  function getVersions() external view returns (uint8[] memory);

  /**
   * @notice Returns all the collaterals used
   * @return List of all collaterals
   */
  function getCollaterals() external view returns (address[] memory);
}

File 14 of 28 : ICreditLine.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ISynthereumFinder} from '../../../core/interfaces/IFinder.sol';
import {
  IStandardERC20,
  IERC20
} from '../../../base/interfaces/IStandardERC20.sol';
import {
  ISynthereumDeployment
} from '../../../common/interfaces/IDeployment.sol';
import {
  IEmergencyShutdown
} from '../../../common/interfaces/IEmergencyShutdown.sol';
import {ICreditLineStorage} from './ICreditLineStorage.sol';
import {ITypology} from '../../../common/interfaces/ITypology.sol';
import {
  FixedPoint
} from '../../../../@uma/core/contracts/common/implementation/FixedPoint.sol';

interface ICreditLine is ITypology, IEmergencyShutdown, ISynthereumDeployment {
  /**
   * @notice Initialize creditLine
   * @param _positionManagerData Params used for initialization (see PositionManagerParams struct)
   */
  function initialize(
    ICreditLineStorage.PositionManagerParams memory _positionManagerData
  ) external;

  /**
   * @notice Transfers `collateralAmount` into the caller's position.
   * @dev Increases the collateralization level of a position after creation. This contract must be approved to spend
   * at least `collateralAmount` of collateral token
   * @param collateralAmount total amount of collateral tokens to be sent to the sponsor's position.
   */
  function deposit(uint256 collateralAmount) external;

  /**
   * @notice Transfers `collateralAmount` into the specified sponsor's position.
   * @dev Increases the collateralization level of a position after creation. This contract must be approved to spend
   * at least `collateralAmount` of collateralCurrency.
   * @param sponsor the sponsor to credit the deposit to.
   * @param collateralAmount total amount of collateral tokens to be sent to the sponsor's position.
   */
  function depositTo(address sponsor, uint256 collateralAmount) external;

  /**
   * @notice Transfers `collateralAmount` from the sponsor's position to the sponsor.
   * @dev Reverts if the withdrawal puts this position's collateralization ratio below the collateral requirement
   * @param collateralAmount is the amount of collateral to withdraw.
   * @return amountWithdrawn The actual amount of collateral withdrawn.
   */
  function withdraw(uint256 collateralAmount)
    external
    returns (uint256 amountWithdrawn);

  /**
   * @notice Pulls `collateralAmount` into the sponsor's position and mints `numTokens` of `tokenCurrency`.
   * Mints new debt tokens by creating a new position or by augmenting an existing position.
   * @dev Can only be called by a token sponsor. This contract must be approved to spend at least `collateralAmount` of
   * `collateralCurrency`.
   * @param collateralAmount is the number of collateral tokens to collateralize the position with
   * @param numTokens is the number of debt tokens to mint to sponsor.
   */
  function create(uint256 collateralAmount, uint256 numTokens)
    external
    returns (uint256 feeAmount);

  /**
   * @notice Burns `numTokens` of `tokenCurrency` and sends back the proportional amount of collateral
   * @dev Can only be called by a token sponsor- This contract must be approved to spend at least `numTokens` of
   * `tokenCurrency`.
   * @param numTokens is the number of tokens to be burnt.
   * @return amountWithdrawn The actual amount of collateral withdrawn.
   */
  function redeem(uint256 numTokens) external returns (uint256 amountWithdrawn);

  /**
   * @notice Burns `numTokens` of `tokenCurrency` to decrease sponsors position size, without sending back collateral.
   * This is done by a sponsor to increase position CR.
   * @dev Can only be called by token sponsor. This contract must be approved to spend `numTokens` of `tokenCurrency`.
   * @param numTokens is the number of tokens to be burnt.
   */
  function repay(uint256 numTokens) external;

  /**
   * @notice Liquidate sponsor position for an amount of synthetic tokens undercollateralized
   * @notice Revert if position is not undercollateralized
   * @param sponsor Address of sponsor to be liquidated.
   * @param maxTokensToLiquidate Max number of synthetic tokens to be liquidated
   * @return tokensLiquidated Amount of debt tokens burned
   * @return collateralLiquidated Amount of received collateral equal to the value of tokens liquidated
   * @return collateralReward Amount of received collateral as reward for the liquidation
   */
  function liquidate(address sponsor, uint256 maxTokensToLiquidate)
    external
    returns (
      uint256 tokensLiquidated,
      uint256 collateralLiquidated,
      uint256 collateralReward
    );

  /**
   * @notice When in emergency shutdown state all token holders and sponsor can redeem their tokens and
   * remaining collateral at the prevailing price defined by the on-chain oracle
   * @dev This burns all tokens from the caller of `tokenCurrency` and sends back the resolved settlement value of
   * collateral. This contract must be approved to spend `tokenCurrency` at least up to the caller's full balance.
   * @dev This contract must have the Burner role for the `tokenCurrency`.
   * @return amountWithdrawn The actual amount of collateral withdrawn.
   */
  function settleEmergencyShutdown() external returns (uint256 amountWithdrawn);

  /**
   * @notice Withdraw fees gained by the sender
   * @return feeClaimed Amount of fee claimed
   */
  function claimFee() external returns (uint256 feeClaimed);

  /**
   * @notice trim any excess funds in the contract to the excessTokenBeneficiary address
   * @return amount the amount of tokens trimmed
   */
  function trimExcess(IERC20 token) external returns (uint256 amount);

  /**
   * @notice Delete a TokenSponsor position. This function can only be called by the contract itself.
   * @param sponsor address of the TokenSponsor.
   */
  function deleteSponsorPosition(address sponsor) external;

  /**
   * @notice Returns the minimum amount of tokens a sponsor must mint
   * @return amount the value
   */
  function minSponsorTokens() external view returns (uint256 amount);

  /**
   * @notice Returns the address of the trim excess tokens receiver
   * @return beneficiary the addess
   */
  function excessTokensBeneficiary()
    external
    view
    returns (address beneficiary);

  /**
   * @notice Returns the cap mint amount of the derivative contract
   * @return capMint cap mint amount
   */
  function capMintAmount() external view returns (uint256 capMint);

  /**
   * @notice Returns the fee parameters of the derivative contract
   * @return fee Fee struct
   */
  function feeInfo() external view returns (ICreditLineStorage.Fee memory fee);

  /**
   * @notice Returns the total fee produced by the contract
   * @return totalFee total amount of fees
   */
  function totalFeeAmount() external view returns (uint256 totalFee);

  /**
   * @notice Returns the total fee gained by the input address
   * @param feeGainer address to check claimable fees
   * @return feeGained amount of fess claimable by feeGainer
   */
  function userFeeGained(address feeGainer)
    external
    view
    returns (uint256 feeGained);

  /**
   * @notice Returns the liquidation rewrd percentage of the derivative contract
   * @return rewardPct liquidator reward percentage
   */
  function liquidationReward() external view returns (uint256 rewardPct);

  /**
   * @notice Returns the over collateralization percentage of the derivative contract
   * @return collReq percentage of overcollateralization
   */
  function collateralRequirement() external view returns (uint256 collReq);

  /**
   * @notice Accessor method for a sponsor's position.
   * @param sponsor address whose position data is retrieved.
   * @return collateralAmount amount of collateral of the sponsor's position.
   * @return tokensAmount amount of outstanding tokens of the sponsor's position.
   */
  function getPositionData(address sponsor)
    external
    view
    returns (uint256 collateralAmount, uint256 tokensAmount);

  /**
   * @notice Accessor method for contract's global position (aggregate).
   * @return totCollateral total amount of collateral deposited by lps
   * @return totTokensOutstanding total amount of outstanding tokens.
   */
  function getGlobalPositionData()
    external
    view
    returns (uint256 totCollateral, uint256 totTokensOutstanding);

  /**
   * @notice Returns if sponsor position is overcollateralized and thepercentage of coverage of the collateral according to the last price
   * @return True if position is overcollaterlized, otherwise false + percentage of coverage (totalCollateralAmount / (price * tokensCollateralized))
   */
  function collateralCoverage(address sponsor)
    external
    view
    returns (bool, uint256);

  /**
   * @notice Returns liquidation price of a position
   * @param sponsor address whose liquidation price is calculated.
   * @return liquidationPrice
   */
  function liquidationPrice(address sponsor)
    external
    view
    returns (uint256 liquidationPrice);

  /**
   * @notice Get synthetic token price identifier as represented by the oracle interface
   * @return identifier Synthetic token price identifier
   */
  function priceIdentifier() external view returns (bytes32 identifier);

  /**
   * @notice Get the price of synthetic token set by DVM after emergencyShutdown call
   * @return price Price of synthetic token
   */
  function emergencyShutdownPrice() external view returns (uint256 price);

  /**
   * @notice Get the block number when the emergency shutdown was called
   * @return time Block time
   */
  function emergencyShutdownTime() external view returns (uint256 time);
}

File 15 of 28 : IFactoryVersioning.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/**
 * @title Provides addresses of different versions of pools factory and derivative factory
 */
interface ISynthereumFactoryVersioning {
  /** @notice Sets a Factory
   * @param factoryType Type of factory
   * @param version Version of the factory to be set
   * @param factory The pool factory address to be set
   */
  function setFactory(
    bytes32 factoryType,
    uint8 version,
    address factory
  ) external;

  /** @notice Removes a factory
   * @param factoryType The type of factory to be removed
   * @param version Version of the factory to be removed
   */
  function removeFactory(bytes32 factoryType, uint8 version) external;

  /** @notice Gets a factory contract address
   * @param factoryType The type of factory to be checked
   * @param version Version of the factory to be checked
   * @return factory Address of the factory contract
   */
  function getFactoryVersion(bytes32 factoryType, uint8 version)
    external
    view
    returns (address factory);

  /** @notice Gets the number of factory versions for a specific type
   * @param factoryType The type of factory to be checked
   * @return numberOfVersions Total number of versions for a specific factory
   */
  function numberOfFactoryVersions(bytes32 factoryType)
    external
    view
    returns (uint8 numberOfVersions);
}

File 16 of 28 : ICreditLineStorage.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ISynthereumFinder} from '../../../core/interfaces/IFinder.sol';
import {IStandardERC20} from '../../../base/interfaces/IStandardERC20.sol';
import {
  IMintableBurnableERC20
} from '../../../tokens/interfaces/IMintableBurnableERC20.sol';
import {
  FixedPoint
} from '../../../../@uma/core/contracts/common/implementation/FixedPoint.sol';

interface ICreditLineStorage {
  // Describe fee structure
  struct Fee {
    // Fees charged when a user mints, redeem and exchanges tokens
    uint256 feePercentage;
    // Recipient receiving fees
    address[] feeRecipients;
    // Proportion for each recipient
    uint32[] feeProportions;
    // Used with individual proportions to scale values
    uint256 totalFeeProportions;
  }

  struct FeeStatus {
    // Track the fee gained to be withdrawn by an address
    mapping(address => FixedPoint.Unsigned) feeGained;
    // Total amount of fees to be withdrawn
    FixedPoint.Unsigned totalFeeAmount;
  }

  // Represents a single sponsor's position. All collateral is held by this contract.
  // This struct acts as bookkeeping for how much of that collateral is allocated to each sponsor.
  struct PositionData {
    FixedPoint.Unsigned tokensOutstanding;
    FixedPoint.Unsigned rawCollateral;
  }

  struct GlobalPositionData {
    // Keep track of the total collateral and tokens across all positions
    FixedPoint.Unsigned totalTokensOutstanding;
    // Similar to the rawCollateral in PositionData, this value should not be used directly.
    //_getFeeAdjustedCollateral(), _addCollateral() and _removeCollateral() must be used to access and adjust.
    FixedPoint.Unsigned rawTotalPositionCollateral;
  }

  struct PositionManagerData {
    // SynthereumFinder contract
    ISynthereumFinder synthereumFinder;
    // Collateral token
    IStandardERC20 collateralToken;
    // Synthetic token created by this contract.
    IMintableBurnableERC20 tokenCurrency;
    // Unique identifier for DVM price feed ticker.
    bytes32 priceIdentifier;
    // Minimum number of tokens in a sponsor's position.
    FixedPoint.Unsigned minSponsorTokens;
    // Expiry price pulled from Chainlink in the case of an emergency shutdown.
    FixedPoint.Unsigned emergencyShutdownPrice;
    // Timestamp used in case of emergency shutdown.
    uint256 emergencyShutdownTimestamp;
    // The excessTokenBeneficiary of any excess tokens added to the contract.
    address excessTokenBeneficiary;
    // Version of the self-minting derivative
    uint8 version;
  }

  /**
   * @notice Construct the PerpetualPositionManager.
   * @dev Deployer of this contract should consider carefully which parties have ability to mint and burn
   * the synthetic tokens referenced by `_tokenAddress`. This contract's security assumes that no external accounts
   * can mint new tokens, which could be used to steal all of this contract's locked collateral.
   * We recommend to only use synthetic token contracts whose sole Owner role (the role capable of adding & removing roles)
   * is assigned to this contract, whose sole Minter role is assigned to this contract, and whose
   * total supply is 0 prior to construction of this contract.
   * @param collateralAddress ERC20 token used as collateral for all positions.
   * @param tokenAddress ERC20 token used as synthetic token.
   * @param priceFeedIdentifier registered in the ChainLink Oracle for the synthetic.
   * @param minSponsorTokens minimum amount of collateral that must exist at any time in a position.
   * @param timerAddress Contract that stores the current time in a testing environment. Set to 0x0 for production.
   * @param excessTokenBeneficiary Beneficiary to send all excess token balances that accrue in the contract.
   * @param version Version of the self-minting derivative
   * @param synthereumFinder The SynthereumFinder contract
   */
  struct PositionManagerParams {
    IStandardERC20 collateralToken;
    IMintableBurnableERC20 syntheticToken;
    bytes32 priceFeedIdentifier;
    FixedPoint.Unsigned minSponsorTokens;
    address excessTokenBeneficiary;
    uint8 version;
    ISynthereumFinder synthereumFinder;
  }

  struct LiquidationData {
    address sponsor;
    address liquidator;
    uint256 liquidationTime;
    uint256 numTokensBurnt;
    uint256 liquidatedCollateral;
  }

  struct ExecuteLiquidationData {
    FixedPoint.Unsigned tokensToLiquidate;
    FixedPoint.Unsigned collateralValueLiquidatedTokens;
    FixedPoint.Unsigned collateralLiquidated;
    FixedPoint.Unsigned liquidatorReward;
  }
}

File 17 of 28 : Constants.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.9;

/**
 * @title Stores common interface names used throughout Synthereum.
 */
library SynthereumInterfaces {
  bytes32 public constant Deployer = 'Deployer';
  bytes32 public constant FactoryVersioning = 'FactoryVersioning';
  bytes32 public constant TokenFactory = 'TokenFactory';
  bytes32 public constant PoolRegistry = 'PoolRegistry';
  bytes32 public constant SelfMintingRegistry = 'SelfMintingRegistry';
  bytes32 public constant FixedRateRegistry = 'FixedRateRegistry';
  bytes32 public constant PriceFeed = 'PriceFeed';
  bytes32 public constant Manager = 'Manager';
  bytes32 public constant CreditLineController = 'CreditLineController';
  bytes32 public constant CollateralWhitelist = 'CollateralWhitelist';
  bytes32 public constant IdentifierWhitelist = 'IdentifierWhitelist';
  bytes32 public constant TrustedForwarder = 'TrustedForwarder';
  bytes32 public constant MoneyMarketManager = 'MoneyMarketManager';
  bytes32 public constant JarvisBrrrrr = 'JarvisBrrrrr';
  bytes32 public constant LendingManager = 'LendingManager';
  bytes32 public constant LendingStorageManager = 'LendingStorageManager';
  bytes32 public constant CommissionReceiver = 'CommissionReceiver';
  bytes32 public constant BuybackProgramReceiver = 'BuybackProgramReceiver';
  bytes32 public constant LendingRewardsReceiver = 'LendingRewardsReceiver';
  bytes32 public constant JarvisToken = 'JarvisToken';
  bytes32 public constant DebtTokenFactory = 'DebtTokenFactory';
}

library FactoryInterfaces {
  bytes32 public constant PoolFactory = 'PoolFactory';
  bytes32 public constant SelfMintingFactory = 'SelfMintingFactory';
  bytes32 public constant FixedRateFactory = 'FixedRateFactory';
}

File 18 of 28 : FixedPoint.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import "../../../../../@openzeppelin/contracts/utils/math/SafeMath.sol";
import "../../../../../@openzeppelin/contracts/utils/math/SignedSafeMath.sol";

/**
 * @title Library for fixed point arithmetic on uints
 */
library FixedPoint {
    using SafeMath for uint256;
    using SignedSafeMath for int256;

    // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
    // For unsigned values:
    //   This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.
    uint256 private constant FP_SCALING_FACTOR = 10**18;

    // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------
    struct Unsigned {
        uint256 rawValue;
    }

    /**
     * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.
     * @param a uint to convert into a FixedPoint.
     * @return the converted FixedPoint.
     */
    function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {
        return Unsigned(a.mul(FP_SCALING_FACTOR));
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if equal, or False.
     */
    function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue == fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if equal, or False.
     */
    function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue == b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue > fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue >= fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue < fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a < b`, or False.
     */
    function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue <= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue <= fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue <= b.rawValue;
    }

    /**
     * @notice The minimum of `a` and `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the minimum of `a` and `b`.
     */
    function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return a.rawValue < b.rawValue ? a : b;
    }

    /**
     * @notice The maximum of `a` and `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the maximum of `a` and `b`.
     */
    function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return a.rawValue > b.rawValue ? a : b;
    }

    /**
     * @notice Adds two `Unsigned`s, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the sum of `a` and `b`.
     */
    function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.add(b.rawValue));
    }

    /**
     * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the sum of `a` and `b`.
     */
    function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return add(a, fromUnscaledUint(b));
    }

    /**
     * @notice Subtracts two `Unsigned`s, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the difference of `a` and `b`.
     */
    function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.sub(b.rawValue));
    }

    /**
     * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the difference of `a` and `b`.
     */
    function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return sub(a, fromUnscaledUint(b));
    }

    /**
     * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return the difference of `a` and `b`.
     */
    function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return sub(fromUnscaledUint(a), b);
    }

    /**
     * @notice Multiplies two `Unsigned`s, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        // There are two caveats with this computation:
        // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
        // stored internally as a uint256 ~10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
        // would round to 3, but this computation produces the result 2.
        // No need to use SafeMath because FP_SCALING_FACTOR != 0.
        return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);
    }

    /**
     * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the product of `a` and `b`.
     */
    function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.mul(b));
    }

    /**
     * @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        uint256 mulRaw = a.rawValue.mul(b.rawValue);
        uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;
        uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);
        if (mod != 0) {
            return Unsigned(mulFloor.add(1));
        } else {
            return Unsigned(mulFloor);
        }
    }

    /**
     * @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        // Since b is an int, there is no risk of truncation and we can just mul it normally
        return Unsigned(a.rawValue.mul(b));
    }

    /**
     * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        // There are two caveats with this computation:
        // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
        // 10^41 is stored internally as a uint256 10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
        // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
        return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));
    }

    /**
     * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.div(b));
    }

    /**
     * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a uint256 numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return div(fromUnscaledUint(a), b);
    }

    /**
     * @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);
        uint256 divFloor = aScaled.div(b.rawValue);
        uint256 mod = aScaled.mod(b.rawValue);
        if (mod != 0) {
            return Unsigned(divFloor.add(1));
        } else {
            return Unsigned(divFloor);
        }
    }

    /**
     * @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        // Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))"
        // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.
        // This creates the possibility of overflow if b is very large.
        return divCeil(a, fromUnscaledUint(b));
    }

    /**
     * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
     * @dev This will "floor" the result.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return output is `a` to the power of `b`.
     */
    function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {
        output = fromUnscaledUint(1);
        for (uint256 i = 0; i < b; i = i.add(1)) {
            output = mul(output, a);
        }
    }

    // ------------------------------------------------- SIGNED -------------------------------------------------------------
    // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
    // For signed values:
    //   This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.
    int256 private constant SFP_SCALING_FACTOR = 10**18;

    struct Signed {
        int256 rawValue;
    }

    function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {
        require(a.rawValue >= 0, "Negative value provided");
        return Unsigned(uint256(a.rawValue));
    }

    function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {
        require(a.rawValue <= uint256(type(int256).max), "Unsigned too large");
        return Signed(int256(a.rawValue));
    }

    /**
     * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.
     * @param a int to convert into a FixedPoint.Signed.
     * @return the converted FixedPoint.Signed.
     */
    function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {
        return Signed(a.mul(SFP_SCALING_FACTOR));
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a int256.
     * @return True if equal, or False.
     */
    function isEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue == fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if equal, or False.
     */
    function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue == b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue > fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue >= fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue < fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a < b`, or False.
     */
    function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue <= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue <= fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue <= b.rawValue;
    }

    /**
     * @notice The minimum of `a` and `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the minimum of `a` and `b`.
     */
    function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return a.rawValue < b.rawValue ? a : b;
    }

    /**
     * @notice The maximum of `a` and `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the maximum of `a` and `b`.
     */
    function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return a.rawValue > b.rawValue ? a : b;
    }

    /**
     * @notice Adds two `Signed`s, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the sum of `a` and `b`.
     */
    function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.add(b.rawValue));
    }

    /**
     * @notice Adds an `Signed` to an unscaled int, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the sum of `a` and `b`.
     */
    function add(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return add(a, fromUnscaledInt(b));
    }

    /**
     * @notice Subtracts two `Signed`s, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the difference of `a` and `b`.
     */
    function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.sub(b.rawValue));
    }

    /**
     * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the difference of `a` and `b`.
     */
    function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return sub(a, fromUnscaledInt(b));
    }

    /**
     * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return the difference of `a` and `b`.
     */
    function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {
        return sub(fromUnscaledInt(a), b);
    }

    /**
     * @notice Multiplies two `Signed`s, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        // There are two caveats with this computation:
        // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
        // stored internally as an int256 ~10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
        // would round to 3, but this computation produces the result 2.
        // No need to use SafeMath because SFP_SCALING_FACTOR != 0.
        return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);
    }

    /**
     * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the product of `a` and `b`.
     */
    function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.mul(b));
    }

    /**
     * @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        int256 mulRaw = a.rawValue.mul(b.rawValue);
        int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;
        // Manual mod because SignedSafeMath doesn't support it.
        int256 mod = mulRaw % SFP_SCALING_FACTOR;
        if (mod != 0) {
            bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
            int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
            return Signed(mulTowardsZero.add(valueToAdd));
        } else {
            return Signed(mulTowardsZero);
        }
    }

    /**
     * @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
        // Since b is an int, there is no risk of truncation and we can just mul it normally
        return Signed(a.rawValue.mul(b));
    }

    /**
     * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        // There are two caveats with this computation:
        // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
        // 10^41 is stored internally as an int256 10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
        // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
        return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));
    }

    /**
     * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b an int256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.div(b));
    }

    /**
     * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a an int256 numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(int256 a, Signed memory b) internal pure returns (Signed memory) {
        return div(fromUnscaledInt(a), b);
    }

    /**
     * @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);
        int256 divTowardsZero = aScaled.div(b.rawValue);
        // Manual mod because SignedSafeMath doesn't support it.
        int256 mod = aScaled % b.rawValue;
        if (mod != 0) {
            bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
            int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
            return Signed(divTowardsZero.add(valueToAdd));
        } else {
            return Signed(divTowardsZero);
        }
    }

    /**
     * @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b an int256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
        // Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))"
        // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.
        // This creates the possibility of overflow if b is very large.
        return divAwayFromZero(a, fromUnscaledInt(b));
    }

    /**
     * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
     * @dev This will "floor" the result.
     * @param a a FixedPoint.Signed.
     * @param b a uint256 (negative exponents are not allowed).
     * @return output is `a` to the power of `b`.
     */
    function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {
        output = fromUnscaledInt(1);
        for (uint256 i = 0; i < b; i = i.add(1)) {
            output = mul(output, a);
        }
    }
}

File 19 of 28 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 20 of 28 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 21 of 28 : IStandardERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IStandardERC20 is IERC20 {
  /**
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory);

  /**
   * @dev Returns the symbol of the token, usually a shorter version of the
   * name.
   */
  function symbol() external view returns (string memory);

  /**
   * @dev Returns the number of decimals used to get its user representation.
   * For example, if `decimals` equals `2`, a balance of `505` tokens should
   * be displayed to a user as `5,05` (`505 / 10 ** 2`).
   *
   * Tokens usually opt for a value of 18, imitating the relationship between
   * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
   * called.
   *
   * NOTE: This information is only used for _display_ purposes: it in
   * no way affects any of the arithmetic of the contract, including
   * {IERC20-balanceOf} and {IERC20-transfer}.
   */
  function decimals() external view returns (uint8);
}

File 22 of 28 : IMintableBurnableERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol';

/**
 * @title ERC20 interface that includes burn mint and roles methods.
 */
interface IMintableBurnableERC20 is IERC20 {
  /**
   * @notice Burns a specific amount of the caller's tokens.
   * @dev This method should be permissioned to only allow designated parties to burn tokens.
   */
  function burn(uint256 value) external;

  /**
   * @notice Mints tokens and adds them to the balance of the `to` address.
   * @dev This method should be permissioned to only allow designated parties to mint tokens.
   */
  function mint(address to, uint256 value) external returns (bool);

  /**
   * @notice Returns the number of decimals used to get its user representation.
   */
  function decimals() external view returns (uint8);
}

File 23 of 28 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 24 of 28 : SignedSafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SignedSafeMath {
    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        return a / b;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        return a - b;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        return a + b;
    }
}

File 25 of 28 : IDeployment.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {ISynthereumFinder} from '../../core/interfaces/IFinder.sol';

/**
 * @title Interface that a pool MUST have in order to be included in the deployer
 */
interface ISynthereumDeployment {
  /**
   * @notice Get Synthereum finder of the pool/self-minting derivative
   * @return finder Returns finder contract
   */
  function synthereumFinder() external view returns (ISynthereumFinder finder);

  /**
   * @notice Get Synthereum version
   * @return contractVersion Returns the version of this pool/self-minting derivative
   */
  function version() external view returns (uint8 contractVersion);

  /**
   * @notice Get the collateral token of this pool/self-minting derivative
   * @return collateralCurrency The ERC20 collateral token
   */
  function collateralToken() external view returns (IERC20 collateralCurrency);

  /**
   * @notice Get the synthetic token associated to this pool/self-minting derivative
   * @return syntheticCurrency The ERC20 synthetic token
   */
  function syntheticToken() external view returns (IERC20 syntheticCurrency);

  /**
   * @notice Get the synthetic token symbol associated to this pool/self-minting derivative
   * @return symbol The ERC20 synthetic token symbol
   */
  function syntheticTokenSymbol() external view returns (string memory symbol);
}

File 26 of 28 : IEmergencyShutdown.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

interface IEmergencyShutdown {
  /**
   * @notice Shutdown the pool or self-minting-derivative in case of emergency
   * @notice Only Synthereum manager contract can call this function
   * @return timestamp Timestamp of emergency shutdown transaction
   * @return price Price of the pair at the moment of shutdown execution
   */
  function emergencyShutdown()
    external
    returns (uint256 timestamp, uint256 price);
}

File 27 of 28 : ITypology.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

interface ITypology {
  /**
   * @notice Return typology of the contract
   */
  function typology() external view returns (string memory);
}

File 28 of 28 : Finder.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.9;

import {ISynthereumFinder} from './interfaces/IFinder.sol';
import {
  AccessControlEnumerable
} from '../../@openzeppelin/contracts/access/AccessControlEnumerable.sol';

/**
 * @title Provides addresses of contracts implementing certain interfaces.
 */
contract SynthereumFinder is ISynthereumFinder, AccessControlEnumerable {
  bytes32 public constant MAINTAINER_ROLE = keccak256('Maintainer');

  //Describe role structure
  struct Roles {
    address admin;
    address maintainer;
  }

  //----------------------------------------
  // Storage
  //----------------------------------------

  mapping(bytes32 => address) public interfacesImplemented;

  //----------------------------------------
  // Events
  //----------------------------------------

  event InterfaceImplementationChanged(
    bytes32 indexed interfaceName,
    address indexed newImplementationAddress
  );

  //----------------------------------------
  // Modifiers
  //----------------------------------------

  modifier onlyMaintainer() {
    require(
      hasRole(MAINTAINER_ROLE, msg.sender),
      'Sender must be the maintainer'
    );
    _;
  }

  //----------------------------------------
  // Constructors
  //----------------------------------------

  constructor(Roles memory roles) {
    _setRoleAdmin(DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE);
    _setRoleAdmin(MAINTAINER_ROLE, DEFAULT_ADMIN_ROLE);
    _setupRole(DEFAULT_ADMIN_ROLE, roles.admin);
    _setupRole(MAINTAINER_ROLE, roles.maintainer);
  }

  //----------------------------------------
  // External view
  //----------------------------------------

  /**
   * @notice Updates the address of the contract that implements `interfaceName`.
   * @param interfaceName bytes32 of the interface name that is either changed or registered.
   * @param implementationAddress address of the implementation contract.
   */
  function changeImplementationAddress(
    bytes32 interfaceName,
    address implementationAddress
  ) external override onlyMaintainer {
    interfacesImplemented[interfaceName] = implementationAddress;

    emit InterfaceImplementationChanged(interfaceName, implementationAddress);
  }

  /**
   * @notice Gets the address of the contract that implements the given `interfaceName`.
   * @param interfaceName queried interface.
   * @return implementationAddress Address of the defined interface.
   */
  function getImplementationAddress(bytes32 interfaceName)
    external
    view
    override
    returns (address)
  {
    address implementationAddress = interfacesImplemented[interfaceName];
    require(implementationAddress != address(0x0), 'Implementation not found');
    return implementationAddress;
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ISynthereumFinder","name":"_synthereumFinder","type":"address"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"maintainer","type":"address"}],"internalType":"struct CreditLineController.Roles","name":"roles","type":"tuple"},{"internalType":"uint8","name":"version","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"selfMintingDerivative","type":"address"},{"indexed":false,"internalType":"uint256","name":"capMintAmount","type":"uint256"}],"name":"SetCapMintAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"selfMintingDerivative","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralRequirement","type":"uint256"}],"name":"SetCollateralRequirement","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"selfMintingDerivative","type":"address"},{"indexed":false,"internalType":"uint256","name":"feePercentage","type":"uint256"}],"name":"SetFeePercentage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"selfMintingDerivative","type":"address"},{"indexed":false,"internalType":"address[]","name":"feeRecipient","type":"address[]"},{"indexed":false,"internalType":"uint32[]","name":"feeProportions","type":"uint32[]"}],"name":"SetFeeRecipients","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"selfMintingDerivative","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidationReward","type":"uint256"}],"name":"SetLiquidationReward","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINTAINER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"selfMintingDerivative","type":"address"}],"name":"feePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"selfMintingDerivative","type":"address"}],"name":"feeRecipientsInfo","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint32[]","name":"","type":"uint32[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"selfMintingDerivative","type":"address"}],"name":"getCapMintAmount","outputs":[{"internalType":"uint256","name":"capMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"selfMintingDerivative","type":"address"}],"name":"getCollateralRequirement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"selfMintingDerivative","type":"address"}],"name":"getFeeInfo","outputs":[{"components":[{"internalType":"uint256","name":"feePercentage","type":"uint256"},{"internalType":"address[]","name":"feeRecipients","type":"address[]"},{"internalType":"uint32[]","name":"feeProportions","type":"uint32[]"},{"internalType":"uint256","name":"totalFeeProportions","type":"uint256"}],"internalType":"struct ICreditLineStorage.Fee","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"selfMintingDerivative","type":"address"}],"name":"getLiquidationRewardPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"selfMintingVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"selfMintingDerivatives","type":"address[]"},{"internalType":"uint256[]","name":"capMintAmounts","type":"uint256[]"}],"name":"setCapMintAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"selfMintingDerivatives","type":"address[]"},{"internalType":"uint256[]","name":"collateralRequirements","type":"uint256[]"}],"name":"setCollateralRequirement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"selfMintingDerivatives","type":"address[]"},{"internalType":"uint256[]","name":"feePercentages","type":"uint256[]"}],"name":"setFeePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"selfMintingDerivatives","type":"address[]"},{"internalType":"address[][]","name":"feeRecipients","type":"address[][]"},{"internalType":"uint32[][]","name":"feeProportions","type":"uint32[][]"}],"name":"setFeeRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"selfMintingDerivatives","type":"address[]"},{"internalType":"uint256[]","name":"_liquidationRewards","type":"uint256[]"}],"name":"setLiquidationRewardPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"synthereumFinder","outputs":[{"internalType":"contract ISynthereumFinder","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b506040516200384838038062003848833981016040819052620000349162000268565b600160009081556001600160a01b03841660805260ff821660a0526200005b9080620000b5565b62000077600080516020620038288339815191526000620000b5565b8151620000879060009062000102565b620000ac6000805160206200382883398151915283602001516200010260201b60201c565b50505062000320565b6000828152600160208190526040808320909101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6200011982826200014560201b620019361760201c565b6000828152600260209081526040909120620001409183906200194462000155821b17901c565b505050565b62000151828262000175565b5050565b60006200016c836001600160a01b038416620001fd565b90505b92915050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16620001515760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600081815260018301602052604081205462000246575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200016f565b5060006200016f565b6001600160a01b03811681146200026557600080fd5b50565b600080600083850360808112156200027f57600080fd5b84516200028c816200024f565b93506040601f1982011215620002a157600080fd5b50604080519081016001600160401b0381118282101715620002d357634e487b7160e01b600052604160045260246000fd5b6040526020850151620002e6816200024f565b81526040850151620002f8816200024f565b6020820152606085015190925060ff811681146200031557600080fd5b809150509250925092565b60805160a05161349562000393600039600081816101b6015281816106110152818161081201528181610a4901528181610c6b01528181610e520152818161128c015281816114750152818161169601526118980152600081816103c3015281816119c40152611bfc01526134956000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80637439459b116100c3578063a217fddf1161007c578063a217fddf1461037d578063b826fb6c14610385578063ca15c87314610398578063d547741f146103ab578063f6bf3ef6146103be578063f8742254146103e557600080fd5b80637439459b146102c15780637c136ae6146102e157806381b619c7146103035780639010d07c1461031657806391d1485414610341578063a0a1f0981461035457600080fd5b8063282113341161011557806328211334146102235780632e5935fc1461024c5780632f2ff15d1461025f57806336568abe146102725780634dfe06b61461028557806367e8683d146102ae57600080fd5b806301ffc9a714610152578063071499c51461017a5780630d51a4be146101b157806312f19f64146101ea578063248a9ca3146101ff575b600080fd5b6101656101603660046129d8565b6103fa565b60405190151581526020015b60405180910390f35b6101a3610188366004612a1a565b6001600160a01b031660009081526004602052604090205490565b604051908152602001610171565b6101d87f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610171565b6101fd6101f8366004612a83565b610425565b005b6101a361020d366004612aef565b6000908152600160208190526040909120015490565b6101a3610231366004612a1a565b6001600160a01b031660009081526003602052604090205490565b6101fd61025a366004612b08565b6106a8565b6101fd61026d366004612ba2565b610ad8565b6101fd610280366004612ba2565b610aff565b6101a3610293366004612a1a565b6001600160a01b031660009081526005602052604090205490565b6101fd6102bc366004612a83565b610b21565b6102d46102cf366004612a1a565b610ed6565b6040516101719190612c13565b6102f46102ef366004612a1a565b61101f565b60405161017193929190612ca1565b6101fd610311366004612a83565b611141565b610329610324366004612d09565b611501565b6040516001600160a01b039091168152602001610171565b61016561034f366004612ba2565b611520565b6101a3610362366004612a1a565b6001600160a01b031660009081526006602052604090205490565b6101a3600081565b6101fd610393366004612a83565b61154b565b6101a36103a6366004612aef565b611915565b6101fd6103b9366004612ba2565b61192c565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b6101a360008051602061344083398151915281565b60006001600160e01b03198216635a05180f60e01b148061041f575061041f82611959565b92915050565b61042d61198e565b61048e5760405162461bcd60e51b815260206004820152602760248201527f53656e646572206d757374206265207468652073656c662d6d696e74696e6720604482015266666163746f727960c81b60648201526084015b60405180910390fd5b600260005414156104b15760405162461bcd60e51b815260040161048590612d2b565b6002600055826104d35760405162461bcd60e51b815260040161048590612d62565b8281146105485760405162461bcd60e51b815260206004820152603a60248201527f4e756d626572206f6620646572697661746976657320616e64206f766572636f60448201527f6c6c61746572616c73206d757374206265207468652073616d650000000000006064820152608401610485565b600061056260008051602061344083398151915233611520565b905060005b8481101561069b57600086868381811061058357610583612da4565b90506020020160208101906105989190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b1580156105d557600080fd5b505afa1580156105e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060d9190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff16146106545760405162461bcd60e51b815260040161048590612ddd565b8315610664576106648282611bce565b6106868287878681811061067a5761067a612da4565b90506020020135611e40565b5050808061069390612e2a565b915050610567565b5050600160005550505050565b6106c060008051602061344083398151915233611520565b156108d857600260005414156106e85760405162461bcd60e51b815260040161048590612d2b565b6002600055848061070b5760405162461bcd60e51b815260040161048590612d62565b80841461072a5760405162461bcd60e51b815260040161048590612e45565b8082146107495760405162461bcd60e51b815260040161048590612ea2565b600061076360008051602061344083398151915233611520565b905060005b828110156108cb57600089898381811061078457610784612da4565b90506020020160208101906107999190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b1580156107d657600080fd5b505afa1580156107ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080e9190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff16146108555760405162461bcd60e51b815260040161048590612ddd565b8315610865576108658282611bce565b6108b6828a8a8681811061087b5761087b612da4565b905060200281019061088d9190612eff565b8a8a8881811061089f5761089f612da4565b90506020028101906108b19190612eff565b611f7a565b505080806108c390612e2a565b915050610768565b5050600160005550610ad0565b6108e061198e565b6108fc5760405162461bcd60e51b815260040161048590612f49565b6002600054141561091f5760405162461bcd60e51b815260040161048590612d2b565b600260005584806109425760405162461bcd60e51b815260040161048590612d62565b8084146109615760405162461bcd60e51b815260040161048590612e45565b8082146109805760405162461bcd60e51b815260040161048590612ea2565b600061099a60008051602061344083398151915233611520565b905060005b82811015610ac75760008989838181106109bb576109bb612da4565b90506020020160208101906109d09190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0d57600080fd5b505afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a459190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff1614610a8c5760405162461bcd60e51b815260040161048590612ddd565b8315610a9c57610a9c8282611bce565b610ab2828a8a8681811061087b5761087b612da4565b50508080610abf90612e2a565b91505061099f565b50506001600055505b505050505050565b610ae28282612085565b6000828152600260205260409020610afa9082611944565b505050565b610b0982826120ac565b6000828152600260205260409020610afa9082612126565b610b3960008051602061344083398151915233611520565b15610d015760026000541415610b615760405162461bcd60e51b815260040161048590612d2b565b600260005582610b835760405162461bcd60e51b815260040161048590612d62565b828114610ba25760405162461bcd60e51b815260040161048590612fa6565b6000610bbc60008051602061344083398151915233611520565b905060005b84811015610cf5576000868683818110610bdd57610bdd612da4565b9050602002016020810190610bf29190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b158015610c2f57600080fd5b505afa158015610c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c679190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff1614610cae5760405162461bcd60e51b815260040161048590612ddd565b8315610cbe57610cbe8282611bce565b610ce082878786818110610cd457610cd4612da4565b9050602002013561213b565b50508080610ced90612e2a565b915050610bc1565b50506001600055610ed0565b610d0961198e565b610d255760405162461bcd60e51b815260040161048590612f49565b60026000541415610d485760405162461bcd60e51b815260040161048590612d2b565b600260005582610d6a5760405162461bcd60e51b815260040161048590612d62565b828114610d895760405162461bcd60e51b815260040161048590612fa6565b6000610da360008051602061344083398151915233611520565b905060005b8481101561069b576000868683818110610dc457610dc4612da4565b9050602002016020810190610dd99190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b158015610e1657600080fd5b505afa158015610e2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4e9190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff1614610e955760405162461bcd60e51b815260040161048590612ddd565b8315610ea557610ea58282611bce565b610ebb82878786818110610cd457610cd4612da4565b50508080610ec890612e2a565b915050610da8565b50505050565b610f016040518060800160405280600081526020016060815260200160608152602001600081525090565b6001600160a01b03821660009081526006602090815260409182902082516080810184528154815260018201805485518186028101860190965280865291949293858101939290830182828015610f8157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f63575b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561100557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411610fc85790505b505050505081526020016003820154815250509050919050565b60608060008060066000866001600160a01b03166001600160a01b03168152602001908152602001600020905080600101816002018260030154828054806020026020016040519081016040528092919081815260200182805480156110ae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611090575b505050505092508180548060200260200160405190810160405280929190818152602001828054801561112c57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116110ef5790505b50505050509150935093509350509193909250565b61115960008051602061344083398151915233611520565b1561132357600260005414156111815760405162461bcd60e51b815260040161048590612d2b565b600260005582806111a45760405162461bcd60e51b815260040161048590612d62565b8082146111c35760405162461bcd60e51b815260040161048590613003565b60006111dd60008051602061344083398151915233611520565b905060005b828110156113165760008787838181106111fe576111fe612da4565b90506020020160208101906112139190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561125057600080fd5b505afa158015611264573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112889190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff16146112cf5760405162461bcd60e51b815260040161048590612ddd565b83156112df576112df8282611bce565b611301828888868181106112f5576112f5612da4565b905060200201356121f0565b5050808061130e90612e2a565b9150506111e2565b5050600160005550610ed0565b61132b61198e565b6113475760405162461bcd60e51b815260040161048590612f49565b6002600054141561136a5760405162461bcd60e51b815260040161048590612d2b565b6002600055828061138d5760405162461bcd60e51b815260040161048590612d62565b8082146113ac5760405162461bcd60e51b815260040161048590613003565b60006113c660008051602061344083398151915233611520565b905060005b828110156114f35760008787838181106113e7576113e7612da4565b90506020020160208101906113fc9190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561143957600080fd5b505afa15801561144d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114719190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff16146114b85760405162461bcd60e51b815260040161048590612ddd565b83156114c8576114c88282611bce565b6114de828888868181106112f5576112f5612da4565b505080806114eb90612e2a565b9150506113cb565b505060016000555050505050565b6000828152600260205260408120611519908361230b565b9392505050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61156360008051602061344083398151915233611520565b15611746576002600054141561158b5760405162461bcd60e51b815260040161048590612d2b565b600260005582806115ae5760405162461bcd60e51b815260040161048590612d62565b8082146115cd5760405162461bcd60e51b815260040161048590613060565b60006115e760008051602061344083398151915233611520565b905060005b8281101561131657600087878381811061160857611608612da4565b905060200201602081019061161d9190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561165a57600080fd5b505afa15801561166e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116929190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff16146116d95760405162461bcd60e51b815260040161048590612ddd565b83156116e9576116e98282611bce565b6117318989858181106116fe576116fe612da4565b90506020020160208101906117139190612a1a565b88888681811061172557611725612da4565b90506020020135612317565b5050808061173e90612e2a565b9150506115ec565b61174e61198e565b61176a5760405162461bcd60e51b815260040161048590612f49565b6002600054141561178d5760405162461bcd60e51b815260040161048590612d2b565b600260005582806117b05760405162461bcd60e51b815260040161048590612d62565b8082146117cf5760405162461bcd60e51b815260040161048590613060565b60006117e960008051602061344083398151915233611520565b905060005b828110156114f357600087878381811061180a5761180a612da4565b905060200201602081019061181f9190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561185c57600080fd5b505afa158015611870573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118949190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff16146118db5760405162461bcd60e51b815260040161048590612ddd565b83156118eb576118eb8282611bce565b6119008989858181106116fe576116fe612da4565b5050808061190d90612e2a565b9150506117ee565b600081815260026020526040812061041f90612445565b610b09828261244f565b6119408282612476565b5050565b6000611519836001600160a01b0384166124e1565b60006001600160e01b03198216637965db0b60e01b148061041f57506301ffc9a760e01b6001600160e01b031983161461041f565b6040516302abf57960e61b815270466163746f727956657273696f6e696e6760781b600482015260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aafd5e409060240160206040518083038186803b158015611a0657600080fd5b505afa158015611a1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3e91906130bd565b604051636d2721a360e11b81527153656c664d696e74696e67466163746f727960701b60048201529091506000906001600160a01b0383169063da4e43469060240160206040518083038186803b158015611a9857600080fd5b505afa158015611aac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad09190612dba565b60ff1690506000805b82821015611bb557604051636839980160e11b81527153656c664d696e74696e67466163746f727960701b600482015260ff821660248201526001600160a01b0385169063d07330029060440160206040518083038186803b158015611b3e57600080fd5b505afa925050508015611b6e575060408051601f3d908101601f19168201909252611b6b918101906130bd565b60015b611b7757611ba3565b336001600160a01b0382161415611b945760019550505050505090565b82611b9e81612e2a565b935050505b80611bad816130da565b915050611ad9565b5080821415611bc8576000935050505090565b50505090565b6040516302abf57960e61b81527253656c664d696e74696e67526567697374727960681b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aafd5e409060240160206040518083038186803b158015611c4657600080fd5b505afa158015611c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7e91906130bd565b9050806001600160a01b03166321ff88ca846001600160a01b03166336815bb76040518163ffffffff1660e01b815260040160006040518083038186803b158015611cc857600080fd5b505afa158015611cdc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d04919081019061313c565b856001600160a01b031663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b158015611d3d57600080fd5b505afa158015611d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7591906130bd565b85876040518563ffffffff1660e01b8152600401611d969493929190613215565b60206040518083038186803b158015611dae57600080fd5b505afa158015611dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de69190613254565b610afa5760405162461bcd60e51b815260206004820152602560248201527f53656c662d6d696e74696e672064657269766174697665206e6f7420726567696044820152641cdd1c995960da1b6064820152608401610485565b6001600160a01b038216600090815260056020526040902054811415611eb35760405162461bcd60e51b815260206004820152602260248201527f436f6c6c61746572616c20726571756972656d656e74206973207468652073616044820152616d6560f01b6064820152608401610485565b670de0b6b3a76400008111611f215760405162461bcd60e51b815260206004820152602e60248201527f4f766572636f6c6c61746572616c69736174696f6e206d75737420626520626960448201526d67676572207468616e203130302560901b6064820152608401610485565b6001600160a01b03821660008181526005602052604090819020839055517f2e5a927e7e48046893644d70eabc2a235afed3c32c5470769d400e742e262ed390611f6e9084815260200190565b60405180910390a25050565b6000805b8281101561207c57838382818110611f9857611f98612da4565b9050602002016020810190611fad919061328f565b611fbd9063ffffffff16836132aa565b6001600160a01b0388166000908152600660205260409020909250611fe69060010187876128b4565b506001600160a01b038716600090815260066020526040902061200d906002018585612917565b506001600160a01b03871660008181526006602052604090819020600301849055517fd630d6daed151d020915cc030e6b4fde7e3fda228da9e53d79b3e0c259e9c7a8906120629089908990899089906132c2565b60405180910390a28061207481612e2a565b915050611f7e565b50505050505050565b600082815260016020819052604090912001546120a28133612530565b610afa8383612476565b6001600160a01b038116331461211c5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610485565b6119408282612594565b6000611519836001600160a01b0384166125fb565b6001600160a01b0382166000908152600360205260409020548114156121a35760405162461bcd60e51b815260206004820152601b60248201527f436170206d696e7420616d6f756e74206973207468652073616d6500000000006044820152606401610485565b6001600160a01b03821660008181526003602052604090819020839055517f88b73fe96f35e95dbb00be55f30de5fea08993a40983d17cd58ea2994cf7464490611f6e9084815260200190565b6001600160a01b0382166000908152600660205260409020548114156122585760405162461bcd60e51b815260206004820152601a60248201527f4665652070657263656e74616765206973207468652073616d650000000000006044820152606401610485565b670de0b6b3a76400008111156122be5760405162461bcd60e51b815260206004820152602560248201527f4665652070657263656e74616765206d757374206265206c657373207468616e604482015264203130302560d81b6064820152608401610485565b6001600160a01b03821660008181526006602052604090819020839055517f7186c144be98cbb7e0ef7eab9175ac4b810da9d3b1c187de9ba64ec2152e65ce90611f6e9084815260200190565b600061151983836126ee565b6001600160a01b03821660009081526004602052604090205481141561237f5760405162461bcd60e51b815260206004820152601e60248201527f4c69717569646174696f6e20726577617264206973207468652073616d6500006044820152606401610485565b6000811180156123965750670de0b6b3a764000081105b6123f85760405162461bcd60e51b815260206004820152602d60248201527f4c69717569646174696f6e20726577617264206d75737420626520626574776560448201526c656e203020616e64203130302560981b6064820152608401610485565b6001600160a01b03821660008181526004602052604090819020839055517fa7401927a70fe8f49342e51379925b6a05fd0e08f00b0295dbf852e53fe1268390611f6e9084815260200190565b600061041f825490565b6000828152600160208190526040909120015461246c8133612530565b610afa8383612594565b6124808282611520565b6119405760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008181526001830160205260408120546125285750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561041f565b50600061041f565b61253a8282611520565b61194057612552816001600160a01b03166014612718565b61255d836020612718565b60405160200161256e929190613354565b60408051601f198184030181529082905262461bcd60e51b8252610485916004016133c9565b61259e8282611520565b156119405760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600081815260018301602052604081205480156126e457600061261f6001836133dc565b8554909150600090612633906001906133dc565b905081811461269857600086600001828154811061265357612653612da4565b906000526020600020015490508087600001848154811061267657612676612da4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806126a9576126a96133f3565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061041f565b600091505061041f565b600082600001828154811061270557612705612da4565b9060005260206000200154905092915050565b60606000612727836002613409565b6127329060026132aa565b67ffffffffffffffff81111561274a5761274a6130fa565b6040519080825280601f01601f191660200182016040528015612774576020820181803683370190505b509050600360fc1b8160008151811061278f5761278f612da4565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106127be576127be612da4565b60200101906001600160f81b031916908160001a90535060006127e2846002613409565b6127ed9060016132aa565b90505b6001811115612865576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061282157612821612da4565b1a60f81b82828151811061283757612837612da4565b60200101906001600160f81b031916908160001a90535060049490941c9361285e81613428565b90506127f0565b5083156115195760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610485565b828054828255906000526020600020908101928215612907579160200282015b828111156129075781546001600160a01b0319166001600160a01b038435161782556020909201916001909101906128d4565b506129139291506129c3565b5090565b828054828255906000526020600020906007016008900481019282156129075791602002820160005b8382111561298a57833563ffffffff1683826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302612940565b80156129ba5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261298a565b50506129139291505b5b8082111561291357600081556001016129c4565b6000602082840312156129ea57600080fd5b81356001600160e01b03198116811461151957600080fd5b6001600160a01b0381168114612a1757600080fd5b50565b600060208284031215612a2c57600080fd5b813561151981612a02565b60008083601f840112612a4957600080fd5b50813567ffffffffffffffff811115612a6157600080fd5b6020830191508360208260051b8501011115612a7c57600080fd5b9250929050565b60008060008060408587031215612a9957600080fd5b843567ffffffffffffffff80821115612ab157600080fd5b612abd88838901612a37565b90965094506020870135915080821115612ad657600080fd5b50612ae387828801612a37565b95989497509550505050565b600060208284031215612b0157600080fd5b5035919050565b60008060008060008060608789031215612b2157600080fd5b863567ffffffffffffffff80821115612b3957600080fd5b612b458a838b01612a37565b90985096506020890135915080821115612b5e57600080fd5b612b6a8a838b01612a37565b90965094506040890135915080821115612b8357600080fd5b50612b9089828a01612a37565b979a9699509497509295939492505050565b60008060408385031215612bb557600080fd5b823591506020830135612bc781612a02565b809150509250929050565b600081518084526020808501945080840160005b83811015612c0857815163ffffffff1687529582019590820190600101612be6565b509495945050505050565b60208082528251828201528281015160806040840152805160a0840181905260009291820190839060c08601905b80831015612c6a5783516001600160a01b03168252928401926001929092019190840190612c41565b506040870151868203601f190160608801529350612c888185612bd2565b9350505050606084015160808401528091505092915050565b606080825284519082018190526000906020906080840190828801845b82811015612ce35781516001600160a01b031684529284019290840190600101612cbe565b50505083810382850152612cf78187612bd2565b92505050826040830152949350505050565b60008060408385031215612d1c57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526022908201527f4e6f2073656c662d6d696e74696e672064657269766174697665732070617373604082015261195960f21b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612dcc57600080fd5b815160ff8116811461151957600080fd5b6020808252601a908201527f57726f6e672073656c662d6d696e74696e672076657273696f6e000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600019821415612e3e57612e3e612e14565b5060010190565b60208082526039908201527f4d69736d61746368206265747765656e20646572697661746976657320746f2060408201527f75706461746520616e642066656520726563697069656e747300000000000000606082015260800190565b6020808252603a908201527f4d69736d61746368206265747765656e20646572697661746976657320746f2060408201527f75706461746520616e64206665652070726f706f7274696f6e73000000000000606082015260800190565b6000808335601e19843603018112612f1657600080fd5b83018035915067ffffffffffffffff821115612f3157600080fd5b6020019150600581901b3603821315612a7c57600080fd5b60208082526037908201527f53656e646572206d75737420626520746865206d61696e7461696e6572206f7260408201527f20612073656c662d6d696e74696e6720666163746f7279000000000000000000606082015260800190565b6020808252603b908201527f4e756d626572206f6620646572697661746976657320616e64206d696e74206360408201527f617020616d6f756e7473206d757374206265207468652073616d650000000000606082015260800190565b6020808252603a908201527f4e756d626572206f6620646572697661746976657320616e642066656520706560408201527f7263656e7461676573206d757374206265207468652073616d65000000000000606082015260800190565b6020808252603e908201527f4d69736d61746368206265747765656e20646572697661746976657320746f2060408201527f75706461746520616e64206c69717569646174696f6e20726577617264730000606082015260800190565b6000602082840312156130cf57600080fd5b815161151981612a02565b600060ff821660ff8114156130f1576130f1612e14565b60010192915050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561312b578181015183820152602001613113565b83811115610ed05750506000910152565b60006020828403121561314e57600080fd5b815167ffffffffffffffff8082111561316657600080fd5b818401915084601f83011261317a57600080fd5b81518181111561318c5761318c6130fa565b604051601f8201601f19908116603f011681019083821181831017156131b4576131b46130fa565b816040528281528760208487010111156131cd57600080fd5b6131de836020830160208801613110565b979650505050505050565b60008151808452613201816020860160208601613110565b601f01601f19169290920160200192915050565b60808152600061322860808301876131e9565b6001600160a01b03958616602084015260ff949094166040830152509216606090920191909152919050565b60006020828403121561326657600080fd5b8151801515811461151957600080fd5b803563ffffffff8116811461328a57600080fd5b919050565b6000602082840312156132a157600080fd5b61151982613276565b600082198211156132bd576132bd612e14565b500190565b6040808252810184905260008560608301825b878110156133055782356132e881612a02565b6001600160a01b03168252602092830192909101906001016132d5565b5083810360208581019190915285825291508590820160005b868110156133475763ffffffff61333484613276565b168252918301919083019060010161331e565b5098975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161338c816017850160208801613110565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516133bd816028840160208801613110565b01602801949350505050565b60208152600061151960208301846131e9565b6000828210156133ee576133ee612e14565b500390565b634e487b7160e01b600052603160045260246000fd5b600081600019048311821515161561342357613423612e14565b500290565b60008161343757613437612e14565b50600019019056fe126303c860ea810f85e857ad8768056e2eebc24b7796655ff3107e4af18e3f1ea2646970667358221220099175714d5c93d09880cf01767e7c55fd14f18a44a7c83d5725f1f5076837ef64736f6c63430008090033126303c860ea810f85e857ad8768056e2eebc24b7796655ff3107e4af18e3f1e0000000000000000000000003b05b902fe763ad87aa755fab70f86c76bf331f40000000000000000000000008232a29a3744d1c44676f6a198383b214c0b238100000000000000000000000052b063ab1a11d56ac5b2e84bdd59e11920b390b70000000000000000000000000000000000000000000000000000000000000002

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80637439459b116100c3578063a217fddf1161007c578063a217fddf1461037d578063b826fb6c14610385578063ca15c87314610398578063d547741f146103ab578063f6bf3ef6146103be578063f8742254146103e557600080fd5b80637439459b146102c15780637c136ae6146102e157806381b619c7146103035780639010d07c1461031657806391d1485414610341578063a0a1f0981461035457600080fd5b8063282113341161011557806328211334146102235780632e5935fc1461024c5780632f2ff15d1461025f57806336568abe146102725780634dfe06b61461028557806367e8683d146102ae57600080fd5b806301ffc9a714610152578063071499c51461017a5780630d51a4be146101b157806312f19f64146101ea578063248a9ca3146101ff575b600080fd5b6101656101603660046129d8565b6103fa565b60405190151581526020015b60405180910390f35b6101a3610188366004612a1a565b6001600160a01b031660009081526004602052604090205490565b604051908152602001610171565b6101d87f000000000000000000000000000000000000000000000000000000000000000281565b60405160ff9091168152602001610171565b6101fd6101f8366004612a83565b610425565b005b6101a361020d366004612aef565b6000908152600160208190526040909120015490565b6101a3610231366004612a1a565b6001600160a01b031660009081526003602052604090205490565b6101fd61025a366004612b08565b6106a8565b6101fd61026d366004612ba2565b610ad8565b6101fd610280366004612ba2565b610aff565b6101a3610293366004612a1a565b6001600160a01b031660009081526005602052604090205490565b6101fd6102bc366004612a83565b610b21565b6102d46102cf366004612a1a565b610ed6565b6040516101719190612c13565b6102f46102ef366004612a1a565b61101f565b60405161017193929190612ca1565b6101fd610311366004612a83565b611141565b610329610324366004612d09565b611501565b6040516001600160a01b039091168152602001610171565b61016561034f366004612ba2565b611520565b6101a3610362366004612a1a565b6001600160a01b031660009081526006602052604090205490565b6101a3600081565b6101fd610393366004612a83565b61154b565b6101a36103a6366004612aef565b611915565b6101fd6103b9366004612ba2565b61192c565b6103297f0000000000000000000000003b05b902fe763ad87aa755fab70f86c76bf331f481565b6101a360008051602061344083398151915281565b60006001600160e01b03198216635a05180f60e01b148061041f575061041f82611959565b92915050565b61042d61198e565b61048e5760405162461bcd60e51b815260206004820152602760248201527f53656e646572206d757374206265207468652073656c662d6d696e74696e6720604482015266666163746f727960c81b60648201526084015b60405180910390fd5b600260005414156104b15760405162461bcd60e51b815260040161048590612d2b565b6002600055826104d35760405162461bcd60e51b815260040161048590612d62565b8281146105485760405162461bcd60e51b815260206004820152603a60248201527f4e756d626572206f6620646572697661746976657320616e64206f766572636f60448201527f6c6c61746572616c73206d757374206265207468652073616d650000000000006064820152608401610485565b600061056260008051602061344083398151915233611520565b905060005b8481101561069b57600086868381811061058357610583612da4565b90506020020160208101906105989190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b1580156105d557600080fd5b505afa1580156105e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060d9190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff16146106545760405162461bcd60e51b815260040161048590612ddd565b8315610664576106648282611bce565b6106868287878681811061067a5761067a612da4565b90506020020135611e40565b5050808061069390612e2a565b915050610567565b5050600160005550505050565b6106c060008051602061344083398151915233611520565b156108d857600260005414156106e85760405162461bcd60e51b815260040161048590612d2b565b6002600055848061070b5760405162461bcd60e51b815260040161048590612d62565b80841461072a5760405162461bcd60e51b815260040161048590612e45565b8082146107495760405162461bcd60e51b815260040161048590612ea2565b600061076360008051602061344083398151915233611520565b905060005b828110156108cb57600089898381811061078457610784612da4565b90506020020160208101906107999190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b1580156107d657600080fd5b505afa1580156107ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080e9190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff16146108555760405162461bcd60e51b815260040161048590612ddd565b8315610865576108658282611bce565b6108b6828a8a8681811061087b5761087b612da4565b905060200281019061088d9190612eff565b8a8a8881811061089f5761089f612da4565b90506020028101906108b19190612eff565b611f7a565b505080806108c390612e2a565b915050610768565b5050600160005550610ad0565b6108e061198e565b6108fc5760405162461bcd60e51b815260040161048590612f49565b6002600054141561091f5760405162461bcd60e51b815260040161048590612d2b565b600260005584806109425760405162461bcd60e51b815260040161048590612d62565b8084146109615760405162461bcd60e51b815260040161048590612e45565b8082146109805760405162461bcd60e51b815260040161048590612ea2565b600061099a60008051602061344083398151915233611520565b905060005b82811015610ac75760008989838181106109bb576109bb612da4565b90506020020160208101906109d09190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0d57600080fd5b505afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a459190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff1614610a8c5760405162461bcd60e51b815260040161048590612ddd565b8315610a9c57610a9c8282611bce565b610ab2828a8a8681811061087b5761087b612da4565b50508080610abf90612e2a565b91505061099f565b50506001600055505b505050505050565b610ae28282612085565b6000828152600260205260409020610afa9082611944565b505050565b610b0982826120ac565b6000828152600260205260409020610afa9082612126565b610b3960008051602061344083398151915233611520565b15610d015760026000541415610b615760405162461bcd60e51b815260040161048590612d2b565b600260005582610b835760405162461bcd60e51b815260040161048590612d62565b828114610ba25760405162461bcd60e51b815260040161048590612fa6565b6000610bbc60008051602061344083398151915233611520565b905060005b84811015610cf5576000868683818110610bdd57610bdd612da4565b9050602002016020810190610bf29190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b158015610c2f57600080fd5b505afa158015610c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c679190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff1614610cae5760405162461bcd60e51b815260040161048590612ddd565b8315610cbe57610cbe8282611bce565b610ce082878786818110610cd457610cd4612da4565b9050602002013561213b565b50508080610ced90612e2a565b915050610bc1565b50506001600055610ed0565b610d0961198e565b610d255760405162461bcd60e51b815260040161048590612f49565b60026000541415610d485760405162461bcd60e51b815260040161048590612d2b565b600260005582610d6a5760405162461bcd60e51b815260040161048590612d62565b828114610d895760405162461bcd60e51b815260040161048590612fa6565b6000610da360008051602061344083398151915233611520565b905060005b8481101561069b576000868683818110610dc457610dc4612da4565b9050602002016020810190610dd99190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b158015610e1657600080fd5b505afa158015610e2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4e9190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff1614610e955760405162461bcd60e51b815260040161048590612ddd565b8315610ea557610ea58282611bce565b610ebb82878786818110610cd457610cd4612da4565b50508080610ec890612e2a565b915050610da8565b50505050565b610f016040518060800160405280600081526020016060815260200160608152602001600081525090565b6001600160a01b03821660009081526006602090815260409182902082516080810184528154815260018201805485518186028101860190965280865291949293858101939290830182828015610f8157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f63575b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561100557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411610fc85790505b505050505081526020016003820154815250509050919050565b60608060008060066000866001600160a01b03166001600160a01b03168152602001908152602001600020905080600101816002018260030154828054806020026020016040519081016040528092919081815260200182805480156110ae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611090575b505050505092508180548060200260200160405190810160405280929190818152602001828054801561112c57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116110ef5790505b50505050509150935093509350509193909250565b61115960008051602061344083398151915233611520565b1561132357600260005414156111815760405162461bcd60e51b815260040161048590612d2b565b600260005582806111a45760405162461bcd60e51b815260040161048590612d62565b8082146111c35760405162461bcd60e51b815260040161048590613003565b60006111dd60008051602061344083398151915233611520565b905060005b828110156113165760008787838181106111fe576111fe612da4565b90506020020160208101906112139190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561125057600080fd5b505afa158015611264573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112889190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff16146112cf5760405162461bcd60e51b815260040161048590612ddd565b83156112df576112df8282611bce565b611301828888868181106112f5576112f5612da4565b905060200201356121f0565b5050808061130e90612e2a565b9150506111e2565b5050600160005550610ed0565b61132b61198e565b6113475760405162461bcd60e51b815260040161048590612f49565b6002600054141561136a5760405162461bcd60e51b815260040161048590612d2b565b6002600055828061138d5760405162461bcd60e51b815260040161048590612d62565b8082146113ac5760405162461bcd60e51b815260040161048590613003565b60006113c660008051602061344083398151915233611520565b905060005b828110156114f35760008787838181106113e7576113e7612da4565b90506020020160208101906113fc9190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561143957600080fd5b505afa15801561144d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114719190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff16146114b85760405162461bcd60e51b815260040161048590612ddd565b83156114c8576114c88282611bce565b6114de828888868181106112f5576112f5612da4565b505080806114eb90612e2a565b9150506113cb565b505060016000555050505050565b6000828152600260205260408120611519908361230b565b9392505050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61156360008051602061344083398151915233611520565b15611746576002600054141561158b5760405162461bcd60e51b815260040161048590612d2b565b600260005582806115ae5760405162461bcd60e51b815260040161048590612d62565b8082146115cd5760405162461bcd60e51b815260040161048590613060565b60006115e760008051602061344083398151915233611520565b905060005b8281101561131657600087878381811061160857611608612da4565b905060200201602081019061161d9190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561165a57600080fd5b505afa15801561166e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116929190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff16146116d95760405162461bcd60e51b815260040161048590612ddd565b83156116e9576116e98282611bce565b6117318989858181106116fe576116fe612da4565b90506020020160208101906117139190612a1a565b88888681811061172557611725612da4565b90506020020135612317565b5050808061173e90612e2a565b9150506115ec565b61174e61198e565b61176a5760405162461bcd60e51b815260040161048590612f49565b6002600054141561178d5760405162461bcd60e51b815260040161048590612d2b565b600260005582806117b05760405162461bcd60e51b815260040161048590612d62565b8082146117cf5760405162461bcd60e51b815260040161048590613060565b60006117e960008051602061344083398151915233611520565b905060005b828110156114f357600087878381811061180a5761180a612da4565b905060200201602081019061181f9190612a1a565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b15801561185c57600080fd5b505afa158015611870573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118949190612dba565b90507f000000000000000000000000000000000000000000000000000000000000000260ff168160ff16146118db5760405162461bcd60e51b815260040161048590612ddd565b83156118eb576118eb8282611bce565b6119008989858181106116fe576116fe612da4565b5050808061190d90612e2a565b9150506117ee565b600081815260026020526040812061041f90612445565b610b09828261244f565b6119408282612476565b5050565b6000611519836001600160a01b0384166124e1565b60006001600160e01b03198216637965db0b60e01b148061041f57506301ffc9a760e01b6001600160e01b031983161461041f565b6040516302abf57960e61b815270466163746f727956657273696f6e696e6760781b600482015260009081906001600160a01b037f0000000000000000000000003b05b902fe763ad87aa755fab70f86c76bf331f4169063aafd5e409060240160206040518083038186803b158015611a0657600080fd5b505afa158015611a1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3e91906130bd565b604051636d2721a360e11b81527153656c664d696e74696e67466163746f727960701b60048201529091506000906001600160a01b0383169063da4e43469060240160206040518083038186803b158015611a9857600080fd5b505afa158015611aac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad09190612dba565b60ff1690506000805b82821015611bb557604051636839980160e11b81527153656c664d696e74696e67466163746f727960701b600482015260ff821660248201526001600160a01b0385169063d07330029060440160206040518083038186803b158015611b3e57600080fd5b505afa925050508015611b6e575060408051601f3d908101601f19168201909252611b6b918101906130bd565b60015b611b7757611ba3565b336001600160a01b0382161415611b945760019550505050505090565b82611b9e81612e2a565b935050505b80611bad816130da565b915050611ad9565b5080821415611bc8576000935050505090565b50505090565b6040516302abf57960e61b81527253656c664d696e74696e67526567697374727960681b60048201526000907f0000000000000000000000003b05b902fe763ad87aa755fab70f86c76bf331f46001600160a01b03169063aafd5e409060240160206040518083038186803b158015611c4657600080fd5b505afa158015611c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7e91906130bd565b9050806001600160a01b03166321ff88ca846001600160a01b03166336815bb76040518163ffffffff1660e01b815260040160006040518083038186803b158015611cc857600080fd5b505afa158015611cdc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d04919081019061313c565b856001600160a01b031663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b158015611d3d57600080fd5b505afa158015611d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7591906130bd565b85876040518563ffffffff1660e01b8152600401611d969493929190613215565b60206040518083038186803b158015611dae57600080fd5b505afa158015611dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de69190613254565b610afa5760405162461bcd60e51b815260206004820152602560248201527f53656c662d6d696e74696e672064657269766174697665206e6f7420726567696044820152641cdd1c995960da1b6064820152608401610485565b6001600160a01b038216600090815260056020526040902054811415611eb35760405162461bcd60e51b815260206004820152602260248201527f436f6c6c61746572616c20726571756972656d656e74206973207468652073616044820152616d6560f01b6064820152608401610485565b670de0b6b3a76400008111611f215760405162461bcd60e51b815260206004820152602e60248201527f4f766572636f6c6c61746572616c69736174696f6e206d75737420626520626960448201526d67676572207468616e203130302560901b6064820152608401610485565b6001600160a01b03821660008181526005602052604090819020839055517f2e5a927e7e48046893644d70eabc2a235afed3c32c5470769d400e742e262ed390611f6e9084815260200190565b60405180910390a25050565b6000805b8281101561207c57838382818110611f9857611f98612da4565b9050602002016020810190611fad919061328f565b611fbd9063ffffffff16836132aa565b6001600160a01b0388166000908152600660205260409020909250611fe69060010187876128b4565b506001600160a01b038716600090815260066020526040902061200d906002018585612917565b506001600160a01b03871660008181526006602052604090819020600301849055517fd630d6daed151d020915cc030e6b4fde7e3fda228da9e53d79b3e0c259e9c7a8906120629089908990899089906132c2565b60405180910390a28061207481612e2a565b915050611f7e565b50505050505050565b600082815260016020819052604090912001546120a28133612530565b610afa8383612476565b6001600160a01b038116331461211c5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610485565b6119408282612594565b6000611519836001600160a01b0384166125fb565b6001600160a01b0382166000908152600360205260409020548114156121a35760405162461bcd60e51b815260206004820152601b60248201527f436170206d696e7420616d6f756e74206973207468652073616d6500000000006044820152606401610485565b6001600160a01b03821660008181526003602052604090819020839055517f88b73fe96f35e95dbb00be55f30de5fea08993a40983d17cd58ea2994cf7464490611f6e9084815260200190565b6001600160a01b0382166000908152600660205260409020548114156122585760405162461bcd60e51b815260206004820152601a60248201527f4665652070657263656e74616765206973207468652073616d650000000000006044820152606401610485565b670de0b6b3a76400008111156122be5760405162461bcd60e51b815260206004820152602560248201527f4665652070657263656e74616765206d757374206265206c657373207468616e604482015264203130302560d81b6064820152608401610485565b6001600160a01b03821660008181526006602052604090819020839055517f7186c144be98cbb7e0ef7eab9175ac4b810da9d3b1c187de9ba64ec2152e65ce90611f6e9084815260200190565b600061151983836126ee565b6001600160a01b03821660009081526004602052604090205481141561237f5760405162461bcd60e51b815260206004820152601e60248201527f4c69717569646174696f6e20726577617264206973207468652073616d6500006044820152606401610485565b6000811180156123965750670de0b6b3a764000081105b6123f85760405162461bcd60e51b815260206004820152602d60248201527f4c69717569646174696f6e20726577617264206d75737420626520626574776560448201526c656e203020616e64203130302560981b6064820152608401610485565b6001600160a01b03821660008181526004602052604090819020839055517fa7401927a70fe8f49342e51379925b6a05fd0e08f00b0295dbf852e53fe1268390611f6e9084815260200190565b600061041f825490565b6000828152600160208190526040909120015461246c8133612530565b610afa8383612594565b6124808282611520565b6119405760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008181526001830160205260408120546125285750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561041f565b50600061041f565b61253a8282611520565b61194057612552816001600160a01b03166014612718565b61255d836020612718565b60405160200161256e929190613354565b60408051601f198184030181529082905262461bcd60e51b8252610485916004016133c9565b61259e8282611520565b156119405760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600081815260018301602052604081205480156126e457600061261f6001836133dc565b8554909150600090612633906001906133dc565b905081811461269857600086600001828154811061265357612653612da4565b906000526020600020015490508087600001848154811061267657612676612da4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806126a9576126a96133f3565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061041f565b600091505061041f565b600082600001828154811061270557612705612da4565b9060005260206000200154905092915050565b60606000612727836002613409565b6127329060026132aa565b67ffffffffffffffff81111561274a5761274a6130fa565b6040519080825280601f01601f191660200182016040528015612774576020820181803683370190505b509050600360fc1b8160008151811061278f5761278f612da4565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106127be576127be612da4565b60200101906001600160f81b031916908160001a90535060006127e2846002613409565b6127ed9060016132aa565b90505b6001811115612865576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061282157612821612da4565b1a60f81b82828151811061283757612837612da4565b60200101906001600160f81b031916908160001a90535060049490941c9361285e81613428565b90506127f0565b5083156115195760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610485565b828054828255906000526020600020908101928215612907579160200282015b828111156129075781546001600160a01b0319166001600160a01b038435161782556020909201916001909101906128d4565b506129139291506129c3565b5090565b828054828255906000526020600020906007016008900481019282156129075791602002820160005b8382111561298a57833563ffffffff1683826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302612940565b80156129ba5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261298a565b50506129139291505b5b8082111561291357600081556001016129c4565b6000602082840312156129ea57600080fd5b81356001600160e01b03198116811461151957600080fd5b6001600160a01b0381168114612a1757600080fd5b50565b600060208284031215612a2c57600080fd5b813561151981612a02565b60008083601f840112612a4957600080fd5b50813567ffffffffffffffff811115612a6157600080fd5b6020830191508360208260051b8501011115612a7c57600080fd5b9250929050565b60008060008060408587031215612a9957600080fd5b843567ffffffffffffffff80821115612ab157600080fd5b612abd88838901612a37565b90965094506020870135915080821115612ad657600080fd5b50612ae387828801612a37565b95989497509550505050565b600060208284031215612b0157600080fd5b5035919050565b60008060008060008060608789031215612b2157600080fd5b863567ffffffffffffffff80821115612b3957600080fd5b612b458a838b01612a37565b90985096506020890135915080821115612b5e57600080fd5b612b6a8a838b01612a37565b90965094506040890135915080821115612b8357600080fd5b50612b9089828a01612a37565b979a9699509497509295939492505050565b60008060408385031215612bb557600080fd5b823591506020830135612bc781612a02565b809150509250929050565b600081518084526020808501945080840160005b83811015612c0857815163ffffffff1687529582019590820190600101612be6565b509495945050505050565b60208082528251828201528281015160806040840152805160a0840181905260009291820190839060c08601905b80831015612c6a5783516001600160a01b03168252928401926001929092019190840190612c41565b506040870151868203601f190160608801529350612c888185612bd2565b9350505050606084015160808401528091505092915050565b606080825284519082018190526000906020906080840190828801845b82811015612ce35781516001600160a01b031684529284019290840190600101612cbe565b50505083810382850152612cf78187612bd2565b92505050826040830152949350505050565b60008060408385031215612d1c57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526022908201527f4e6f2073656c662d6d696e74696e672064657269766174697665732070617373604082015261195960f21b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612dcc57600080fd5b815160ff8116811461151957600080fd5b6020808252601a908201527f57726f6e672073656c662d6d696e74696e672076657273696f6e000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600019821415612e3e57612e3e612e14565b5060010190565b60208082526039908201527f4d69736d61746368206265747765656e20646572697661746976657320746f2060408201527f75706461746520616e642066656520726563697069656e747300000000000000606082015260800190565b6020808252603a908201527f4d69736d61746368206265747765656e20646572697661746976657320746f2060408201527f75706461746520616e64206665652070726f706f7274696f6e73000000000000606082015260800190565b6000808335601e19843603018112612f1657600080fd5b83018035915067ffffffffffffffff821115612f3157600080fd5b6020019150600581901b3603821315612a7c57600080fd5b60208082526037908201527f53656e646572206d75737420626520746865206d61696e7461696e6572206f7260408201527f20612073656c662d6d696e74696e6720666163746f7279000000000000000000606082015260800190565b6020808252603b908201527f4e756d626572206f6620646572697661746976657320616e64206d696e74206360408201527f617020616d6f756e7473206d757374206265207468652073616d650000000000606082015260800190565b6020808252603a908201527f4e756d626572206f6620646572697661746976657320616e642066656520706560408201527f7263656e7461676573206d757374206265207468652073616d65000000000000606082015260800190565b6020808252603e908201527f4d69736d61746368206265747765656e20646572697661746976657320746f2060408201527f75706461746520616e64206c69717569646174696f6e20726577617264730000606082015260800190565b6000602082840312156130cf57600080fd5b815161151981612a02565b600060ff821660ff8114156130f1576130f1612e14565b60010192915050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561312b578181015183820152602001613113565b83811115610ed05750506000910152565b60006020828403121561314e57600080fd5b815167ffffffffffffffff8082111561316657600080fd5b818401915084601f83011261317a57600080fd5b81518181111561318c5761318c6130fa565b604051601f8201601f19908116603f011681019083821181831017156131b4576131b46130fa565b816040528281528760208487010111156131cd57600080fd5b6131de836020830160208801613110565b979650505050505050565b60008151808452613201816020860160208601613110565b601f01601f19169290920160200192915050565b60808152600061322860808301876131e9565b6001600160a01b03958616602084015260ff949094166040830152509216606090920191909152919050565b60006020828403121561326657600080fd5b8151801515811461151957600080fd5b803563ffffffff8116811461328a57600080fd5b919050565b6000602082840312156132a157600080fd5b61151982613276565b600082198211156132bd576132bd612e14565b500190565b6040808252810184905260008560608301825b878110156133055782356132e881612a02565b6001600160a01b03168252602092830192909101906001016132d5565b5083810360208581019190915285825291508590820160005b868110156133475763ffffffff61333484613276565b168252918301919083019060010161331e565b5098975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161338c816017850160208801613110565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516133bd816028840160208801613110565b01602801949350505050565b60208152600061151960208301846131e9565b6000828210156133ee576133ee612e14565b500390565b634e487b7160e01b600052603160045260246000fd5b600081600019048311821515161561342357613423612e14565b500290565b60008161343757613437612e14565b50600019019056fe126303c860ea810f85e857ad8768056e2eebc24b7796655ff3107e4af18e3f1ea2646970667358221220099175714d5c93d09880cf01767e7c55fd14f18a44a7c83d5725f1f5076837ef64736f6c63430008090033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000003b05b902fe763ad87aa755fab70f86c76bf331f40000000000000000000000008232a29a3744d1c44676f6a198383b214c0b238100000000000000000000000052b063ab1a11d56ac5b2e84bdd59e11920b390b70000000000000000000000000000000000000000000000000000000000000002

-----Decoded View---------------
Arg [0] : _synthereumFinder (address): 0x3b05B902Fe763AD87Aa755Fab70F86c76Bf331F4
Arg [1] : roles (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : version (uint8): 2

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000003b05b902fe763ad87aa755fab70f86c76bf331f4
Arg [1] : 0000000000000000000000008232a29a3744d1c44676f6a198383b214c0b2381
Arg [2] : 00000000000000000000000052b063ab1a11d56ac5b2e84bdd59e11920b390b7
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000002


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.