Contract Overview
Balance:
122.125100999992873973 Ether
More Info
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
CollateralEth
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-01-13 */ /* ____ __ __ __ _ / __/__ __ ___ / /_ / / ___ / /_ (_)__ __ _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ / /___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\ /___/ * Synthetix: CollateralEth.sol * * Latest source (may be newer): https://github.com/Synthetixio/synthetix/blob/master/contracts/CollateralEth.sol * Docs: https://docs.synthetix.io/contracts/CollateralEth * * Contract Dependencies: * - Collateral * - IAddressResolver * - ICollateralEth * - ICollateralLoan * - MixinResolver * - MixinSystemSettings * - Owned * - ReentrancyGuard * - State * Libraries: * - SafeDecimalMath * - SafeMath * * MIT License * =========== * * Copyright (c) 2021 Synthetix * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ pragma solidity ^0.5.16; // https://docs.synthetix.io/contracts/source/contracts/owned contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { _onlyOwner(); _; } function _onlyOwner() private view { require(msg.sender == owner, "Only the contract owner may perform this action"); } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // https://docs.synthetix.io/contracts/source/interfaces/iaddressresolver interface IAddressResolver { function getAddress(bytes32 name) external view returns (address); function getSynth(bytes32 key) external view returns (address); function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address); } // https://docs.synthetix.io/contracts/source/interfaces/isynth interface ISynth { // Views function currencyKey() external view returns (bytes32); function transferableSynths(address account) external view returns (uint); // Mutative functions function transferAndSettle(address to, uint value) external returns (bool); function transferFromAndSettle( address from, address to, uint value ) external returns (bool); // Restricted: used internally to Synthetix function burn(address account, uint amount) external; function issue(address account, uint amount) external; } // https://docs.synthetix.io/contracts/source/interfaces/iissuer interface IIssuer { // Views function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid); function availableCurrencyKeys() external view returns (bytes32[] memory); function availableSynthCount() external view returns (uint); function availableSynths(uint index) external view returns (ISynth); function canBurnSynths(address account) external view returns (bool); function collateral(address account) external view returns (uint); function collateralisationRatio(address issuer) external view returns (uint); function collateralisationRatioAndAnyRatesInvalid(address _issuer) external view returns (uint cratio, bool anyRateIsInvalid); function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint debtBalance); function issuanceRatio() external view returns (uint); function lastIssueEvent(address account) external view returns (uint); function maxIssuableSynths(address issuer) external view returns (uint maxIssuable); function minimumStakeTime() external view returns (uint); function remainingIssuableSynths(address issuer) external view returns ( uint maxIssuable, uint alreadyIssued, uint totalSystemDebt ); function synths(bytes32 currencyKey) external view returns (ISynth); function getSynths(bytes32[] calldata currencyKeys) external view returns (ISynth[] memory); function synthsByAddress(address synthAddress) external view returns (bytes32); function totalIssuedSynths(bytes32 currencyKey, bool excludeEtherCollateral) external view returns (uint); function transferableSynthetixAndAnyRateIsInvalid(address account, uint balance) external view returns (uint transferable, bool anyRateIsInvalid); // Restricted: used internally to Synthetix function issueSynths(address from, uint amount) external; function issueSynthsOnBehalf( address issueFor, address from, uint amount ) external; function issueMaxSynths(address from) external; function issueMaxSynthsOnBehalf(address issueFor, address from) external; function burnSynths(address from, uint amount) external; function burnSynthsOnBehalf( address burnForAddress, address from, uint amount ) external; function burnSynthsToTarget(address from) external; function burnSynthsToTargetOnBehalf(address burnForAddress, address from) external; function liquidateDelinquentAccount( address account, uint susdAmount, address liquidator ) external returns (uint totalRedeemed, uint amountToLiquidate); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/addressresolver contract AddressResolver is Owned, IAddressResolver { mapping(bytes32 => address) public repository; constructor(address _owner) public Owned(_owner) {} /* ========== RESTRICTED FUNCTIONS ========== */ function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner { require(names.length == destinations.length, "Input lengths must match"); for (uint i = 0; i < names.length; i++) { bytes32 name = names[i]; address destination = destinations[i]; repository[name] = destination; emit AddressImported(name, destination); } } /* ========= PUBLIC FUNCTIONS ========== */ function rebuildCaches(MixinResolver[] calldata destinations) external { for (uint i = 0; i < destinations.length; i++) { destinations[i].rebuildCache(); } } /* ========== VIEWS ========== */ function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) { for (uint i = 0; i < names.length; i++) { if (repository[names[i]] != destinations[i]) { return false; } } return true; } function getAddress(bytes32 name) external view returns (address) { return repository[name]; } function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address) { address _foundAddress = repository[name]; require(_foundAddress != address(0), reason); return _foundAddress; } function getSynth(bytes32 key) external view returns (address) { IIssuer issuer = IIssuer(repository["Issuer"]); require(address(issuer) != address(0), "Cannot find Issuer address"); return address(issuer.synths(key)); } /* ========== EVENTS ========== */ event AddressImported(bytes32 name, address destination); } // solhint-disable payable-fallback // https://docs.synthetix.io/contracts/source/contracts/readproxy contract ReadProxy is Owned { address public target; constructor(address _owner) public Owned(_owner) {} function setTarget(address _target) external onlyOwner { target = _target; emit TargetUpdated(target); } function() external { // The basics of a proxy read call // Note that msg.sender in the underlying will always be the address of this contract. assembly { calldatacopy(0, 0, calldatasize) // Use of staticcall - this will revert if the underlying function mutates state let result := staticcall(gas, sload(target_slot), 0, calldatasize, 0, 0) returndatacopy(0, 0, returndatasize) if iszero(result) { revert(0, returndatasize) } return(0, returndatasize) } } event TargetUpdated(address newTarget); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/mixinresolver contract MixinResolver { AddressResolver public resolver; mapping(bytes32 => address) private addressCache; constructor(address _resolver) internal { resolver = AddressResolver(_resolver); } /* ========== INTERNAL FUNCTIONS ========== */ function combineArrays(bytes32[] memory first, bytes32[] memory second) internal pure returns (bytes32[] memory combination) { combination = new bytes32[](first.length + second.length); for (uint i = 0; i < first.length; i++) { combination[i] = first[i]; } for (uint j = 0; j < second.length; j++) { combination[first.length + j] = second[j]; } } /* ========== PUBLIC FUNCTIONS ========== */ // Note: this function is public not external in order for it to be overridden and invoked via super in subclasses function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {} function rebuildCache() public { bytes32[] memory requiredAddresses = resolverAddressesRequired(); // The resolver must call this function whenver it updates its state for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // Note: can only be invoked once the resolver has all the targets needed added address destination = resolver.requireAndGetAddress( name, string(abi.encodePacked("Resolver missing target: ", name)) ); addressCache[name] = destination; emit CacheUpdated(name, destination); } } /* ========== VIEWS ========== */ function isResolverCached() external view returns (bool) { bytes32[] memory requiredAddresses = resolverAddressesRequired(); for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // false if our cache is invalid or if the resolver doesn't have the required address if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) { return false; } } return true; } /* ========== INTERNAL FUNCTIONS ========== */ function requireAndGetAddress(bytes32 name) internal view returns (address) { address _foundAddress = addressCache[name]; require(_foundAddress != address(0), string(abi.encodePacked("Missing address: ", name))); return _foundAddress; } /* ========== EVENTS ========== */ event CacheUpdated(bytes32 name, address destination); } // https://docs.synthetix.io/contracts/source/interfaces/iflexiblestorage interface IFlexibleStorage { // Views function getUIntValue(bytes32 contractName, bytes32 record) external view returns (uint); function getUIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (uint[] memory); function getIntValue(bytes32 contractName, bytes32 record) external view returns (int); function getIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (int[] memory); function getAddressValue(bytes32 contractName, bytes32 record) external view returns (address); function getAddressValues(bytes32 contractName, bytes32[] calldata records) external view returns (address[] memory); function getBoolValue(bytes32 contractName, bytes32 record) external view returns (bool); function getBoolValues(bytes32 contractName, bytes32[] calldata records) external view returns (bool[] memory); function getBytes32Value(bytes32 contractName, bytes32 record) external view returns (bytes32); function getBytes32Values(bytes32 contractName, bytes32[] calldata records) external view returns (bytes32[] memory); // Mutative functions function deleteUIntValue(bytes32 contractName, bytes32 record) external; function deleteIntValue(bytes32 contractName, bytes32 record) external; function deleteAddressValue(bytes32 contractName, bytes32 record) external; function deleteBoolValue(bytes32 contractName, bytes32 record) external; function deleteBytes32Value(bytes32 contractName, bytes32 record) external; function setUIntValue( bytes32 contractName, bytes32 record, uint value ) external; function setUIntValues( bytes32 contractName, bytes32[] calldata records, uint[] calldata values ) external; function setIntValue( bytes32 contractName, bytes32 record, int value ) external; function setIntValues( bytes32 contractName, bytes32[] calldata records, int[] calldata values ) external; function setAddressValue( bytes32 contractName, bytes32 record, address value ) external; function setAddressValues( bytes32 contractName, bytes32[] calldata records, address[] calldata values ) external; function setBoolValue( bytes32 contractName, bytes32 record, bool value ) external; function setBoolValues( bytes32 contractName, bytes32[] calldata records, bool[] calldata values ) external; function setBytes32Value( bytes32 contractName, bytes32 record, bytes32 value ) external; function setBytes32Values( bytes32 contractName, bytes32[] calldata records, bytes32[] calldata values ) external; } // Internal references // https://docs.synthetix.io/contracts/source/contracts/mixinsystemsettings contract MixinSystemSettings is MixinResolver { bytes32 internal constant SETTING_CONTRACT_NAME = "SystemSettings"; bytes32 internal constant SETTING_WAITING_PERIOD_SECS = "waitingPeriodSecs"; bytes32 internal constant SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR = "priceDeviationThresholdFactor"; bytes32 internal constant SETTING_ISSUANCE_RATIO = "issuanceRatio"; bytes32 internal constant SETTING_FEE_PERIOD_DURATION = "feePeriodDuration"; bytes32 internal constant SETTING_TARGET_THRESHOLD = "targetThreshold"; bytes32 internal constant SETTING_LIQUIDATION_DELAY = "liquidationDelay"; bytes32 internal constant SETTING_LIQUIDATION_RATIO = "liquidationRatio"; bytes32 internal constant SETTING_LIQUIDATION_PENALTY = "liquidationPenalty"; bytes32 internal constant SETTING_RATE_STALE_PERIOD = "rateStalePeriod"; bytes32 internal constant SETTING_EXCHANGE_FEE_RATE = "exchangeFeeRate"; bytes32 internal constant SETTING_MINIMUM_STAKE_TIME = "minimumStakeTime"; bytes32 internal constant SETTING_AGGREGATOR_WARNING_FLAGS = "aggregatorWarningFlags"; bytes32 internal constant SETTING_TRADING_REWARDS_ENABLED = "tradingRewardsEnabled"; bytes32 internal constant SETTING_DEBT_SNAPSHOT_STALE_TIME = "debtSnapshotStaleTime"; bytes32 internal constant SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT = "crossDomainDepositGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT = "crossDomainEscrowGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT = "crossDomainRewardGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT = "crossDomainWithdrawalGasLimit"; bytes32 internal constant CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage"; enum CrossDomainMessageGasLimits {Deposit, Escrow, Reward, Withdrawal} constructor(address _resolver) internal MixinResolver(_resolver) {} function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { addresses = new bytes32[](1); addresses[0] = CONTRACT_FLEXIBLESTORAGE; } function flexibleStorage() internal view returns (IFlexibleStorage) { return IFlexibleStorage(requireAndGetAddress(CONTRACT_FLEXIBLESTORAGE)); } function _getGasLimitSetting(CrossDomainMessageGasLimits gasLimitType) internal pure returns (bytes32) { if (gasLimitType == CrossDomainMessageGasLimits.Deposit) { return SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Escrow) { return SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Reward) { return SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Withdrawal) { return SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT; } else { revert("Unknown gas limit type"); } } function getCrossDomainMessageGasLimit(CrossDomainMessageGasLimits gasLimitType) internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, _getGasLimitSetting(gasLimitType)); } function getTradingRewardsEnabled() internal view returns (bool) { return flexibleStorage().getBoolValue(SETTING_CONTRACT_NAME, SETTING_TRADING_REWARDS_ENABLED); } function getWaitingPeriodSecs() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_WAITING_PERIOD_SECS); } function getPriceDeviationThresholdFactor() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR); } function getIssuanceRatio() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ISSUANCE_RATIO); } function getFeePeriodDuration() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_FEE_PERIOD_DURATION); } function getTargetThreshold() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_TARGET_THRESHOLD); } function getLiquidationDelay() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_DELAY); } function getLiquidationRatio() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_RATIO); } function getLiquidationPenalty() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_PENALTY); } function getRateStalePeriod() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_RATE_STALE_PERIOD); } function getExchangeFeeRate(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_EXCHANGE_FEE_RATE, currencyKey)) ); } function getMinimumStakeTime() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_MINIMUM_STAKE_TIME); } function getAggregatorWarningFlags() internal view returns (address) { return flexibleStorage().getAddressValue(SETTING_CONTRACT_NAME, SETTING_AGGREGATOR_WARNING_FLAGS); } function getDebtSnapshotStaleTime() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_DEBT_SNAPSHOT_STALE_TIME); } } pragma experimental ABIEncoderV2; interface ICollateralLoan { struct Loan { // ID for the loan uint id; // Acccount that created the loan address payable account; // Amount of collateral deposited uint collateral; // The synth that was borowed bytes32 currency; // Amount of synths borrowed uint amount; // Indicates if the position was short sold bool short; // interest amounts accrued uint accruedInterest; // last interest index uint interestIndex; // time of last interaction. uint lastInteraction; } } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @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) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @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) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @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) { // 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-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts 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) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // Libraries // https://docs.synthetix.io/contracts/source/libraries/safedecimalmath library SafeDecimalMath { using SafeMath for uint; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint public constant UNIT = 10**uint(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint x, uint y) internal pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return x.mul(y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint x, uint y) internal pure returns (uint) { /* Reintroduce the UNIT factor that will be divided out by y. */ return x.mul(UNIT).div(y); } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } } // Inheritance // https://docs.synthetix.io/contracts/source/contracts/state contract State is Owned { // the address of the contract that can modify variables // this can only be changed by the owner of this contract address public associatedContract; constructor(address _associatedContract) internal { // This contract is abstract, and thus cannot be instantiated directly require(owner != address(0), "Owner must be set"); associatedContract = _associatedContract; emit AssociatedContractUpdated(_associatedContract); } /* ========== SETTERS ========== */ // Change the associated contract to a new address function setAssociatedContract(address _associatedContract) external onlyOwner { associatedContract = _associatedContract; emit AssociatedContractUpdated(_associatedContract); } /* ========== MODIFIERS ========== */ modifier onlyAssociatedContract { require(msg.sender == associatedContract, "Only the associated contract can perform this action"); _; } /* ========== EVENTS ========== */ event AssociatedContractUpdated(address associatedContract); } // Inheritance // Libraries contract CollateralState is Owned, State, ICollateralLoan { using SafeMath for uint; using SafeDecimalMath for uint; mapping(address => Loan[]) public loans; constructor(address _owner, address _associatedContract) public Owned(_owner) State(_associatedContract) {} /* ========== VIEWS ========== */ // If we do not find the loan, this returns a struct with 0'd values. function getLoan(address account, uint256 loanID) external view returns (Loan memory) { Loan[] memory accountLoans = loans[account]; for (uint i = 0; i < accountLoans.length; i++) { if (accountLoans[i].id == loanID) { return (accountLoans[i]); } } } function getNumLoans(address account) external view returns (uint numLoans) { return loans[account].length; } /* ========== MUTATIVE FUNCTIONS ========== */ function createLoan(Loan memory loan) public onlyAssociatedContract { loans[loan.account].push(loan); } function updateLoan(Loan memory loan) public onlyAssociatedContract { Loan[] storage accountLoans = loans[loan.account]; for (uint i = 0; i < accountLoans.length; i++) { if (accountLoans[i].id == loan.id) { loans[loan.account][i] = loan; } } } } interface ICollateralManager { // Manager information function hasCollateral(address collateral) external view returns (bool); function isSynthManaged(bytes32 currencyKey) external view returns (bool); // State information function long(bytes32 synth) external view returns (uint amount); function short(bytes32 synth) external view returns (uint amount); function totalLong() external view returns (uint susdValue, bool anyRateIsInvalid); function totalShort() external view returns (uint susdValue, bool anyRateIsInvalid); function getBorrowRate() external view returns (uint borrowRate, bool anyRateIsInvalid); function getShortRate(bytes32 synth) external view returns (uint shortRate, bool rateIsInvalid); function getRatesAndTime(uint index) external view returns ( uint entryRate, uint lastRate, uint lastUpdated, uint newIndex ); function getShortRatesAndTime(bytes32 currency, uint index) external view returns ( uint entryRate, uint lastRate, uint lastUpdated, uint newIndex ); function exceedsDebtLimit(uint amount, bytes32 currency) external view returns (bool canIssue, bool anyRateIsInvalid); function areSynthsAndCurrenciesSet(bytes32[] calldata requiredSynthNamesInResolver, bytes32[] calldata synthKeys) external view returns (bool); function areShortableSynthsSet(bytes32[] calldata requiredSynthNamesInResolver, bytes32[] calldata synthKeys) external view returns (bool); // Loans function getNewLoanId() external returns (uint id); // Manager mutative function addCollaterals(address[] calldata collaterals) external; function removeCollaterals(address[] calldata collaterals) external; function addSynths(bytes32[] calldata synthNamesInResolver, bytes32[] calldata synthKeys) external; function removeSynths(bytes32[] calldata synths, bytes32[] calldata synthKeys) external; function addShortableSynths(bytes32[2][] calldata requiredSynthAndInverseNamesInResolver, bytes32[] calldata synthKeys) external; function removeShortableSynths(bytes32[] calldata synths) external; // State mutative function updateBorrowRates(uint rate) external; function updateShortRates(bytes32 currency, uint rate) external; function incrementLongs(bytes32 synth, uint amount) external; function decrementLongs(bytes32 synth, uint amount) external; function incrementShorts(bytes32 synth, uint amount) external; function decrementShorts(bytes32 synth, uint amount) external; } // https://docs.synthetix.io/contracts/source/interfaces/isystemstatus interface ISystemStatus { struct Status { bool canSuspend; bool canResume; } struct Suspension { bool suspended; // reason is an integer code, // 0 => no reason, 1 => upgrading, 2+ => defined by system usage uint248 reason; } // Views function accessControl(bytes32 section, address account) external view returns (bool canSuspend, bool canResume); function requireSystemActive() external view; function requireIssuanceActive() external view; function requireExchangeActive() external view; function requireSynthActive(bytes32 currencyKey) external view; function requireSynthsActive(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view; function synthSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason); // Restricted functions function suspendSynth(bytes32 currencyKey, uint256 reason) external; function updateAccessControl( bytes32 section, address account, bool canSuspend, bool canResume ) external; } // https://docs.synthetix.io/contracts/source/interfaces/ifeepool interface IFeePool { // Views // solhint-disable-next-line func-name-mixedcase function FEE_ADDRESS() external view returns (address); function feesAvailable(address account) external view returns (uint, uint); function feePeriodDuration() external view returns (uint); function isFeesClaimable(address account) external view returns (bool); function targetThreshold() external view returns (uint); function totalFeesAvailable() external view returns (uint); function totalRewardsAvailable() external view returns (uint); // Mutative Functions function claimFees() external returns (bool); function claimOnBehalf(address claimingForAddress) external returns (bool); function closeCurrentFeePeriod() external; // Restricted: used internally to Synthetix function appendAccountIssuanceRecord( address account, uint lockedAmount, uint debtEntryIndex ) external; function recordFeePaid(uint sUSDAmount) external; function setRewardsToDistribute(uint amount) external; } // https://docs.synthetix.io/contracts/source/interfaces/ierc20 interface IERC20 { // ERC20 Optional Views function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); // Views function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); // Mutative functions function transfer(address to, uint value) external returns (bool); function approve(address spender, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); // Events event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } // https://docs.synthetix.io/contracts/source/interfaces/iexchangerates interface IExchangeRates { // Structs struct RateAndUpdatedTime { uint216 rate; uint40 time; } struct InversePricing { uint entryPoint; uint upperLimit; uint lowerLimit; bool frozenAtUpperLimit; bool frozenAtLowerLimit; } // Views function aggregators(bytes32 currencyKey) external view returns (address); function aggregatorWarningFlags() external view returns (address); function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool); function canFreezeRate(bytes32 currencyKey) external view returns (bool); function currentRoundForRate(bytes32 currencyKey) external view returns (uint); function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint value); function effectiveValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns ( uint value, uint sourceRate, uint destinationRate ); function effectiveValueAtRound( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, uint roundIdForSrc, uint roundIdForDest ) external view returns (uint value); function getCurrentRoundId(bytes32 currencyKey) external view returns (uint); function getLastRoundIdBeforeElapsedSecs( bytes32 currencyKey, uint startingRoundId, uint startingTimestamp, uint timediff ) external view returns (uint); function inversePricing(bytes32 currencyKey) external view returns ( uint entryPoint, uint upperLimit, uint lowerLimit, bool frozenAtUpperLimit, bool frozenAtLowerLimit ); function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256); function oracle() external view returns (address); function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time); function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time); function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid); function rateForCurrency(bytes32 currencyKey) external view returns (uint); function rateIsFlagged(bytes32 currencyKey) external view returns (bool); function rateIsFrozen(bytes32 currencyKey) external view returns (bool); function rateIsInvalid(bytes32 currencyKey) external view returns (bool); function rateIsStale(bytes32 currencyKey) external view returns (bool); function rateStalePeriod() external view returns (uint); function ratesAndUpdatedTimeForCurrencyLastNRounds(bytes32 currencyKey, uint numRounds) external view returns (uint[] memory rates, uint[] memory times); function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory rates, bool anyRateInvalid); function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory); // Mutative functions function freezeRate(bytes32 currencyKey) external; } interface IVirtualSynth { // Views function balanceOfUnderlying(address account) external view returns (uint); function rate() external view returns (uint); function readyToSettle() external view returns (bool); function secsLeftInWaitingPeriod() external view returns (uint); function settled() external view returns (bool); function synth() external view returns (ISynth); // Mutative functions function settle(address account) external; } // https://docs.synthetix.io/contracts/source/interfaces/iexchanger interface IExchanger { // Views function calculateAmountAfterSettlement( address from, bytes32 currencyKey, uint amount, uint refunded ) external view returns (uint amountAfterSettlement); function isSynthRateInvalid(bytes32 currencyKey) external view returns (bool); function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) external view returns (uint); function settlementOwing(address account, bytes32 currencyKey) external view returns ( uint reclaimAmount, uint rebateAmount, uint numEntries ); function hasWaitingPeriodOrSettlementOwing(address account, bytes32 currencyKey) external view returns (bool); function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint exchangeFeeRate); function getAmountsForExchange( uint sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns ( uint amountReceived, uint fee, uint exchangeFeeRate ); function priceDeviationThresholdFactor() external view returns (uint); function waitingPeriodSecs() external view returns (uint); // Mutative functions function exchange( address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress ) external returns (uint amountReceived); function exchangeOnBehalf( address exchangeForAddress, address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external returns (uint amountReceived); function exchangeWithTracking( address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, address originator, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeOnBehalfWithTracking( address exchangeForAddress, address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address originator, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeWithVirtual( address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, bytes32 trackingCode ) external returns (uint amountReceived, IVirtualSynth vSynth); function settle(address from, bytes32 currencyKey) external returns ( uint reclaimed, uint refunded, uint numEntries ); function setLastExchangeRateForSynth(bytes32 currencyKey, uint rate) external; function suspendSynthWithInvalidRate(bytes32 currencyKey) external; } // https://docs.synthetix.io/contracts/source/interfaces/istakingrewards interface IShortingRewards { // Views function lastTimeRewardApplicable() external view returns (uint256); function rewardPerToken() external view returns (uint256); function earned(address account) external view returns (uint256); function getRewardForDuration() external view returns (uint256); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); // Mutative function enrol(address account, uint256 amount) external; function withdraw(address account, uint256 amount) external; function getReward(address account) external; function exit(address account) external; } // Inheritance // Libraries // Internal references contract Collateral is ICollateralLoan, Owned, MixinSystemSettings { /* ========== LIBRARIES ========== */ using SafeMath for uint; using SafeDecimalMath for uint; /* ========== CONSTANTS ========== */ bytes32 private constant sUSD = "sUSD"; // ========== STATE VARIABLES ========== // The synth corresponding to the collateral. bytes32 public collateralKey; // Stores loans CollateralState public state; address public manager; // The synths that this contract can issue. bytes32[] public synths; // Map from currency key to synth contract name. mapping(bytes32 => bytes32) public synthsByKey; // Map from currency key to the shorting rewards contract mapping(bytes32 => address) public shortingRewards; // ========== SETTER STATE VARIABLES ========== // The minimum collateral ratio required to avoid liquidation. uint public minCratio; // The minimum amount of collateral to create a loan. uint public minCollateral; // The fee charged for issuing a loan. uint public issueFeeRate; // The maximum number of loans that an account can create with this collateral. uint public maxLoansPerAccount = 50; // Time in seconds that a user must wait between interacting with a loan. // Provides front running and flash loan protection. uint public interactionDelay = 300; bool public canOpenLoans = true; /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus"; bytes32 private constant CONTRACT_EXRATES = "ExchangeRates"; bytes32 private constant CONTRACT_EXCHANGER = "Exchanger"; bytes32 private constant CONTRACT_FEEPOOL = "FeePool"; bytes32 private constant CONTRACT_SYNTHSUSD = "SynthsUSD"; /* ========== CONSTRUCTOR ========== */ constructor( CollateralState _state, address _owner, address _manager, address _resolver, bytes32 _collateralKey, uint _minCratio, uint _minCollateral ) public Owned(_owner) MixinSystemSettings(_resolver) { manager = _manager; state = _state; collateralKey = _collateralKey; minCratio = _minCratio; minCollateral = _minCollateral; } /* ========== VIEWS ========== */ function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](5); newAddresses[0] = CONTRACT_FEEPOOL; newAddresses[1] = CONTRACT_EXRATES; newAddresses[2] = CONTRACT_EXCHANGER; newAddresses[3] = CONTRACT_SYSTEMSTATUS; newAddresses[4] = CONTRACT_SYNTHSUSD; bytes32[] memory combined = combineArrays(existingAddresses, newAddresses); addresses = combineArrays(combined, synths); } /* ---------- Related Contracts ---------- */ function _systemStatus() internal view returns (ISystemStatus) { return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS)); } function _synth(bytes32 synthName) internal view returns (ISynth) { return ISynth(requireAndGetAddress(synthName)); } function _synthsUSD() internal view returns (ISynth) { return ISynth(requireAndGetAddress(CONTRACT_SYNTHSUSD)); } function _exchangeRates() internal view returns (IExchangeRates) { return IExchangeRates(requireAndGetAddress(CONTRACT_EXRATES)); } function _exchanger() internal view returns (IExchanger) { return IExchanger(requireAndGetAddress(CONTRACT_EXCHANGER)); } function _feePool() internal view returns (IFeePool) { return IFeePool(requireAndGetAddress(CONTRACT_FEEPOOL)); } function _manager() internal view returns (ICollateralManager) { return ICollateralManager(manager); } /* ---------- Public Views ---------- */ function collateralRatio(Loan memory loan) public view returns (uint cratio) { uint cvalue = _exchangeRates().effectiveValue(collateralKey, loan.collateral, sUSD); uint dvalue = _exchangeRates().effectiveValue(loan.currency, loan.amount.add(loan.accruedInterest), sUSD); cratio = cvalue.divideDecimal(dvalue); } // The maximum number of synths issuable for this amount of collateral function maxLoan(uint amount, bytes32 currency) public view returns (uint max) { max = issuanceRatio().multiplyDecimal(_exchangeRates().effectiveValue(collateralKey, amount, currency)); } /** * r = target issuance ratio * D = debt value in sUSD * V = collateral value in sUSD * P = liquidation penalty * Calculates amount of synths = (D - V * r) / (1 - (1 + P) * r) * Note: if you pass a loan in here that is not eligible for liquidation it will revert. * We check the ratio first in liquidateInternal and only pass eligible loans in. */ function liquidationAmount(Loan memory loan) public view returns (uint amount) { uint liquidationPenalty = getLiquidationPenalty(); uint debtValue = _exchangeRates().effectiveValue(loan.currency, loan.amount.add(loan.accruedInterest), sUSD); uint collateralValue = _exchangeRates().effectiveValue(collateralKey, loan.collateral, sUSD); uint unit = SafeDecimalMath.unit(); uint dividend = debtValue.sub(collateralValue.divideDecimal(minCratio)); uint divisor = unit.sub(unit.add(liquidationPenalty).divideDecimal(minCratio)); uint sUSDamount = dividend.divideDecimal(divisor); return _exchangeRates().effectiveValue(sUSD, sUSDamount, loan.currency); } // amount is the amount of synths we are liquidating function collateralRedeemed(bytes32 currency, uint amount) public view returns (uint collateral) { uint liquidationPenalty = getLiquidationPenalty(); collateral = _exchangeRates().effectiveValue(currency, amount, collateralKey); collateral = collateral.multiplyDecimal(SafeDecimalMath.unit().add(liquidationPenalty)); } function areSynthsAndCurrenciesSet(bytes32[] calldata _synthNamesInResolver, bytes32[] calldata _synthKeys) external view returns (bool) { if (synths.length != _synthNamesInResolver.length) { return false; } for (uint i = 0; i < _synthNamesInResolver.length; i++) { bytes32 synthName = _synthNamesInResolver[i]; if (synths[i] != synthName) { return false; } if (synthsByKey[_synthKeys[i]] != synths[i]) { return false; } } return true; } /* ---------- UTILITIES ---------- */ // Check the account has enough of the synth to make the payment function _checkSynthBalance( address payer, bytes32 key, uint amount ) internal view { require(IERC20(address(_synth(synthsByKey[key]))).balanceOf(payer) >= amount, "Not enough synth balance"); } // We set the interest index to 0 to indicate the loan has been closed. function _checkLoanAvailable(Loan memory _loan) internal view { require(_loan.interestIndex > 0, "Loan does not exist"); require(_loan.lastInteraction.add(interactionDelay) <= block.timestamp, "Loan recently interacted with"); } function issuanceRatio() internal view returns (uint ratio) { ratio = SafeDecimalMath.unit().divideDecimalRound(minCratio); } /* ========== MUTATIVE FUNCTIONS ========== */ /* ---------- Synths ---------- */ function addSynths(bytes32[] calldata _synthNamesInResolver, bytes32[] calldata _synthKeys) external onlyOwner { require(_synthNamesInResolver.length == _synthKeys.length, "Input array length mismatch"); for (uint i = 0; i < _synthNamesInResolver.length; i++) { bytes32 synthName = _synthNamesInResolver[i]; synths.push(synthName); synthsByKey[_synthKeys[i]] = synthName; } // ensure cache has the latest rebuildCache(); } /* ---------- Rewards Contracts ---------- */ function addRewardsContracts(address rewardsContract, bytes32 synth) external onlyOwner { shortingRewards[synth] = rewardsContract; } /* ---------- SETTERS ---------- */ function setMinCratio(uint _minCratio) external onlyOwner { require(_minCratio > SafeDecimalMath.unit(), "Must be greater than 1"); minCratio = _minCratio; emit MinCratioRatioUpdated(minCratio); } function setIssueFeeRate(uint _issueFeeRate) external onlyOwner { issueFeeRate = _issueFeeRate; emit IssueFeeRateUpdated(issueFeeRate); } function setInteractionDelay(uint _interactionDelay) external onlyOwner { require(_interactionDelay <= SafeDecimalMath.unit() * 3600, "Max 1 hour"); interactionDelay = _interactionDelay; emit InteractionDelayUpdated(interactionDelay); } function setManager(address _newManager) external onlyOwner { manager = _newManager; emit ManagerUpdated(manager); } function setCanOpenLoans(bool _canOpenLoans) external onlyOwner { canOpenLoans = _canOpenLoans; emit CanOpenLoansUpdated(canOpenLoans); } /* ---------- LOAN INTERACTIONS ---------- */ function openInternal( uint collateral, uint amount, bytes32 currency, bool short ) internal returns (uint id) { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); require(canOpenLoans, "Opening is disabled"); // 1. Make sure the collateral rate is valid. require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. We can only issue certain synths. require(synthsByKey[currency] > 0, "Not allowed to issue this synth"); // 3. Make sure the synth rate is not invalid. require(!_exchangeRates().rateIsInvalid(currency), "Currency rate is invalid"); // 4. Collateral >= minimum collateral size. require(collateral >= minCollateral, "Not enough collateral to open"); // 5. Cap the number of loans so that the array doesn't get too big. require(state.getNumLoans(msg.sender) < maxLoansPerAccount, "Max loans exceeded"); // 6. Check we haven't hit the debt cap for non snx collateral. (bool canIssue, bool anyRateIsInvalid) = _manager().exceedsDebtLimit(amount, currency); require(canIssue && !anyRateIsInvalid, "Debt limit or invalid rate"); // 7. Require requested loan < max loan require(amount <= maxLoan(collateral, currency), "Exceeds max borrowing power"); // 8. This fee is denominated in the currency of the loan uint issueFee = amount.multiplyDecimalRound(issueFeeRate); // 9. Calculate the minting fee and subtract it from the loan amount uint loanAmountMinusFee = amount.sub(issueFee); // 10. Get a Loan ID id = _manager().getNewLoanId(); // 11. Create the loan struct. Loan memory loan = Loan({ id: id, account: msg.sender, collateral: collateral, currency: currency, amount: amount, short: short, accruedInterest: 0, interestIndex: 0, lastInteraction: block.timestamp }); // 12. Accrue interest on the loan. loan = accrueInterest(loan); // 13. Save the loan to storage state.createLoan(loan); // 14. Pay the minting fees to the fee pool _payFees(issueFee, currency); // 15. If its short, convert back to sUSD, otherwise issue the loan. if (short) { _synthsUSD().issue(msg.sender, _exchangeRates().effectiveValue(currency, loanAmountMinusFee, sUSD)); _manager().incrementShorts(currency, amount); if (shortingRewards[currency] != address(0)) { IShortingRewards(shortingRewards[currency]).enrol(msg.sender, amount); } } else { _synth(synthsByKey[currency]).issue(msg.sender, loanAmountMinusFee); _manager().incrementLongs(currency, amount); } // 16. Emit event emit LoanCreated(msg.sender, id, amount, collateral, currency, issueFee); } function closeInternal(address borrower, uint id) internal returns (uint collateral) { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); // 1. Make sure the collateral rate is valid require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. Get the loan. Loan memory loan = state.getLoan(borrower, id); // 3. Check loan is open and the last interaction time. _checkLoanAvailable(loan); // 4. Accrue interest on the loan. loan = accrueInterest(loan); // 5. Work out the total amount owing on the loan. uint total = loan.amount.add(loan.accruedInterest); // 6. Check they have enough balance to close the loan. _checkSynthBalance(loan.account, loan.currency, total); // 7. Burn the synths require( !_exchanger().hasWaitingPeriodOrSettlementOwing(borrower, loan.currency), "Waiting secs or settlement owing" ); _synth(synthsByKey[loan.currency]).burn(borrower, total); // 8. Tell the manager. if (loan.short) { _manager().decrementShorts(loan.currency, loan.amount); if (shortingRewards[loan.currency] != address(0)) { IShortingRewards(shortingRewards[loan.currency]).withdraw(borrower, loan.amount); } } else { _manager().decrementLongs(loan.currency, loan.amount); } // 9. Assign the collateral to be returned. collateral = loan.collateral; // 10. Pay fees _payFees(loan.accruedInterest, loan.currency); // 11. Record loan as closed loan.amount = 0; loan.collateral = 0; loan.accruedInterest = 0; loan.interestIndex = 0; loan.lastInteraction = block.timestamp; state.updateLoan(loan); // 12. Emit the event emit LoanClosed(borrower, id); } function closeByLiquidationInternal( address borrower, address liquidator, Loan memory loan ) internal returns (uint collateral) { // 1. Work out the total amount owing on the loan. uint total = loan.amount.add(loan.accruedInterest); // 2. Store this for the event. uint amount = loan.amount; // 3. Return collateral to the child class so it knows how much to transfer. collateral = loan.collateral; // 4. Burn the synths require(!_exchanger().hasWaitingPeriodOrSettlementOwing(liquidator, loan.currency), "Waiting or settlement owing"); _synth(synthsByKey[loan.currency]).burn(liquidator, total); // 5. Tell the manager. if (loan.short) { _manager().decrementShorts(loan.currency, loan.amount); if (shortingRewards[loan.currency] != address(0)) { IShortingRewards(shortingRewards[loan.currency]).withdraw(borrower, loan.amount); } } else { _manager().decrementLongs(loan.currency, loan.amount); } // 6. Pay fees _payFees(loan.accruedInterest, loan.currency); // 7. Record loan as closed loan.amount = 0; loan.collateral = 0; loan.accruedInterest = 0; loan.interestIndex = 0; loan.lastInteraction = block.timestamp; state.updateLoan(loan); // 8. Emit the event. emit LoanClosedByLiquidation(borrower, loan.id, liquidator, amount, collateral); } function depositInternal( address account, uint id, uint amount ) internal { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); // 1. Make sure the collateral rate is valid. require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. They sent some value > 0 require(amount > 0, "Deposit must be greater than 0"); // 3. Get the loan Loan memory loan = state.getLoan(account, id); // 4. Check loan is open and last interaction time. _checkLoanAvailable(loan); // 5. Accrue interest loan = accrueInterest(loan); // 6. Add the collateral loan.collateral = loan.collateral.add(amount); // 7. Update the last interaction time. loan.lastInteraction = block.timestamp; // 8. Store the loan state.updateLoan(loan); // 9. Emit the event emit CollateralDeposited(account, id, amount, loan.collateral); } function withdrawInternal(uint id, uint amount) internal returns (uint withdraw) { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); // 1. Make sure the collateral rate is valid. require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. Get the loan. Loan memory loan = state.getLoan(msg.sender, id); // 3. Check loan is open and last interaction time. _checkLoanAvailable(loan); // 4. Accrue interest. loan = accrueInterest(loan); // 5. Subtract the collateral. loan.collateral = loan.collateral.sub(amount); // 6. Update the last interaction time. loan.lastInteraction = block.timestamp; // 7. Check that the new amount does not put them under the minimum c ratio. require(collateralRatio(loan) > minCratio, "Cratio too low"); // 8. Store the loan. state.updateLoan(loan); // 9. Assign the return variable. withdraw = amount; // 10. Emit the event. emit CollateralWithdrawn(msg.sender, id, amount, loan.collateral); } function liquidateInternal( address borrower, uint id, uint payment ) internal returns (uint collateralLiquidated) { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); // 1. Make sure the collateral rate is valid. require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. Check the payment amount. require(payment > 0, "Payment must be greater than 0"); // 3. Get the loan. Loan memory loan = state.getLoan(borrower, id); // 4. Check loan is open and last interaction time. _checkLoanAvailable(loan); // 5. Accrue interest. loan = accrueInterest(loan); // 6. Check they have enough balance to make the payment. _checkSynthBalance(msg.sender, loan.currency, payment); // 7. Check they are eligible for liquidation. require(collateralRatio(loan) < minCratio, "Cratio above liquidation ratio"); // 8. Determine how much needs to be liquidated to fix their c ratio. uint liqAmount = liquidationAmount(loan); // 9. Only allow them to liquidate enough to fix the c ratio. uint amountToLiquidate = liqAmount < payment ? liqAmount : payment; // 10. Work out the total amount owing on the loan. uint amountOwing = loan.amount.add(loan.accruedInterest); // 11. If its greater than the amount owing, we need to close the loan. if (amountToLiquidate >= amountOwing) { return closeByLiquidationInternal(borrower, msg.sender, loan); } // 12. Process the payment to workout interest/principal split. loan = _processPayment(loan, amountToLiquidate); // 13. Work out how much collateral to redeem. collateralLiquidated = collateralRedeemed(loan.currency, amountToLiquidate); loan.collateral = loan.collateral.sub(collateralLiquidated); // 14. Update the last interaction time. loan.lastInteraction = block.timestamp; // 15. Burn the synths from the liquidator. require(!_exchanger().hasWaitingPeriodOrSettlementOwing(msg.sender, loan.currency), "Waiting or settlement owing"); _synth(synthsByKey[loan.currency]).burn(msg.sender, amountToLiquidate); // 16. Store the loan. state.updateLoan(loan); // 17. Emit the event emit LoanPartiallyLiquidated(borrower, id, msg.sender, amountToLiquidate, collateralLiquidated); } function repayInternal( address borrower, address repayer, uint id, uint payment ) internal { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); // 1. Make sure the collateral rate is valid. require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. Check the payment amount. require(payment > 0, "Payment must be greater than 0"); // 3. Get loan Loan memory loan = state.getLoan(borrower, id); // 4. Check loan is open and last interaction time. _checkLoanAvailable(loan); // 5. Accrue interest. loan = accrueInterest(loan); // 6. Check the spender has enough synths to make the repayment _checkSynthBalance(repayer, loan.currency, payment); // 7. Process the payment. loan = _processPayment(loan, payment); // 8. Update the last interaction time. loan.lastInteraction = block.timestamp; // 9. Burn synths from the payer require(!_exchanger().hasWaitingPeriodOrSettlementOwing(repayer, loan.currency), "Waiting or settlement owing"); _synth(synthsByKey[loan.currency]).burn(repayer, payment); // 10. Store the loan state.updateLoan(loan); // 11. Emit the event. emit LoanRepaymentMade(borrower, repayer, id, payment, loan.amount); } function drawInternal(uint id, uint amount) internal { // 0. Check the system is active. _systemStatus().requireIssuanceActive(); // 1. Make sure the collateral rate is valid. require(!_exchangeRates().rateIsInvalid(collateralKey), "Collateral rate is invalid"); // 2. Get loan. Loan memory loan = state.getLoan(msg.sender, id); // 3. Check loan is open and last interaction time. _checkLoanAvailable(loan); // 4. Accrue interest. loan = accrueInterest(loan); // 5. Add the requested amount. loan.amount = loan.amount.add(amount); // 6. If it is below the minimum, don't allow this draw. require(collateralRatio(loan) > minCratio, "Cannot draw this much"); // 7. This fee is denominated in the currency of the loan uint issueFee = amount.multiplyDecimalRound(issueFeeRate); // 8. Calculate the minting fee and subtract it from the draw amount uint amountMinusFee = amount.sub(issueFee); // 9. If its short, let the child handle it, otherwise issue the synths. if (loan.short) { _manager().incrementShorts(loan.currency, amount); _synthsUSD().issue(msg.sender, _exchangeRates().effectiveValue(loan.currency, amountMinusFee, sUSD)); if (shortingRewards[loan.currency] != address(0)) { IShortingRewards(shortingRewards[loan.currency]).enrol(msg.sender, amount); } } else { _manager().incrementLongs(loan.currency, amount); _synth(synthsByKey[loan.currency]).issue(msg.sender, amountMinusFee); } // 10. Pay the minting fees to the fee pool _payFees(issueFee, loan.currency); // 11. Update the last interaction time. loan.lastInteraction = block.timestamp; // 12. Store the loan state.updateLoan(loan); // 13. Emit the event. emit LoanDrawnDown(msg.sender, id, amount); } // Update the cumulative interest rate for the currency that was interacted with. function accrueInterest(Loan memory loan) internal returns (Loan memory loanAfter) { loanAfter = loan; // 1. Get the rates we need. (uint entryRate, uint lastRate, uint lastUpdated, uint newIndex) = loan.short ? _manager().getShortRatesAndTime(loan.currency, loan.interestIndex) : _manager().getRatesAndTime(loan.interestIndex); // 2. Get the instantaneous rate. (uint rate, bool invalid) = loan.short ? _manager().getShortRate(synthsByKey[loan.currency]) : _manager().getBorrowRate(); require(!invalid, "Rates are invalid"); // 3. Get the time since we last updated the rate. uint timeDelta = block.timestamp.sub(lastUpdated).mul(SafeDecimalMath.unit()); // 4. Get the latest cumulative rate. F_n+1 = F_n + F_last uint latestCumulative = lastRate.add(rate.multiplyDecimal(timeDelta)); // 5. If the loan was just opened, don't record any interest. Otherwise multiple by the amount outstanding. uint interest = loan.interestIndex == 0 ? 0 : loan.amount.multiplyDecimal(latestCumulative.sub(entryRate)); // 7. Update rates with the lastest cumulative rate. This also updates the time. loan.short ? _manager().updateShortRates(loan.currency, latestCumulative) : _manager().updateBorrowRates(latestCumulative); // 8. Update loan loanAfter.accruedInterest = loan.accruedInterest.add(interest); loanAfter.interestIndex = newIndex; state.updateLoan(loanAfter); } // Works out the amount of interest and principal after a repayment is made. function _processPayment(Loan memory loanBefore, uint payment) internal returns (Loan memory loanAfter) { loanAfter = loanBefore; if (payment > 0 && loanBefore.accruedInterest > 0) { uint interestPaid = payment > loanBefore.accruedInterest ? loanBefore.accruedInterest : payment; loanAfter.accruedInterest = loanBefore.accruedInterest.sub(interestPaid); payment = payment.sub(interestPaid); _payFees(interestPaid, loanBefore.currency); } // If there is more payment left after the interest, pay down the principal. if (payment > 0) { loanAfter.amount = loanBefore.amount.sub(payment); // And get the manager to reduce the total long/short balance. if (loanAfter.short) { _manager().decrementShorts(loanAfter.currency, payment); if (shortingRewards[loanAfter.currency] != address(0)) { IShortingRewards(shortingRewards[loanAfter.currency]).withdraw(loanAfter.account, payment); } } else { _manager().decrementLongs(loanAfter.currency, payment); } } } // Take an amount of fees in a certain synth and convert it to sUSD before paying the fee pool. function _payFees(uint amount, bytes32 synth) internal { if (amount > 0) { if (synth != sUSD) { amount = _exchangeRates().effectiveValue(synth, amount, sUSD); } _synthsUSD().issue(_feePool().FEE_ADDRESS(), amount); _feePool().recordFeePaid(amount); } } // ========== EVENTS ========== // Setters event MinCratioRatioUpdated(uint minCratio); event MinCollateralUpdated(uint minCollateral); event IssueFeeRateUpdated(uint issueFeeRate); event MaxLoansPerAccountUpdated(uint maxLoansPerAccount); event InteractionDelayUpdated(uint interactionDelay); event ManagerUpdated(address manager); event CanOpenLoansUpdated(bool canOpenLoans); // Loans event LoanCreated(address indexed account, uint id, uint amount, uint collateral, bytes32 currency, uint issuanceFee); event LoanClosed(address indexed account, uint id); event CollateralDeposited(address indexed account, uint id, uint amountDeposited, uint collateralAfter); event CollateralWithdrawn(address indexed account, uint id, uint amountWithdrawn, uint collateralAfter); event LoanRepaymentMade(address indexed account, address indexed repayer, uint id, uint amountRepaid, uint amountAfter); event LoanDrawnDown(address indexed account, uint id, uint amount); event LoanPartiallyLiquidated( address indexed account, uint id, address liquidator, uint amountLiquidated, uint collateralLiquidated ); event LoanClosedByLiquidation( address indexed account, uint id, address indexed liquidator, uint amountLiquidated, uint collateralLiquidated ); } /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier * available, which can be aplied 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. */ contract ReentrancyGuard { /// @dev counter to allow mutex lock with only one SSTORE operation uint256 private _guardCounter; constructor () internal { // The counter starts at one to prevent changing it from zero to a non-zero // value, which is a more expensive operation. _guardCounter = 1; } /** * @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() { _guardCounter += 1; uint256 localCounter = _guardCounter; _; require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call"); } } interface ICollateralEth { function open(uint amount, bytes32 currency) external payable; function close(uint id) external; function deposit(address borrower, uint id) external payable; function withdraw(uint id, uint amount) external; function repay( address borrower, uint id, uint amount ) external; function liquidate( address borrower, uint id, uint amount ) external; function claim(uint amount) external; } // Inheritance // Internal references // This contract handles the payable aspects of eth loans. contract CollateralEth is Collateral, ICollateralEth, ReentrancyGuard { mapping(address => uint) public pendingWithdrawals; constructor( CollateralState _state, address _owner, address _manager, address _resolver, bytes32 _collateralKey, uint _minCratio, uint _minCollateral ) public Collateral(_state, _owner, _manager, _resolver, _collateralKey, _minCratio, _minCollateral) {} function open(uint amount, bytes32 currency) external payable { openInternal(msg.value, amount, currency, false); } function close(uint id) external { uint collateral = closeInternal(msg.sender, id); pendingWithdrawals[msg.sender] = pendingWithdrawals[msg.sender].add(collateral); } function deposit(address borrower, uint id) external payable { depositInternal(borrower, id, msg.value); } function withdraw(uint id, uint withdrawAmount) external { uint amount = withdrawInternal(id, withdrawAmount); pendingWithdrawals[msg.sender] = pendingWithdrawals[msg.sender].add(amount); } function repay( address account, uint id, uint amount ) external { repayInternal(account, msg.sender, id, amount); } function draw(uint id, uint amount) external { drawInternal(id, amount); } function liquidate( address borrower, uint id, uint amount ) external { uint collateralLiquidated = liquidateInternal(borrower, id, amount); pendingWithdrawals[msg.sender] = pendingWithdrawals[msg.sender].add(collateralLiquidated); } function claim(uint amount) external nonReentrant { // If they try to withdraw more than their total balance, it will fail on the safe sub. pendingWithdrawals[msg.sender] = pendingWithdrawals[msg.sender].sub(amount); (bool success, ) = msg.sender.call.value(amount)(""); require(success, "Transfer failed"); } }
[{"inputs":[{"internalType":"contract CollateralState","name":"_state","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_manager","type":"address"},{"internalType":"address","name":"_resolver","type":"address"},{"internalType":"bytes32","name":"_collateralKey","type":"bytes32"},{"internalType":"uint256","name":"_minCratio","type":"uint256"},{"internalType":"uint256","name":"_minCollateral","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"canOpenLoans","type":"bool"}],"name":"CanOpenLoansUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountDeposited","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralAfter","type":"uint256"}],"name":"CollateralDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountWithdrawn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralAfter","type":"uint256"}],"name":"CollateralWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"interactionDelay","type":"uint256"}],"name":"InteractionDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"issueFeeRate","type":"uint256"}],"name":"IssueFeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"LoanClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLiquidated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralLiquidated","type":"uint256"}],"name":"LoanClosedByLiquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"currency","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"issuanceFee","type":"uint256"}],"name":"LoanCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LoanDrawnDown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLiquidated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralLiquidated","type":"uint256"}],"name":"LoanPartiallyLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"repayer","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRepaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountAfter","type":"uint256"}],"name":"LoanRepaymentMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"ManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxLoansPerAccount","type":"uint256"}],"name":"MaxLoansPerAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minCollateral","type":"uint256"}],"name":"MinCollateralUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minCratio","type":"uint256"}],"name":"MinCratioRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"rewardsContract","type":"address"},{"internalType":"bytes32","name":"synth","type":"bytes32"}],"name":"addRewardsContracts","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"_synthNamesInResolver","type":"bytes32[]"},{"internalType":"bytes32[]","name":"_synthKeys","type":"bytes32[]"}],"name":"addSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"_synthNamesInResolver","type":"bytes32[]"},{"internalType":"bytes32[]","name":"_synthKeys","type":"bytes32[]"}],"name":"areSynthsAndCurrenciesSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canOpenLoans","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"close","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"collateralKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address payable","name":"account","type":"address"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"bytes32","name":"currency","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"short","type":"bool"},{"internalType":"uint256","name":"accruedInterest","type":"uint256"},{"internalType":"uint256","name":"interestIndex","type":"uint256"},{"internalType":"uint256","name":"lastInteraction","type":"uint256"}],"internalType":"struct ICollateralLoan.Loan","name":"loan","type":"tuple"}],"name":"collateralRatio","outputs":[{"internalType":"uint256","name":"cratio","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currency","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"collateralRedeemed","outputs":[{"internalType":"uint256","name":"collateral","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"draw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"interactionDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"issueFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"liquidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address payable","name":"account","type":"address"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"bytes32","name":"currency","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"short","type":"bool"},{"internalType":"uint256","name":"accruedInterest","type":"uint256"},{"internalType":"uint256","name":"interestIndex","type":"uint256"},{"internalType":"uint256","name":"lastInteraction","type":"uint256"}],"internalType":"struct ICollateralLoan.Loan","name":"loan","type":"tuple"}],"name":"liquidationAmount","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"manager","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"currency","type":"bytes32"}],"name":"maxLoan","outputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxLoansPerAccount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minCratio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"currency","type":"bytes32"}],"name":"open","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingWithdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"_canOpenLoans","type":"bool"}],"name":"setCanOpenLoans","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_interactionDelay","type":"uint256"}],"name":"setInteractionDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_issueFeeRate","type":"uint256"}],"name":"setIssueFeeRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newManager","type":"address"}],"name":"setManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_minCratio","type":"uint256"}],"name":"setMinCratio","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"shortingRewards","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"internalType":"contract CollateralState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"synths","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"synthsByKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526032600d5561012c600e55600f805460ff191660011790553480156200002957600080fd5b5060405162006240380380620062408339810160408190526200004c916200016c565b868686868686868380876001600160a01b038116620000885760405162461bcd60e51b81526004016200007f9062000294565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000d59184906200026e565b60405180910390a150600280546001600160a01b03199081166001600160a01b03938416179091556006805482169883169890981790975560058054909716981697909717909455600491909155600a5550600b5550506001601055506200031595505050505050565b80516200014c81620002e5565b92915050565b80516200014c81620002ff565b80516200014c816200030a565b600080600080600080600060e0888a0312156200018857600080fd5b6000620001968a8a6200015f565b9750506020620001a98a828b016200013f565b9650506040620001bc8a828b016200013f565b9550506060620001cf8a828b016200013f565b9450506080620001e28a828b0162000152565b93505060a0620001f58a828b0162000152565b92505060c0620002088a828b0162000152565b91505092959891949750929550565b6200022281620002d8565b82525050565b6200022281620002af565b600062000242601983620002a6565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b604081016200027e828562000217565b6200028d602083018462000228565b9392505050565b602080825281016200014c8162000233565b90815260200190565b60006200014c82620002cc565b90565b60006200014c82620002af565b6001600160a01b031690565b60006200014c82620002bf565b620002f081620002af565b8114620002fc57600080fd5b50565b620002f081620002bc565b620002f081620002bf565b615f1b80620003256000396000f3fe6080604052600436106102465760003560e01c80635eb2ad0111610139578063a76cdfa5116100b6578063d2b8035a1161007a578063d2b8035a14610638578063dac8cf6814610658578063de81eda914610678578063e74337c614610698578063eb8e3b65146106b8578063f3f43703146106cd57610246565b8063a76cdfa5146105b9578063b562a1ab146105d9578063ba2de9bc146105ee578063c19d93fb14610603578063d0ebdbe71461061857610246565b8063899ffef4116100fd578063899ffef41461052d5780638cd2e0c71461054f5780638da5cb5b1461056f57806390abb4d914610584578063925ead11146105a457610246565b80635eb2ad01146104a357806372e18b6a146104c357806374185360146104e357806379ba5097146104f85780637e1323551461050d57610246565b806330edd961116101c7578063441a3e701161018b578063441a3e701461041957806347e7ef2414610439578063481c6a751461044c5780634c17ace41461046e57806353a47bb71461048e57610246565b806330edd9611461038f578063361e2086146103af578063379607f5146103c457806338245377146103e45780634065b81b1461040457610246565b80630cdd1c651161020e5780630cdd1c65146102f857806315aaf4dd146103185780631627540c1461032d57806323d60e2e1461034d5780632af64bd31461036d57610246565b806304f3bcec1461024b57806306c19e3f146102765780630710285c1461028b5780630a153c97146102ab5780630aebeb4e146102d8575b600080fd5b34801561025757600080fd5b506102606106ed565b60405161026d9190615b77565b60405180910390f35b6102896102843660046150c9565b6106fc565b005b34801561029757600080fd5b506102896102a6366004614f82565b61070e565b3480156102b757600080fd5b506102cb6102c63660046150c9565b610754565b60405161026d9190615b05565b3480156102e457600080fd5b506102896102f33660046150ab565b610890565b34801561030457600080fd5b506102896103133660046150ab565b6108d3565b34801561032457600080fd5b506102cb6109be565b34801561033957600080fd5b50610289610348366004614f0c565b6109c4565b34801561035957600080fd5b50610289610368366004614fcf565b610a17565b34801561037957600080fd5b50610382610add565b60405161026d9190615af7565b34801561039b57600080fd5b506102cb6103aa3660046150ab565b610bf5565b3480156103bb57600080fd5b506102cb610c13565b3480156103d057600080fd5b506102896103df3660046150ab565b610c19565b3480156103f057600080fd5b506102cb6103ff3660046150ab565b610cee565b34801561041057600080fd5b50610382610d00565b34801561042557600080fd5b506102896104343660046150c9565b610d09565b610289610447366004614f48565b610d4d565b34801561045857600080fd5b50610461610d58565b60405161026d9190615a86565b34801561047a57600080fd5b506102896104893660046150ab565b610d67565b34801561049a57600080fd5b50610461610e43565b3480156104af57600080fd5b506102896104be366004614f48565b610e52565b3480156104cf57600080fd5b506103826104de366004614fcf565b610e88565b3480156104ef57600080fd5b50610289610f4a565b34801561050457600080fd5b5061028961109c565b34801561051957600080fd5b506102cb6105283660046150c9565b611138565b34801561053957600080fd5b506105426111e1565b60405161026d9190615ae6565b34801561055b57600080fd5b5061028961056a366004614f82565b611346565b34801561057b57600080fd5b50610461611352565b34801561059057600080fd5b5061028961059f36600461503f565b611361565b3480156105b057600080fd5b506102cb6113ad565b3480156105c557600080fd5b506102896105d43660046150ab565b6113b3565b3480156105e557600080fd5b506102cb6113f0565b3480156105fa57600080fd5b506102cb6113f6565b34801561060f57600080fd5b506102606113fc565b34801561062457600080fd5b50610289610633366004614f0c565b61140b565b34801561064457600080fd5b506102896106533660046150c9565b611464565b34801561066457600080fd5b506102cb6106733660046150e8565b61146e565b34801561068457600080fd5b506104616106933660046150ab565b6115c7565b3480156106a457600080fd5b506102cb6106b33660046150e8565b6115e2565b3480156106c457600080fd5b506102cb6118cc565b3480156106d957600080fd5b506102cb6106e8366004614f0c565b6118d2565b6002546001600160a01b031681565b61070934838360006118e4565b505050565b600061071b84848461210d565b3360009081526011602052604090205490915061073e908263ffffffff61257216565b3360009081526011602052604090205550505050565b60008061075f6125a0565b9050610769612652565b6001600160a01b031663654a60ac85856004546040518463ffffffff1660e01b815260040161079a93929190615b4f565b60206040518083038186803b1580156107b257600080fd5b505afa1580156107c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107ea9190810190615126565b915061088861087b82731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561083757600080fd5b505af415801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061086f9190810190615126565b9063ffffffff61257216565b839063ffffffff61266d16565b949350505050565b600061089c3383612697565b336000908152601160205260409020549091506108bf908263ffffffff61257216565b336000908152601160205260409020555050565b6108db612bfc565b731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561091f57600080fd5b505af4158015610933573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109579190810190615126565b811161097e5760405162461bcd60e51b815260040161097590615ba6565b60405180910390fd5b600a8190556040517f813a44586e8ecb9390b2568dbe810e193087f80e415c8845340ef06d4cbb42a5906109b3908390615b05565b60405180910390a150565b600e5481565b6109cc612bfc565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906109b3908390615a86565b610a1f612bfc565b828114610a3e5760405162461bcd60e51b815260040161097590615b96565b60005b83811015610ace576000858583818110610a5757fe5b600780546001810182556000918252602090920293909301357fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889091018190559250829160089150868686818110610aab57fe5b602090810292909201358352508101919091526040016000205550600101610a41565b50610ad7610f4a565b50505050565b60006060610ae96111e1565b905060005b8151811015610beb576000828281518110610b0557fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a72190610b56908590600401615b05565b60206040518083038186803b158015610b6e57600080fd5b505afa158015610b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ba69190810190614f2a565b6001600160a01b0316141580610bd157506000818152600360205260409020546001600160a01b0316155b15610be25760009350505050610bf2565b50600101610aee565b5060019150505b90565b60078181548110610c0257fe5b600091825260209091200154905081565b600c5481565b601080546001019081905533600090815260116020526040902054610c44908363ffffffff612c2816565b336000818152601160205260408082209390935591518490610c6590615a7b565b60006040518083038185875af1925050503d8060008114610ca2576040519150601f19603f3d011682016040523d82523d6000602084013e610ca7565b606091505b5050905080610cc85760405162461bcd60e51b815260040161097590615be6565b506010548114610cea5760405162461bcd60e51b815260040161097590615d56565b5050565b60086020526000908152604090205481565b600f5460ff1681565b6000610d158383612c50565b33600090815260116020526040902054909150610d38908263ffffffff61257216565b33600090815260116020526040902055505050565b610cea828234612eed565b6006546001600160a01b031681565b610d6f612bfc565b731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015610db357600080fd5b505af4158015610dc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610deb9190810190615126565b610e1002811115610e0e5760405162461bcd60e51b815260040161097590615cb6565b600e8190556040517f4d71c92b0a9dc236066597b95637bb04d58cd135e9165aee13eb68e3199c2361906109b3908390615b05565b6001546001600160a01b031681565b610e5a612bfc565b600090815260096020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b6007546000908414610e9c57506000610888565b60005b84811015610f3e576000868683818110610eb557fe5b9050602002013590508060078381548110610ecc57fe5b906000526020600020015414610ee757600092505050610888565b60078281548110610ef457fe5b906000526020600020015460086000878786818110610f0f57fe5b9050602002013581526020019081526020016000205414610f3557600092505050610888565b50600101610e9f565b50600195945050505050565b6060610f546111e1565b905060005b8151811015610cea576000828281518110610f7057fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610fb29190615a70565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610fde929190615b2f565b60206040518083038186803b158015610ff657600080fd5b505afa15801561100a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061102e9190810190614f2a565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa689061108a9084908490615b13565b60405180910390a15050600101610f59565b6001546001600160a01b031633146110c65760405162461bcd60e51b815260040161097590615bd6565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92611109926001600160a01b0391821692911690615abd565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60006111da611145612652565b6001600160a01b031663654a60ac60045486866040518463ffffffff1660e01b815260040161117693929190615b4f565b60206040518083038186803b15801561118e57600080fd5b505afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111c69190810190615126565b6111ce61317e565b9063ffffffff61266d16565b9392505050565b6060806111ec61320e565b60408051600580825260c08201909252919250606091906020820160a08038833901905050905066119959541bdbdb60ca1b8160008151811061122b57fe5b6020026020010181815250506c45786368616e6765526174657360981b8160018151811061125557fe5b6020026020010181815250506822bc31b430b733b2b960b91b8160028151811061127b57fe5b6020026020010181815250506b53797374656d53746174757360a01b816003815181106112a457fe5b6020026020010181815250506814de5b9d1a1cd554d160ba1b816004815181106112ca57fe5b60200260200101818152505060606112e2838361325f565b905061133e81600780548060200260200160405190810160405280929190818152602001828054801561133457602002820191906000526020600020905b815481526020019060010190808311611320575b505050505061325f565b935050505090565b6107098333848461331b565b6000546001600160a01b031681565b611369612bfc565b600f805460ff191682151517908190556040517f261991749e1b2436706a31bde8bf184bb37fe21e303709b78d3b881afacadaa2916109b39160ff90911690615af7565b600a5481565b6113bb612bfc565b600c8190556040517fe7bd72551c54d568cd97b00dc52d2787b5c5d4f0070d3582c1e8ba25141f799c906109b3908390615b05565b60045481565b600b5481565b6005546001600160a01b031681565b611413612bfc565b600680546001600160a01b0319166001600160a01b0383811691909117918290556040517f2c1c11af44aa5608f1dca38c00275c30ea091e02417d36e70e9a1538689c433d926109b3921690615a86565b610cea82826136d6565b600080611479612652565b6001600160a01b031663654a60ac6004548560400151631cd554d160e21b6040518463ffffffff1660e01b81526004016114b593929190615b4f565b60206040518083038186803b1580156114cd57600080fd5b505afa1580156114e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115059190810190615126565b90506000611511612652565b6001600160a01b031663654a60ac856060015161153f8760c00151886080015161257290919063ffffffff16565b631cd554d160e21b6040518463ffffffff1660e01b815260040161156593929190615b4f565b60206040518083038186803b15801561157d57600080fd5b505afa158015611591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115b59190810190615126565b9050610888828263ffffffff613c9616565b6009602052600090815260409020546001600160a01b031681565b6000806115ed6125a0565b905060006115f9612652565b6001600160a01b031663654a60ac85606001516116278760c00151886080015161257290919063ffffffff16565b631cd554d160e21b6040518463ffffffff1660e01b815260040161164d93929190615b4f565b60206040518083038186803b15801561166557600080fd5b505afa158015611679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061169d9190810190615126565b905060006116a9612652565b6001600160a01b031663654a60ac6004548760400151631cd554d160e21b6040518463ffffffff1660e01b81526004016116e593929190615b4f565b60206040518083038186803b1580156116fd57600080fd5b505afa158015611711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117359190810190615126565b90506000731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561177d57600080fd5b505af4158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117b59190810190615126565b905060006117de6117d1600a5485613c9690919063ffffffff16565b859063ffffffff612c2816565b9050600061181761180a600a546117fe898761257290919063ffffffff16565b9063ffffffff613c9616565b849063ffffffff612c2816565b9050600061182b838363ffffffff613c9616565b9050611835612652565b6001600160a01b031663654a60ac631cd554d160e21b838c606001516040518463ffffffff1660e01b815260040161186f93929190615b4f565b60206040518083038186803b15801561188757600080fd5b505afa15801561189b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118bf9190810190615126565b9998505050505050505050565b600d5481565b60116020526000908152604090205481565b60006118ee613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561192657600080fd5b505afa15801561193a573d6000803e3d6000fd5b5050600f5460ff16915061196290505760405162461bcd60e51b815260040161097590615ca6565b61196a612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b81526004016119979190615b05565b60206040518083038186803b1580156119af57600080fd5b505afa1580156119c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119e7919081019061505d565b15611a045760405162461bcd60e51b815260040161097590615cc6565b600083815260086020526040902054611a2f5760405162461bcd60e51b815260040161097590615cf6565b611a37612652565b6001600160a01b0316632528f0fe846040518263ffffffff1660e01b8152600401611a629190615b05565b60206040518083038186803b158015611a7a57600080fd5b505afa158015611a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ab2919081019061505d565b15611acf5760405162461bcd60e51b815260040161097590615c56565b600b54851015611af15760405162461bcd60e51b815260040161097590615c46565b600d5460055460405163382dab6f60e21b81526001600160a01b039091169063e0b6adbc90611b24903390600401615a94565b60206040518083038186803b158015611b3c57600080fd5b505afa158015611b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b749190810190615126565b10611b915760405162461bcd60e51b815260040161097590615c26565b600080611b9c613cda565b6001600160a01b031663b4d6cb4087876040518363ffffffff1660e01b8152600401611bc9929190615b21565b604080518083038186803b158015611be057600080fd5b505afa158015611bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c18919081019061507b565b91509150818015611c27575080155b611c435760405162461bcd60e51b815260040161097590615d36565b611c4d8786611138565b861115611c6c5760405162461bcd60e51b815260040161097590615cd6565b6000611c83600c5488613ce990919063ffffffff16565b90506000611c97888363ffffffff612c2816565b9050611ca1613cda565b6001600160a01b031663b3b467326040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cdb57600080fd5b505af1158015611cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d139190810190615126565b9450611d1d614c86565b604051806101200160405280878152602001336001600160a01b031681526020018b81526020018981526020018a815260200188151581526020016000815260200160008152602001428152509050611d7581613cfe565b60055460405163170cc48160e21b81529192506001600160a01b031690635c33120490611da6908490600401615d76565b600060405180830381600087803b158015611dc057600080fd5b505af1158015611dd4573d6000803e3d6000fd5b50505050611de283896141ea565b8615611fd857611df06143d6565b6001600160a01b031663867904b433611e07612652565b6001600160a01b031663654a60ac8c87631cd554d160e21b6040518463ffffffff1660e01b8152600401611e3d93929190615b4f565b60206040518083038186803b158015611e5557600080fd5b505afa158015611e69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e8d9190810190615126565b6040518363ffffffff1660e01b8152600401611eaa929190615aa2565b600060405180830381600087803b158015611ec457600080fd5b505af1158015611ed8573d6000803e3d6000fd5b50505050611ee4613cda565b6001600160a01b031663e31f27c1898b6040518363ffffffff1660e01b8152600401611f11929190615b21565b600060405180830381600087803b158015611f2b57600080fd5b505af1158015611f3f573d6000803e3d6000fd5b5050506000898152600960205260409020546001600160a01b0316159050611fd3576000888152600960205260409081902054905163db454a5160e01b81526001600160a01b039091169063db454a5190611fa09033908d90600401615aa2565b600060405180830381600087803b158015611fba57600080fd5b505af1158015611fce573d6000803e3d6000fd5b505050505b6120b7565b600088815260086020526040902054611ff0906143ed565b6001600160a01b031663867904b433846040518363ffffffff1660e01b815260040161201d929190615aa2565b600060405180830381600087803b15801561203757600080fd5b505af115801561204b573d6000803e3d6000fd5b50505050612057613cda565b6001600160a01b031663eb94bbde898b6040518363ffffffff1660e01b8152600401612084929190615b21565b600060405180830381600087803b15801561209e57600080fd5b505af11580156120b2573d6000803e3d6000fd5b505050505b336001600160a01b03167f604952b18be5fed608cbdd28101dc57bd667055c9678ec6d44fb1d8e4c7c172a878b8d8c886040516120f8959493929190615dc3565b60405180910390a25050505050949350505050565b6000612117613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561214f57600080fd5b505afa158015612163573d6000803e3d6000fd5b5050505061216f612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b815260040161219c9190615b05565b60206040518083038186803b1580156121b457600080fd5b505afa1580156121c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506121ec919081019061505d565b156122095760405162461bcd60e51b815260040161097590615cc6565b600082116122295760405162461bcd60e51b815260040161097590615c06565b612231614c86565b6005546040516350e28ac360e11b81526001600160a01b039091169063a1c51586906122639088908890600401615ad8565b6101206040518083038186803b15801561227c57600080fd5b505afa158015612290573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122b49190810190615107565b90506122bf816143f8565b6122c881613cfe565b90506122d933826060015185614458565b600a546122e58261146e565b106123025760405162461bcd60e51b815260040161097590615c36565b600061230d826115e2565b9050600084821061231e5784612320565b815b9050600061233f8460c00151856080015161257290919063ffffffff16565b905080821061235e5761235388338661450b565b9450505050506111da565b61236884836148da565b9350612378846060015183610754565b6040850151909550612390908663ffffffff612c2816565b6040850152426101008501526123a4614afd565b6001600160a01b031663d6f32e063386606001516040518363ffffffff1660e01b81526004016123d5929190615aa2565b60206040518083038186803b1580156123ed57600080fd5b505afa158015612401573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612425919081019061505d565b156124425760405162461bcd60e51b815260040161097590615d66565b606084015160009081526008602052604090205461245f906143ed565b6001600160a01b0316639dc29fac33846040518363ffffffff1660e01b815260040161248c929190615aa2565b600060405180830381600087803b1580156124a657600080fd5b505af11580156124ba573d6000803e3d6000fd5b5050600554604051631137390760e21b81526001600160a01b0390911692506344dce41c91506124ee908790600401615d76565b600060405180830381600087803b15801561250857600080fd5b505af115801561251c573d6000803e3d6000fd5b50505050876001600160a01b03167fb6e43890aeea54fbe6c0ed628e78172a0ff30bbcb1d70d8b130b12c366bac4c58833858960405161255f9493929190615d85565b60405180910390a2505050509392505050565b6000828201838110156125975760405162461bcd60e51b815260040161097590615c16565b90505b92915050565b60006125aa614b14565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b716c69717569646174696f6e50656e616c747960701b6040518363ffffffff1660e01b81526004016125fd929190615b21565b60206040518083038186803b15801561261557600080fd5b505afa158015612629573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061264d9190810190615126565b905090565b600061264d6c45786368616e6765526174657360981b614b2d565b6000670de0b6b3a7640000612688848463ffffffff614b8a16565b8161268f57fe5b049392505050565b60006126a1613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b1580156126d957600080fd5b505afa1580156126ed573d6000803e3d6000fd5b505050506126f9612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b81526004016127269190615b05565b60206040518083038186803b15801561273e57600080fd5b505afa158015612752573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612776919081019061505d565b156127935760405162461bcd60e51b815260040161097590615cc6565b61279b614c86565b6005546040516350e28ac360e11b81526001600160a01b039091169063a1c51586906127cd9087908790600401615ad8565b6101206040518083038186803b1580156127e657600080fd5b505afa1580156127fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061281e9190810190615107565b9050612829816143f8565b61283281613cfe565b905060006128518260c00151836080015161257290919063ffffffff16565b90506128668260200151836060015183614458565b61286e614afd565b6001600160a01b031663d6f32e068684606001516040518363ffffffff1660e01b815260040161289f929190615ad8565b60206040518083038186803b1580156128b757600080fd5b505afa1580156128cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128ef919081019061505d565b1561290c5760405162461bcd60e51b815260040161097590615c66565b6060820151600090815260086020526040902054612929906143ed565b6001600160a01b0316639dc29fac86836040518363ffffffff1660e01b8152600401612956929190615ad8565b600060405180830381600087803b15801561297057600080fd5b505af1158015612984573d6000803e3d6000fd5b505050508160a0015115612aa25761299a613cda565b6001600160a01b0316635246f2b9836060015184608001516040518363ffffffff1660e01b81526004016129cf929190615b21565b600060405180830381600087803b1580156129e957600080fd5b505af11580156129fd573d6000803e3d6000fd5b5050505060608201516000908152600960205260409020546001600160a01b031615612a9d57606082015160009081526009602052604090819020546080840151915163f3fef3a360e01b81526001600160a01b039091169163f3fef3a391612a6a918991600401615ad8565b600060405180830381600087803b158015612a8457600080fd5b505af1158015612a98573d6000803e3d6000fd5b505050505b612b12565b612aaa613cda565b6001600160a01b031663e50a31b3836060015184608001516040518363ffffffff1660e01b8152600401612adf929190615b21565b600060405180830381600087803b158015612af957600080fd5b505af1158015612b0d573d6000803e3d6000fd5b505050505b81604001519250612b2b8260c0015183606001516141ea565b600060808301819052604080840182905260c0840182905260e0840191909152426101008401526005549051631137390760e21b81526001600160a01b03909116906344dce41c90612b81908590600401615d76565b600060405180830381600087803b158015612b9b57600080fd5b505af1158015612baf573d6000803e3d6000fd5b50505050846001600160a01b03167fcab22a4e95d29d40da2ace3f6ec72b49954a9bc7b2584f8fd47bf7f357a3ed6f85604051612bec9190615b05565b60405180910390a2505092915050565b6000546001600160a01b03163314612c265760405162461bcd60e51b815260040161097590615ce6565b565b600082821115612c4a5760405162461bcd60e51b815260040161097590615c76565b50900390565b6000612c5a613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015612c9257600080fd5b505afa158015612ca6573d6000803e3d6000fd5b50505050612cb2612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b8152600401612cdf9190615b05565b60206040518083038186803b158015612cf757600080fd5b505afa158015612d0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d2f919081019061505d565b15612d4c5760405162461bcd60e51b815260040161097590615cc6565b612d54614c86565b6005546040516350e28ac360e11b81526001600160a01b039091169063a1c5158690612d869033908890600401615aa2565b6101206040518083038186803b158015612d9f57600080fd5b505afa158015612db3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612dd79190810190615107565b9050612de2816143f8565b612deb81613cfe565b6040810151909150612e03908463ffffffff612c2816565b604082015242610100820152600a54612e1b8261146e565b11612e385760405162461bcd60e51b815260040161097590615bb6565b600554604051631137390760e21b81526001600160a01b03909116906344dce41c90612e68908490600401615d76565b600060405180830381600087803b158015612e8257600080fd5b505af1158015612e96573d6000803e3d6000fd5b50505050829150336001600160a01b03167ffae26280bca25d80f1501a9e363c73d3845e651c9aaae54f1fc09a9dcd5f330385858460400151604051612ede93929190615b4f565b60405180910390a25092915050565b612ef5613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015612f2d57600080fd5b505afa158015612f41573d6000803e3d6000fd5b50505050612f4d612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b8152600401612f7a9190615b05565b60206040518083038186803b158015612f9257600080fd5b505afa158015612fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612fca919081019061505d565b15612fe75760405162461bcd60e51b815260040161097590615cc6565b600081116130075760405162461bcd60e51b815260040161097590615d26565b61300f614c86565b6005546040516350e28ac360e11b81526001600160a01b039091169063a1c51586906130419087908790600401615ad8565b6101206040518083038186803b15801561305a57600080fd5b505afa15801561306e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130929190810190615107565b905061309d816143f8565b6130a681613cfe565b60408101519091506130be908363ffffffff61257216565b604080830191909152426101008301526005549051631137390760e21b81526001600160a01b03909116906344dce41c906130fd908490600401615d76565b600060405180830381600087803b15801561311757600080fd5b505af115801561312b573d6000803e3d6000fd5b50505050836001600160a01b03167f0b1992dffc262be88559dcaf96464e9d661d8bfca7e82f2bb73e31932a82187c8484846040015160405161317093929190615b4f565b60405180910390a250505050565b600061264d600a54731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ca57600080fd5b505af41580156131de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506132029190810190615126565b9063ffffffff614bc416565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b8160008151811061325057fe5b60200260200101818152505090565b6060815183510160405190808252806020026020018201604052801561328f578160200160208202803883390190505b50905060005b83518110156132d1578381815181106132aa57fe5b60200260200101518282815181106132be57fe5b6020908102919091010152600101613295565b5060005b8251811015613314578281815181106132ea57fe5b602002602001015182828651018151811061330157fe5b60209081029190910101526001016132d5565b5092915050565b613323613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561335b57600080fd5b505afa15801561336f573d6000803e3d6000fd5b5050505061337b612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b81526004016133a89190615b05565b60206040518083038186803b1580156133c057600080fd5b505afa1580156133d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506133f8919081019061505d565b156134155760405162461bcd60e51b815260040161097590615cc6565b600081116134355760405162461bcd60e51b815260040161097590615c06565b61343d614c86565b6005546040516350e28ac360e11b81526001600160a01b039091169063a1c515869061346f9088908790600401615ad8565b6101206040518083038186803b15801561348857600080fd5b505afa15801561349c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506134c09190810190615107565b90506134cb816143f8565b6134d481613cfe565b90506134e584826060015184614458565b6134ef81836148da565b426101008201529050613500614afd565b6001600160a01b031663d6f32e068583606001516040518363ffffffff1660e01b8152600401613531929190615ad8565b60206040518083038186803b15801561354957600080fd5b505afa15801561355d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613581919081019061505d565b1561359e5760405162461bcd60e51b815260040161097590615d66565b60608101516000908152600860205260409020546135bb906143ed565b6001600160a01b0316639dc29fac85846040518363ffffffff1660e01b81526004016135e8929190615ad8565b600060405180830381600087803b15801561360257600080fd5b505af1158015613616573d6000803e3d6000fd5b5050600554604051631137390760e21b81526001600160a01b0390911692506344dce41c915061364a908490600401615d76565b600060405180830381600087803b15801561366457600080fd5b505af1158015613678573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b03167fdf10512219e869922340b1b24b21d7d79bf71f411a6391cc7c3ef5dd2fe89e7f858585608001516040516136c793929190615b4f565b60405180910390a35050505050565b6136de613cc0565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561371657600080fd5b505afa15801561372a573d6000803e3d6000fd5b50505050613736612652565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b81526004016137639190615b05565b60206040518083038186803b15801561377b57600080fd5b505afa15801561378f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137b3919081019061505d565b156137d05760405162461bcd60e51b815260040161097590615cc6565b6137d8614c86565b6005546040516350e28ac360e11b81526001600160a01b039091169063a1c515869061380a9033908790600401615aa2565b6101206040518083038186803b15801561382357600080fd5b505afa158015613837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061385b9190810190615107565b9050613866816143f8565b61386f81613cfe565b6080810151909150613887908363ffffffff61257216565b6080820152600a546138988261146e565b116138b55760405162461bcd60e51b815260040161097590615bc6565b60006138cc600c5484613ce990919063ffffffff16565b905060006138e0848363ffffffff612c2816565b90508260a0015115613aed576138f4613cda565b6001600160a01b031663e31f27c18460600151866040518363ffffffff1660e01b8152600401613925929190615b21565b600060405180830381600087803b15801561393f57600080fd5b505af1158015613953573d6000803e3d6000fd5b5050505061395f6143d6565b6001600160a01b031663867904b433613976612652565b6001600160a01b031663654a60ac876060015186631cd554d160e21b6040518463ffffffff1660e01b81526004016139b093929190615b4f565b60206040518083038186803b1580156139c857600080fd5b505afa1580156139dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613a009190810190615126565b6040518363ffffffff1660e01b8152600401613a1d929190615aa2565b600060405180830381600087803b158015613a3757600080fd5b505af1158015613a4b573d6000803e3d6000fd5b5050505060608301516000908152600960205260409020546001600160a01b031615613ae85760608301516000908152600960205260409081902054905163db454a5160e01b81526001600160a01b039091169063db454a5190613ab59033908890600401615aa2565b600060405180830381600087803b158015613acf57600080fd5b505af1158015613ae3573d6000803e3d6000fd5b505050505b613bd5565b613af5613cda565b6001600160a01b031663eb94bbde8460600151866040518363ffffffff1660e01b8152600401613b26929190615b21565b600060405180830381600087803b158015613b4057600080fd5b505af1158015613b54573d6000803e3d6000fd5b5050506060840151600090815260086020526040902054613b7591506143ed565b6001600160a01b031663867904b433836040518363ffffffff1660e01b8152600401613ba2929190615aa2565b600060405180830381600087803b158015613bbc57600080fd5b505af1158015613bd0573d6000803e3d6000fd5b505050505b613be38284606001516141ea565b42610100840152600554604051631137390760e21b81526001600160a01b03909116906344dce41c90613c1a908690600401615d76565b600060405180830381600087803b158015613c3457600080fd5b505af1158015613c48573d6000803e3d6000fd5b50505050336001600160a01b03167f5754fe57f36ac0f121901d7555aba517e6608590429d86a81c662cf3583106548686604051613c87929190615b21565b60405180910390a25050505050565b60006111da82613cb485670de0b6b3a764000063ffffffff614b8a16565b9063ffffffff614bd916565b600061264d6b53797374656d53746174757360a01b614b2d565b6006546001600160a01b031690565b60006111da8383670de0b6b3a7640000614c0e565b613d06614c86565b8190506000806000808560a00151613da457613d20613cda565b6001600160a01b03166303f048b08760e001516040518263ffffffff1660e01b8152600401613d4f9190615b05565b60806040518083038186803b158015613d6757600080fd5b505afa158015613d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613d9f9190810190615163565b613e31565b613dac613cda565b6001600160a01b031663af07aa9d87606001518860e001516040518363ffffffff1660e01b8152600401613de1929190615b21565b60806040518083038186803b158015613df957600080fd5b505afa158015613e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613e319190810190615163565b93509350935093506000808760a00151613ec157613e4d613cda565b6001600160a01b031663ba1c5e806040518163ffffffff1660e01b8152600401604080518083038186803b158015613e8457600080fd5b505afa158015613e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613ebc9190810190615144565b613f59565b613ec9613cda565b606089015160009081526008602052604090819020549051630ee81f7960e41b81526001600160a01b03929092169163ee81f79091613f0a91600401615b05565b604080518083038186803b158015613f2157600080fd5b505afa158015613f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613f599190810190615144565b915091508015613f7b5760405162461bcd60e51b815260040161097590615c96565b6000614018731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015613fc457600080fd5b505af4158015613fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613ffc9190810190615126565b61400c428863ffffffff612c2816565b9063ffffffff614b8a16565b9050600061403c61402f858463ffffffff61266d16565b889063ffffffff61257216565b905060008a60e001516000146140755761407061405f838b63ffffffff612c2816565b60808d01519063ffffffff61266d16565b614078565b60005b90508a60a001516140ed5761408b613cda565b6001600160a01b031663f53037b6836040518263ffffffff1660e01b81526004016140b69190615b05565b600060405180830381600087803b1580156140d057600080fd5b505af11580156140e4573d6000803e3d6000fd5b50505050614159565b6140f5613cda565b6001600160a01b031663246206398c60600151846040518363ffffffff1660e01b8152600401614126929190615b21565b600060405180830381600087803b15801561414057600080fd5b505af1158015614154573d6000803e3d6000fd5b505050505b60c08b015161416e908263ffffffff61257216565b60c08b015260e08a01869052600554604051631137390760e21b81526001600160a01b03909116906344dce41c906141aa908d90600401615d76565b600060405180830381600087803b1580156141c457600080fd5b505af11580156141d8573d6000803e3d6000fd5b50505050505050505050505050919050565b8115610cea57631cd554d160e21b811461428f57614206612652565b6001600160a01b031663654a60ac8284631cd554d160e21b6040518463ffffffff1660e01b815260040161423c93929190615b4f565b60206040518083038186803b15801561425457600080fd5b505afa158015614268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061428c9190810190615126565b91505b6142976143d6565b6001600160a01b031663867904b46142ad614c4b565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b1580156142e557600080fd5b505afa1580156142f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061431d9190810190614f2a565b846040518363ffffffff1660e01b815260040161433b929190615ad8565b600060405180830381600087803b15801561435557600080fd5b505af1158015614369573d6000803e3d6000fd5b50505050614375614c4b565b6001600160a01b03166322bf55ef836040518263ffffffff1660e01b81526004016143a09190615b05565b600060405180830381600087803b1580156143ba57600080fd5b505af11580156143ce573d6000803e3d6000fd5b505050505050565b600061264d6814de5b9d1a1cd554d160ba1b614b2d565b600061259a82614b2d565b60008160e001511161441c5760405162461bcd60e51b815260040161097590615d46565b42614437600e5483610100015161257290919063ffffffff16565b11156144555760405162461bcd60e51b815260040161097590615bf6565b50565b6000828152600860205260409020548190614472906143ed565b6001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161449d9190615a86565b60206040518083038186803b1580156144b557600080fd5b505afa1580156144c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506144ed9190810190615126565b10156107095760405162461bcd60e51b815260040161097590615d16565b6000806145298360c00151846080015161257290919063ffffffff16565b608084015160408501519350909150614540614afd565b6001600160a01b031663d6f32e068686606001516040518363ffffffff1660e01b8152600401614571929190615ad8565b60206040518083038186803b15801561458957600080fd5b505afa15801561459d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506145c1919081019061505d565b156145de5760405162461bcd60e51b815260040161097590615d66565b60608401516000908152600860205260409020546145fb906143ed565b6001600160a01b0316639dc29fac86846040518363ffffffff1660e01b8152600401614628929190615ad8565b600060405180830381600087803b15801561464257600080fd5b505af1158015614656573d6000803e3d6000fd5b505050508360a00151156147745761466c613cda565b6001600160a01b0316635246f2b9856060015186608001516040518363ffffffff1660e01b81526004016146a1929190615b21565b600060405180830381600087803b1580156146bb57600080fd5b505af11580156146cf573d6000803e3d6000fd5b5050505060608401516000908152600960205260409020546001600160a01b03161561476f57606084015160009081526009602052604090819020546080860151915163f3fef3a360e01b81526001600160a01b039091169163f3fef3a39161473c918a91600401615ad8565b600060405180830381600087803b15801561475657600080fd5b505af115801561476a573d6000803e3d6000fd5b505050505b6147e4565b61477c613cda565b6001600160a01b031663e50a31b3856060015186608001516040518363ffffffff1660e01b81526004016147b1929190615b21565b600060405180830381600087803b1580156147cb57600080fd5b505af11580156147df573d6000803e3d6000fd5b505050505b6147f68460c0015185606001516141ea565b600060808501819052604080860182905260c0860182905260e0860191909152426101008601526005549051631137390760e21b81526001600160a01b03909116906344dce41c9061484c908790600401615d76565b600060405180830381600087803b15801561486657600080fd5b505af115801561487a573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b03167f697721ed1b9d4866cb1aaa0692f62bb3abc1b01c2dafeaad053ffd4532aa7dbb866000015184876040516148c993929190615b4f565b60405180910390a350509392505050565b6148e2614c86565b508181158015906148f7575060008360c00151115b156149545760008360c00151831161490f5782614915565b8360c001515b60c085015190915061492d908263ffffffff612c2816565b60c0830152614942838263ffffffff612c2816565b92506149528185606001516141ea565b505b811561259a57608083015161496f908363ffffffff612c2816565b608082015260a081015115614a8c57614986613cda565b6001600160a01b0316635246f2b98260600151846040518363ffffffff1660e01b81526004016149b7929190615b21565b600060405180830381600087803b1580156149d157600080fd5b505af11580156149e5573d6000803e3d6000fd5b5050505060608101516000908152600960205260409020546001600160a01b031615614a875760608101516000908152600960209081526040918290205490830151915163f3fef3a360e01b81526001600160a01b039091169163f3fef3a391614a5491908690600401615aa2565b600060405180830381600087803b158015614a6e57600080fd5b505af1158015614a82573d6000803e3d6000fd5b505050505b61259a565b614a94613cda565b6001600160a01b031663e50a31b38260600151846040518363ffffffff1660e01b8152600401614ac5929190615b21565b600060405180830381600087803b158015614adf57600080fd5b505af1158015614af3573d6000803e3d6000fd5b5050505092915050565b600061264d6822bc31b430b733b2b960b91b614b2d565b600061264d6e466c657869626c6553746f7261676560881b5b60008181526003602090815260408083205490516001600160a01b039091169182151591614b5d91869101615a50565b604051602081830303815290604052906133145760405162461bcd60e51b81526004016109759190615b85565b600082614b995750600061259a565b82820282848281614ba657fe5b04146125975760405162461bcd60e51b815260040161097590615d06565b60006111da8383670de0b6b3a7640000614c60565b6000808211614bfa5760405162461bcd60e51b815260040161097590615c86565b6000828481614c0557fe5b04949350505050565b600080600a8304614c25868663ffffffff614b8a16565b81614c2c57fe5b0490506005600a825b0610614c3f57600a015b600a9004949350505050565b600061264d66119959541bdbdb60ca1b614b2d565b600080614c7a84613cb487600a870263ffffffff614b8a16565b90506005600a82614c35565b6040518061012001604052806000815260200160006001600160a01b031681526020016000815260200160008019168152602001600081526020016000151581526020016000815260200160008152602001600081525090565b803561259a81615eb2565b805161259a81615eb2565b60008083601f840112614d0857600080fd5b50813567ffffffffffffffff811115614d2057600080fd5b602083019150836020820283011115614d3857600080fd5b9250929050565b803561259a81615ec6565b805161259a81615ec6565b803561259a81615ecf565b805161259a81615ecf565b60006101208284031215614d7e57600080fd5b614d89610120615e0f565b90506000614d978484614d55565b8252506020614da884848301614ce0565b6020830152506040614dbc84828501614d55565b6040830152506060614dd084828501614d55565b6060830152506080614de484828501614d55565b60808301525060a0614df884828501614d3f565b60a08301525060c0614e0c84828501614d55565b60c08301525060e0614e2084828501614d55565b60e083015250610100614e3584828501614d55565b6101008301525092915050565b60006101208284031215614e5557600080fd5b614e60610120615e0f565b90506000614e6e8484614d60565b8252506020614e7f84848301614ceb565b6020830152506040614e9384828501614d60565b6040830152506060614ea784828501614d60565b6060830152506080614ebb84828501614d60565b60808301525060a0614ecf84828501614d4a565b60a08301525060c0614ee384828501614d60565b60c08301525060e0614ef784828501614d60565b60e083015250610100614e3584828501614d60565b600060208284031215614f1e57600080fd5b60006108888484614ce0565b600060208284031215614f3c57600080fd5b60006108888484614ceb565b60008060408385031215614f5b57600080fd5b6000614f678585614ce0565b9250506020614f7885828601614d55565b9150509250929050565b600080600060608486031215614f9757600080fd5b6000614fa38686614ce0565b9350506020614fb486828701614d55565b9250506040614fc586828701614d55565b9150509250925092565b60008060008060408587031215614fe557600080fd5b843567ffffffffffffffff811115614ffc57600080fd5b61500887828801614cf6565b9450945050602085013567ffffffffffffffff81111561502757600080fd5b61503387828801614cf6565b95989497509550505050565b60006020828403121561505157600080fd5b60006108888484614d3f565b60006020828403121561506f57600080fd5b60006108888484614d4a565b6000806040838503121561508e57600080fd5b600061509a8585614d4a565b9250506020614f7885828601614d4a565b6000602082840312156150bd57600080fd5b60006108888484614d55565b600080604083850312156150dc57600080fd5b6000614f678585614d55565b600061012082840312156150fb57600080fd5b60006108888484614d6b565b6000610120828403121561511a57600080fd5b60006108888484614e42565b60006020828403121561513857600080fd5b60006108888484614d60565b6000806040838503121561515757600080fd5b600061509a8585614d60565b6000806000806080858703121561517957600080fd5b60006151858787614d60565b945050602061519687828801614d60565b93505060406151a787828801614d60565b92505060606151b887828801614d60565b91505092959194509250565b60006151d08383615252565b505060200190565b6151e181615e6a565b82525050565b6151e181615e4e565b60006151fb82615e3c565b6152058185615e40565b935061521083615e36565b8060005b8381101561523e57815161522888826151c4565b975061523383615e36565b925050600101615214565b509495945050505050565b6151e181615e59565b6151e181610bf2565b6151e161526782610bf2565b610bf2565b6151e181615e71565b600061528082615e3c565b61528a8185615e40565b935061529a818560208601615e7c565b6152a381615ea8565b9093019392505050565b60006152ba601b83615e40565b7f496e707574206172726179206c656e677468206d69736d617463680000000000815260200192915050565b60006152f3601683615e40565b754d7573742062652067726561746572207468616e203160501b815260200192915050565b6000615325600e83615e40565b6d43726174696f20746f6f206c6f7760901b815260200192915050565b600061534f601583615e40565b74086c2dcdcdee840c8e4c2ee40e8d0d2e640daeac6d605b1b815260200192915050565b6000615380603583615e40565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b60006153d7600f83615e40565b6e151c985b9cd9995c8819985a5b1959608a1b815260200192915050565b6000615402601d83615e40565b7f4c6f616e20726563656e746c7920696e74657261637465642077697468000000815260200192915050565b600061543b601e83615e40565b7f5061796d656e74206d7573742062652067726561746572207468616e20300000815260200192915050565b6000615474601b83615e40565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006154ad601283615e40565b7113585e081b1bd85b9cc8195e18d95959195960721b815260200192915050565b60006154db601e83615e40565b7f43726174696f2061626f7665206c69717569646174696f6e20726174696f0000815260200192915050565b6000615514601d83615e40565b7f4e6f7420656e6f75676820636f6c6c61746572616c20746f206f70656e000000815260200192915050565b600061554d601883615e40565b7f43757272656e6379207261746520697320696e76616c69640000000000000000815260200192915050565b6000615586602083615e40565b7f57616974696e672073656373206f7220736574746c656d656e74206f77696e67815260200192915050565b60006155bf601e83615e40565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b60006155f8601a83615e40565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b6000615631601183615e49565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b600061565e601183615e40565b7014985d195cc8185c99481a5b9d985b1a59607a1b815260200192915050565b600061568b601383615e40565b7213dc195b9a5b99c81a5cc8191a5cd8589b1959606a1b815260200192915050565b60006156ba600a83615e40565b6926b0bc1018903437bab960b11b815260200192915050565b60006156e0601a83615e40565b7f436f6c6c61746572616c207261746520697320696e76616c6964000000000000815260200192915050565b6000615719601b83615e40565b7f45786365656473206d617820626f72726f77696e6720706f7765720000000000815260200192915050565b6000615752602f83615e40565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b60006157a3601f83615e40565b7f4e6f7420616c6c6f77656420746f20697373756520746869732073796e746800815260200192915050565b60006157dc602183615e40565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061581f601883615e40565b7f4e6f7420656e6f7567682073796e74682062616c616e63650000000000000000815260200192915050565b6000615858601e83615e40565b7f4465706f736974206d7573742062652067726561746572207468616e20300000815260200192915050565b6000615891601a83615e40565b7f44656274206c696d6974206f7220696e76616c69642072617465000000000000815260200192915050565b60006158ca601983615e49565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b600061259a600083615e49565b6000615910601383615e40565b72131bd85b88191bd95cc81b9bdd08195e1a5cdd606a1b815260200192915050565b600061593f601f83615e40565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000615978601b83615e40565b7f57616974696e67206f7220736574746c656d656e74206f77696e670000000000815260200192915050565b80516101208301906159b68482615252565b5060208201516159c960208501826151e7565b5060408201516159dc6040850182615252565b5060608201516159ef6060850182615252565b506080820151615a026080850182615252565b5060a0820151615a1560a0850182615249565b5060c0820151615a2860c0850182615252565b5060e0820151615a3b60e0850182615252565b50610100820151610ad7610100850182615252565b6000615a5b82615624565b9150615a67828461525b565b50602001919050565b6000615a5b826158bd565b600061259a826158f6565b6020810161259a82846151e7565b6020810161259a82846151d8565b60408101615ab082856151d8565b6111da6020830184615252565b60408101615acb82856151e7565b6111da60208301846151e7565b60408101615ab082856151e7565b602080825281016111da81846151f0565b6020810161259a8284615249565b6020810161259a8284615252565b60408101615acb8285615252565b60408101615ab08285615252565b60408101615b3d8285615252565b81810360208301526108888184615275565b60608101615b5d8286615252565b615b6a6020830185615252565b6108886040830184615252565b6020810161259a828461526c565b602080825281016111da8184615275565b6020808252810161259a816152ad565b6020808252810161259a816152e6565b6020808252810161259a81615318565b6020808252810161259a81615342565b6020808252810161259a81615373565b6020808252810161259a816153ca565b6020808252810161259a816153f5565b6020808252810161259a8161542e565b6020808252810161259a81615467565b6020808252810161259a816154a0565b6020808252810161259a816154ce565b6020808252810161259a81615507565b6020808252810161259a81615540565b6020808252810161259a81615579565b6020808252810161259a816155b2565b6020808252810161259a816155eb565b6020808252810161259a81615651565b6020808252810161259a8161567e565b6020808252810161259a816156ad565b6020808252810161259a816156d3565b6020808252810161259a8161570c565b6020808252810161259a81615745565b6020808252810161259a81615796565b6020808252810161259a816157cf565b6020808252810161259a81615812565b6020808252810161259a8161584b565b6020808252810161259a81615884565b6020808252810161259a81615903565b6020808252810161259a81615932565b6020808252810161259a8161596b565b610120810161259a82846159a4565b60808101615d938287615252565b615da060208301866151d8565b615dad6040830185615252565b615dba6060830184615252565b95945050505050565b60a08101615dd18288615252565b615dde6020830187615252565b615deb6040830186615252565b615df86060830185615252565b615e056080830184615252565b9695505050505050565b60405181810167ffffffffffffffff81118282101715615e2e57600080fd5b604052919050565b60200190565b5190565b90815260200190565b919050565b600061259a82615e5e565b151590565b6001600160a01b031690565b600061259a825b600061259a82615e4e565b60005b83811015615e97578181015183820152602001615e7f565b83811115610ad75750506000910152565b601f01601f191690565b615ebb81615e4e565b811461445557600080fd5b615ebb81615e59565b615ebb81610bf256fea365627a7a723158204f8c74024927e46661278ea6cfe2e203eefaf23b2400b6cd678f30b0a7e255d96c6578706572696d656e74616cf564736f6c634300051000400000000000000000000000004b58bbb4ff947315b558904fdcebbda65b9523ad000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f617688200000000000000000000000053bae964339e8a742b5b47f6c10bbfa8ff138f34000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd27345544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120a871cc00200000000000000000000000000000000000000000000000000001bc16d674ec80000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004b58bbb4ff947315b558904fdcebbda65b9523ad000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f617688200000000000000000000000053bae964339e8a742b5b47f6c10bbfa8ff138f34000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd27345544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120a871cc00200000000000000000000000000000000000000000000000000001bc16d674ec80000
-----Decoded View---------------
Arg [0] : _state (address): 0x4b58bbb4ff947315b558904fdcebbda65b9523ad
Arg [1] : _owner (address): 0xb64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [2] : _manager (address): 0x53bae964339e8a742b5b47f6c10bbfa8ff138f34
Arg [3] : _resolver (address): 0x242a3df52c375bee81b1c668741d7c63af68fdd2
Arg [4] : _collateralKey (bytes32): 0x7345544800000000000000000000000000000000000000000000000000000000
Arg [5] : _minCratio (uint256): 1300000000000000000
Arg [6] : _minCollateral (uint256): 2000000000000000000
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000004b58bbb4ff947315b558904fdcebbda65b9523ad
Arg [1] : 000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [2] : 00000000000000000000000053bae964339e8a742b5b47f6c10bbfa8ff138f34
Arg [3] : 000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2
Arg [4] : 7345544800000000000000000000000000000000000000000000000000000000
Arg [5] : 000000000000000000000000000000000000000000000000120a871cc0020000
Arg [6] : 0000000000000000000000000000000000000000000000001bc16d674ec80000
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.