More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x61016060 | 18113589 | 366 days ago | IN | 0 ETH | 0.10563236 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
DsrAsset
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; // ==================================================================== // ========================= DsrAsset.sol ========================== // ==================================================================== /** * @title DSR Asset * @dev Representation of an on-chain investment on a DAI */ import "./DAI/IDsrManager.sol"; import "./DAI/IPot.sol"; import "./DAI/IPsm.sol"; import "../Libraries/RMath.sol"; import "../Stabilizer/Stabilizer.sol"; contract DsrAsset is Stabilizer { IERC20Metadata private immutable dai; IDsrManager private immutable dsrManager; IPot private immutable pot; IPsm private immutable psm; IPriceFeed private immutable oracleDai; address private immutable gemJoin; uint256 private constant WAD = 10 ** 18; // Events event Invested(uint256 indexed usdxAmount); event Divested(uint256 indexed usdxAmount); // Errors error UnExpectedAmount(); constructor( string memory _name, address _sweep, address _usdx, address _dai, address _dsrManager, address _dssPsm, address _oracleUsdx, address _oracleDai, address _borrower ) Stabilizer(_name, _sweep, _usdx, _oracleUsdx, _borrower) { dai = IERC20Metadata(_dai); dsrManager = IDsrManager(_dsrManager); pot = IPot(dsrManager.pot()); psm = IPsm(_dssPsm); gemJoin = psm.gemJoin(); oracleDai = IPriceFeed(_oracleDai); } /* ========== Views ========== */ /** * @notice Get Current Value * @return uint256 Current Value. * @dev this value represents the invested amount plus the staked amount in the contract. */ function currentValue() public view override returns (uint256) { uint256 accruedFeeInUsd = sweep.convertToUSD(accruedFee()); return assetValue() + super.currentValue() - accruedFeeInUsd; } /** * @notice Get Asset Value * @return uint256 Asset Amount. * @dev the invested amount in USDX on the DSR. */ function assetValue() public view returns (uint256) { uint256 daiAmount = dsrManager.pieOf(address(this)); uint256 chi = pot.chi(); daiAmount = RMath.rmul(chi, daiAmount); // included reward return _oracleDaiToUsd(daiAmount); } /* ========== Actions ========== */ /** * @notice dsrDaiBalance * @dev Get the invested dai amount */ function dsrDaiBalance() external nonReentrant returns (uint256) { return dsrManager.daiBalance(address(this)); } /** * @notice Invest USDX * @param usdxAmount USDX Amount to be invested. * @param slippage . * @dev Sends balance to DSR. */ function invest( uint256 usdxAmount, uint256 slippage ) external onlyBorrower whenNotPaused nonReentrant validAmount(usdxAmount) { _invest(usdxAmount, 0, slippage); } /** * @notice Divests From DSR. * @param usdxAmount Amount to be divested. * @param slippage . * @dev Sends balance from the DSR to the Asset. */ function divest( uint256 usdxAmount, uint256 slippage ) external onlyBorrower nonReentrant validAmount(usdxAmount) returns (uint256) { return _divest(usdxAmount, slippage); } /** * @notice Liquidate * @dev When the asset is defaulted anyone can liquidate it by * repaying the debt and getting the same value at a discount. */ function liquidate() external nonReentrant { _liquidate(address(dai)); } /* ========== Internals ========== */ /** * @notice Invest * @dev Deposits the amount into the DSR. */ function _invest( uint256 usdxAmount, uint256, uint256 slippage ) internal override { uint256 usdxBalance = usdx.balanceOf(address(this)); uint256 daiBalance = dai.balanceOf(address(this)); if (usdxBalance == 0) revert NotEnoughBalance(); if (usdxBalance < usdxAmount) usdxAmount = usdxBalance; // Exchange Usdx to Dai by using PSM uint256 estimatedAmount = _usdxToDai( OvnMath.subBasisPoints(usdxAmount, slippage) ); TransferHelper.safeApprove(address(usdx), address(gemJoin), usdxAmount); psm.sellGem(address(this), usdxAmount); uint256 investDaiAmount = dai.balanceOf(address(this)) - daiBalance; // Check return amount validation if (investDaiAmount == 0 || investDaiAmount < estimatedAmount) revert UnExpectedAmount(); // Invest Dai to the dsr TransferHelper.safeApprove( address(dai), address(dsrManager), investDaiAmount ); dsrManager.join(address(this), investDaiAmount); emit Invested(_daiToUsdx(investDaiAmount)); } /** * @notice Divest * @dev Withdraws the amount from the DSR. */ function _divest( uint256 usdxAmount, uint256 slippage ) internal override returns (uint256 divestedAmount) { uint256 usdxBalance = usdx.balanceOf(address(this)); uint256 daiBalance = dai.balanceOf(address(this)); uint256 daiAmount = _oracleUsdxToDai(usdxAmount); uint256 investedAmount = dsrManager.daiBalance(address(this)); // Withdraw Dai from DSR if (daiAmount < investedAmount) { dsrManager.exit(address(this), daiAmount); } else { dsrManager.exitAll(address(this)); daiAmount = investedAmount; } uint256 redeemDaiAmount = dai.balanceOf(address(this)) - daiBalance; // Check return amount from dsrManager if (redeemDaiAmount == 0 || redeemDaiAmount < daiAmount) revert UnExpectedAmount(); // Exchange Dai to Usdx by using PSM uint256 estimatedAmount = _daiToUsdx( OvnMath.subBasisPoints(redeemDaiAmount, slippage) ); TransferHelper.safeApprove(address(dai), address(psm), redeemDaiAmount); // Reduce fee from the request Usdx amount uint256 psmFee = psm.tout(); redeemDaiAmount = (redeemDaiAmount * WAD) / (WAD + psmFee); uint256 daiInUsdx = _daiToUsdx(redeemDaiAmount); psm.buyGem(address(this), daiInUsdx); // Sanity check && Calculate real divested Usdx amount if ( estimatedAmount > (divestedAmount = usdx.balanceOf(address(this)) - usdxBalance) ) revert UnExpectedAmount(); emit Divested(divestedAmount); } /** * @notice Convert Dai to Usd by using Oracle */ function _oracleDaiToUsd( uint256 daiAmount ) internal view returns (uint256) { return ChainlinkLibrary.convertTokenToUsd( daiAmount, dai.decimals(), oracleDai ); } /** * @notice Convert Usdx to Dai by using Oracle */ function _oracleUsdxToDai( uint256 usdxAmount ) internal view returns (uint256) { return ChainlinkLibrary.convertTokenToToken( usdxAmount, usdx.decimals(), dai.decimals(), oracleUsdx, oracleDai ); } /** * @notice Convert Dai to Usdx (1:1 rate) */ function _daiToUsdx(uint256 daiAmount) internal view returns (uint256) { return (daiAmount * (10 ** usdx.decimals())) / (10 ** dai.decimals()); } /** * @notice Convert Usdx to Dai (1:1 rate) */ function _usdxToDai(uint256 usdxAmount) internal view returns (uint256) { return (usdxAmount * (10 ** dai.decimals())) / (10 ** usdx.decimals()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC20/extensions/IERC20Metadata.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, 'STE'); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IAMM { function swapExactInput( address tokenA, address tokenB, uint24 fee, uint256 amountIn, uint256 amountOutMin ) external returns (uint256); function buySweep( address token, uint256 amountIn, uint256 amountOutMin ) external returns (uint256); function sellSweep( address token, uint256 amountIn, uint256 amountOutMin ) external returns (uint256); function sequencer() external view returns (address); function poolFee() external view returns (uint24); function getTWAPrice() external view returns (uint256 amountOut); function getPrice() external view returns (uint256 amountOut); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IDsrManager { function pot() external view returns (address); function pieOf(address usr) external view returns(uint256); function daiBalance(address usr) external returns (uint256 wad); function join(address dst, uint256 wad) external; function exit(address dst, uint256 wad) external; function exitAll(address dst) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IPot { function chi() external view returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IPsm { function tout() external view returns (uint256); function daiJoin() external view returns (address); function gemJoin() external view returns (address); function sellGem(address usr, uint256 gemAmt) external; function buyGem(address usr, uint256 gemAmt) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.8.19; // ========================================================== // ======================= Owned.sol ======================== // ========================================================== import "../Sweep/ISweep.sol"; contract Owned { ISweep public immutable sweep; // Errors error NotGovernance(); error NotMultisigOrGov(); error ZeroAddressDetected(); constructor(address _sweep) { if(_sweep == address(0)) revert ZeroAddressDetected(); sweep = ISweep(_sweep); } modifier onlyGov() { if (msg.sender != sweep.owner()) revert NotGovernance(); _; } modifier onlyMultisigOrGov() { if (msg.sender != sweep.fastMultisig() && msg.sender != sweep.owner()) revert NotMultisigOrGov(); _; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IPriceFeed { function latestAnswer() external view returns (int256); function latestTimestamp() external view returns (uint256); function latestRound() external view returns (uint256); function getAnswer(uint256 roundId) external view returns (int256); function getTimestamp(uint256 roundId) external view returns (uint256); function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } library ChainlinkLibrary { uint8 constant USD_DECIMALS = 6; function getDecimals(IPriceFeed oracle) internal view returns (uint8) { return oracle.decimals(); } function getPrice(IPriceFeed oracle) internal view returns (uint256) { ( uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound ) = oracle.latestRoundData(); require(answeredInRound >= roundID, "Old data"); require(timeStamp > 0, "Round not complete"); return uint256(price); } function getPrice( IPriceFeed oracle, IPriceFeed sequencerOracle, uint256 frequency ) internal view returns (uint256) { if (address(sequencerOracle) != address(0)) checkUptime(sequencerOracle); (uint256 roundId, int256 price, , uint256 updatedAt, ) = oracle .latestRoundData(); require(price > 0 && roundId != 0 && updatedAt != 0, "Invalid Price"); if (frequency > 0) require(block.timestamp - updatedAt <= frequency, "Stale Price"); return uint256(price); } function checkUptime(IPriceFeed sequencerOracle) internal view { (, int256 answer, uint256 startedAt, , ) = sequencerOracle .latestRoundData(); require(answer <= 0, "Sequencer Down"); // 0: Sequencer is up, 1: Sequencer is down require(block.timestamp - startedAt > 1 hours, "Grace Period Not Over"); } function convertTokenToToken( uint256 amount0, uint8 token0Decimals, uint8 token1Decimals, IPriceFeed oracle0, IPriceFeed oracle1 ) internal view returns (uint256 amount1) { uint256 price0 = getPrice(oracle0); uint256 price1 = getPrice(oracle1); amount1 = (amount0 * price0 * (10 ** token1Decimals)) / (price1 * (10 ** token0Decimals)); } function convertTokenToUsd( uint256 amount, uint8 tokenDecimals, IPriceFeed oracle ) internal view returns (uint256 amountUsd) { uint8 decimals = getDecimals(oracle); uint256 price = getPrice(oracle); amountUsd = (amount * price * (10 ** USD_DECIMALS)) / 10 ** (decimals + tokenDecimals); } function convertUsdToToken( uint256 amountUsd, uint256 tokenDecimals, IPriceFeed oracle ) internal view returns (uint256 amount) { uint8 decimals = getDecimals(oracle); uint256 price = getPrice(oracle); amount = (amountUsd * 10 ** (decimals + tokenDecimals)) / (price * (10 ** USD_DECIMALS)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; library OvnMath { uint256 constant BASIS_DENOMINATOR = 1e6; function abs(uint256 x, uint256 y) internal pure returns (uint256) { return (x > y) ? (x - y) : (y - x); } function addBasisPoints( uint256 amount, uint256 basisPoints ) internal pure returns (uint256) { return (amount * (BASIS_DENOMINATOR + basisPoints)) / BASIS_DENOMINATOR; } function reverseAddBasisPoints( uint256 amount, uint256 basisPoints ) internal pure returns (uint256) { return (amount * BASIS_DENOMINATOR) / (BASIS_DENOMINATOR + basisPoints); } function subBasisPoints( uint256 amount, uint256 basisPoints ) internal pure returns (uint256) { return (amount * (BASIS_DENOMINATOR - basisPoints)) / BASIS_DENOMINATOR; } function reverseSubBasisPoints( uint256 amount, uint256 basisPoints ) internal pure returns (uint256) { return (amount * BASIS_DENOMINATOR) / (BASIS_DENOMINATOR - basisPoints); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; library RMath { uint256 constant RAY = 10 ** 27; function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { // always rounds down z = mul(x, y) / RAY; } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { // always rounds down z = mul(x, RAY) / y; } function rdivup(uint256 x, uint256 y) internal pure returns (uint256 z) { // always rounds up z = add(mul(x, RAY), sub(y, 1)) / y; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; // ==================================================================== // ====================== Stabilizer.sol ============================== // ==================================================================== /** * @title Stabilizer * @dev Implementation: * Allows to take debt by minting sweep and repaying by burning sweep * Allows to buy and sell sweep in an AMM * Allows auto invest according the borrower configuration * Allows auto repays by the balancer to control sweep price * Allow liquidate the Asset when is defaulted * Repayments made by burning sweep * EquityRatio = Junior / (Junior + Senior) */ import "../AMM/IAMM.sol"; import "../Common/Owned.sol"; import "../Libraries/Chainlink.sol"; import "../Libraries/OvnMath.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; contract Stabilizer is Owned, Pausable, ReentrancyGuard { using Math for uint256; IERC20Metadata public usdx; IPriceFeed public oracleUsdx; // Variables string public name; address public borrower; int256 public minEquityRatio; // Minimum Equity Ratio. 10000 is 1% uint256 public sweepBorrowed; uint256 public loanLimit; uint256 public callTime; uint256 public callDelay; // 86400 is 1 day uint256 public callAmount; uint256 public spreadFee; // 10000 is 1% uint256 public spreadDate; uint256 public liquidatorDiscount; // 10000 is 1% string public link; int256 public autoInvestMinRatio; // 10000 is 1% uint256 public autoInvestMinAmount; bool public autoInvestEnabled; bool public settingsEnabled; // Constants for various precisions uint256 private constant DAY_SECONDS = 60 * 60 * 24; // seconds of Day uint256 private constant DAYS_ONE_YEAR = 365; // days of Year uint256 private constant PRECISION = 1e6; uint256 private constant ORACLE_FREQUENCY = 1 days; /* ========== Events ========== */ event Borrowed(uint256 indexed sweepAmount); event Repaid(uint256 indexed sweepAmount); event Withdrawn(address indexed token, uint256 indexed amount); event PayFee(uint256 indexed sweepAmount); event Bought(uint256 indexed sweepAmount); event Sold(uint256 indexed sweepAmount); event BoughtSWEEP(uint256 indexed sweepAmount); event SoldSWEEP(uint256 indexed usdxAmount); event LoanLimitChanged(uint256 loanLimit); event Proposed(address indexed borrower); event Rejected(address indexed borrower); event SweepBorrowedChanged(uint256 indexed sweepAmount); event Liquidated(address indexed user); event AutoCalled(uint256 indexed sweepAmount); event AutoInvested(uint256 indexed sweepAmount); event CallCancelled(uint256 indexed sweepAmount); event ConfigurationChanged( int256 indexed minEquityRatio, uint256 indexed spreadFee, uint256 loanLimit, uint256 liquidatorDiscount, uint256 callDelay, int256 autoInvestMinRatio, uint256 autoInvestMinAmount, bool autoInvestEnabled, string url ); /* ========== Errors ========== */ error NotBorrower(); error NotBalancer(); error NotSweep(); error SettingsDisabled(); error OverZero(); error WrongMinimumRatio(); error InvalidMinter(); error NotEnoughBalance(); error EquityRatioExcessed(); error InvalidToken(); error SpreadNotEnough(); error NotDefaulted(); error ZeroPrice(); error NotAutoInvest(); error NotAutoInvestMinAmount(); error NotAutoInvestMinRatio(); /* ========== Modifies ========== */ modifier onlyBorrower() { _onlyBorrower(); _; } modifier onlySettingsEnabled() { _onlySettingsEnabled(); _; } modifier validAmount(uint256 amount) { _validAmount(amount); _; } constructor( string memory _name, address _sweep, address _usdx, address _oracleUsdx, address _borrower ) Owned(_sweep) { if (_borrower == address(0)) revert ZeroAddressDetected(); name = _name; usdx = IERC20Metadata(_usdx); oracleUsdx = IPriceFeed(_oracleUsdx); borrower = _borrower; settingsEnabled = true; } /* ========== Views ========== */ /** * @notice Defaulted * @return bool that tells if stabilizer is in default. */ function isDefaulted() public view returns (bool) { return (callDelay > 0 && callAmount > 0 && block.timestamp > callTime) || (sweepBorrowed > 0 && getEquityRatio() < minEquityRatio); } /** * @notice Get Equity Ratio * @return the current equity ratio based in the internal storage. * @dev this value have a precision of 6 decimals. */ function getEquityRatio() public view returns (int256) { return _calculateEquityRatio(0, 0); } /** * @notice Get Spread Amount * fee = borrow_amount * spread_ratio * (time / time_per_year) * @return uint256 calculated spread amount. */ function accruedFee() public view returns (uint256) { if (sweepBorrowed > 0) { uint256 period = (block.timestamp - spreadDate) / DAY_SECONDS; return (sweepBorrowed * spreadFee * period) / (DAYS_ONE_YEAR * PRECISION); } return 0; } /** * @notice Get Debt Amount * debt = borrow_amount + spread fee * @return uint256 calculated debt amount. */ function getDebt() public view returns (uint256) { return sweepBorrowed + accruedFee(); } /** * @notice Get Current Value * value = sweep balance + usdx balance * @return uint256. */ function currentValue() public view virtual returns (uint256) { (uint256 usdxBalance, uint256 sweepBalance) = _balances(); uint256 sweepInUsd = sweep.convertToUSD(sweepBalance); uint256 usdxInUsd = _oracleUsdxToUsd(usdxBalance); return usdxInUsd + sweepInUsd; } /** * @notice Get AMM from Sweep * @return address. */ function amm() public view virtual returns (IAMM) { return IAMM(sweep.amm()); } /** * @notice Get Junior Tranche Value * @return int256 calculated junior tranche amount. */ function getJuniorTrancheValue() external view returns (int256) { uint256 seniorTrancheInUSD = sweep.convertToUSD(sweepBorrowed); uint256 totalValue = currentValue(); return int256(totalValue) - int256(seniorTrancheInUSD); } /** * @notice Returns the SWEEP required to liquidate the stabilizer * @return uint256 */ function getLiquidationValue() public view returns (uint256) { return accruedFee() + sweep.convertToSWEEP( (currentValue() * (1e6 - liquidatorDiscount)) / PRECISION ); } /* ========== Settings ========== */ /** * @notice Pause * @dev Stops investment actions. */ function pause() external onlyMultisigOrGov { _pause(); } /** * @notice Unpause * @dev Start investment actions. */ function unpause() external onlyMultisigOrGov { _unpause(); } /** * @notice Configure intial settings * @param _minEquityRatio The minimum equity ratio can be negative. * @param _spreadFee The fee that the protocol will get for providing the loan when the stabilizer takes debt * @param _loanLimit How much debt a Stabilizer can take in SWEEP. * @param _liquidatorDiscount A percentage that will be discounted in favor to the liquidator when the stabilizer is liquidated * @param _callDelay Time in seconds after AutoCall until the Stabilizer gets defaulted if the debt is not paid in that period * @param _autoInvestMinRatio Minimum equity ratio that should be kept to allow the execution of an auto invest * @param _autoInvestMinAmount Minimum amount to be invested to allow the execution of an auto invest * @param _autoInvestEnabled Represents if an auto invest execution is allowed or not * @param _url A URL link to a Web page that describes the borrower and the asset * @dev Sets the initial configuration of the Stabilizer. * This configuration will be analyzed by the protocol and if accepted, * used to include the Stabilizer in the minter's whitelist of Sweep. * The minimum equity ratio can not be less than 1% */ function configure( int256 _minEquityRatio, uint256 _spreadFee, uint256 _loanLimit, uint256 _liquidatorDiscount, uint256 _callDelay, int256 _autoInvestMinRatio, uint256 _autoInvestMinAmount, bool _autoInvestEnabled, string calldata _url ) external onlyBorrower onlySettingsEnabled { minEquityRatio = _minEquityRatio; spreadFee = _spreadFee; loanLimit = _loanLimit; liquidatorDiscount = _liquidatorDiscount; callDelay = _callDelay; autoInvestMinRatio = _autoInvestMinRatio; autoInvestMinAmount = _autoInvestMinAmount; autoInvestEnabled = _autoInvestEnabled; link = _url; emit ConfigurationChanged( _minEquityRatio, _spreadFee, _loanLimit, _liquidatorDiscount, _callDelay, _autoInvestMinRatio, _autoInvestMinAmount, _autoInvestEnabled, _url ); } /** * @notice Changes the account that control the global configuration to the protocol/governance admin * @dev after disable settings by admin * the protocol will evaluate adding the stabilizer to the minter list. */ function propose() external onlyBorrower { settingsEnabled = false; emit Proposed(borrower); } /** * @notice Changes the account that control the global configuration to the borrower * @dev after enable settings for the borrower * he/she should edit the values to align to the protocol requirements */ function reject() external onlyGov { settingsEnabled = true; emit Rejected(borrower); } /* ========== Actions ========== */ /** * @notice Borrows Sweep * Asks the stabilizer to mint a certain amount of sweep token. * @param sweepAmount. * @dev Increases the sweepBorrowed (senior tranche). */ function borrow( uint256 sweepAmount ) external onlyBorrower whenNotPaused validAmount(sweepAmount) nonReentrant { if (!sweep.isValidMinter(address(this))) revert InvalidMinter(); uint256 sweepAvailable = loanLimit - sweepBorrowed; if (sweepAvailable < sweepAmount) revert NotEnoughBalance(); int256 currentEquityRatio = _calculateEquityRatio(sweepAmount, 0); if (currentEquityRatio < minEquityRatio) revert EquityRatioExcessed(); _borrow(sweepAmount); } /** * @notice Repays Sweep * Burns the sweep amount to reduce the debt (senior tranche). * @param sweepAmount Amount to be burnt by Sweep. * @dev Decreases the sweep borrowed. */ function repay(uint256 sweepAmount) external onlyBorrower nonReentrant { _repay(sweepAmount); } /** * @notice Pay the spread to the treasury */ function payFee() external onlyBorrower nonReentrant { uint256 spreadAmount = accruedFee(); spreadDate = block.timestamp; uint256 sweepBalance = sweep.balanceOf(address(this)); if (spreadAmount > sweepBalance) revert SpreadNotEnough(); if (spreadAmount > 0) { TransferHelper.safeTransfer( address(sweep), sweep.treasury(), spreadAmount ); emit PayFee(spreadAmount); } } /** * @notice Set Loan Limit. * @param newLoanLimit. * @dev How much debt an Stabilizer can take in SWEEP. */ function setLoanLimit(uint256 newLoanLimit) external { if (msg.sender != sweep.balancer()) revert NotBalancer(); loanLimit = newLoanLimit; emit LoanLimitChanged(newLoanLimit); } /** * @notice Update Sweep Borrowed Amount. * @param amount. */ function updateSweepBorrowed(uint256 amount) external { if (msg.sender != address(sweep)) revert NotSweep(); sweepBorrowed = amount; emit SweepBorrowedChanged(amount); } /** * @notice Auto Call. * @param sweepAmount to repay. * @dev Strategy: * 1) repays debt with SWEEP balance * 2) repays remaining debt by divesting * 3) repays remaining debt by buying on SWEEP in the AMM */ function autoCall( uint256 sweepAmount, uint256 price, uint256 slippage ) external nonReentrant { if (msg.sender != sweep.balancer()) revert NotBalancer(); (uint256 usdxBalance, uint256 sweepBalance) = _balances(); uint256 repayAmount = sweepAmount.min(sweepBorrowed); if (callDelay > 0) { callTime = block.timestamp + callDelay; callAmount = repayAmount; } if (sweepBalance < repayAmount) { uint256 missingSweep = repayAmount - sweepBalance; uint256 sweepInUsd = sweep.convertToUSD(missingSweep); uint256 missingUsdx = _oracleUsdToUsdx(sweepInUsd); if (missingUsdx > usdxBalance) { _divest(missingUsdx - usdxBalance, slippage); } if (usdx.balanceOf(address(this)) > 0) { uint256 missingUsd = _oracleUsdxToUsd(missingUsdx); uint256 sweepInUsdx = missingUsd.mulDiv( 10 ** sweep.decimals(), price ); uint256 minAmountOut = OvnMath.subBasisPoints( sweepInUsdx, slippage ); _buy(missingUsdx, minAmountOut); } } if (sweep.balanceOf(address(this)) > 0 && repayAmount > 0) { _repay(repayAmount); } emit AutoCalled(sweepAmount); } /** * @notice Cancel Call * @dev Cancels the auto call request by clearing variables for an asset * that has a callDelay: meaning that it does not autorepay. */ function cancelCall() external { if (msg.sender != sweep.balancer()) revert NotBalancer(); callAmount = 0; callTime = 0; emit CallCancelled(callAmount); } /** * @notice Auto Invest. * @param sweepAmount to mint. * @param price. * @param slippage. */ function autoInvest( uint256 sweepAmount, uint256 price, uint256 slippage ) external nonReentrant { if (msg.sender != sweep.balancer()) revert NotBalancer(); uint256 sweepLimit = sweep.minters(address(this)).maxAmount; uint256 sweepAvailable = sweepLimit - sweepBorrowed; sweepAmount = sweepAmount.min(sweepAvailable); int256 currentEquityRatio = _calculateEquityRatio(sweepAmount, 0); if (!autoInvestEnabled) revert NotAutoInvest(); if (sweepAmount < autoInvestMinAmount) revert NotAutoInvestMinAmount(); if (currentEquityRatio < autoInvestMinRatio) revert NotAutoInvestMinRatio(); _borrow(sweepAmount); uint256 usdAmount = sweepAmount.mulDiv(price, 10 ** sweep.decimals()); uint256 usdInUsdx = _oracleUsdToUsdx(usdAmount); uint256 minAmountOut = OvnMath.subBasisPoints(usdInUsdx, slippage); uint256 usdxAmount = _sell(sweepAmount, minAmountOut); _invest(usdxAmount, 0, slippage); emit AutoInvested(sweepAmount); } /** * @notice Buy * Buys sweep amount from the stabilizer's balance to the AMM (swaps USDX to SWEEP). * @param usdxAmount Amount to be changed in the AMM. * @param amountOutMin Minimum amount out. * @dev Increases the sweep balance and decrease usdx balance. */ function buySweepOnAMM( uint256 usdxAmount, uint256 amountOutMin ) external onlyBorrower whenNotPaused nonReentrant returns (uint256 sweepAmount) { sweepAmount = _buy(usdxAmount, amountOutMin); emit Bought(sweepAmount); } /** * @notice Sell Sweep * Sells sweep amount from the stabilizer's balance to the AMM (swaps SWEEP to USDX). * @param sweepAmount. * @param amountOutMin Minimum amount out. * @dev Decreases the sweep balance and increase usdx balance */ function sellSweepOnAMM( uint256 sweepAmount, uint256 amountOutMin ) external onlyBorrower whenNotPaused nonReentrant returns (uint256 usdxAmount) { usdxAmount = _sell(sweepAmount, amountOutMin); emit Sold(sweepAmount); } /** * @notice Buy Sweep with Stabilizer * Buys sweep amount from the stabilizer's balance to the Borrower (swaps USDX to SWEEP). * @param usdxAmount. * @dev Decreases the sweep balance and increase usdx balance */ function swapUsdxToSweep( uint256 usdxAmount ) external onlyBorrower whenNotPaused validAmount(usdxAmount) nonReentrant { uint256 usdxInUsd = _oracleUsdxToUsd(usdxAmount); uint256 sweepAmount = sweep.convertToSWEEP(usdxInUsd); uint256 sweepBalance = sweep.balanceOf(address(this)); if (sweepAmount > sweepBalance) revert NotEnoughBalance(); TransferHelper.safeTransferFrom( address(usdx), msg.sender, address(this), usdxAmount ); TransferHelper.safeTransfer(address(sweep), msg.sender, sweepAmount); emit BoughtSWEEP(sweepAmount); } /** * @notice Sell Sweep with Stabilizer * Sells sweep amount to the stabilizer (swaps SWEEP to USDX). * @param sweepAmount. * @dev Decreases the sweep balance and increase usdx balance */ function swapSweepToUsdx( uint256 sweepAmount ) external onlyBorrower whenNotPaused validAmount(sweepAmount) nonReentrant { uint256 sweepInUsd = sweep.convertToUSD(sweepAmount); uint256 usdxAmount = _oracleUsdToUsdx(sweepInUsd); uint256 usdxBalance = usdx.balanceOf(address(this)); if (usdxAmount > usdxBalance) revert NotEnoughBalance(); TransferHelper.safeTransferFrom( address(sweep), msg.sender, address(this), sweepAmount ); TransferHelper.safeTransfer(address(usdx), msg.sender, usdxAmount); emit SoldSWEEP(usdxAmount); } /** * @notice Withdraw SWEEP * Takes out sweep balance if the new equity ratio is higher than the minimum equity ratio. * @param token. * @param amount. * @dev Decreases the sweep balance. */ function withdraw( address token, uint256 amount ) external onlyBorrower whenNotPaused validAmount(amount) nonReentrant { if (token != address(sweep) && token != address(usdx)) revert InvalidToken(); if (amount > IERC20Metadata(token).balanceOf(address(this))) revert NotEnoughBalance(); if (sweepBorrowed > 0) { uint256 usdAmount = token == address(sweep) ? sweep.convertToUSD(amount) : _oracleUsdxToUsd(amount); int256 currentEquityRatio = _calculateEquityRatio(0, usdAmount); if (currentEquityRatio < minEquityRatio) revert EquityRatioExcessed(); } TransferHelper.safeTransfer(token, msg.sender, amount); emit Withdrawn(token, amount); } /* ========== Internals ========== */ /** * @notice Invest To Asset. */ function _invest(uint256, uint256, uint256) internal virtual {} /** * @notice Divest From Asset. */ function _divest(uint256, uint256) internal virtual returns (uint256) {} /** * @notice Liquidates * A liquidator repays the debt in sweep and gets the same value * of the assets that the stabilizer holds at a discount */ function _liquidate(address token) internal { if (!isDefaulted()) revert NotDefaulted(); address self = address(this); (uint256 usdxBalance, uint256 sweepBalance) = _balances(); uint256 tokenBalance = IERC20Metadata(token).balanceOf(self); uint256 debt = getDebt(); uint256 sweepToLiquidate = debt - sweepBalance; // Takes SWEEP from the liquidator and repays debt TransferHelper.safeTransferFrom( address(sweep), msg.sender, self, sweepToLiquidate ); _repay(debt); // Gives all the assets to the liquidator TransferHelper.safeTransfer(address(usdx), msg.sender, usdxBalance); TransferHelper.safeTransfer(token, msg.sender, tokenBalance); emit Liquidated(msg.sender); } function _buy( uint256 usdxAmount, uint256 amountOutMin ) internal returns (uint256) { uint256 usdxBalance = usdx.balanceOf(address(this)); usdxAmount = usdxAmount.min(usdxBalance); if (usdxAmount == 0) revert NotEnoughBalance(); IAMM _amm = amm(); TransferHelper.safeApprove(address(usdx), address(_amm), usdxAmount); uint256 sweepAmount = _amm.buySweep( address(usdx), usdxAmount, amountOutMin ); return sweepAmount; } function _sell( uint256 sweepAmount, uint256 amountOutMin ) internal returns (uint256) { uint256 sweepBalance = sweep.balanceOf(address(this)); sweepAmount = sweepAmount.min(sweepBalance); if (sweepAmount == 0) revert NotEnoughBalance(); IAMM _amm = amm(); TransferHelper.safeApprove(address(sweep), address(_amm), sweepAmount); uint256 usdxAmount = _amm.sellSweep( address(usdx), sweepAmount, amountOutMin ); return usdxAmount; } function _borrow(uint256 sweepAmount) internal { uint256 spreadAmount = accruedFee(); sweep.mint(sweepAmount); sweepBorrowed += sweepAmount; spreadDate = block.timestamp; if (spreadAmount > 0) { TransferHelper.safeTransfer( address(sweep), sweep.treasury(), spreadAmount ); emit PayFee(spreadAmount); } emit Borrowed(sweepAmount); } function _repay(uint256 sweepAmount) internal { uint256 sweepBalance = sweep.balanceOf(address(this)); sweepAmount = sweepAmount.min(sweepBalance); if (sweepAmount == 0) revert NotEnoughBalance(); callAmount = (callAmount > sweepAmount) ? (callAmount - sweepAmount) : 0; if (callDelay > 0 && callAmount == 0) callTime = 0; uint256 spreadAmount = accruedFee(); spreadDate = block.timestamp; sweepAmount = sweepAmount - spreadAmount; if (sweepBorrowed < sweepAmount) { sweepAmount = sweepBorrowed; sweepBorrowed = 0; } else { sweepBorrowed -= sweepAmount; } TransferHelper.safeTransfer( address(sweep), sweep.treasury(), spreadAmount ); TransferHelper.safeApprove(address(sweep), address(this), sweepAmount); sweep.burn(sweepAmount); emit Repaid(sweepAmount); } /** * @notice Calculate Equity Ratio * Calculated the equity ratio based on the internal storage. * @param sweepDelta Variation of SWEEP to recalculate the new equity ratio. * @param usdDelta Variation of USD to recalculate the new equity ratio. * @return the new equity ratio used to control the Mint and Withdraw functions. * @dev Current Equity Ratio percentage has a precision of 4 decimals. */ function _calculateEquityRatio( uint256 sweepDelta, uint256 usdDelta ) internal view returns (int256) { uint256 currentValue_ = currentValue(); uint256 sweepDeltaInUsd = sweep.convertToUSD(sweepDelta); uint256 totalValue = currentValue_ + sweepDeltaInUsd - usdDelta; if (totalValue == 0) { if (sweepBorrowed > 0) return -1e6; else return 0; } uint256 seniorTrancheInUsd = sweep.convertToUSD( sweepBorrowed + sweepDelta ); // 1e6 is decimals of the percentage result int256 currentEquityRatio = ((int256(totalValue) - int256(seniorTrancheInUsd)) * 1e6) / int256(totalValue); if (currentEquityRatio < -1e6) currentEquityRatio = -1e6; return currentEquityRatio; } /** * @notice Get Balances of the usdx and SWEEP. **/ function _balances() internal view returns (uint256 usdxBalance, uint256 sweepBalance) { usdxBalance = usdx.balanceOf(address(this)); sweepBalance = sweep.balanceOf(address(this)); } function _onlyBorrower() internal view { if (msg.sender != borrower) revert NotBorrower(); } function _onlySettingsEnabled() internal view { if (!settingsEnabled) revert SettingsDisabled(); } function _validAmount(uint256 amount) internal pure { if (amount == 0) revert OverZero(); } function _oracleUsdxToUsd( uint256 usdxAmount ) internal view returns (uint256) { return ChainlinkLibrary.convertTokenToUsd( usdxAmount, usdx.decimals(), oracleUsdx ); } function _oracleUsdToUsdx( uint256 usdAmount ) internal view returns (uint256) { return ChainlinkLibrary.convertUsdToToken( usdAmount, usdx.decimals(), oracleUsdx ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface ISweep { struct Minter { uint256 maxAmount; uint256 mintedAmount; bool isListed; bool isEnabled; } function DEFAULT_ADMIN_ADDRESS() external view returns (address); function balancer() external view returns (address); function treasury() external view returns (address); function allowance( address holder, address spender ) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); function decimals() external view returns (uint8); function decreaseAllowance( address spender, uint256 subtractedValue ) external returns (bool); function isValidMinter(address) external view returns (bool); function amm() external view returns (address); function ammPrice() external view returns (uint256); function twaPrice() external view returns (uint256); function increaseAllowance( address spender, uint256 addedValue ) external returns (bool); function name() external view returns (string memory); function owner() external view returns (address); function fastMultisig() external view returns (address); function burn(uint256 amount) external; function mint(uint256 amount) external; function minters(address minterAaddress) external returns (Minter memory); function minterAddresses(uint256 index) external view returns (address); function getMinters() external view returns (address[] memory); function targetPrice() external view returns (uint256); function interestRate() external view returns (int256); function periodStart() external view returns (uint256); function stepValue() external view returns (int256); function arbSpread() external view returns (uint256); function refreshInterestRate(int256 newInterestRate, uint256 newPeriodStart) external; function setTargetPrice( uint256 currentTargetPrice, uint256 nextTargetPrice ) external; function setInterestRate( int256 currentInterestRate, int256 nextInterestRate ) external; function setPeriodStart( uint256 currentPeriodStart, uint256 nextPeriodStart ) external; function startNewPeriod() external; function symbol() external view returns (string memory); function totalSupply() external view returns (uint256); function convertToUSD(uint256 amount) external view returns (uint256); function convertToSWEEP(uint256 amount) external view returns (uint256); function transfer( address recipient, uint256 amount ) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_sweep","type":"address"},{"internalType":"address","name":"_usdx","type":"address"},{"internalType":"address","name":"_dai","type":"address"},{"internalType":"address","name":"_dsrManager","type":"address"},{"internalType":"address","name":"_dssPsm","type":"address"},{"internalType":"address","name":"_oracleUsdx","type":"address"},{"internalType":"address","name":"_oracleDai","type":"address"},{"internalType":"address","name":"_borrower","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EquityRatioExcessed","type":"error"},{"inputs":[],"name":"InvalidMinter","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"NotAutoInvest","type":"error"},{"inputs":[],"name":"NotAutoInvestMinAmount","type":"error"},{"inputs":[],"name":"NotAutoInvestMinRatio","type":"error"},{"inputs":[],"name":"NotBalancer","type":"error"},{"inputs":[],"name":"NotBorrower","type":"error"},{"inputs":[],"name":"NotDefaulted","type":"error"},{"inputs":[],"name":"NotEnoughBalance","type":"error"},{"inputs":[],"name":"NotGovernance","type":"error"},{"inputs":[],"name":"NotMultisigOrGov","type":"error"},{"inputs":[],"name":"NotSweep","type":"error"},{"inputs":[],"name":"OverZero","type":"error"},{"inputs":[],"name":"SettingsDisabled","type":"error"},{"inputs":[],"name":"SpreadNotEnough","type":"error"},{"inputs":[],"name":"UnExpectedAmount","type":"error"},{"inputs":[],"name":"WrongMinimumRatio","type":"error"},{"inputs":[],"name":"ZeroAddressDetected","type":"error"},{"inputs":[],"name":"ZeroPrice","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"AutoCalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"AutoInvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"Borrowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"BoughtSWEEP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"CallCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"int256","name":"minEquityRatio","type":"int256"},{"indexed":true,"internalType":"uint256","name":"spreadFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidatorDiscount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"callDelay","type":"uint256"},{"indexed":false,"internalType":"int256","name":"autoInvestMinRatio","type":"int256"},{"indexed":false,"internalType":"uint256","name":"autoInvestMinAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"autoInvestEnabled","type":"bool"},{"indexed":false,"internalType":"string","name":"url","type":"string"}],"name":"ConfigurationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"name":"Divested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"name":"Invested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanLimit","type":"uint256"}],"name":"LoanLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"PayFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"}],"name":"Proposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"}],"name":"Rejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"Repaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"Sold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"name":"SoldSWEEP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"SweepBorrowedChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"accruedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm","outputs":[{"internalType":"contract IAMM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"autoCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"autoInvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"autoInvestEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoInvestMinAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoInvestMinRatio","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrower","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"buySweepOnAMM","outputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"callAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"_minEquityRatio","type":"int256"},{"internalType":"uint256","name":"_spreadFee","type":"uint256"},{"internalType":"uint256","name":"_loanLimit","type":"uint256"},{"internalType":"uint256","name":"_liquidatorDiscount","type":"uint256"},{"internalType":"uint256","name":"_callDelay","type":"uint256"},{"internalType":"int256","name":"_autoInvestMinRatio","type":"int256"},{"internalType":"uint256","name":"_autoInvestMinAmount","type":"uint256"},{"internalType":"bool","name":"_autoInvestEnabled","type":"bool"},{"internalType":"string","name":"_url","type":"string"}],"name":"configure","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"divest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dsrDaiBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEquityRatio","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getJuniorTrancheValue","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLiquidationValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"invest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isDefaulted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"link","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidatorDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loanLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minEquityRatio","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleUsdx","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"propose","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"sellSweepOnAMM","outputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLoanLimit","type":"uint256"}],"name":"setLoanLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settingsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spreadDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spreadFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"swapSweepToUsdx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"name":"swapUsdxToSweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sweep","outputs":[{"internalType":"contract ISweep","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sweepBorrowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"updateSweepBorrowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdx","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101606040523480156200001257600080fd5b50604051620055f5380380620055f583398101604081905262000035916200023e565b8888888584836001600160a01b0381166200006357604051632887dd7560e11b815260040160405180910390fd5b6001600160a01b039081166080526000805460ff191690556001805581166200009f57604051632887dd7560e11b815260040160405180910390fd5b6004620000ad868262000438565b50600280546001600160a01b039485166001600160a01b031991821617909155600380549385169382169390931790925560058054918416919092161790556012805461ff00191661010017905588811660a052871660c0819052604080516325d11b1d60e11b81529051919350634ba2363a92506004808201926020929091908290030181865afa15801562000148573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016e919062000504565b6001600160a01b0390811660e05284166101008190526040805162b327b360e11b815290516301664f66916004808201926020929091908290030181865afa158015620001bf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e5919062000504565b6001600160a01b0390811661014052919091166101205250620005299650505050505050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200023957600080fd5b919050565b60008060008060008060008060006101208a8c0312156200025e57600080fd5b89516001600160401b03808211156200027657600080fd5b818c0191508c601f8301126200028b57600080fd5b815181811115620002a057620002a06200020b565b604051601f8201601f19908116603f01168101908382118183101715620002cb57620002cb6200020b565b81604052828152602093508f84848701011115620002e857600080fd5b600091505b828210156200030c5784820184015181830185015290830190620002ed565b6000848483010152809d5050505062000327818d0162000221565b995050506200033960408b0162000221565b96506200034960608b0162000221565b95506200035960808b0162000221565b94506200036960a08b0162000221565b93506200037960c08b0162000221565b92506200038960e08b0162000221565b91506200039a6101008b0162000221565b90509295985092959850929598565b600181811c90821680620003be57607f821691505b602082108103620003df57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200043357600081815260208120601f850160051c810160208610156200040e5750805b601f850160051c820191505b818110156200042f578281556001016200041a565b5050505b505050565b81516001600160401b038111156200045457620004546200020b565b6200046c81620004658454620003a9565b84620003e5565b602080601f831160018114620004a457600084156200048b5750858301515b600019600386901b1c1916600185901b1785556200042f565b600085815260208120601f198616915b82811015620004d557888601518255948401946001909101908401620004b4565b5085821015620004f45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200051757600080fd5b620005228262000221565b9392505050565b60805160a05160c05160e051610100516101205161014051614ea3620007526000396000613bb7015260008181613f0501526142d401526000818161301b01528181613044015281816131200152613bf80152600061197301526000818161099d0152818161190201528181612da301528181612e3601528181612eb401528181613d450152613d86015260008181610b1601528181612d0801528181612f3e01528181612ffa01528181613af401528181613c7e01528181613d2401528181613e8301528181614246015281816142fc01526144eb01526000818161040401528181610719015281816107a70152818161085201528181610a2201528181610b7e01528181610c1e01528181610c3f01528181610d0701528181610d7c01528181610dfe01528181610f1101528181610faf015281816110a5015281816111ff015281816112bf0152818161137701528181611440015281816115610152818161166d0152818161170b015281816117cb01528181611a1401528181611b4401528181611c6201528181611d3001528181611e7901528181611fed015281816120ed01528181612148015281816122d2015281816123ec015281816128d60152818161297401528181612aa601528181612ac701528181612b5201528181612b8e015281816133da015281816134ae0152818161356301528181613666015281816136f00152818161371101528181613951015281816139fc0152613fb20152614ea36000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c806361ab077f1161019d578063bc5477ad116100e9578063d87aa643116100a2578063f686138d1161007c578063f686138d14610593578063f69aa3d51461059c578063f95c1b26146105af578063fa45d562146105bc57600080fd5b8063d87aa64314610564578063de839ba414610577578063f3fef3a31461058057600080fd5b8063bc5477ad14610513578063c0f4a00514610526578063c198f8ba14610538578063c5ebeaec14610540578063c6beb58614610553578063d366a41f1461055c57600080fd5b8063867e5cb811610156578063a195166511610130578063a1951665146104f1578063a38aaa90146104fa578063a71891c314610502578063ad81fced1461050a57600080fd5b8063867e5cb8146104cd5780638d1d7c61146104d6578063907a9429146104e957600080fd5b806361ab077f1461047c578063698996f81461048f578063717e794d146104975780637df1f1b91461049f5780638351faf5146104b25780638456cb59146104c557600080fd5b8063296102521161025c57806335faa416116102155780634696c749116101ef5780634696c7491461044157806348dcacab146104545780634dc415de1461045d5780635c975abb1461046557600080fd5b806335faa416146103ff578063371fd8e6146104265780633f4ba83a1461043957600080fd5b8063296102521461039557806329b154c31461039d5780632a943945146103b05780632d76643c146103d0578063311176d7146103d95780633168b03f146103ec57600080fd5b80631b0e0898116102ae5780631b0e0898146103595780631c4695f41461036c5780631ce070a8146103745780631de01bc91461037c578063234439441461038557806328a070251461038d57600080fd5b806306fdde03146102f65780630e5f5dbd146103145780630f5e07c71461032a57806312f21a1a146103335780631370720f1461033c57806314a6bf0f14610351575b600080fd5b6102fe6105cf565b60405161030b9190614776565b60405180910390f35b61031c61065d565b60405190815260200161030b565b61031c60095481565b61031c600d5481565b61034f61034a3660046147a9565b6106c8565b005b61031c6108b3565b61034f6103673660046147d0565b6108cf565b6102fe610971565b61031c61097e565b61031c600a5481565b61034f610a20565b61034f610b09565b61034f610b45565b61034f6103ab3660046147a9565b610cfc565b6103b8610d78565b6040516001600160a01b03909116815260200161030b565b61031c60075481565b6002546103b8906001600160a01b031681565b61034f6103fa3660046147a9565b610dfc565b6103b87f000000000000000000000000000000000000000000000000000000000000000081565b61034f6104343660046147a9565b610eea565b61034f610f0f565b61031c61044f36600461489a565b61106b565b61031c600b5481565b61034f6110a3565b60005460ff165b604051901515815260200161030b565b61031c61048a36600461489a565b61119f565b61031c6111fa565b61031c6112ba565b6005546103b8906001600160a01b031681565b61034f6104c03660046148bc565b61136d565b61034f61166b565b61031c600e5481565b6003546103b8906001600160a01b031681565b61031c6117c7565b61031c60115481565b61046c61189a565b61031c6118e0565b61031c60085481565b61034f6105213660046148bc565b611a0a565b60125461046c90610100900460ff1681565b61034f611df5565b61034f61054e3660046147a9565b611e42565b61031c60065481565b61031c611f84565b61034f61057236600461489a565b611f91565b61031c600c5481565b61034f61058e3660046148fd565b611fc9565b61031c60105481565b61031c6105aa36600461489a565b61223c565b60125461046c9060ff1681565b61034f6105ca3660046147a9565b612297565b600480546105dc90614929565b80601f016020809104026020016040519081016040528092919081815260200182805461060890614929565b80156106555780601f1061062a57610100808354040283529160200191610655565b820191906000526020600020905b81548152906001019060200180831161063857829003601f168201915b505050505081565b600754600090156106c257600062015180600d544261067c9190614979565b61068691906149a2565b9050610697620f424061016d6149b6565b81600c546007546106a891906149b6565b6106b291906149b6565b6106bc91906149a2565b91505090565b50600090565b6106d0612461565b6106d861248c565b806106e2816124d7565b6106ea6124f8565b60006106f583612551565b604051633068b6b560e21b8152600481018290529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c1a2dad490602401602060405180830381865afa158015610760573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078491906149cd565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156107ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081291906149cd565b9050808211156108355760405163569d45cf60e11b815260040160405180910390fd5b60025461084d906001600160a01b03163330886125df565b6108787f000000000000000000000000000000000000000000000000000000000000000033846126e9565b60405182907fbc87b68cd9f40bbab98db9b9e4d393c4ef32d4660271a908b81cfa10d8a59df990600090a25050506108af60018055565b5050565b60006108bd61065d565b6007546108ca91906149e6565b905090565b6108d7612461565b6108df6127e9565b60068a9055600c8990556008889055600e879055600a869055601085905560118490556012805460ff1916841515179055600f61091d828483614a55565b50888a7f121fb6640f56eb27441fa0c6f0633ab58b088a848f720a1f4a3e26d02a095f6c8a8a8a8a8a8a8a8a60405161095d989796959493929190614b15565b60405180910390a350505050505050505050565b600f80546105dc90614929565b60006109886124f8565b60405163d7f7098f60e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d7f7098f906024016020604051808303816000875af11580156109ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1291906149cd565b9050610a1d60018055565b90565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614b73565b6001600160a01b0316336001600160a01b031614610ad35760405163698bba4b60e01b815260040160405180910390fd5b6000600b81905560098190556040517f219124ae95cc25cf220d998f2867d37fb4ab4908cce7c51adfa33ce747aa5747908290a2565b610b116124f8565b610b3a7f0000000000000000000000000000000000000000000000000000000000000000612811565b610b4360018055565b565b610b4d612461565b610b556124f8565b6000610b5f61065d565b42600d556040516370a0823160e01b81523060048201529091506000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf191906149cd565b905080821115610c13576040516206230160eb1b815260040160405180910390fd5b8115610cf157610cc57f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbf9190614b73565b846126e9565b60405182907fda0ff68ccd5fb797a8f86207386ea961ca6990c15ace2424ab51eb871ed4959990600090a25b5050610b4360018055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d455760405163bc9eca6160e01b815260040160405180910390fd5b600781905560405181907f35ba42ee3c2daa6cf14836eefff16b184565798767ec1e5d723008848aeaf7e390600090a250565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632a9439456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dd8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ca9190614b73565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7e9190614b73565b6001600160a01b0316336001600160a01b031614610eaf5760405163698bba4b60e01b815260040160405180910390fd5b60088190556040518181527f7760d892a7883522367f0eaea35e968381a018418c249cd9aaaca190fe5d88179060200160405180910390a150565b610ef2612461565b610efa6124f8565b610f038161295c565b610f0c60018055565b50565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f919190614b73565b6001600160a01b0316336001600160a01b03161415801561104557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561100b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102f9190614b73565b6001600160a01b0316336001600160a01b031614155b1561106357604051631e1c735b60e21b815260040160405180910390fd5b610b43612c22565b6000611075612461565b61107d6124f8565b82611087816124d7565b6110918484612c74565b91505061109d60018055565b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111259190614b73565b6001600160a01b0316336001600160a01b03161461115657604051632d5be4cb60e21b815260040160405180910390fd5b6012805461ff0019166101001790556005546040516001600160a01b03909116907faf77f8960cf590e245ec8b6d41c193a5dcacad8986ae4eb57ac9e5be7b6af03190600090a2565b60006111a9612461565b6111b161248c565b6111b96124f8565b6111c38383613258565b60405190915081907f4e08ba899977cf7d4c2964bce71c6b9a7ef76ee5166a4c1249a1e08016e33ef190600090a261109d60018055565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166389da7df861123461065d565b6040518263ffffffff1660e01b815260040161125291815260200190565b602060405180830381865afa15801561126f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129391906149cd565b90508061129e6133a7565b6112a66118e0565b6112b091906149e6565b6106bc9190614979565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166389da7df86007546040518263ffffffff1660e01b815260040161130d91815260200190565b602060405180830381865afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e91906149cd565b9050600061135a6111fa565b90506113668282614b90565b9250505090565b6113756124f8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f79190614b73565b6001600160a01b0316336001600160a01b0316146114285760405163698bba4b60e01b815260040160405180910390fd5b604051633d1bb33160e21b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f46eccc4906024016080604051808303816000875af1158015611491573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b59190614bb7565b516007549091506000906114c99083614979565b90506114d58582613467565b945060006114e486600061347f565b60125490915060ff1661150a576040516305b02a1960e01b815260040160405180910390fd5b60115486101561152d576040516312cd610d60e21b815260040160405180910390fd5b601054811215611550576040516378764b0f60e01b815260040160405180910390fd5b61155986613643565b60006115f4867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e19190614c2c565b6115ec90600a614d33565b8991906137c8565b9050600061160182613876565b9050600061160f828861390b565b9050600061161d8a8361392f565b905061162b8160008a613a64565b6040518a907f8f77e6a87a8210bff9857b08990b1f360b73d6e92d422a9a0e2c78e449682a9c90600090a25050505050505061166660018055565b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190614b73565b6001600160a01b0316336001600160a01b0316141580156117a157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178b9190614b73565b6001600160a01b0316336001600160a01b031614155b156117bf57604051631e1c735b60e21b815260040160405180910390fd5b610b43613e25565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c1a2dad4620f4240600e54620f424061180d9190614979565b6118156111fa565b61181f91906149b6565b61182991906149a2565b6040518263ffffffff1660e01b815260040161184791815260200190565b602060405180830381865afa158015611864573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188891906149cd565b61189061065d565b6108ca91906149e6565b600080600a541180156118af57506000600b54115b80156118bc575060095442115b806108ca575060006007541180156108ca57506006546118da611f84565b12905090565b6040516388787f2b60e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906388787f2b90602401602060405180830381865afa158015611949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196d91906149cd565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f391906149cd565b90506119ff8183613e62565b915061136682613e7b565b611a126124f8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a949190614b73565b6001600160a01b0316336001600160a01b031614611ac55760405163698bba4b60e01b815260040160405180910390fd5b600080611ad0613f29565b915091506000611aeb6007548761346790919063ffffffff16565b600a5490915015611b0c57600a54611b0390426149e6565b600955600b8190555b80821015611d18576000611b208383614979565b60405163113b4fbf60e31b8152600481018290529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906389da7df890602401602060405180830381865afa158015611b8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611baf91906149cd565b90506000611bbc82613876565b905085811115611bdb57611bd9611bd38783614979565b88612c74565b505b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611c24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4891906149cd565b1115611d14576000611c5982612551565b90506000611cf57f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce29190614c2c565b611ced90600a614d33565b83908c6137c8565b90506000611d03828b61390b565b9050611d0f8482613258565b505050505b5050505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da391906149cd565b118015611db05750600081115b15611dbe57611dbe8161295c565b60405186907fdfcd68ceed46252749a4089f344aec4b4ee7f28a068f704c21799355325f3da990600090a250505061166660018055565b611dfd612461565b6012805461ff00191690556005546040516001600160a01b03909116907facf29ad8d63913d38e7e1176963a4afb76bf0918516051da68408ecb6f98065d90600090a2565b611e4a612461565b611e5261248c565b80611e5c816124d7565b611e646124f8565b60405163b67e9df760e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b67e9df790602401602060405180830381865afa158015611ec8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eec9190614d42565b611f095760405163d8d5894f60e01b815260040160405180910390fd5b6000600754600854611f1b9190614979565b905082811015611f3e5760405163569d45cf60e11b815260040160405180910390fd5b6000611f4b84600061347f565b9050600654811215611f705760405163374c72ff60e11b815260040160405180910390fd5b611f7984613643565b50506108af60018055565b60006108ca60008061347f565b611f99612461565b611fa161248c565b611fa96124f8565b81611fb3816124d7565b611fbf83600084613a64565b506108af60018055565b611fd1612461565b611fd961248c565b80611fe3816124d7565b611feb6124f8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161415801561203b57506002546001600160a01b03848116911614155b156120595760405163c1ab6dc160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561209d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c191906149cd565b8211156120e15760405163569d45cf60e11b815260040160405180910390fd5b600754156121f25760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316146121325761212d83612551565b6121bb565b60405163113b4fbf60e31b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906389da7df890602401602060405180830381865afa158015612197573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121bb91906149cd565b905060006121ca60008361347f565b90506006548112156121ef5760405163374c72ff60e11b815260040160405180910390fd5b50505b6121fd8333846126e9565b60405182906001600160a01b038516907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d590600090a361166660018055565b6000612246612461565b61224e61248c565b6122566124f8565b612260838361392f565b60405190915083907f92f64ca637d023f354075a4be751b169c1a8a9ccb6d33cdd0cb352054399572790600090a261109d60018055565b61229f612461565b6122a761248c565b806122b1816124d7565b6122b96124f8565b60405163113b4fbf60e31b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906389da7df890602401602060405180830381865afa158015612321573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234591906149cd565b9050600061235282613876565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156123a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c491906149cd565b9050808211156123e75760405163569d45cf60e11b815260040160405180910390fd5b6124137f00000000000000000000000000000000000000000000000000000000000000003330886125df565b60025461242a906001600160a01b031633846126e9565b60405182907fdcadafc28aac48a048c875f5f3127f2189b02d21291b563568cf8892a596bbb090600090a25050506108af60018055565b6005546001600160a01b03163314610b4357604051631963d1e760e31b815260040160405180910390fd5b60005460ff1615610b435760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064015b60405180910390fd5b80600003610f0c57604051639d635cff60e01b815260040160405180910390fd5b60026001540361254a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016124ce565b6002600155565b600061109d82600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ce9190614c2c565b6003546001600160a01b031661402b565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916126439190614d5f565b6000604051808303816000865af19150503d8060008114612680576040519150601f19603f3d011682016040523d82523d6000602084013e612685565b606091505b50915091508180156126af5750805115806126af5750808060200190518101906126af9190614d42565b6126e15760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b60448201526064016124ce565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916127459190614d5f565b6000604051808303816000865af19150503d8060008114612782576040519150601f19603f3d011682016040523d82523d6000602084013e612787565b606091505b50915091508180156127b15750805115806127b15750808060200190518101906127b19190614d42565b6127e25760405162461bcd60e51b815260206004820152600260248201526114d560f21b60448201526064016124ce565b5050505050565b601254610100900460ff16610b4357604051634e751a9560e11b815260040160405180910390fd5b61281961189a565b6128365760405163038cbd4b60e31b815260040160405180910390fd5b30600080612842613f29565b6040516370a0823160e01b81526001600160a01b0386811660048301529294509092506000918616906370a0823190602401602060405180830381865afa158015612891573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b591906149cd565b905060006128c16108b3565b905060006128cf8483614979565b90506128fd7f00000000000000000000000000000000000000000000000000000000000000003388846125df565b6129068261295c565b60025461291d906001600160a01b031633876126e9565b6129288733856126e9565b60405133907f1e1ef858062a7196d1891e397a5cde9891e6ddf61a81e9d269a3aaa7a95dacd890600090a250505050505050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156129c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e791906149cd565b90506129f38282613467565b915081600003612a165760405163569d45cf60e11b815260040160405180910390fd5b81600b5411612a26576000612a34565b81600b54612a349190614979565b600b55600a5415801590612a485750600b54155b15612a535760006009555b6000612a5d61065d565b42600d559050612a6d8184614979565b9250826007541015612a89576007805460009091559250612aa1565b8260076000828254612a9b9190614979565b90915550505b612b4d7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b479190614b73565b836126e9565b612b787f00000000000000000000000000000000000000000000000000000000000000003085614085565b604051630852cd8d60e31b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b158015612bda57600080fd5b505af1158015612bee573d6000803e3d6000fd5b50506040518592507f33a382daad6aace935340a474d09fec82af4bec7e2b69518d283231b03a65f249150600090a2505050565b612c2a61417e565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015612cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce591906149cd565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7391906149cd565b90506000612d80866141c7565b60405163d7f7098f60e01b81523060048201529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d7f7098f906024016020604051808303816000875af1158015612dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1091906149cd565b905080821015612e9f5760405163ef693bed60e01b8152306004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ef693bed90604401600060405180830381600087803b158015612e8257600080fd5b505af1158015612e96573d6000803e3d6000fd5b50505050612f1c565b604051637586ffb360e11b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063eb0dff6690602401600060405180830381600087803b158015612f0057600080fd5b505af1158015612f14573d6000803e3d6000fd5b505050508091505b6040516370a0823160e01b815230600482015260009084906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa991906149cd565b612fb39190614979565b9050801580612fc157508281105b15612fdf5760405163122d7f5760e01b815260040160405180910390fd5b6000612ff3612fee838a61390b565b6142f8565b90506130407f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000084614085565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fae036d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c491906149cd565b90506130d881670de0b6b3a76400006149e6565b6130ea670de0b6b3a7640000856149b6565b6130f491906149a2565b92506000613101846142f8565b604051638d7ef9bb60e01b8152306004820152602481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638d7ef9bb90604401600060405180830381600087803b15801561316c57600080fd5b505af1158015613180573d6000803e3d6000fd5b50506002546040516370a0823160e01b81523060048201528b93506001600160a01b0390911691506370a0823190602401602060405180830381865afa1580156131ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f291906149cd565b6131fc9190614979565b98508883111561321f5760405163122d7f5760e01b815260040160405180910390fd5b60405189907f0dbc40ccd4fca1b5bf46f23e99aaefe371e661e9ca0c45dc1b79e5e321d3b99d90600090a2505050505050505092915050565b6002546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156132a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c991906149cd565b90506132d58482613467565b9350836000036132f85760405163569d45cf60e11b815260040160405180910390fd5b6000613302610d78565b60025490915061331c906001600160a01b03168287614085565b60025460405163231831c760e21b81526001600160a01b0391821660048201526024810187905260448101869052600091831690638c60c71c906064015b6020604051808303816000875af1158015613379573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339d91906149cd565b9695505050505050565b60008060006133b4613f29565b60405163113b4fbf60e31b81526004810182905291935091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906389da7df890602401602060405180830381865afa158015613421573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344591906149cd565b9050600061345284612551565b905061345e82826149e6565b94505050505090565b60008183106134765781613478565b825b9392505050565b60008061348a6111fa565b60405163113b4fbf60e31b8152600481018690529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906389da7df890602401602060405180830381865afa1580156134f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351991906149cd565b905060008461352883856149e6565b6135329190614979565b90508060000361355f576007541561355357620f423f19935050505061109d565b6000935050505061109d565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166389da7df88860075461359e91906149e6565b6040518263ffffffff1660e01b81526004016135bc91815260200190565b602060405180830381865afa1580156135d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135fd91906149cd565b905060008261360c8382614b90565b61361990620f4240614d7b565b6136239190614dab565b9050620f423f198112156136385750620f423f195b979650505050505050565b600061364d61065d565b60405163140e25ad60e31b8152600481018490529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a0712d6890602401600060405180830381600087803b1580156136b257600080fd5b505af11580156136c6573d6000803e3d6000fd5b5050505081600760008282546136dc91906149e6565b909155505042600d5580156137995761376d7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b23573d6000803e3d6000fd5b60405181907fda0ff68ccd5fb797a8f86207386ea961ca6990c15ace2424ab51eb871ed4959990600090a25b60405182907f69c0ed5a77051ba5f0c42418bb6db6d3f73884dea69811c50bf320298df6ca5c90600090a25050565b6000808060001985870985870292508281108382030391505080600003613802578382816137f8576137f861498c565b0492505050613478565b80841161380e57600080fd5b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b600061109d82600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f39190614c2c565b60035460ff91909116906001600160a01b031661441d565b6000620f424061391b8382614979565b61392590856149b6565b61347891906149a2565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139bc91906149cd565b90506139c88482613467565b9350836000036139eb5760405163569d45cf60e11b815260040160405180910390fd5b60006139f5610d78565b9050613a227f00000000000000000000000000000000000000000000000000000000000000008287614085565b600254604051631c6d209760e11b81526001600160a01b03918216600482015260248101879052604481018690526000918316906338da412e9060640161335a565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015613aad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad191906149cd565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5f91906149cd565b905081600003613b825760405163569d45cf60e11b815260040160405180910390fd5b84821015613b8e578194505b6000613ba2613b9d878661390b565b614470565b600254909150613bdc906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000088614085565b604051634acc893b60e11b8152306004820152602481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639599127690604401600060405180830381600087803b158015613c4457600080fd5b505af1158015613c58573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092508491506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613cc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce991906149cd565b613cf39190614979565b9050801580613d0157508181105b15613d1f5760405163122d7f5760e01b815260040160405180910390fd5b613d6a7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083614085565b604051633b4da69f60e01b8152306004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690633b4da69f90604401600060405180830381600087803b158015613dd257600080fd5b505af1158015613de6573d6000803e3d6000fd5b50505050613df3816142f8565b6040517fac9f7997c30b6a3cc9c74953898b5de154359339c7ec0d6d70ceb98e55db1a4b90600090a250505050505050565b613e2d61248c565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c573390565b60006b033b2e3c9fd0803ce80000006139258484614547565b600061109d827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f039190614c2c565b7f000000000000000000000000000000000000000000000000000000000000000061402b565b6002546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015613f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9a91906149cd565b6040516370a0823160e01b81523060048201529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015614001573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402591906149cd565b90509091565b60008061403783614574565b90506000614044846145d8565b90506140508583614dd9565b61405b90600a614d33565b6140676006600a614d33565b61407183896149b6565b61407b91906149b6565b61339d91906149a2565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916140e19190614d5f565b6000604051808303816000865af19150503d806000811461411e576040519150601f19603f3d011682016040523d82523d6000602084013e614123565b606091505b509150915081801561414d57508051158061414d57508080602001905181019061414d9190614d42565b6127e25760405162461bcd60e51b8152602060048201526002602482015261534160f01b60448201526064016124ce565b60005460ff16610b435760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016124ce565b600061109d82600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142449190614c2c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c69190614c2c565b6003546001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006146ed565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614358573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061437c9190614c2c565b61438790600a614d33565b600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143fe9190614c2c565b61440990600a614d33565b61441390846149b6565b61109d91906149a2565b60008061442983614574565b90506000614436846145d8565b90506144446006600a614d33565b61444e90826149b6565b61445b8660ff85166149e6565b61446690600a614df2565b61407b90886149b6565b6002546040805163313ce56760e01b815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa1580156144ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144de9190614c2c565b6144e990600a614d33565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143da573d6000803e3d6000fd5b600081158061456b5750828261455d81836149b6565b925061456990836149a2565b145b61109d57600080fd5b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156145b4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109d9190614c2c565b6000806000806000856001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561461e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146429190614e1d565b9450945050935093508369ffffffffffffffffffff168169ffffffffffffffffffff16101561469e5760405162461bcd60e51b81526020600482015260086024820152674f6c64206461746160c01b60448201526064016124ce565b600082116146e35760405162461bcd60e51b8152602060048201526012602482015271526f756e64206e6f7420636f6d706c65746560701b60448201526064016124ce565b5090949350505050565b6000806146f9846145d8565b90506000614706846145d8565b905061471387600a614d33565b61471d90826149b6565b61472887600a614d33565b614732848b6149b6565b61473c91906149b6565b61474691906149a2565b98975050505050505050565b60005b8381101561476d578181015183820152602001614755565b50506000910152565b6020815260008251806020840152614795816040850160208701614752565b601f01601f19169190910160400192915050565b6000602082840312156147bb57600080fd5b5035919050565b8015158114610f0c57600080fd5b6000806000806000806000806000806101208b8d0312156147f057600080fd5b8a35995060208b0135985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935060e08b013561482c816147c2565b92506101008b013567ffffffffffffffff8082111561484a57600080fd5b818d0191508d601f83011261485e57600080fd5b81358181111561486d57600080fd5b8e602082850101111561487f57600080fd5b6020830194508093505050509295989b9194979a5092959850565b600080604083850312156148ad57600080fd5b50508035926020909101359150565b6000806000606084860312156148d157600080fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114610f0c57600080fd5b6000806040838503121561491057600080fd5b823561491b816148e8565b946020939093013593505050565b600181811c9082168061493d57607f821691505b60208210810361495d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561109d5761109d614963565b634e487b7160e01b600052601260045260246000fd5b6000826149b1576149b161498c565b500490565b808202811582820484141761109d5761109d614963565b6000602082840312156149df57600080fd5b5051919050565b8082018082111561109d5761109d614963565b634e487b7160e01b600052604160045260246000fd5b601f82111561166657600081815260208120601f850160051c81016020861015614a365750805b601f850160051c820191505b818110156126e157828155600101614a42565b67ffffffffffffffff831115614a6d57614a6d6149f9565b614a8183614a7b8354614929565b83614a0f565b6000601f841160018114614ab55760008515614a9d5750838201355b600019600387901b1c1916600186901b1783556127e2565b600083815260209020601f19861690835b82811015614ae65786850135825560209485019460019092019101614ac6565b5086821015614b035760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b88815287602082015286604082015285606082015284608082015283151560a082015260e060c08201528160e082015260006101008385828501376000838501820152601f909301601f191690910190910198975050505050505050565b600060208284031215614b8557600080fd5b8151613478816148e8565b8181036000831280158383131683831282161715614bb057614bb0614963565b5092915050565b600060808284031215614bc957600080fd5b6040516080810181811067ffffffffffffffff82111715614bec57614bec6149f9565b806040525082518152602083015160208201526040830151614c0d816147c2565b60408201526060830151614c20816147c2565b60608201529392505050565b600060208284031215614c3e57600080fd5b815160ff8116811461347857600080fd5b600181815b80851115614c8a578160001904821115614c7057614c70614963565b80851615614c7d57918102915b93841c9390800290614c54565b509250929050565b600082614ca15750600161109d565b81614cae5750600061109d565b8160018114614cc45760028114614cce57614cea565b600191505061109d565b60ff841115614cdf57614cdf614963565b50506001821b61109d565b5060208310610133831016604e8410600b8410161715614d0d575081810a61109d565b614d178383614c4f565b8060001904821115614d2b57614d2b614963565b029392505050565b600061347860ff841683614c92565b600060208284031215614d5457600080fd5b8151613478816147c2565b60008251614d71818460208701614752565b9190910192915050565b80820260008212600160ff1b84141615614d9757614d97614963565b818105831482151761109d5761109d614963565b600082614dba57614dba61498c565b600160ff1b821460001984141615614dd457614dd4614963565b500590565b60ff818116838216019081111561109d5761109d614963565b60006134788383614c92565b805169ffffffffffffffffffff81168114614e1857600080fd5b919050565b600080600080600060a08688031215614e3557600080fd5b614e3e86614dfe565b9450602086015193506040860151925060608601519150614e6160808701614dfe565b9050929550929590935056fea2646970667358221220c58c8eb0af145ec4e88eea27388bf9799321a0501b98d23db365fb2c9e6940fc64736f6c634300081300330000000000000000000000000000000000000000000000000000000000000120000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6000000000000000000000000aed0c38402a5d19df6e4c03f4e2dced6e29c1ee90000000000000000000000003afd8feed6bbd1d8254d92eafa1f695dce16387a00000000000000000000000000000000000000000000000000000000000000094453522041737365740000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102f15760003560e01c806361ab077f1161019d578063bc5477ad116100e9578063d87aa643116100a2578063f686138d1161007c578063f686138d14610593578063f69aa3d51461059c578063f95c1b26146105af578063fa45d562146105bc57600080fd5b8063d87aa64314610564578063de839ba414610577578063f3fef3a31461058057600080fd5b8063bc5477ad14610513578063c0f4a00514610526578063c198f8ba14610538578063c5ebeaec14610540578063c6beb58614610553578063d366a41f1461055c57600080fd5b8063867e5cb811610156578063a195166511610130578063a1951665146104f1578063a38aaa90146104fa578063a71891c314610502578063ad81fced1461050a57600080fd5b8063867e5cb8146104cd5780638d1d7c61146104d6578063907a9429146104e957600080fd5b806361ab077f1461047c578063698996f81461048f578063717e794d146104975780637df1f1b91461049f5780638351faf5146104b25780638456cb59146104c557600080fd5b8063296102521161025c57806335faa416116102155780634696c749116101ef5780634696c7491461044157806348dcacab146104545780634dc415de1461045d5780635c975abb1461046557600080fd5b806335faa416146103ff578063371fd8e6146104265780633f4ba83a1461043957600080fd5b8063296102521461039557806329b154c31461039d5780632a943945146103b05780632d76643c146103d0578063311176d7146103d95780633168b03f146103ec57600080fd5b80631b0e0898116102ae5780631b0e0898146103595780631c4695f41461036c5780631ce070a8146103745780631de01bc91461037c578063234439441461038557806328a070251461038d57600080fd5b806306fdde03146102f65780630e5f5dbd146103145780630f5e07c71461032a57806312f21a1a146103335780631370720f1461033c57806314a6bf0f14610351575b600080fd5b6102fe6105cf565b60405161030b9190614776565b60405180910390f35b61031c61065d565b60405190815260200161030b565b61031c60095481565b61031c600d5481565b61034f61034a3660046147a9565b6106c8565b005b61031c6108b3565b61034f6103673660046147d0565b6108cf565b6102fe610971565b61031c61097e565b61031c600a5481565b61034f610a20565b61034f610b09565b61034f610b45565b61034f6103ab3660046147a9565b610cfc565b6103b8610d78565b6040516001600160a01b03909116815260200161030b565b61031c60075481565b6002546103b8906001600160a01b031681565b61034f6103fa3660046147a9565b610dfc565b6103b87f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357481565b61034f6104343660046147a9565b610eea565b61034f610f0f565b61031c61044f36600461489a565b61106b565b61031c600b5481565b61034f6110a3565b60005460ff165b604051901515815260200161030b565b61031c61048a36600461489a565b61119f565b61031c6111fa565b61031c6112ba565b6005546103b8906001600160a01b031681565b61034f6104c03660046148bc565b61136d565b61034f61166b565b61031c600e5481565b6003546103b8906001600160a01b031681565b61031c6117c7565b61031c60115481565b61046c61189a565b61031c6118e0565b61031c60085481565b61034f6105213660046148bc565b611a0a565b60125461046c90610100900460ff1681565b61034f611df5565b61034f61054e3660046147a9565b611e42565b61031c60065481565b61031c611f84565b61034f61057236600461489a565b611f91565b61031c600c5481565b61034f61058e3660046148fd565b611fc9565b61031c60105481565b61031c6105aa36600461489a565b61223c565b60125461046c9060ff1681565b61034f6105ca3660046147a9565b612297565b600480546105dc90614929565b80601f016020809104026020016040519081016040528092919081815260200182805461060890614929565b80156106555780601f1061062a57610100808354040283529160200191610655565b820191906000526020600020905b81548152906001019060200180831161063857829003601f168201915b505050505081565b600754600090156106c257600062015180600d544261067c9190614979565b61068691906149a2565b9050610697620f424061016d6149b6565b81600c546007546106a891906149b6565b6106b291906149b6565b6106bc91906149a2565b91505090565b50600090565b6106d0612461565b6106d861248c565b806106e2816124d7565b6106ea6124f8565b60006106f583612551565b604051633068b6b560e21b8152600481018290529091506000906001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574169063c1a2dad490602401602060405180830381865afa158015610760573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078491906149cd565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357416906370a0823190602401602060405180830381865afa1580156107ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081291906149cd565b9050808211156108355760405163569d45cf60e11b815260040160405180910390fd5b60025461084d906001600160a01b03163330886125df565b6108787f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357433846126e9565b60405182907fbc87b68cd9f40bbab98db9b9e4d393c4ef32d4660271a908b81cfa10d8a59df990600090a25050506108af60018055565b5050565b60006108bd61065d565b6007546108ca91906149e6565b905090565b6108d7612461565b6108df6127e9565b60068a9055600c8990556008889055600e879055600a869055601085905560118490556012805460ff1916841515179055600f61091d828483614a55565b50888a7f121fb6640f56eb27441fa0c6f0633ab58b088a848f720a1f4a3e26d02a095f6c8a8a8a8a8a8a8a8a60405161095d989796959493929190614b15565b60405180910390a350505050505050505050565b600f80546105dc90614929565b60006109886124f8565b60405163d7f7098f60e01b81523060048201527f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb6001600160a01b03169063d7f7098f906024016020604051808303816000875af11580156109ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1291906149cd565b9050610a1d60018055565b90565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614b73565b6001600160a01b0316336001600160a01b031614610ad35760405163698bba4b60e01b815260040160405180910390fd5b6000600b81905560098190556040517f219124ae95cc25cf220d998f2867d37fb4ab4908cce7c51adfa33ce747aa5747908290a2565b610b116124f8565b610b3a7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f612811565b610b4360018055565b565b610b4d612461565b610b556124f8565b6000610b5f61065d565b42600d556040516370a0823160e01b81523060048201529091506000907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906370a0823190602401602060405180830381865afa158015610bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf191906149cd565b905080821115610c13576040516206230160eb1b815260040160405180910390fd5b8115610cf157610cc57f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435747f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbf9190614b73565b846126e9565b60405182907fda0ff68ccd5fb797a8f86207386ea961ca6990c15ace2424ab51eb871ed4959990600090a25b5050610b4360018055565b336001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435741614610d455760405163bc9eca6160e01b815260040160405180910390fd5b600781905560405181907f35ba42ee3c2daa6cf14836eefff16b184565798767ec1e5d723008848aeaf7e390600090a250565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316632a9439456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dd8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ca9190614b73565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7e9190614b73565b6001600160a01b0316336001600160a01b031614610eaf5760405163698bba4b60e01b815260040160405180910390fd5b60088190556040518181527f7760d892a7883522367f0eaea35e968381a018418c249cd9aaaca190fe5d88179060200160405180910390a150565b610ef2612461565b610efa6124f8565b610f038161295c565b610f0c60018055565b50565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f919190614b73565b6001600160a01b0316336001600160a01b03161415801561104557507f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561100b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102f9190614b73565b6001600160a01b0316336001600160a01b031614155b1561106357604051631e1c735b60e21b815260040160405180910390fd5b610b43612c22565b6000611075612461565b61107d6124f8565b82611087816124d7565b6110918484612c74565b91505061109d60018055565b92915050565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111259190614b73565b6001600160a01b0316336001600160a01b03161461115657604051632d5be4cb60e21b815260040160405180910390fd5b6012805461ff0019166101001790556005546040516001600160a01b03909116907faf77f8960cf590e245ec8b6d41c193a5dcacad8986ae4eb57ac9e5be7b6af03190600090a2565b60006111a9612461565b6111b161248c565b6111b96124f8565b6111c38383613258565b60405190915081907f4e08ba899977cf7d4c2964bce71c6b9a7ef76ee5166a4c1249a1e08016e33ef190600090a261109d60018055565b6000807f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03166389da7df861123461065d565b6040518263ffffffff1660e01b815260040161125291815260200190565b602060405180830381865afa15801561126f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129391906149cd565b90508061129e6133a7565b6112a66118e0565b6112b091906149e6565b6106bc9190614979565b6000807f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03166389da7df86007546040518263ffffffff1660e01b815260040161130d91815260200190565b602060405180830381865afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e91906149cd565b9050600061135a6111fa565b90506113668282614b90565b9250505090565b6113756124f8565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f79190614b73565b6001600160a01b0316336001600160a01b0316146114285760405163698bba4b60e01b815260040160405180910390fd5b604051633d1bb33160e21b81523060048201526000907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03169063f46eccc4906024016080604051808303816000875af1158015611491573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b59190614bb7565b516007549091506000906114c99083614979565b90506114d58582613467565b945060006114e486600061347f565b60125490915060ff1661150a576040516305b02a1960e01b815260040160405180910390fd5b60115486101561152d576040516312cd610d60e21b815260040160405180910390fd5b601054811215611550576040516378764b0f60e01b815260040160405180910390fd5b61155986613643565b60006115f4867f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e19190614c2c565b6115ec90600a614d33565b8991906137c8565b9050600061160182613876565b9050600061160f828861390b565b9050600061161d8a8361392f565b905061162b8160008a613a64565b6040518a907f8f77e6a87a8210bff9857b08990b1f360b73d6e92d422a9a0e2c78e449682a9c90600090a25050505050505061166660018055565b505050565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190614b73565b6001600160a01b0316336001600160a01b0316141580156117a157507f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178b9190614b73565b6001600160a01b0316336001600160a01b031614155b156117bf57604051631e1c735b60e21b815260040160405180910390fd5b610b43613e25565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663c1a2dad4620f4240600e54620f424061180d9190614979565b6118156111fa565b61181f91906149b6565b61182991906149a2565b6040518263ffffffff1660e01b815260040161184791815260200190565b602060405180830381865afa158015611864573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188891906149cd565b61189061065d565b6108ca91906149e6565b600080600a541180156118af57506000600b54115b80156118bc575060095442115b806108ca575060006007541180156108ca57506006546118da611f84565b12905090565b6040516388787f2b60e01b815230600482015260009081906001600160a01b037f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb16906388787f2b90602401602060405180830381865afa158015611949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196d91906149cd565b905060007f000000000000000000000000197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f391906149cd565b90506119ff8183613e62565b915061136682613e7b565b611a126124f8565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663e563037e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a949190614b73565b6001600160a01b0316336001600160a01b031614611ac55760405163698bba4b60e01b815260040160405180910390fd5b600080611ad0613f29565b915091506000611aeb6007548761346790919063ffffffff16565b600a5490915015611b0c57600a54611b0390426149e6565b600955600b8190555b80821015611d18576000611b208383614979565b60405163113b4fbf60e31b8152600481018290529091506000906001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357416906389da7df890602401602060405180830381865afa158015611b8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611baf91906149cd565b90506000611bbc82613876565b905085811115611bdb57611bd9611bd38783614979565b88612c74565b505b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611c24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4891906149cd565b1115611d14576000611c5982612551565b90506000611cf57f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce29190614c2c565b611ced90600a614d33565b83908c6137c8565b90506000611d03828b61390b565b9050611d0f8482613258565b505050505b5050505b6040516370a0823160e01b81523060048201526000907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906370a0823190602401602060405180830381865afa158015611d7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da391906149cd565b118015611db05750600081115b15611dbe57611dbe8161295c565b60405186907fdfcd68ceed46252749a4089f344aec4b4ee7f28a068f704c21799355325f3da990600090a250505061166660018055565b611dfd612461565b6012805461ff00191690556005546040516001600160a01b03909116907facf29ad8d63913d38e7e1176963a4afb76bf0918516051da68408ecb6f98065d90600090a2565b611e4a612461565b611e5261248c565b80611e5c816124d7565b611e646124f8565b60405163b67e9df760e01b81523060048201527f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03169063b67e9df790602401602060405180830381865afa158015611ec8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eec9190614d42565b611f095760405163d8d5894f60e01b815260040160405180910390fd5b6000600754600854611f1b9190614979565b905082811015611f3e5760405163569d45cf60e11b815260040160405180910390fd5b6000611f4b84600061347f565b9050600654811215611f705760405163374c72ff60e11b815260040160405180910390fd5b611f7984613643565b50506108af60018055565b60006108ca60008061347f565b611f99612461565b611fa161248c565b611fa96124f8565b81611fb3816124d7565b611fbf83600084613a64565b506108af60018055565b611fd1612461565b611fd961248c565b80611fe3816124d7565b611feb6124f8565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316836001600160a01b03161415801561203b57506002546001600160a01b03848116911614155b156120595760405163c1ab6dc160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561209d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c191906149cd565b8211156120e15760405163569d45cf60e11b815260040160405180910390fd5b600754156121f25760007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316846001600160a01b0316146121325761212d83612551565b6121bb565b60405163113b4fbf60e31b8152600481018490527f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906389da7df890602401602060405180830381865afa158015612197573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121bb91906149cd565b905060006121ca60008361347f565b90506006548112156121ef5760405163374c72ff60e11b815260040160405180910390fd5b50505b6121fd8333846126e9565b60405182906001600160a01b038516907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d590600090a361166660018055565b6000612246612461565b61224e61248c565b6122566124f8565b612260838361392f565b60405190915083907f92f64ca637d023f354075a4be751b169c1a8a9ccb6d33cdd0cb352054399572790600090a261109d60018055565b61229f612461565b6122a761248c565b806122b1816124d7565b6122b96124f8565b60405163113b4fbf60e31b8152600481018390526000907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906389da7df890602401602060405180830381865afa158015612321573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234591906149cd565b9050600061235282613876565b6002546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156123a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c491906149cd565b9050808211156123e75760405163569d45cf60e11b815260040160405180910390fd5b6124137f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435743330886125df565b60025461242a906001600160a01b031633846126e9565b60405182907fdcadafc28aac48a048c875f5f3127f2189b02d21291b563568cf8892a596bbb090600090a25050506108af60018055565b6005546001600160a01b03163314610b4357604051631963d1e760e31b815260040160405180910390fd5b60005460ff1615610b435760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064015b60405180910390fd5b80600003610f0c57604051639d635cff60e01b815260040160405180910390fd5b60026001540361254a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016124ce565b6002600155565b600061109d82600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ce9190614c2c565b6003546001600160a01b031661402b565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916126439190614d5f565b6000604051808303816000865af19150503d8060008114612680576040519150601f19603f3d011682016040523d82523d6000602084013e612685565b606091505b50915091508180156126af5750805115806126af5750808060200190518101906126af9190614d42565b6126e15760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b60448201526064016124ce565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916127459190614d5f565b6000604051808303816000865af19150503d8060008114612782576040519150601f19603f3d011682016040523d82523d6000602084013e612787565b606091505b50915091508180156127b15750805115806127b15750808060200190518101906127b19190614d42565b6127e25760405162461bcd60e51b815260206004820152600260248201526114d560f21b60448201526064016124ce565b5050505050565b601254610100900460ff16610b4357604051634e751a9560e11b815260040160405180910390fd5b61281961189a565b6128365760405163038cbd4b60e31b815260040160405180910390fd5b30600080612842613f29565b6040516370a0823160e01b81526001600160a01b0386811660048301529294509092506000918616906370a0823190602401602060405180830381865afa158015612891573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b591906149cd565b905060006128c16108b3565b905060006128cf8483614979565b90506128fd7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435743388846125df565b6129068261295c565b60025461291d906001600160a01b031633876126e9565b6129288733856126e9565b60405133907f1e1ef858062a7196d1891e397a5cde9891e6ddf61a81e9d269a3aaa7a95dacd890600090a250505050505050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906370a0823190602401602060405180830381865afa1580156129c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e791906149cd565b90506129f38282613467565b915081600003612a165760405163569d45cf60e11b815260040160405180910390fd5b81600b5411612a26576000612a34565b81600b54612a349190614979565b600b55600a5415801590612a485750600b54155b15612a535760006009555b6000612a5d61065d565b42600d559050612a6d8184614979565b9250826007541015612a89576007805460009091559250612aa1565b8260076000828254612a9b9190614979565b90915550505b612b4d7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435747f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b479190614b73565b836126e9565b612b787f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435743085614085565b604051630852cd8d60e31b8152600481018490527f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906342966c6890602401600060405180830381600087803b158015612bda57600080fd5b505af1158015612bee573d6000803e3d6000fd5b50506040518592507f33a382daad6aace935340a474d09fec82af4bec7e2b69518d283231b03a65f249150600090a2505050565b612c2a61417e565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015612cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce591906149cd565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16906370a0823190602401602060405180830381865afa158015612d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7391906149cd565b90506000612d80866141c7565b60405163d7f7098f60e01b81523060048201529091506000906001600160a01b037f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb169063d7f7098f906024016020604051808303816000875af1158015612dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1091906149cd565b905080821015612e9f5760405163ef693bed60e01b8152306004820152602481018390527f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb6001600160a01b03169063ef693bed90604401600060405180830381600087803b158015612e8257600080fd5b505af1158015612e96573d6000803e3d6000fd5b50505050612f1c565b604051637586ffb360e11b81523060048201527f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb6001600160a01b03169063eb0dff6690602401600060405180830381600087803b158015612f0057600080fd5b505af1158015612f14573d6000803e3d6000fd5b505050508091505b6040516370a0823160e01b815230600482015260009084906001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16906370a0823190602401602060405180830381865afa158015612f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa991906149cd565b612fb39190614979565b9050801580612fc157508281105b15612fdf5760405163122d7f5760e01b815260040160405180910390fd5b6000612ff3612fee838a61390b565b6142f8565b90506130407f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f7f00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a84614085565b60007f00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a6001600160a01b031663fae036d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c491906149cd565b90506130d881670de0b6b3a76400006149e6565b6130ea670de0b6b3a7640000856149b6565b6130f491906149a2565b92506000613101846142f8565b604051638d7ef9bb60e01b8152306004820152602481018290529091507f00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a6001600160a01b031690638d7ef9bb90604401600060405180830381600087803b15801561316c57600080fd5b505af1158015613180573d6000803e3d6000fd5b50506002546040516370a0823160e01b81523060048201528b93506001600160a01b0390911691506370a0823190602401602060405180830381865afa1580156131ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f291906149cd565b6131fc9190614979565b98508883111561321f5760405163122d7f5760e01b815260040160405180910390fd5b60405189907f0dbc40ccd4fca1b5bf46f23e99aaefe371e661e9ca0c45dc1b79e5e321d3b99d90600090a2505050505050505092915050565b6002546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156132a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c991906149cd565b90506132d58482613467565b9350836000036132f85760405163569d45cf60e11b815260040160405180910390fd5b6000613302610d78565b60025490915061331c906001600160a01b03168287614085565b60025460405163231831c760e21b81526001600160a01b0391821660048201526024810187905260448101869052600091831690638c60c71c906064015b6020604051808303816000875af1158015613379573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339d91906149cd565b9695505050505050565b60008060006133b4613f29565b60405163113b4fbf60e31b81526004810182905291935091506000906001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357416906389da7df890602401602060405180830381865afa158015613421573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344591906149cd565b9050600061345284612551565b905061345e82826149e6565b94505050505090565b60008183106134765781613478565b825b9392505050565b60008061348a6111fa565b60405163113b4fbf60e31b8152600481018690529091506000906001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357416906389da7df890602401602060405180830381865afa1580156134f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351991906149cd565b905060008461352883856149e6565b6135329190614979565b90508060000361355f576007541561355357620f423f19935050505061109d565b6000935050505061109d565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03166389da7df88860075461359e91906149e6565b6040518263ffffffff1660e01b81526004016135bc91815260200190565b602060405180830381865afa1580156135d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135fd91906149cd565b905060008261360c8382614b90565b61361990620f4240614d7b565b6136239190614dab565b9050620f423f198112156136385750620f423f195b979650505050505050565b600061364d61065d565b60405163140e25ad60e31b8152600481018490529091507f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03169063a0712d6890602401600060405180830381600087803b1580156136b257600080fd5b505af11580156136c6573d6000803e3d6000fd5b5050505081600760008282546136dc91906149e6565b909155505042600d5580156137995761376d7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435747f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b23573d6000803e3d6000fd5b60405181907fda0ff68ccd5fb797a8f86207386ea961ca6990c15ace2424ab51eb871ed4959990600090a25b60405182907f69c0ed5a77051ba5f0c42418bb6db6d3f73884dea69811c50bf320298df6ca5c90600090a25050565b6000808060001985870985870292508281108382030391505080600003613802578382816137f8576137f861498c565b0492505050613478565b80841161380e57600080fd5b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b600061109d82600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f39190614c2c565b60035460ff91909116906001600160a01b031661441d565b6000620f424061391b8382614979565b61392590856149b6565b61347891906149a2565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357416906370a0823190602401602060405180830381865afa158015613998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139bc91906149cd565b90506139c88482613467565b9350836000036139eb5760405163569d45cf60e11b815260040160405180910390fd5b60006139f5610d78565b9050613a227f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435748287614085565b600254604051631c6d209760e11b81526001600160a01b03918216600482015260248101879052604481018690526000918316906338da412e9060640161335a565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015613aad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad191906149cd565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16906370a0823190602401602060405180830381865afa158015613b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5f91906149cd565b905081600003613b825760405163569d45cf60e11b815260040160405180910390fd5b84821015613b8e578194505b6000613ba2613b9d878661390b565b614470565b600254909150613bdc906001600160a01b03167f0000000000000000000000000a59649758aa4d66e25f08dd01271e891fe5219988614085565b604051634acc893b60e11b8152306004820152602481018790527f00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a6001600160a01b031690639599127690604401600060405180830381600087803b158015613c4457600080fd5b505af1158015613c58573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092508491506001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f16906370a0823190602401602060405180830381865afa158015613cc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce991906149cd565b613cf39190614979565b9050801580613d0157508181105b15613d1f5760405163122d7f5760e01b815260040160405180910390fd5b613d6a7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f7f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb83614085565b604051633b4da69f60e01b8152306004820152602481018290527f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb6001600160a01b031690633b4da69f90604401600060405180830381600087803b158015613dd257600080fd5b505af1158015613de6573d6000803e3d6000fd5b50505050613df3816142f8565b6040517fac9f7997c30b6a3cc9c74953898b5de154359339c7ec0d6d70ceb98e55db1a4b90600090a250505050505050565b613e2d61248c565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c573390565b60006b033b2e3c9fd0803ce80000006139258484614547565b600061109d827f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f039190614c2c565b7f000000000000000000000000aed0c38402a5d19df6e4c03f4e2dced6e29c1ee961402b565b6002546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015613f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9a91906149cd565b6040516370a0823160e01b81523060048201529092507f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316906370a0823190602401602060405180830381865afa158015614001573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402591906149cd565b90509091565b60008061403783614574565b90506000614044846145d8565b90506140508583614dd9565b61405b90600a614d33565b6140676006600a614d33565b61407183896149b6565b61407b91906149b6565b61339d91906149a2565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916140e19190614d5f565b6000604051808303816000865af19150503d806000811461411e576040519150601f19603f3d011682016040523d82523d6000602084013e614123565b606091505b509150915081801561414d57508051158061414d57508080602001905181019061414d9190614d42565b6127e25760405162461bcd60e51b8152602060048201526002602482015261534160f01b60448201526064016124ce565b60005460ff16610b435760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016124ce565b600061109d82600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142449190614c2c565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c69190614c2c565b6003546001600160a01b03167f000000000000000000000000aed0c38402a5d19df6e4c03f4e2dced6e29c1ee96146ed565b60007f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614358573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061437c9190614c2c565b61438790600a614d33565b600260009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143fe9190614c2c565b61440990600a614d33565b61441390846149b6565b61109d91906149a2565b60008061442983614574565b90506000614436846145d8565b90506144446006600a614d33565b61444e90826149b6565b61445b8660ff85166149e6565b61446690600a614df2565b61407b90886149b6565b6002546040805163313ce56760e01b815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa1580156144ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144de9190614c2c565b6144e990600a614d33565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143da573d6000803e3d6000fd5b600081158061456b5750828261455d81836149b6565b925061456990836149a2565b145b61109d57600080fd5b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156145b4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109d9190614c2c565b6000806000806000856001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561461e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146429190614e1d565b9450945050935093508369ffffffffffffffffffff168169ffffffffffffffffffff16101561469e5760405162461bcd60e51b81526020600482015260086024820152674f6c64206461746160c01b60448201526064016124ce565b600082116146e35760405162461bcd60e51b8152602060048201526012602482015271526f756e64206e6f7420636f6d706c65746560701b60448201526064016124ce565b5090949350505050565b6000806146f9846145d8565b90506000614706846145d8565b905061471387600a614d33565b61471d90826149b6565b61472887600a614d33565b614732848b6149b6565b61473c91906149b6565b61474691906149a2565b98975050505050505050565b60005b8381101561476d578181015183820152602001614755565b50506000910152565b6020815260008251806020840152614795816040850160208701614752565b601f01601f19169190910160400192915050565b6000602082840312156147bb57600080fd5b5035919050565b8015158114610f0c57600080fd5b6000806000806000806000806000806101208b8d0312156147f057600080fd5b8a35995060208b0135985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135935060e08b013561482c816147c2565b92506101008b013567ffffffffffffffff8082111561484a57600080fd5b818d0191508d601f83011261485e57600080fd5b81358181111561486d57600080fd5b8e602082850101111561487f57600080fd5b6020830194508093505050509295989b9194979a5092959850565b600080604083850312156148ad57600080fd5b50508035926020909101359150565b6000806000606084860312156148d157600080fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114610f0c57600080fd5b6000806040838503121561491057600080fd5b823561491b816148e8565b946020939093013593505050565b600181811c9082168061493d57607f821691505b60208210810361495d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561109d5761109d614963565b634e487b7160e01b600052601260045260246000fd5b6000826149b1576149b161498c565b500490565b808202811582820484141761109d5761109d614963565b6000602082840312156149df57600080fd5b5051919050565b8082018082111561109d5761109d614963565b634e487b7160e01b600052604160045260246000fd5b601f82111561166657600081815260208120601f850160051c81016020861015614a365750805b601f850160051c820191505b818110156126e157828155600101614a42565b67ffffffffffffffff831115614a6d57614a6d6149f9565b614a8183614a7b8354614929565b83614a0f565b6000601f841160018114614ab55760008515614a9d5750838201355b600019600387901b1c1916600186901b1783556127e2565b600083815260209020601f19861690835b82811015614ae65786850135825560209485019460019092019101614ac6565b5086821015614b035760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b88815287602082015286604082015285606082015284608082015283151560a082015260e060c08201528160e082015260006101008385828501376000838501820152601f909301601f191690910190910198975050505050505050565b600060208284031215614b8557600080fd5b8151613478816148e8565b8181036000831280158383131683831282161715614bb057614bb0614963565b5092915050565b600060808284031215614bc957600080fd5b6040516080810181811067ffffffffffffffff82111715614bec57614bec6149f9565b806040525082518152602083015160208201526040830151614c0d816147c2565b60408201526060830151614c20816147c2565b60608201529392505050565b600060208284031215614c3e57600080fd5b815160ff8116811461347857600080fd5b600181815b80851115614c8a578160001904821115614c7057614c70614963565b80851615614c7d57918102915b93841c9390800290614c54565b509250929050565b600082614ca15750600161109d565b81614cae5750600061109d565b8160018114614cc45760028114614cce57614cea565b600191505061109d565b60ff841115614cdf57614cdf614963565b50506001821b61109d565b5060208310610133831016604e8410600b8410161715614d0d575081810a61109d565b614d178383614c4f565b8060001904821115614d2b57614d2b614963565b029392505050565b600061347860ff841683614c92565b600060208284031215614d5457600080fd5b8151613478816147c2565b60008251614d71818460208701614752565b9190910192915050565b80820260008212600160ff1b84141615614d9757614d97614963565b818105831482151761109d5761109d614963565b600082614dba57614dba61498c565b600160ff1b821460001984141615614dd457614dd4614963565b500590565b60ff818116838216019081111561109d5761109d614963565b60006134788383614c92565b805169ffffffffffffffffffff81168114614e1857600080fd5b919050565b600080600080600060a08688031215614e3557600080fd5b614e3e86614dfe565b9450602086015193506040860151925060608601519150614e6160808701614dfe565b9050929550929590935056fea2646970667358221220c58c8eb0af145ec4e88eea27388bf9799321a0501b98d23db365fb2c9e6940fc64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6000000000000000000000000aed0c38402a5d19df6e4c03f4e2dced6e29c1ee90000000000000000000000003afd8feed6bbd1d8254d92eafa1f695dce16387a00000000000000000000000000000000000000000000000000000000000000094453522041737365740000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _name (string): DSR Asset
Arg [1] : _sweep (address): 0xB88a5Ac00917a02d82c7cd6CEBd73E2852d43574
Arg [2] : _usdx (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [3] : _dai (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [4] : _dsrManager (address): 0x373238337Bfe1146fb49989fc222523f83081dDb
Arg [5] : _dssPsm (address): 0x89B78CfA322F6C5dE0aBcEecab66Aee45393cC5A
Arg [6] : _oracleUsdx (address): 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6
Arg [7] : _oracleDai (address): 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9
Arg [8] : _borrower (address): 0x3afd8feED6Bbd1D8254d92eAFA1F695Dce16387a
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [1] : 000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574
Arg [2] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [3] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [4] : 000000000000000000000000373238337bfe1146fb49989fc222523f83081ddb
Arg [5] : 00000000000000000000000089b78cfa322f6c5de0abceecab66aee45393cc5a
Arg [6] : 0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6
Arg [7] : 000000000000000000000000aed0c38402a5d19df6e4c03f4e2dced6e29c1ee9
Arg [8] : 0000000000000000000000003afd8feed6bbd1d8254d92eafa1f695dce16387a
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [10] : 4453522041737365740000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.