Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 5 from a total of 5 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Set Performance ... | 24491750 | 2 days ago | IN | 0 ETH | 0.00000995 | ||||
| Set Pending Mana... | 24491750 | 2 days ago | IN | 0 ETH | 0.00001522 | ||||
| Set Allowed | 24491750 | 2 days ago | IN | 0 ETH | 0.00001516 | ||||
| Set Profit Max U... | 24491750 | 2 days ago | IN | 0 ETH | 0.00001193 | ||||
| Accept Managemen... | 24491750 | 2 days ago | IN | 0 ETH | 0.00000931 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61014060 | 24491746 | 2 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LiquityV2SPStrategy
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
No with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
import {BaseHealthCheck, BaseStrategy, ERC20} from "@periphery/Bases/HealthCheck/BaseHealthCheck.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IPriceFeed} from "./interfaces/IPriceFeed.sol";
import {IStabilityPool} from "./interfaces/IStabilityPool.sol";
import {IAuction} from "./interfaces/IAuction.sol";
import {IAuctionFactory} from "./interfaces/IAuctionFactory.sol";
import {IAddressesRegistry} from "./interfaces/IAddressesRegistry.sol";
contract LiquityV2SPStrategy is BaseHealthCheck {
using SafeERC20 for ERC20;
// ===============================================================
// Storage
// ===============================================================
/// @notice Whether deposits are open to everyone
bool public openDeposits;
/// @notice Minimum acceptable auction price expressed in basis points of the oracle price
/// @dev Set to 0 to disable the check
uint256 public minAuctionPriceBps;
/// @notice Maximum amount of collateral that can be auctioned at once
uint256 public maxAuctionAmount;
/// @notice Max base fee (in gwei) for a tend
uint256 public maxGasPriceToTend;
/// @notice Buffer percentage for the auction starting price
uint256 public bufferPercentage;
/// @notice Minimum amount of collateral considered significant for claiming, auctioning, or tending
uint256 public dustThreshold;
/// @notice Addresses allowed to deposit when openDeposits is false
mapping(address => bool) public allowed;
// ===============================================================
// Constants
// ===============================================================
/// @notice WAD constant
uint256 private constant WAD = 1e18;
/// @notice Auction starting price buffer percentage increase when the oracle is down
uint256 public constant ORACLE_DOWN_BUFFER_PCT_MULTIPLIER = 200; // 200x
/// @notice Minimum buffer percentage for the auction starting price
uint256 public constant MIN_BUFFER_PERCENTAGE = WAD + 15e16; // 15%
/// @notice Minimum `maxGasPriceToTend`
uint256 public constant MIN_MAX_GAS_PRICE_TO_TEND = 50 * 1e9; // 50 gwei
/// @notice Minimum allowable dust threshold for collateral
/// @dev Serves two purposes:
/// - Defines the lowest value that `dustThreshold` (the collateral dust threshold) can be set to
/// - Also reused as the fixed `ASSET_DUST_THRESHOLD`, representing the minimum asset amount
/// considered worth depositing during harvests
uint256 public constant MIN_DUST_THRESHOLD = 1e15;
/// @notice Asset dust threshold. We will not bother depositing amounts below this value on harvests
uint256 public constant ASSET_DUST_THRESHOLD = MIN_DUST_THRESHOLD;
/// @notice Collateral reward token of the Stability Pool
ERC20 public immutable COLL;
/// @notice Liquity's price oracle for the collateral token
/// @dev Assumes the price feed is using 18 decimals
IPriceFeed public immutable COLL_PRICE_ORACLE;
/// @notice Stability Pool contract
IStabilityPool public immutable SP;
/// @notice Auction contract for selling the collateral reward token
IAuction public immutable AUCTION;
// ===============================================================
// Constructor
// ===============================================================
/// @param _addressesRegistry Address of the AddressesRegistry
/// @param _asset Address of the strategy's underlying asset
/// @param _auctionFactory Address of the AuctionFactory
/// @param _name Name of the strategy
constructor(
address _addressesRegistry,
address _asset,
address _auctionFactory,
string memory _name
) BaseHealthCheck(_asset, _name) {
COLL_PRICE_ORACLE = IAddressesRegistry(_addressesRegistry).priceFeed();
(, bool _isOracleDown) = COLL_PRICE_ORACLE.fetchPrice();
require(!_isOracleDown && COLL_PRICE_ORACLE.priceSource() == IPriceFeed.PriceSource.primary, "!oracle");
SP = IAddressesRegistry(_addressesRegistry).stabilityPool();
require(SP.boldToken() == _asset, "!sp");
COLL = ERC20(SP.collToken());
AUCTION = IAuctionFactory(_auctionFactory).createNewAuction(_asset);
AUCTION.setGovernanceOnlyKick(true);
AUCTION.enable(address(COLL));
minAuctionPriceBps = 9_500; // 95%
maxAuctionAmount = type(uint256).max;
maxGasPriceToTend = 200 * 1e9;
bufferPercentage = MIN_BUFFER_PERCENTAGE;
dustThreshold = MIN_DUST_THRESHOLD;
}
// ===============================================================
// View functions
// ===============================================================
/// @notice Check if there are collateral gains to claim from the Stability Pool
/// @return True if there are collateral gains to claim
function isCollateralGainToClaim() public view returns (bool) {
return SP.getDepositorCollGain(address(this)) > dustThreshold;
}
/// @notice Estimated total assets held by the strategy
/// @dev Does not account for pending collateral reward value
/// @return Estimated total assets held by the strategy
function estimatedTotalAssets() public view returns (uint256) {
return asset.balanceOf(address(this)) + SP.getCompoundedBoldDeposit(address(this));
}
/// @inheritdoc BaseStrategy
function availableDepositLimit(
address _owner
) public view override returns (uint256) {
return openDeposits || allowed[_owner] ? type(uint256).max : 0;
}
/// @inheritdoc BaseStrategy
function availableWithdrawLimit(
address /*_owner*/
) public view override returns (uint256) {
return estimatedTotalAssets();
}
// ===============================================================
// Management functions
// ===============================================================
/// @notice Allow anyone to deposit
/// @dev This is irreversible
function allowDeposits() external onlyManagement {
openDeposits = true;
}
/// @notice Set the minimum acceptable auction price
/// @dev Setting to 0 disables the check
/// @param _minAuctionPriceBps New minimum acceptable auction price in BPS of the oracle price
function setMinAuctionPriceBps(
uint256 _minAuctionPriceBps
) external onlyManagement {
require(_minAuctionPriceBps < MAX_BPS, "!minAuctionPriceBps");
minAuctionPriceBps = _minAuctionPriceBps;
}
/// @notice Set the maximum amount of collateral that can be auctioned at once
/// @param _maxAuctionAmount New maximum collateral amount to auction at once
function setMaxAuctionAmount(
uint256 _maxAuctionAmount
) external onlyManagement {
require(_maxAuctionAmount > 0, "!maxAuctionAmount");
maxAuctionAmount = _maxAuctionAmount;
}
/// @notice Set the maximum gas price for tending
/// @param _maxGasPriceToTend New maximum gas price
function setMaxGasPriceToTend(
uint256 _maxGasPriceToTend
) external onlyManagement {
require(_maxGasPriceToTend >= MIN_MAX_GAS_PRICE_TO_TEND, "!minMaxGasPrice");
maxGasPriceToTend = _maxGasPriceToTend;
}
/// @notice Set the buffer percentage for the auction starting price
/// @param _bufferPercentage New buffer percentage
function setBufferPercentage(
uint256 _bufferPercentage
) external onlyManagement {
require(_bufferPercentage >= MIN_BUFFER_PERCENTAGE, "!minBuffer");
bufferPercentage = _bufferPercentage;
}
/// @notice Set the dust threshold for the collateral token
/// @param _dustThreshold New collateral dust threshold
function setDustThreshold(
uint256 _dustThreshold
) external onlyManagement {
require(_dustThreshold >= MIN_DUST_THRESHOLD, "!minDust");
dustThreshold = _dustThreshold;
}
/// @notice Allow a specific address to deposit
/// @dev This is irreversible
/// @param _address Address to allow
function setAllowed(
address _address
) external onlyManagement {
allowed[_address] = true;
}
/// @notice Sweep stuck tokens
/// @dev Cannot sweep strategy asset or collateral token
/// @param _token Address of token to sweep
function sweep(
ERC20 _token
) external onlyManagement {
require(_token != asset && _token != COLL, "!token");
uint256 _balance = _token.balanceOf(address(this));
require(_balance > 0, "!balance");
_token.safeTransfer(TokenizedStrategy.management(), _balance);
}
// ===============================================================
// Mutated functions
// ===============================================================
/// @notice Claim collateral and yield gains from the Stability Pool
function claim() public {
_freeFunds(0);
}
// ===============================================================
// Internal mutated functions
// ===============================================================
/// @inheritdoc BaseStrategy
function _deployFunds(
uint256 _amount
) internal override {
SP.provideToSP(_amount, false);
}
/// @inheritdoc BaseStrategy
function _freeFunds(
uint256 _amount
) internal override {
SP.withdrawFromSP(_amount, true);
}
/// @inheritdoc BaseStrategy
function _harvestAndReport() internal override returns (uint256 _totalAssets) {
if (!TokenizedStrategy.isShutdown()) {
uint256 _toClaim = SP.getDepositorYieldGain(address(this));
if (_toClaim > ASSET_DUST_THRESHOLD) claim();
uint256 _toDeploy = asset.balanceOf(address(this));
if (_toDeploy > ASSET_DUST_THRESHOLD) _deployFunds(_toDeploy);
}
return estimatedTotalAssets();
}
/// @inheritdoc BaseStrategy
function _emergencyWithdraw(
uint256 /*_amount*/
) internal override {
_freeFunds(type(uint256).max); // Stability pool scales down to actual balance for us
}
/// @inheritdoc BaseStrategy
function _tend(
uint256 /*_totalIdle*/
) internal override {
if (isCollateralGainToClaim()) claim();
if (AUCTION.isActive(address(COLL))) {
if (AUCTION.available(address(COLL)) > 0) AUCTION.sweep(address(COLL));
AUCTION.settle(address(COLL));
}
uint256 _toAuction = Math.min(COLL.balanceOf(address(this)), maxAuctionAmount);
uint256 _available = COLL.balanceOf(address(AUCTION)) + _toAuction;
if (_available > dustThreshold) {
(uint256 _price, bool _isOracleDown) = COLL_PRICE_ORACLE.fetchPrice();
uint256 _bufferPercentage = bufferPercentage;
if (_isOracleDown || COLL_PRICE_ORACLE.priceSource() != IPriceFeed.PriceSource.primary) {
_bufferPercentage *= ORACLE_DOWN_BUFFER_PCT_MULTIPLIER;
}
// slither-disable-next-line divide-before-multiply
AUCTION.setStartingPrice(_available * _price / WAD * _bufferPercentage / WAD / WAD);
AUCTION.setMinimumPrice(_price * minAuctionPriceBps / MAX_BPS);
COLL.safeTransfer(address(AUCTION), _toAuction);
AUCTION.kick(address(COLL));
}
}
// ===============================================================
// Internal view functions
// ===============================================================
/// @inheritdoc BaseStrategy
function _tendTrigger() internal view override returns (bool) {
if (TokenizedStrategy.totalAssets() == 0) return false;
// If active auction, wait
if (AUCTION.available(address(COLL)) > dustThreshold) return false;
// Determine how much collateral we can kick
uint256 _toAuction = Math.min(COLL.balanceOf(address(this)), maxAuctionAmount);
uint256 _available = COLL.balanceOf(address(AUCTION)) + _toAuction;
// If base fee is acceptable and there's collateral to sell, tend to minimize exchange rate exposure
return block.basefee <= maxGasPriceToTend && (isCollateralGainToClaim() || _available > dustThreshold);
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import {BaseStrategy, ERC20} from "@tokenized-strategy/BaseStrategy.sol";
/**
* @title Base Health Check
* @author Yearn.finance
* @notice This contract can be inherited by any Yearn
* V3 strategy wishing to implement a health check during
* the `report` function in order to prevent any unexpected
* behavior from being permanently recorded as well as the
* `checkHealth` modifier.
*
* A strategist simply needs to inherit this contract. Set
* the limit ratios to the desired amounts and then
* override `_harvestAndReport()` just as they otherwise
* would. If the profit or loss that would be recorded is
* outside the acceptable bounds the tx will revert.
*
* The healthcheck does not prevent a strategy from reporting
* losses, but rather can make sure manual intervention is
* needed before reporting an unexpected loss or profit.
*/
abstract contract BaseHealthCheck is BaseStrategy {
// Can be used to determine if a healthcheck should be called.
// Defaults to true;
bool public doHealthCheck = true;
uint256 internal constant MAX_BPS = 10_000;
// Default profit limit to 100%.
uint16 private _profitLimitRatio = uint16(MAX_BPS);
// Defaults loss limit to 0.
uint16 private _lossLimitRatio;
constructor(
address _asset,
string memory _name
) BaseStrategy(_asset, _name) {}
/**
* @notice Returns the current profit limit ratio.
* @dev Use a getter function to keep the variable private.
* @return . The current profit limit ratio.
*/
function profitLimitRatio() public view returns (uint256) {
return _profitLimitRatio;
}
/**
* @notice Returns the current loss limit ratio.
* @dev Use a getter function to keep the variable private.
* @return . The current loss limit ratio.
*/
function lossLimitRatio() public view returns (uint256) {
return _lossLimitRatio;
}
/**
* @notice Set the `profitLimitRatio`.
* @dev Denominated in basis points. I.E. 1_000 == 10%.
* @param _newProfitLimitRatio The mew profit limit ratio.
*/
function setProfitLimitRatio(
uint256 _newProfitLimitRatio
) external onlyManagement {
_setProfitLimitRatio(_newProfitLimitRatio);
}
/**
* @dev Internally set the profit limit ratio. Denominated
* in basis points. I.E. 1_000 == 10%.
* @param _newProfitLimitRatio The mew profit limit ratio.
*/
function _setProfitLimitRatio(
uint256 _newProfitLimitRatio
) internal {
require(_newProfitLimitRatio > 0, "!zero profit");
require(_newProfitLimitRatio <= type(uint16).max, "!too high");
_profitLimitRatio = uint16(_newProfitLimitRatio);
}
/**
* @notice Set the `lossLimitRatio`.
* @dev Denominated in basis points. I.E. 1_000 == 10%.
* @param _newLossLimitRatio The new loss limit ratio.
*/
function setLossLimitRatio(
uint256 _newLossLimitRatio
) external onlyManagement {
_setLossLimitRatio(_newLossLimitRatio);
}
/**
* @dev Internally set the loss limit ratio. Denominated
* in basis points. I.E. 1_000 == 10%.
* @param _newLossLimitRatio The new loss limit ratio.
*/
function _setLossLimitRatio(
uint256 _newLossLimitRatio
) internal {
require(_newLossLimitRatio < MAX_BPS, "!loss limit");
_lossLimitRatio = uint16(_newLossLimitRatio);
}
/**
* @notice Turns the healthcheck on and off.
* @dev If turned off the next report will auto turn it back on.
* @param _doHealthCheck Bool if healthCheck should be done.
*/
function setDoHealthCheck(
bool _doHealthCheck
) public onlyManagement {
doHealthCheck = _doHealthCheck;
}
/**
* @notice OVerrides the default {harvestAndReport} to include a healthcheck.
* @return _totalAssets New totalAssets post report.
*/
function harvestAndReport() external override onlySelf returns (uint256 _totalAssets) {
// Let the strategy report.
_totalAssets = _harvestAndReport();
// Run the healthcheck on the amount returned.
_executeHealthCheck(_totalAssets);
}
/**
* @dev To be called during a report to make sure the profit
* or loss being recorded is within the acceptable bound.
*
* @param _newTotalAssets The amount that will be reported.
*/
function _executeHealthCheck(
uint256 _newTotalAssets
) internal virtual {
if (!doHealthCheck) {
doHealthCheck = true;
return;
}
// Get the current total assets from the implementation.
uint256 currentTotalAssets = TokenizedStrategy.totalAssets();
if (_newTotalAssets > currentTotalAssets) {
require(
((_newTotalAssets - currentTotalAssets) <= (currentTotalAssets * uint256(_profitLimitRatio)) / MAX_BPS),
"healthCheck"
);
} else if (currentTotalAssets > _newTotalAssets) {
require(
(currentTotalAssets - _newTotalAssets <= ((currentTotalAssets * uint256(_lossLimitRatio)) / MAX_BPS)),
"healthCheck"
);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(
IERC20 token,
address spender,
uint256 value
) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(
IERC20 token,
bytes memory data
) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(
IERC20 token,
bytes memory data
) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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 256, 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 << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
interface IPriceFeed {
enum PriceSource {
primary,
ETHUSDxCanonical,
lastGoodPrice
}
function priceSource() external view returns (PriceSource);
function fetchPrice() external returns (uint256 _price, bool _isOracleDown);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
import {ITroveManager} from "./ITroveManager.sol";
interface IStabilityPool {
function boldToken() external view returns (address);
function collToken() external view returns (address);
function troveManager() external view returns (ITroveManager);
function getCompoundedBoldDeposit(
address _depositor
) external view returns (uint256);
function getDepositorCollGain(
address _depositor
) external view returns (uint256);
function getTotalBoldDeposits() external view returns (uint256);
function activePool() external view returns (address);
function getDepositorYieldGain(
address _depositor
) external view returns (uint256);
function getDepositorYieldGainWithPending(
address _depositor
) external view returns (uint256);
function provideToSP(
uint256 _amount,
bool _doClaim
) external;
function withdrawFromSP(
uint256 _amount,
bool doClaim
) external;
function triggerBoldRewards(
uint256 _boldYield
) external;
function offset(
uint256 _debtToOffset,
uint256 _collToAdd
) external;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
interface IAuction {
function auctionLength() external view returns (uint256);
function available(
address _token
) external view returns (uint256);
function isActive(
address _token
) external view returns (bool);
function price(
address _from
) external view returns (uint256);
function minimumPrice() external view returns (uint256);
function startingPrice() external view returns (uint256);
function kick(
address _token
) external returns (uint256);
function setGovernanceOnlyKick(
bool _governanceOnlyKick
) external;
function setMinimumPrice(
uint256 _minimumPrice
) external;
function setStartingPrice(
uint256 _startingPrice
) external;
function enable(
address _from
) external;
function settle(
address _token
) external;
function sweep(
address _token
) external;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
import {IAuction} from "./IAuction.sol";
interface IAuctionFactory {
function createNewAuction(
address _want
) external returns (IAuction);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
import {IPriceFeed} from "./IPriceFeed.sol";
import {IStabilityPool} from "./IStabilityPool.sol";
interface IAddressesRegistry {
function priceFeed() external view returns (IPriceFeed);
function stabilityPool() external view returns (IStabilityPool);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// TokenizedStrategy interface used for internal view delegateCalls.
import {ITokenizedStrategy} from "./interfaces/ITokenizedStrategy.sol";
/**
* @title YearnV3 Base Strategy
* @author yearn.finance
* @notice
* BaseStrategy implements all of the required functionality to
* seamlessly integrate with the `TokenizedStrategy` implementation contract
* allowing anyone to easily build a fully permissionless ERC-4626 compliant
* Vault by inheriting this contract and overriding three simple functions.
*
* It utilizes an immutable proxy pattern that allows the BaseStrategy
* to remain simple and small. All standard logic is held within the
* `TokenizedStrategy` and is reused over any n strategies all using the
* `fallback` function to delegatecall the implementation so that strategists
* can only be concerned with writing their strategy specific code.
*
* This contract should be inherited and the three main abstract methods
* `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt
* the Strategy to the particular needs it has to generate yield. There are
* other optional methods that can be implemented to further customize
* the strategy if desired.
*
* All default storage for the strategy is controlled and updated by the
* `TokenizedStrategy`. The implementation holds a storage struct that
* contains all needed global variables in a manual storage slot. This
* means strategists can feel free to implement their own custom storage
* variables as they need with no concern of collisions. All global variables
* can be viewed within the Strategy by a simple call using the
* `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();.
*/
abstract contract BaseStrategy {
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @dev Used on TokenizedStrategy callback functions to make sure it is post
* a delegateCall from this address to the TokenizedStrategy.
*/
modifier onlySelf() {
_onlySelf();
_;
}
/**
* @dev Use to assure that the call is coming from the strategies management.
*/
modifier onlyManagement() {
TokenizedStrategy.requireManagement(msg.sender);
_;
}
/**
* @dev Use to assure that the call is coming from either the strategies
* management or the keeper.
*/
modifier onlyKeepers() {
TokenizedStrategy.requireKeeperOrManagement(msg.sender);
_;
}
/**
* @dev Use to assure that the call is coming from either the strategies
* management or the emergency admin.
*/
modifier onlyEmergencyAuthorized() {
TokenizedStrategy.requireEmergencyAuthorized(msg.sender);
_;
}
/**
* @dev Require that the msg.sender is this address.
*/
function _onlySelf() internal view {
require(msg.sender == address(this), "!self");
}
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/**
* @dev This is the address of the TokenizedStrategy implementation
* contract that will be used by all strategies to handle the
* accounting, logic, storage etc.
*
* Any external calls to the that don't hit one of the functions
* defined in this base or the strategy will end up being forwarded
* through the fallback function, which will delegateCall this address.
*
* This address should be the same for every strategy, never be adjusted
* and always be checked before any integration with the Strategy.
*/
address public constant tokenizedStrategyAddress = 0xD377919FA87120584B21279a491F82D5265A139c;
/*//////////////////////////////////////////////////////////////
IMMUTABLES
//////////////////////////////////////////////////////////////*/
/**
* @dev Underlying asset the Strategy is earning yield on.
* Stored here for cheap retrievals within the strategy.
*/
ERC20 internal immutable asset;
/**
* @dev This variable is set to address(this) during initialization of each strategy.
*
* This can be used to retrieve storage data within the strategy
* contract as if it were a linked library.
*
* i.e. uint256 totalAssets = TokenizedStrategy.totalAssets()
*
* Using address(this) will mean any calls using this variable will lead
* to a call to itself. Which will hit the fallback function and
* delegateCall that to the actual TokenizedStrategy.
*/
ITokenizedStrategy internal immutable TokenizedStrategy;
/**
* @notice Used to initialize the strategy on deployment.
*
* This will set the `TokenizedStrategy` variable for easy
* internal view calls to the implementation. As well as
* initializing the default storage variables based on the
* parameters and using the deployer for the permissioned roles.
*
* @param _asset Address of the underlying asset.
* @param _name Name the strategy will use.
*/
constructor(
address _asset,
string memory _name
) {
asset = ERC20(_asset);
// Set instance of the implementation for internal use.
TokenizedStrategy = ITokenizedStrategy(address(this));
// Initialize the strategy's storage variables.
_delegateCall(
abi.encodeCall(ITokenizedStrategy.initialize, (_asset, _name, msg.sender, msg.sender, msg.sender))
);
// Store the tokenizedStrategyAddress at the standard implementation
// address storage slot so etherscan picks up the interface. This gets
// stored on initialization and never updated.
assembly {
sstore(
// keccak256('eip1967.proxy.implementation' - 1)
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,
tokenizedStrategyAddress
)
}
}
/*//////////////////////////////////////////////////////////////
NEEDED TO BE OVERRIDDEN BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Can deploy up to '_amount' of 'asset' in the yield source.
*
* This function is called at the end of a {deposit} or {mint}
* call. Meaning that unless a whitelist is implemented it will
* be entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* @param _amount The amount of 'asset' that the strategy can attempt
* to deposit in the yield source.
*/
function _deployFunds(
uint256 _amount
) internal virtual;
/**
* @dev Should attempt to free the '_amount' of 'asset'.
*
* NOTE: The amount of 'asset' that is already loose has already
* been accounted for.
*
* This function is called during {withdraw} and {redeem} calls.
* Meaning that unless a whitelist is implemented it will be
* entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* Should not rely on asset.balanceOf(address(this)) calls other than
* for diff accounting purposes.
*
* Any difference between `_amount` and what is actually freed will be
* counted as a loss and passed on to the withdrawer. This means
* care should be taken in times of illiquidity. It may be better to revert
* if withdraws are simply illiquid so not to realize incorrect losses.
*
* @param _amount, The amount of 'asset' to be freed.
*/
function _freeFunds(
uint256 _amount
) internal virtual;
/**
* @dev Internal function to harvest all rewards, redeploy any idle
* funds and return an accurate accounting of all funds currently
* held by the Strategy.
*
* This should do any needed harvesting, rewards selling, accrual,
* redepositing etc. to get the most accurate view of current assets.
*
* NOTE: All applicable assets including loose assets should be
* accounted for in this function.
*
* Care should be taken when relying on oracles or swap values rather
* than actual amounts as all Strategy profit/loss accounting will
* be done based on this returned value.
*
* This can still be called post a shutdown, a strategist can check
* `TokenizedStrategy.isShutdown()` to decide if funds should be
* redeployed or simply realize any profits/losses.
*
* @return _totalAssets A trusted and accurate account for the total
* amount of 'asset' the strategy currently holds including idle funds.
*/
function _harvestAndReport() internal virtual returns (uint256 _totalAssets);
/*//////////////////////////////////////////////////////////////
OPTIONAL TO OVERRIDE BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Optional function for strategist to override that can
* be called in between reports.
*
* If '_tend' is used tendTrigger() will also need to be overridden.
*
* This call can only be called by a permissioned role so may be
* through protected relays.
*
* This can be used to harvest and compound rewards, deposit idle funds,
* perform needed position maintenance or anything else that doesn't need
* a full report for.
*
* EX: A strategy that can not deposit funds without getting
* sandwiched can use the tend when a certain threshold
* of idle to totalAssets has been reached.
*
* This will have no effect on PPS of the strategy till report() is called.
*
* @param _totalIdle The current amount of idle funds that are available to deploy.
*/
function _tend(
uint256 _totalIdle
) internal virtual {}
/**
* @dev Optional trigger to override if tend() will be used by the strategy.
* This must be implemented if the strategy hopes to invoke _tend().
*
* @return . Should return true if tend() should be called by keeper or false if not.
*/
function _tendTrigger() internal view virtual returns (bool) {
return false;
}
/**
* @notice Returns if tend() should be called by a keeper.
*
* @return . Should return true if tend() should be called by keeper or false if not.
* @return . Calldata for the tend call.
*/
function tendTrigger() external view virtual returns (bool, bytes memory) {
return (
// Return the status of the tend trigger.
_tendTrigger(),
// And the needed calldata either way.
abi.encodeWithSelector(ITokenizedStrategy.tend.selector)
);
}
/**
* @notice Gets the max amount of `asset` that an address can deposit.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any deposit or mints to enforce
* any limits desired by the strategist. This can be used for either a
* traditional deposit limit or for implementing a whitelist etc.
*
* EX:
* if(isAllowed[_owner]) return super.availableDepositLimit(_owner);
*
* This does not need to take into account any conversion rates
* from shares to assets. But should know that any non max uint256
* amounts may be converted to shares. So it is recommended to keep
* custom amounts low enough as not to cause overflow when multiplied
* by `totalSupply`.
*
* @param . The address that is depositing into the strategy.
* @return . The available amount the `_owner` can deposit in terms of `asset`
*/
function availableDepositLimit(
address /*_owner*/
) public view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @notice Gets the max amount of `asset` that can be withdrawn.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any withdraw or redeem to enforce
* any limits desired by the strategist. This can be used for illiquid
* or sandwichable strategies. It should never be lower than `totalIdle`.
*
* EX:
* return TokenIzedStrategy.totalIdle();
*
* This does not need to take into account the `_owner`'s share balance
* or conversion rates from shares to assets.
*
* @param . The address that is withdrawing from the strategy.
* @return . The available amount that can be withdrawn in terms of `asset`
*/
function availableWithdrawLimit(
address /*_owner*/
) public view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Optional function for a strategist to override that will
* allow management to manually withdraw deployed funds from the
* yield source if a strategy is shutdown.
*
* This should attempt to free `_amount`, noting that `_amount` may
* be more than is currently deployed.
*
* NOTE: This will not realize any profits or losses. A separate
* {report} will be needed in order to record any profit/loss. If
* a report may need to be called after a shutdown it is important
* to check if the strategy is shutdown during {_harvestAndReport}
* so that it does not simply re-deploy all funds that had been freed.
*
* EX:
* if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) {
* depositFunds...
* }
*
* @param _amount The amount of asset to attempt to free.
*/
function _emergencyWithdraw(
uint256 _amount
) internal virtual {}
/*//////////////////////////////////////////////////////////////
TokenizedStrategy HOOKS
//////////////////////////////////////////////////////////////*/
/**
* @notice Can deploy up to '_amount' of 'asset' in yield source.
* @dev Callback for the TokenizedStrategy to call during a {deposit}
* or {mint} to tell the strategy it can deploy funds.
*
* Since this can only be called after a {deposit} or {mint}
* delegateCall to the TokenizedStrategy msg.sender == address(this).
*
* Unless a whitelist is implemented this will be entirely permissionless
* and thus can be sandwiched or otherwise manipulated.
*
* @param _amount The amount of 'asset' that the strategy can
* attempt to deposit in the yield source.
*/
function deployFunds(
uint256 _amount
) external virtual onlySelf {
_deployFunds(_amount);
}
/**
* @notice Should attempt to free the '_amount' of 'asset'.
* @dev Callback for the TokenizedStrategy to call during a withdraw
* or redeem to free the needed funds to service the withdraw.
*
* This can only be called after a 'withdraw' or 'redeem' delegateCall
* to the TokenizedStrategy so msg.sender == address(this).
*
* @param _amount The amount of 'asset' that the strategy should attempt to free up.
*/
function freeFunds(
uint256 _amount
) external virtual onlySelf {
_freeFunds(_amount);
}
/**
* @notice Returns the accurate amount of all funds currently
* held by the Strategy.
* @dev Callback for the TokenizedStrategy to call during a report to
* get an accurate accounting of assets the strategy controls.
*
* This can only be called after a report() delegateCall to the
* TokenizedStrategy so msg.sender == address(this).
*
* @return . A trusted and accurate account for the total amount
* of 'asset' the strategy currently holds including idle funds.
*/
function harvestAndReport() external virtual onlySelf returns (uint256) {
return _harvestAndReport();
}
/**
* @notice Will call the internal '_tend' when a keeper tends the strategy.
* @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy.
*
* This can only be called after a tend() delegateCall to the TokenizedStrategy
* so msg.sender == address(this).
*
* We name the function `tendThis` so that `tend` calls are forwarded to
* the TokenizedStrategy.
*
* @param _totalIdle The amount of current idle funds that can be
* deployed during the tend
*/
function tendThis(
uint256 _totalIdle
) external virtual onlySelf {
_tend(_totalIdle);
}
/**
* @notice Will call the internal '_emergencyWithdraw' function.
* @dev Callback for the TokenizedStrategy during an emergency withdraw.
*
* This can only be called after a emergencyWithdraw() delegateCall to
* the TokenizedStrategy so msg.sender == address(this).
*
* We name the function `shutdownWithdraw` so that `emergencyWithdraw`
* calls are forwarded to the TokenizedStrategy.
*
* @param _amount The amount of asset to attempt to free.
*/
function shutdownWithdraw(
uint256 _amount
) external virtual onlySelf {
_emergencyWithdraw(_amount);
}
/**
* @dev Function used to delegate call the TokenizedStrategy with
* certain `_calldata` and return any return values.
*
* This is used to setup the initial storage of the strategy, and
* can be used by strategist to forward any other call to the
* TokenizedStrategy implementation.
*
* @param _calldata The abi encoded calldata to use in delegatecall.
* @return . The return value if the call was successful in bytes.
*/
function _delegateCall(
bytes memory _calldata
) internal returns (bytes memory) {
// Delegate call the tokenized strategy with provided calldata.
(bool success, bytes memory result) = tokenizedStrategyAddress.delegatecall(_calldata);
// If the call reverted. Return the error.
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
// Return the result.
return result;
}
/**
* @dev Execute a function on the TokenizedStrategy and return any value.
*
* This fallback function will be executed when any of the standard functions
* defined in the TokenizedStrategy are called since they wont be defined in
* this contract.
*
* It will delegatecall the TokenizedStrategy implementation with the exact
* calldata and return any relevant values.
*
*/
fallback() external {
// load our target address
address _tokenizedStrategyAddress = tokenizedStrategyAddress;
// Execute external function using delegatecall and return any value.
assembly {
// Copy function selector and any arguments.
calldatacopy(0, 0, calldatasize())
// Execute function delegatecall.
let result := delegatecall(gas(), _tokenizedStrategyAddress, 0, calldatasize(), 0, 0)
// Get any return value
returndatacopy(0, 0, returndatasize())
// Return any return value or error back to the caller
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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 (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(
address owner
) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(
address account
) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(
address payable recipient,
uint256 amount
) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success,) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data
) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) return returndata;
else _revert(returndata, errorMessage);
}
function _revert(
bytes memory returndata,
string memory errorMessage
) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
import {ISortedTroves} from "./ISortedTroves.sol";
import {IStabilityPool} from "./IStabilityPool.sol";
interface ITroveManager {
function sortedTroves() external view returns (ISortedTroves);
function stabilityPool() external view returns (IStabilityPool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(
string memory name_,
string memory symbol_
) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(
address account
) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(
address to,
uint256 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(
address owner,
address spender
) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(
address spender,
uint256 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(
address spender,
uint256 addedValue
) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/**
* @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(
address account,
uint256 amount
) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(
address account,
uint256 amount
) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.18;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
// Interface that implements the 4626 standard and the implementation functions
interface ITokenizedStrategy is IERC4626, IERC20Permit {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event StrategyShutdown();
event NewTokenizedStrategy(address indexed strategy, address indexed asset, string apiVersion);
event Reported(uint256 profit, uint256 loss, uint256 protocolFees, uint256 performanceFees);
event UpdatePerformanceFeeRecipient(address indexed newPerformanceFeeRecipient);
event UpdateKeeper(address indexed newKeeper);
event UpdatePerformanceFee(uint16 newPerformanceFee);
event UpdateManagement(address indexed newManagement);
event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);
event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);
event UpdatePendingManagement(address indexed newPendingManagement);
/*//////////////////////////////////////////////////////////////
INITIALIZATION
//////////////////////////////////////////////////////////////*/
function initialize(
address _asset,
string memory _name,
address _management,
address _performanceFeeRecipient,
address _keeper
) external;
/*//////////////////////////////////////////////////////////////
NON-STANDARD 4626 OPTIONS
//////////////////////////////////////////////////////////////*/
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxLoss
) external returns (uint256);
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 maxLoss
) external returns (uint256);
function maxWithdraw(
address owner,
uint256 /*maxLoss*/
) external view returns (uint256);
function maxRedeem(
address owner,
uint256 /*maxLoss*/
) external view returns (uint256);
/*//////////////////////////////////////////////////////////////
MODIFIER HELPERS
//////////////////////////////////////////////////////////////*/
function requireManagement(
address _sender
) external view;
function requireKeeperOrManagement(
address _sender
) external view;
function requireEmergencyAuthorized(
address _sender
) external view;
/*//////////////////////////////////////////////////////////////
KEEPERS FUNCTIONS
//////////////////////////////////////////////////////////////*/
function tend() external;
function report() external returns (uint256 _profit, uint256 _loss);
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
function MAX_FEE() external view returns (uint16);
function FACTORY() external view returns (address);
/*//////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////*/
function apiVersion() external view returns (string memory);
function pricePerShare() external view returns (uint256);
function management() external view returns (address);
function pendingManagement() external view returns (address);
function keeper() external view returns (address);
function emergencyAdmin() external view returns (address);
function performanceFee() external view returns (uint16);
function performanceFeeRecipient() external view returns (address);
function fullProfitUnlockDate() external view returns (uint256);
function profitUnlockingRate() external view returns (uint256);
function profitMaxUnlockTime() external view returns (uint256);
function lastReport() external view returns (uint256);
function isShutdown() external view returns (bool);
function unlockedShares() external view returns (uint256);
/*//////////////////////////////////////////////////////////////
SETTERS
//////////////////////////////////////////////////////////////*/
function setPendingManagement(
address
) external;
function acceptManagement() external;
function setKeeper(
address _keeper
) external;
function setEmergencyAdmin(
address _emergencyAdmin
) external;
function setPerformanceFee(
uint16 _performanceFee
) external;
function setPerformanceFeeRecipient(
address _performanceFeeRecipient
) external;
function setProfitMaxUnlockTime(
uint256 _profitMaxUnlockTime
) external;
function setName(
string calldata _newName
) external;
function shutdownStrategy() external;
function emergencyWithdraw(
uint256 _amount
) external;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.23;
interface ISortedTroves {
function getSize() external view returns (uint256);
}// 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.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(
uint256 assets
) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(
uint256 shares
) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(
address receiver
) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(
uint256 assets
) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(
uint256 assets,
address receiver
) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(
address receiver
) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(
uint256 shares
) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(
uint256 shares,
address receiver
) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(
address owner
) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(
uint256 assets
) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(
address owner
) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(
uint256 shares
) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"forge-std/=lib/forge-std/src/",
"@tokenized-strategy/=lib/tokenized-strategy/src/",
"@periphery/=lib/tokenized-strategy-periphery/src/",
"@vault-periphery/=lib/vault-periphery/src/",
"@yearn-vaults/=lib/yearn-vaults-v3/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/tokenized-strategy/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/",
"tokenized-strategy-periphery/=lib/tokenized-strategy-periphery/",
"tokenized-strategy/=lib/tokenized-strategy/",
"vault-periphery/=lib/vault-periphery/",
"yearn-vaults-v3/=lib/yearn-vaults-v3/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_addressesRegistry","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_auctionFactory","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"ASSET_DUST_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AUCTION","outputs":[{"internalType":"contract IAuction","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLL","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLL_PRICE_ORACLE","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BUFFER_PERCENTAGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DUST_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_MAX_GAS_PRICE_TO_TEND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_DOWN_BUFFER_PCT_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SP","outputs":[{"internalType":"contract IStabilityPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"availableDepositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"availableWithdrawLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bufferPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deployFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"doHealthCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dustThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimatedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"freeFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestAndReport","outputs":[{"internalType":"uint256","name":"_totalAssets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCollateralGainToClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossLimitRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAuctionAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasPriceToTend","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAuctionPriceBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openDeposits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitLimitRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bufferPercentage","type":"uint256"}],"name":"setBufferPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_doHealthCheck","type":"bool"}],"name":"setDoHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dustThreshold","type":"uint256"}],"name":"setDustThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newLossLimitRatio","type":"uint256"}],"name":"setLossLimitRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAuctionAmount","type":"uint256"}],"name":"setMaxAuctionAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPriceToTend","type":"uint256"}],"name":"setMaxGasPriceToTend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minAuctionPriceBps","type":"uint256"}],"name":"setMinAuctionPriceBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newProfitLimitRatio","type":"uint256"}],"name":"setProfitLimitRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"shutdownWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalIdle","type":"uint256"}],"name":"tendThis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenizedStrategyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61014060405260015f806101000a81548160ff0219169083151502179055506127105f60016101000a81548161ffff021916908361ffff16021790555034801562000048575f80fd5b5060405162004c0b38038062004c0b83398181016040528101906200006e919062000a44565b828181818173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250503073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250506200014a8282333333604051602401620000f995949392919062000b3d565b6040516020818303038152906040526397073ae660e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050620007bf60201b60201c565b5073d377919fa87120584b21279a491f82d5265a139c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55505050508373ffffffffffffffffffffffffffffffffffffffff1663741bef1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001d0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001f6919062000be1565b73ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff16815250505f60e05173ffffffffffffffffffffffffffffffffffffffff16630fdb11cf6040518163ffffffff1660e01b815260040160408051808303815f875af115801562000276573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200029c919062000c83565b915050801580156200034857505f6002811115620002bf57620002be62000cc8565b5b60e05173ffffffffffffffffffffffffffffffffffffffff166320531bc96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200030b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000331919062000d1b565b600281111562000346576200034562000cc8565b5b145b6200038a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003819062000d99565b60405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff1663048c661d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003d4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620003fa919062000dfb565b73ffffffffffffffffffffffffffffffffffffffff166101008173ffffffffffffffffffffffffffffffffffffffff16815250508373ffffffffffffffffffffffffffffffffffffffff166101005173ffffffffffffffffffffffffffffffffffffffff1663630afce56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000492573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620004b8919062000e2b565b73ffffffffffffffffffffffffffffffffffffffff161462000511576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005089062000ea9565b60405180910390fd5b6101005173ffffffffffffffffffffffffffffffffffffffff166331b8c9466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200055e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000584919062000e2b565b73ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff16630935861e856040518263ffffffff1660e01b8152600401620005f2919062000ec9565b6020604051808303815f875af11580156200060f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000635919062000f26565b73ffffffffffffffffffffffffffffffffffffffff166101208173ffffffffffffffffffffffffffffffffffffffff16815250506101205173ffffffffffffffffffffffffffffffffffffffff1663adec61d760016040518263ffffffff1660e01b8152600401620006a8919062000f67565b5f604051808303815f87803b158015620006c0575f80fd5b505af1158015620006d3573d5f803e3d5ffd5b505050506101205173ffffffffffffffffffffffffffffffffffffffff16635bfa1b6860c0516040518263ffffffff1660e01b815260040162000717919062000ec9565b5f604051808303815f87803b1580156200072f575f80fd5b505af115801562000742573d5f803e3d5ffd5b5050505061251c6001819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600281905550642e90edd000600381905550670214e8348c4f0000670de0b6b3a7640000620007a0919062000faf565b60048190555066038d7ea4c6800060058190555050505050506200104b565b60605f8073d377919fa87120584b21279a491f82d5265a139c73ffffffffffffffffffffffffffffffffffffffff1684604051620007fe919062001033565b5f60405180830381855af49150503d805f811462000838576040519150601f19603f3d011682016040523d82523d5f602084013e6200083d565b606091505b50915091508162000854576040513d805f833e8082fd5b8092505050919050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200089a826200086f565b9050919050565b620008ac816200088e565b8114620008b7575f80fd5b50565b5f81519050620008ca81620008a1565b92915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200092082620008d8565b810181811067ffffffffffffffff82111715620009425762000941620008e8565b5b80604052505050565b5f620009566200085e565b905062000964828262000915565b919050565b5f67ffffffffffffffff821115620009865762000985620008e8565b5b6200099182620008d8565b9050602081019050919050565b5f5b83811015620009bd578082015181840152602081019050620009a0565b5f8484015250505050565b5f620009de620009d88462000969565b6200094b565b905082815260208101848484011115620009fd57620009fc620008d4565b5b62000a0a8482856200099e565b509392505050565b5f82601f83011262000a295762000a28620008d0565b5b815162000a3b848260208601620009c8565b91505092915050565b5f805f806080858703121562000a5f5762000a5e62000867565b5b5f62000a6e87828801620008ba565b945050602062000a8187828801620008ba565b935050604062000a9487828801620008ba565b925050606085015167ffffffffffffffff81111562000ab85762000ab76200086b565b5b62000ac68782880162000a12565b91505092959194509250565b62000add816200088e565b82525050565b5f81519050919050565b5f82825260208201905092915050565b5f62000b098262000ae3565b62000b15818562000aed565b935062000b278185602086016200099e565b62000b3281620008d8565b840191505092915050565b5f60a08201905062000b525f83018862000ad2565b818103602083015262000b66818762000afd565b905062000b77604083018662000ad2565b62000b86606083018562000ad2565b62000b95608083018462000ad2565b9695505050505050565b5f62000bab826200088e565b9050919050565b62000bbd8162000b9f565b811462000bc8575f80fd5b50565b5f8151905062000bdb8162000bb2565b92915050565b5f6020828403121562000bf95762000bf862000867565b5b5f62000c088482850162000bcb565b91505092915050565b5f819050919050565b62000c258162000c11565b811462000c30575f80fd5b50565b5f8151905062000c438162000c1a565b92915050565b5f8115159050919050565b62000c5f8162000c49565b811462000c6a575f80fd5b50565b5f8151905062000c7d8162000c54565b92915050565b5f806040838503121562000c9c5762000c9b62000867565b5b5f62000cab8582860162000c33565b925050602062000cbe8582860162000c6d565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6003811062000d02575f80fd5b50565b5f8151905062000d158162000cf5565b92915050565b5f6020828403121562000d335762000d3262000867565b5b5f62000d428482850162000d05565b91505092915050565b7f216f7261636c65000000000000000000000000000000000000000000000000005f82015250565b5f62000d8160078362000aed565b915062000d8e8262000d4b565b602082019050919050565b5f6020820190508181035f83015262000db28162000d73565b9050919050565b5f62000dc5826200088e565b9050919050565b62000dd78162000db9565b811462000de2575f80fd5b50565b5f8151905062000df58162000dcc565b92915050565b5f6020828403121562000e135762000e1262000867565b5b5f62000e228482850162000de5565b91505092915050565b5f6020828403121562000e435762000e4262000867565b5b5f62000e5284828501620008ba565b91505092915050565b7f21737000000000000000000000000000000000000000000000000000000000005f82015250565b5f62000e9160038362000aed565b915062000e9e8262000e5b565b602082019050919050565b5f6020820190508181035f83015262000ec28162000e83565b9050919050565b5f60208201905062000ede5f83018462000ad2565b92915050565b5f62000ef0826200088e565b9050919050565b62000f028162000ee4565b811462000f0d575f80fd5b50565b5f8151905062000f208162000ef7565b92915050565b5f6020828403121562000f3e5762000f3d62000867565b5b5f62000f4d8482850162000f10565b91505092915050565b62000f618162000c49565b82525050565b5f60208201905062000f7c5f83018462000f56565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f62000fbb8262000c11565b915062000fc88362000c11565b925082820190508082111562000fe35762000fe262000f82565b5b92915050565b5f81519050919050565b5f81905092915050565b5f620010098262000fe9565b62001015818562000ff3565b9350620010278185602086016200099e565b80840191505092915050565b5f62001040828462000ffd565b915081905092915050565b60805160a05160c05160e0516101005161012051613a36620011d55f395f818161105e01528181611d5a01528181611f040152818161207401528181612132015281816121f001528181612297015281816124220152818161261e015281816126eb0152818161278e01526127f601525f8181610cff01528181610dba0152818161157f015281816117ce015281816118ed0152611c3001525f8181610bdf015281816124b6015261256701525f818161085501528181610eca01528181611d9601528181611e2401528181611ec8015281816120b00152818161216e0152818161222c015281816122d301528181612342015281816123e6015281816127b0015261283201525f8181610779015281816109a501528181610a6d01528181610b0e01528181610c0301528181610f0d015281816110b2015281816111430152818161122e015281816112ce015281816113be015281816114e20152818161185b01528181611a930152611cbd01525f81816107fe0152818161161701526119a00152613a365ff3fe608060405234801561000f575f80fd5b5060043610610260575f3560e01c80636718835f11610144578063bbf88267116100c1578063d696860111610085578063d6968601146106c7578063e8462e8f146106e3578063ea2b192314610701578063efbb5cb01461071f578063f50c952f1461073d578063fde813a81461075b57610261565b8063bbf8826714610621578063c0e79a111461063f578063c3f81cc51461065b578063d19a3bb814610679578063d63a8e111461069757610261565b80639d7fb70c116101085780639d7fb70c14610591578063ac00ff26146105ad578063ad7e55ba146105c9578063b1e03ca0146105e5578063b6a165061461060357610261565b80636718835f146104ff5780637d9699321461051d57806393fd25ec1461053b578063950b3d73146105595780639b90fb161461057557610261565b80634426ebd0116101dd578063503160d9116101a1578063503160d91461044e5780635262e5de1461046a57806353fc1db4146104885780635c911892146104a65780635d265d3f146104c257806363779c74146104e157610261565b80634426ebd0146103ba57806346aa2f12146103d857806349317f1d146104085780634a5d0943146104265780634e71d92d1461044457610261565b80632b371ecf116102245780632b371ecf146103285780632b45732a14610344578063332c557a1461036257806333d1a1c4146103805780633d6cb5751461039e57610261565b806301681a621461029857806304bd4629146102b4578063157c7ff6146102e4578063184aea26146102ee5780632851b6691461030a57610261565b5b5f73d377919fa87120584b21279a491f82d5265a139c9050365f80375f80365f845af43d5f803e805f8114610294573d5ff35b3d5ffd5b6102b260048036038101906102ad9190612c58565b610777565b005b6102ce60048036038101906102c99190612cad565b610a5b565b6040516102db9190612cf0565b60405180910390f35b6102ec610a6b565b005b61030860048036038101906103039190612d33565b610b0c565b005b610312610bdd565b60405161031f9190612db9565b60405180910390f35b610342600480360381019061033d9190612d33565b610c01565b005b61034c610cee565b6040516103599190612cf0565b60405180910390f35b61036a610cf9565b6040516103779190612dec565b60405180910390f35b610388610d9b565b6040516103959190612cf0565b60405180910390f35b6103b860048036038101906103b39190612d33565b610da4565b005b6103c2610db8565b6040516103cf9190612e25565b60405180910390f35b6103f260048036038101906103ed9190612cad565b610ddc565b6040516103ff9190612cf0565b60405180910390f35b610410610e70565b60405161041d9190612cf0565b60405180910390f35b61042e610e8f565b60405161043b9190612cf0565b60405180910390f35b61044c610ea9565b005b61046860048036038101906104639190612d33565b610eb4565b005b610472610ec8565b60405161047f9190612e5e565b60405180910390f35b610490610eec565b60405161049d9190612cf0565b60405180910390f35b6104c060048036038101906104bb9190612d33565b610f0b565b005b6104ca610fde565b6040516104d8929190612f01565b60405180910390f35b6104e961105c565b6040516104f69190612f4f565b60405180910390f35b610507611080565b6040516105149190612dec565b60405180910390f35b610525611090565b6040516105329190612cf0565b60405180910390f35b6105436110aa565b6040516105509190612cf0565b60405180910390f35b610573600480360381019061056e9190612d33565b6110b0565b005b61058f600480360381019061058a9190612d33565b611141565b005b6105ab60048036038101906105a69190612d33565b611218565b005b6105c760048036038101906105c29190612f92565b61122c565b005b6105e360048036038101906105de9190612d33565b6112cc565b005b6105ed6113a5565b6040516105fa9190612cf0565b60405180910390f35b61060b6113b0565b6040516106189190612cf0565b60405180910390f35b6106296113b6565b6040516106369190612cf0565b60405180910390f35b61065960048036038101906106549190612cad565b6113bc565b005b610663611499565b6040516106709190612dec565b60405180910390f35b6106816114ab565b60405161068e9190612fcc565b60405180910390f35b6106b160048036038101906106ac9190612cad565b6114c3565b6040516106be9190612dec565b60405180910390f35b6106e160048036038101906106dc9190612d33565b6114e0565b005b6106eb611571565b6040516106f89190612cf0565b60405180910390f35b610709611577565b6040516107169190612cf0565b60405180910390f35b61072761157c565b6040516107349190612cf0565b60405180910390f35b6107456116bc565b6040516107529190612cf0565b60405180910390f35b61077560048036038101906107709190612d33565b6116c2565b005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016107d09190612fcc565b5f6040518083038186803b1580156107e6575f80fd5b505afa1580156107f8573d5f803e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156108a457507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b6108e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108da9061303f565b60405180910390fd5b5f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161091d9190612fcc565b602060405180830381865afa158015610938573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061095c9190613071565b90505f81116109a0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610997906130e6565b60405180910390fd5b610a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a309190613118565b828473ffffffffffffffffffffffffffffffffffffffff166116d69092919063ffffffff16565b5050565b5f610a6461157c565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610ac49190612fcc565b5f6040518083038186803b158015610ada575f80fd5b505afa158015610aec573d5f803e3d5ffd5b5050505060015f60056101000a81548160ff021916908315150217905550565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610b659190612fcc565b5f6040518083038186803b158015610b7b575f80fd5b505afa158015610b8d573d5f803e3d5ffd5b505050505f8111610bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bca9061318d565b60405180910390fd5b8060028190555050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610c5a9190612fcc565b5f6040518083038186803b158015610c70575f80fd5b505afa158015610c82573d5f803e3d5ffd5b50505050670214e8348c4f0000670de0b6b3a7640000610ca291906131d8565b811015610ce4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cdb90613255565b60405180910390fd5b8060048190555050565b66038d7ea4c6800081565b5f6005547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166347ea8354306040518263ffffffff1660e01b8152600401610d569190612fcc565b602060405180830381865afa158015610d71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d959190613071565b11905090565b640ba43b740081565b610dac61175c565b610db5816117cc565b50565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f8060059054906101000a900460ff1680610e3d575060065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff165b610e47575f610e69565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b9050919050565b5f610e7961175c565b610e81611858565b9050610e8c81611a61565b90565b5f8060019054906101000a900461ffff1661ffff16905090565b610eb25f6117cc565b565b610ebc61175c565b610ec581611c2e565b50565b7f000000000000000000000000000000000000000000000000000000000000000081565b670214e8348c4f0000670de0b6b3a7640000610f0891906131d8565b81565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610f649190612fcc565b5f6040518083038186803b158015610f7a575f80fd5b505afa158015610f8c573d5f803e3d5ffd5b505050506127108110610fd4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fcb906132bd565b60405180910390fd5b8060018190555050565b5f6060610fe9611cb9565b63440368a360e01b604051602401604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050915091509091565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f8054906101000a900460ff1681565b5f8060039054906101000a900461ffff1661ffff16905090565b60045481565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016111099190612fcc565b5f6040518083038186803b15801561111f575f80fd5b505afa158015611131573d5f803e3d5ffd5b5050505061113e81611fb4565b50565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b815260040161119a9190612fcc565b5f6040518083038186803b1580156111b0575f80fd5b505afa1580156111c2573d5f803e3d5ffd5b50505050640ba43b740081101561120e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120590613325565b60405180910390fd5b8060038190555050565b61122061175c565b6112298161205c565b50565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016112859190612fcc565b5f6040518083038186803b15801561129b575f80fd5b505afa1580156112ad573d5f803e3d5ffd5b50505050805f806101000a81548160ff02191690831515021790555050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016113259190612fcc565b5f6040518083038186803b15801561133b575f80fd5b505afa15801561134d573d5f803e3d5ffd5b5050505066038d7ea4c6800081101561139b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113929061338d565b60405180910390fd5b8060058190555050565b66038d7ea4c6800081565b60035481565b60025481565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016114159190612fcc565b5f6040518083038186803b15801561142b575f80fd5b505afa15801561143d573d5f803e3d5ffd5b50505050600160065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555050565b5f60059054906101000a900460ff1681565b73d377919fa87120584b21279a491f82d5265a139c81565b6006602052805f5260405f205f915054906101000a900460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016115399190612fcc565b5f6040518083038186803b15801561154f575f80fd5b505afa158015611561573d5f803e3d5ffd5b5050505061156e816128b7565b50565b60055481565b60c881565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663065f566d306040518263ffffffff1660e01b81526004016115d69190612fcc565b602060405180830381865afa1580156115f1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116159190613071565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161166e9190612fcc565b602060405180830381865afa158015611689573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116ad9190613071565b6116b791906131d8565b905090565b60015481565b6116ca61175c565b6116d38161291a565b50565b6117578363a9059cbb60e01b84846040516024016116f59291906133ab565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612946565b505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146117ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117c19061341c565b60405180910390fd5b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663cfddf5f58260016040518363ffffffff1660e01b815260040161182892919061343a565b5f604051808303815f87803b15801561183f575f80fd5b505af1158015611851573d5f803e3d5ffd5b5050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118e69190613475565b611a54575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663daed0a9b306040518263ffffffff1660e01b81526004016119449190612fcc565b602060405180830381865afa15801561195f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119839190613071565b905066038d7ea4c6800081111561199d5761199c610ea9565b5b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016119f79190612fcc565b602060405180830381865afa158015611a12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a369190613071565b905066038d7ea4c68000811115611a5157611a5081611c2e565b5b50505b611a5c61157c565b905090565b5f8054906101000a900460ff16611a905760015f806101000a81548160ff021916908315150217905550611c2b565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611afa573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b1e9190613071565b905080821115611ba6576127105f60019054906101000a900461ffff1661ffff1682611b4a91906134a0565b611b54919061350e565b8183611b60919061353e565b1115611ba1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b98906135bb565b60405180910390fd5b611c29565b81811115611c28576127105f60039054906101000a900461ffff1661ffff1682611bd091906134a0565b611bda919061350e565b8282611be6919061353e565b1115611c27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c1e906135bb565b60405180910390fd5b5b5b505b50565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663aeb4b970825f6040518363ffffffff1660e01b8152600401611c8992919061343a565b5f604051808303815f87803b158015611ca0575f80fd5b505af1158015611cb2573d5f803e3d5ffd5b5050505050565b5f807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d489190613071565b03611d55575f9050611fb1565b6005547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166310098ad57f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401611dd19190612fcc565b602060405180830381865afa158015611dec573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e109190613071565b1115611e1e575f9050611fb1565b5f611ec27f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611e7b9190612fcc565b602060405180830381865afa158015611e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eba9190613071565b600254612a0c565b90505f817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a082317f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401611f3f9190612fcc565b602060405180830381865afa158015611f5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7e9190613071565b611f8891906131d8565b90506003544811158015611fac5750611f9f610cf9565b80611fab575060055481115b5b925050505b90565b5f8111611ff6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fed90613623565b60405180910390fd5b61ffff801681111561203d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120349061368b565b60405180910390fd5b805f60016101000a81548161ffff021916908361ffff16021790555050565b612064610cf9565b1561207257612071610ea9565b5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639f8a13d77f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016120eb9190612fcc565b602060405180830381865afa158015612106573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061212a9190613475565b1561233c575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166310098ad57f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016121a99190612fcc565b602060405180830381865afa1580156121c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121e89190613071565b1115612295577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166301681a627f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016122679190612fcc565b5f604051808303815f87803b15801561227e575f80fd5b505af1158015612290573d5f803e3d5ffd5b505050505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636a256b297f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040161230e9190612fcc565b5f604051808303815f87803b158015612325575f80fd5b505af1158015612337573d5f803e3d5ffd5b505050505b5f6123e07f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123999190612fcc565b602060405180830381865afa1580156123b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123d89190613071565b600254612a0c565b90505f817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a082317f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040161245d9190612fcc565b602060405180830381865afa158015612478573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061249c9190613071565b6124a691906131d8565b90506005548111156128b2575f807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630fdb11cf6040518163ffffffff1660e01b815260040160408051808303815f875af115801561251d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061254191906136a9565b915091505f6004549050818061260757505f6002811115612565576125646136e7565b5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166320531bc96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125f29190613737565b6002811115612604576126036136e7565b5b14155b1561261c5760c88161261991906134a0565b90505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630f73b4f4670de0b6b3a76400008084670de0b6b3a7640000888a61267891906134a0565b612682919061350e565b61268c91906134a0565b612696919061350e565b6126a0919061350e565b6040518263ffffffff1660e01b81526004016126bc9190612cf0565b5f604051808303815f87803b1580156126d3575f80fd5b505af11580156126e5573d5f803e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166325cea9766127106001548661273691906134a0565b612740919061350e565b6040518263ffffffff1660e01b815260040161275c9190612cf0565b5f604051808303815f87803b158015612773575f80fd5b505af1158015612785573d5f803e3d5ffd5b505050506127f47f0000000000000000000000000000000000000000000000000000000000000000867f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166116d69092919063ffffffff16565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166396c551757f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040161286d9190612fcc565b6020604051808303815f875af1158015612889573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128ad9190613071565b505050505b505050565b61271081106128fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128f2906137ac565b60405180910390fd5b805f60036101000a81548161ffff021916908361ffff16021790555050565b6129437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6117cc565b50565b5f6129a7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612a249092919063ffffffff16565b90505f815114806129c85750808060200190518101906129c79190613475565b5b612a07576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129fe9061383a565b60405180910390fd5b505050565b5f818310612a1a5781612a1c565b825b905092915050565b6060612a3284845f85612a3b565b90509392505050565b606082471015612a80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a77906138c8565b60405180910390fd5b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051612aa89190613920565b5f6040518083038185875af1925050503d805f8114612ae2576040519150601f19603f3d011682016040523d82523d5f602084013e612ae7565b606091505b5091509150612af887838387612b04565b92505050949350505050565b60608315612b65575f835103612b5d57612b1d85612b78565b612b5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b5390613980565b60405180910390fd5b5b829050612b70565b612b6f8383612b9a565b5b949350505050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f82511115612bac5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612be091906139e0565b60405180910390fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612c1682612bed565b9050919050565b5f612c2782612c0c565b9050919050565b612c3781612c1d565b8114612c41575f80fd5b50565b5f81359050612c5281612c2e565b92915050565b5f60208284031215612c6d57612c6c612be9565b5b5f612c7a84828501612c44565b91505092915050565b612c8c81612c0c565b8114612c96575f80fd5b50565b5f81359050612ca781612c83565b92915050565b5f60208284031215612cc257612cc1612be9565b5b5f612ccf84828501612c99565b91505092915050565b5f819050919050565b612cea81612cd8565b82525050565b5f602082019050612d035f830184612ce1565b92915050565b612d1281612cd8565b8114612d1c575f80fd5b50565b5f81359050612d2d81612d09565b92915050565b5f60208284031215612d4857612d47612be9565b5b5f612d5584828501612d1f565b91505092915050565b5f819050919050565b5f612d81612d7c612d7784612bed565b612d5e565b612bed565b9050919050565b5f612d9282612d67565b9050919050565b5f612da382612d88565b9050919050565b612db381612d99565b82525050565b5f602082019050612dcc5f830184612daa565b92915050565b5f8115159050919050565b612de681612dd2565b82525050565b5f602082019050612dff5f830184612ddd565b92915050565b5f612e0f82612d88565b9050919050565b612e1f81612e05565b82525050565b5f602082019050612e385f830184612e16565b92915050565b5f612e4882612d88565b9050919050565b612e5881612e3e565b82525050565b5f602082019050612e715f830184612e4f565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015612eae578082015181840152602081019050612e93565b5f8484015250505050565b5f601f19601f8301169050919050565b5f612ed382612e77565b612edd8185612e81565b9350612eed818560208601612e91565b612ef681612eb9565b840191505092915050565b5f604082019050612f145f830185612ddd565b8181036020830152612f268184612ec9565b90509392505050565b5f612f3982612d88565b9050919050565b612f4981612f2f565b82525050565b5f602082019050612f625f830184612f40565b92915050565b612f7181612dd2565b8114612f7b575f80fd5b50565b5f81359050612f8c81612f68565b92915050565b5f60208284031215612fa757612fa6612be9565b5b5f612fb484828501612f7e565b91505092915050565b612fc681612c0c565b82525050565b5f602082019050612fdf5f830184612fbd565b92915050565b5f82825260208201905092915050565b7f21746f6b656e00000000000000000000000000000000000000000000000000005f82015250565b5f613029600683612fe5565b915061303482612ff5565b602082019050919050565b5f6020820190508181035f8301526130568161301d565b9050919050565b5f8151905061306b81612d09565b92915050565b5f6020828403121561308657613085612be9565b5b5f6130938482850161305d565b91505092915050565b7f2162616c616e63650000000000000000000000000000000000000000000000005f82015250565b5f6130d0600883612fe5565b91506130db8261309c565b602082019050919050565b5f6020820190508181035f8301526130fd816130c4565b9050919050565b5f8151905061311281612c83565b92915050565b5f6020828403121561312d5761312c612be9565b5b5f61313a84828501613104565b91505092915050565b7f216d617841756374696f6e416d6f756e740000000000000000000000000000005f82015250565b5f613177601183612fe5565b915061318282613143565b602082019050919050565b5f6020820190508181035f8301526131a48161316b565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6131e282612cd8565b91506131ed83612cd8565b9250828201905080821115613205576132046131ab565b5b92915050565b7f216d696e427566666572000000000000000000000000000000000000000000005f82015250565b5f61323f600a83612fe5565b915061324a8261320b565b602082019050919050565b5f6020820190508181035f83015261326c81613233565b9050919050565b7f216d696e41756374696f6e5072696365427073000000000000000000000000005f82015250565b5f6132a7601383612fe5565b91506132b282613273565b602082019050919050565b5f6020820190508181035f8301526132d48161329b565b9050919050565b7f216d696e4d6178476173507269636500000000000000000000000000000000005f82015250565b5f61330f600f83612fe5565b915061331a826132db565b602082019050919050565b5f6020820190508181035f83015261333c81613303565b9050919050565b7f216d696e447573740000000000000000000000000000000000000000000000005f82015250565b5f613377600883612fe5565b915061338282613343565b602082019050919050565b5f6020820190508181035f8301526133a48161336b565b9050919050565b5f6040820190506133be5f830185612fbd565b6133cb6020830184612ce1565b9392505050565b7f2173656c660000000000000000000000000000000000000000000000000000005f82015250565b5f613406600583612fe5565b9150613411826133d2565b602082019050919050565b5f6020820190508181035f830152613433816133fa565b9050919050565b5f60408201905061344d5f830185612ce1565b61345a6020830184612ddd565b9392505050565b5f8151905061346f81612f68565b92915050565b5f6020828403121561348a57613489612be9565b5b5f61349784828501613461565b91505092915050565b5f6134aa82612cd8565b91506134b583612cd8565b92508282026134c381612cd8565b915082820484148315176134da576134d96131ab565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61351882612cd8565b915061352383612cd8565b925082613533576135326134e1565b5b828204905092915050565b5f61354882612cd8565b915061355383612cd8565b925082820390508181111561356b5761356a6131ab565b5b92915050565b7f6865616c7468436865636b0000000000000000000000000000000000000000005f82015250565b5f6135a5600b83612fe5565b91506135b082613571565b602082019050919050565b5f6020820190508181035f8301526135d281613599565b9050919050565b7f217a65726f2070726f66697400000000000000000000000000000000000000005f82015250565b5f61360d600c83612fe5565b9150613618826135d9565b602082019050919050565b5f6020820190508181035f83015261363a81613601565b9050919050565b7f21746f6f206869676800000000000000000000000000000000000000000000005f82015250565b5f613675600983612fe5565b915061368082613641565b602082019050919050565b5f6020820190508181035f8301526136a281613669565b9050919050565b5f80604083850312156136bf576136be612be9565b5b5f6136cc8582860161305d565b92505060206136dd85828601613461565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110613720575f80fd5b50565b5f8151905061373181613714565b92915050565b5f6020828403121561374c5761374b612be9565b5b5f61375984828501613723565b91505092915050565b7f216c6f7373206c696d69740000000000000000000000000000000000000000005f82015250565b5f613796600b83612fe5565b91506137a182613762565b602082019050919050565b5f6020820190508181035f8301526137c38161378a565b9050919050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f613824602a83612fe5565b915061382f826137ca565b604082019050919050565b5f6020820190508181035f83015261385181613818565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f6138b2602683612fe5565b91506138bd82613858565b604082019050919050565b5f6020820190508181035f8301526138df816138a6565b9050919050565b5f81905092915050565b5f6138fa82612e77565b61390481856138e6565b9350613914818560208601612e91565b80840191505092915050565b5f61392b82846138f0565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f61396a601d83612fe5565b915061397582613936565b602082019050919050565b5f6020820190508181035f8301526139978161395e565b9050919050565b5f81519050919050565b5f6139b28261399e565b6139bc8185612fe5565b93506139cc818560208601612e91565b6139d581612eb9565b840191505092915050565b5f6020820190508181035f8301526139f881846139a8565b90509291505056fea26469706673582212209b7946aff52db623e50113ae23778950974980fd18efb5abe970a5394dc43ea764736f6c634300081700330000000000000000000000002c5a85a3fd181857d02baff169d1e1cb220ead6d0000000000000000000000009cf12ccd6020b6888e4d4c4e4c7aca33c1eb91f8000000000000000000000000ba7fcb508c7195ee5ae823f37ee2c11d7ed52f8e0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001b5553446166205742544331382053746162696c69747920506f6f6c0000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610260575f3560e01c80636718835f11610144578063bbf88267116100c1578063d696860111610085578063d6968601146106c7578063e8462e8f146106e3578063ea2b192314610701578063efbb5cb01461071f578063f50c952f1461073d578063fde813a81461075b57610261565b8063bbf8826714610621578063c0e79a111461063f578063c3f81cc51461065b578063d19a3bb814610679578063d63a8e111461069757610261565b80639d7fb70c116101085780639d7fb70c14610591578063ac00ff26146105ad578063ad7e55ba146105c9578063b1e03ca0146105e5578063b6a165061461060357610261565b80636718835f146104ff5780637d9699321461051d57806393fd25ec1461053b578063950b3d73146105595780639b90fb161461057557610261565b80634426ebd0116101dd578063503160d9116101a1578063503160d91461044e5780635262e5de1461046a57806353fc1db4146104885780635c911892146104a65780635d265d3f146104c257806363779c74146104e157610261565b80634426ebd0146103ba57806346aa2f12146103d857806349317f1d146104085780634a5d0943146104265780634e71d92d1461044457610261565b80632b371ecf116102245780632b371ecf146103285780632b45732a14610344578063332c557a1461036257806333d1a1c4146103805780633d6cb5751461039e57610261565b806301681a621461029857806304bd4629146102b4578063157c7ff6146102e4578063184aea26146102ee5780632851b6691461030a57610261565b5b5f73d377919fa87120584b21279a491f82d5265a139c9050365f80375f80365f845af43d5f803e805f8114610294573d5ff35b3d5ffd5b6102b260048036038101906102ad9190612c58565b610777565b005b6102ce60048036038101906102c99190612cad565b610a5b565b6040516102db9190612cf0565b60405180910390f35b6102ec610a6b565b005b61030860048036038101906103039190612d33565b610b0c565b005b610312610bdd565b60405161031f9190612db9565b60405180910390f35b610342600480360381019061033d9190612d33565b610c01565b005b61034c610cee565b6040516103599190612cf0565b60405180910390f35b61036a610cf9565b6040516103779190612dec565b60405180910390f35b610388610d9b565b6040516103959190612cf0565b60405180910390f35b6103b860048036038101906103b39190612d33565b610da4565b005b6103c2610db8565b6040516103cf9190612e25565b60405180910390f35b6103f260048036038101906103ed9190612cad565b610ddc565b6040516103ff9190612cf0565b60405180910390f35b610410610e70565b60405161041d9190612cf0565b60405180910390f35b61042e610e8f565b60405161043b9190612cf0565b60405180910390f35b61044c610ea9565b005b61046860048036038101906104639190612d33565b610eb4565b005b610472610ec8565b60405161047f9190612e5e565b60405180910390f35b610490610eec565b60405161049d9190612cf0565b60405180910390f35b6104c060048036038101906104bb9190612d33565b610f0b565b005b6104ca610fde565b6040516104d8929190612f01565b60405180910390f35b6104e961105c565b6040516104f69190612f4f565b60405180910390f35b610507611080565b6040516105149190612dec565b60405180910390f35b610525611090565b6040516105329190612cf0565b60405180910390f35b6105436110aa565b6040516105509190612cf0565b60405180910390f35b610573600480360381019061056e9190612d33565b6110b0565b005b61058f600480360381019061058a9190612d33565b611141565b005b6105ab60048036038101906105a69190612d33565b611218565b005b6105c760048036038101906105c29190612f92565b61122c565b005b6105e360048036038101906105de9190612d33565b6112cc565b005b6105ed6113a5565b6040516105fa9190612cf0565b60405180910390f35b61060b6113b0565b6040516106189190612cf0565b60405180910390f35b6106296113b6565b6040516106369190612cf0565b60405180910390f35b61065960048036038101906106549190612cad565b6113bc565b005b610663611499565b6040516106709190612dec565b60405180910390f35b6106816114ab565b60405161068e9190612fcc565b60405180910390f35b6106b160048036038101906106ac9190612cad565b6114c3565b6040516106be9190612dec565b60405180910390f35b6106e160048036038101906106dc9190612d33565b6114e0565b005b6106eb611571565b6040516106f89190612cf0565b60405180910390f35b610709611577565b6040516107169190612cf0565b60405180910390f35b61072761157c565b6040516107349190612cf0565b60405180910390f35b6107456116bc565b6040516107529190612cf0565b60405180910390f35b61077560048036038101906107709190612d33565b6116c2565b005b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016107d09190612fcc565b5f6040518083038186803b1580156107e6575f80fd5b505afa1580156107f8573d5f803e3d5ffd5b505050507f0000000000000000000000009cf12ccd6020b6888e4d4c4e4c7aca33c1eb91f873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156108a457507f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b6108e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108da9061303f565b60405180910390fd5b5f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161091d9190612fcc565b602060405180830381865afa158015610938573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061095c9190613071565b90505f81116109a0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610997906130e6565b60405180910390fd5b610a577f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a309190613118565b828473ffffffffffffffffffffffffffffffffffffffff166116d69092919063ffffffff16565b5050565b5f610a6461157c565b9050919050565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610ac49190612fcc565b5f6040518083038186803b158015610ada575f80fd5b505afa158015610aec573d5f803e3d5ffd5b5050505060015f60056101000a81548160ff021916908315150217905550565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610b659190612fcc565b5f6040518083038186803b158015610b7b575f80fd5b505afa158015610b8d573d5f803e3d5ffd5b505050505f8111610bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bca9061318d565b60405180910390fd5b8060028190555050565b7f0000000000000000000000004b74d043336678d2f62dae6595bc42dccabc3bb181565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610c5a9190612fcc565b5f6040518083038186803b158015610c70575f80fd5b505afa158015610c82573d5f803e3d5ffd5b50505050670214e8348c4f0000670de0b6b3a7640000610ca291906131d8565b811015610ce4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cdb90613255565b60405180910390fd5b8060048190555050565b66038d7ea4c6800081565b5f6005547f000000000000000000000000922faa141e95e43a9deeab8dade3ac8d4a32ad5c73ffffffffffffffffffffffffffffffffffffffff166347ea8354306040518263ffffffff1660e01b8152600401610d569190612fcc565b602060405180830381865afa158015610d71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d959190613071565b11905090565b640ba43b740081565b610dac61175c565b610db5816117cc565b50565b7f000000000000000000000000922faa141e95e43a9deeab8dade3ac8d4a32ad5c81565b5f8060059054906101000a900460ff1680610e3d575060065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff165b610e47575f610e69565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b9050919050565b5f610e7961175c565b610e81611858565b9050610e8c81611a61565b90565b5f8060019054906101000a900461ffff1661ffff16905090565b610eb25f6117cc565b565b610ebc61175c565b610ec581611c2e565b50565b7f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4781565b670214e8348c4f0000670de0b6b3a7640000610f0891906131d8565b81565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b8152600401610f649190612fcc565b5f6040518083038186803b158015610f7a575f80fd5b505afa158015610f8c573d5f803e3d5ffd5b505050506127108110610fd4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fcb906132bd565b60405180910390fd5b8060018190555050565b5f6060610fe9611cb9565b63440368a360e01b604051602401604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050915091509091565b7f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb81565b5f8054906101000a900460ff1681565b5f8060039054906101000a900461ffff1661ffff16905090565b60045481565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016111099190612fcc565b5f6040518083038186803b15801561111f575f80fd5b505afa158015611131573d5f803e3d5ffd5b5050505061113e81611fb4565b50565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b815260040161119a9190612fcc565b5f6040518083038186803b1580156111b0575f80fd5b505afa1580156111c2573d5f803e3d5ffd5b50505050640ba43b740081101561120e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120590613325565b60405180910390fd5b8060038190555050565b61122061175c565b6112298161205c565b50565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016112859190612fcc565b5f6040518083038186803b15801561129b575f80fd5b505afa1580156112ad573d5f803e3d5ffd5b50505050805f806101000a81548160ff02191690831515021790555050565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016113259190612fcc565b5f6040518083038186803b15801561133b575f80fd5b505afa15801561134d573d5f803e3d5ffd5b5050505066038d7ea4c6800081101561139b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113929061338d565b60405180910390fd5b8060058190555050565b66038d7ea4c6800081565b60035481565b60025481565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016114159190612fcc565b5f6040518083038186803b15801561142b575f80fd5b505afa15801561143d573d5f803e3d5ffd5b50505050600160065f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555050565b5f60059054906101000a900460ff1681565b73d377919fa87120584b21279a491f82d5265a139c81565b6006602052805f5260405f205f915054906101000a900460ff1681565b7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166348e4a649336040518263ffffffff1660e01b81526004016115399190612fcc565b5f6040518083038186803b15801561154f575f80fd5b505afa158015611561573d5f803e3d5ffd5b5050505061156e816128b7565b50565b60055481565b60c881565b5f7f000000000000000000000000922faa141e95e43a9deeab8dade3ac8d4a32ad5c73ffffffffffffffffffffffffffffffffffffffff1663065f566d306040518263ffffffff1660e01b81526004016115d69190612fcc565b602060405180830381865afa1580156115f1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116159190613071565b7f0000000000000000000000009cf12ccd6020b6888e4d4c4e4c7aca33c1eb91f873ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161166e9190612fcc565b602060405180830381865afa158015611689573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116ad9190613071565b6116b791906131d8565b905090565b60015481565b6116ca61175c565b6116d38161291a565b50565b6117578363a9059cbb60e01b84846040516024016116f59291906133ab565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612946565b505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146117ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117c19061341c565b60405180910390fd5b565b7f000000000000000000000000922faa141e95e43a9deeab8dade3ac8d4a32ad5c73ffffffffffffffffffffffffffffffffffffffff1663cfddf5f58260016040518363ffffffff1660e01b815260040161182892919061343a565b5f604051808303815f87803b15801561183f575f80fd5b505af1158015611851573d5f803e3d5ffd5b5050505050565b5f7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff1663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118e69190613475565b611a54575f7f000000000000000000000000922faa141e95e43a9deeab8dade3ac8d4a32ad5c73ffffffffffffffffffffffffffffffffffffffff1663daed0a9b306040518263ffffffff1660e01b81526004016119449190612fcc565b602060405180830381865afa15801561195f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119839190613071565b905066038d7ea4c6800081111561199d5761199c610ea9565b5b5f7f0000000000000000000000009cf12ccd6020b6888e4d4c4e4c7aca33c1eb91f873ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016119f79190612fcc565b602060405180830381865afa158015611a12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a369190613071565b905066038d7ea4c68000811115611a5157611a5081611c2e565b5b50505b611a5c61157c565b905090565b5f8054906101000a900460ff16611a905760015f806101000a81548160ff021916908315150217905550611c2b565b5f7f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611afa573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b1e9190613071565b905080821115611ba6576127105f60019054906101000a900461ffff1661ffff1682611b4a91906134a0565b611b54919061350e565b8183611b60919061353e565b1115611ba1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b98906135bb565b60405180910390fd5b611c29565b81811115611c28576127105f60039054906101000a900461ffff1661ffff1682611bd091906134a0565b611bda919061350e565b8282611be6919061353e565b1115611c27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c1e906135bb565b60405180910390fd5b5b5b505b50565b7f000000000000000000000000922faa141e95e43a9deeab8dade3ac8d4a32ad5c73ffffffffffffffffffffffffffffffffffffffff1663aeb4b970825f6040518363ffffffff1660e01b8152600401611c8992919061343a565b5f604051808303815f87803b158015611ca0575f80fd5b505af1158015611cb2573d5f803e3d5ffd5b5050505050565b5f807f0000000000000000000000001fb3f503d51480c25c1f2d64b6f4018d4c2805f773ffffffffffffffffffffffffffffffffffffffff166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d489190613071565b03611d55575f9050611fb1565b6005547f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff166310098ad57f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c476040518263ffffffff1660e01b8152600401611dd19190612fcc565b602060405180830381865afa158015611dec573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e109190613071565b1115611e1e575f9050611fb1565b5f611ec27f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4773ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611e7b9190612fcc565b602060405180830381865afa158015611e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eba9190613071565b600254612a0c565b90505f817f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4773ffffffffffffffffffffffffffffffffffffffff166370a082317f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb6040518263ffffffff1660e01b8152600401611f3f9190612fcc565b602060405180830381865afa158015611f5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7e9190613071565b611f8891906131d8565b90506003544811158015611fac5750611f9f610cf9565b80611fab575060055481115b5b925050505b90565b5f8111611ff6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fed90613623565b60405180910390fd5b61ffff801681111561203d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120349061368b565b60405180910390fd5b805f60016101000a81548161ffff021916908361ffff16021790555050565b612064610cf9565b1561207257612071610ea9565b5b7f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff16639f8a13d77f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c476040518263ffffffff1660e01b81526004016120eb9190612fcc565b602060405180830381865afa158015612106573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061212a9190613475565b1561233c575f7f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff166310098ad57f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c476040518263ffffffff1660e01b81526004016121a99190612fcc565b602060405180830381865afa1580156121c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121e89190613071565b1115612295577f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff166301681a627f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c476040518263ffffffff1660e01b81526004016122679190612fcc565b5f604051808303815f87803b15801561227e575f80fd5b505af1158015612290573d5f803e3d5ffd5b505050505b7f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff16636a256b297f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c476040518263ffffffff1660e01b815260040161230e9190612fcc565b5f604051808303815f87803b158015612325575f80fd5b505af1158015612337573d5f803e3d5ffd5b505050505b5f6123e07f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4773ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123999190612fcc565b602060405180830381865afa1580156123b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123d89190613071565b600254612a0c565b90505f817f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4773ffffffffffffffffffffffffffffffffffffffff166370a082317f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb6040518263ffffffff1660e01b815260040161245d9190612fcc565b602060405180830381865afa158015612478573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061249c9190613071565b6124a691906131d8565b90506005548111156128b2575f807f0000000000000000000000004b74d043336678d2f62dae6595bc42dccabc3bb173ffffffffffffffffffffffffffffffffffffffff16630fdb11cf6040518163ffffffff1660e01b815260040160408051808303815f875af115801561251d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061254191906136a9565b915091505f6004549050818061260757505f6002811115612565576125646136e7565b5b7f0000000000000000000000004b74d043336678d2f62dae6595bc42dccabc3bb173ffffffffffffffffffffffffffffffffffffffff166320531bc96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125f29190613737565b6002811115612604576126036136e7565b5b14155b1561261c5760c88161261991906134a0565b90505b7f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff16630f73b4f4670de0b6b3a76400008084670de0b6b3a7640000888a61267891906134a0565b612682919061350e565b61268c91906134a0565b612696919061350e565b6126a0919061350e565b6040518263ffffffff1660e01b81526004016126bc9190612cf0565b5f604051808303815f87803b1580156126d3575f80fd5b505af11580156126e5573d5f803e3d5ffd5b505050507f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff166325cea9766127106001548661273691906134a0565b612740919061350e565b6040518263ffffffff1660e01b815260040161275c9190612cf0565b5f604051808303815f87803b158015612773575f80fd5b505af1158015612785573d5f803e3d5ffd5b505050506127f47f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb867f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c4773ffffffffffffffffffffffffffffffffffffffff166116d69092919063ffffffff16565b7f0000000000000000000000004a3a48d1d08cc86cb778e6ac9c8fcabbcd8016fb73ffffffffffffffffffffffffffffffffffffffff166396c551757f000000000000000000000000e065bc161b90c9c4bba2de7f1e194b70a3267c476040518263ffffffff1660e01b815260040161286d9190612fcc565b6020604051808303815f875af1158015612889573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128ad9190613071565b505050505b505050565b61271081106128fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128f2906137ac565b60405180910390fd5b805f60036101000a81548161ffff021916908361ffff16021790555050565b6129437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6117cc565b50565b5f6129a7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612a249092919063ffffffff16565b90505f815114806129c85750808060200190518101906129c79190613475565b5b612a07576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129fe9061383a565b60405180910390fd5b505050565b5f818310612a1a5781612a1c565b825b905092915050565b6060612a3284845f85612a3b565b90509392505050565b606082471015612a80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a77906138c8565b60405180910390fd5b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051612aa89190613920565b5f6040518083038185875af1925050503d805f8114612ae2576040519150601f19603f3d011682016040523d82523d5f602084013e612ae7565b606091505b5091509150612af887838387612b04565b92505050949350505050565b60608315612b65575f835103612b5d57612b1d85612b78565b612b5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b5390613980565b60405180910390fd5b5b829050612b70565b612b6f8383612b9a565b5b949350505050565b5f808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f82511115612bac5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612be091906139e0565b60405180910390fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612c1682612bed565b9050919050565b5f612c2782612c0c565b9050919050565b612c3781612c1d565b8114612c41575f80fd5b50565b5f81359050612c5281612c2e565b92915050565b5f60208284031215612c6d57612c6c612be9565b5b5f612c7a84828501612c44565b91505092915050565b612c8c81612c0c565b8114612c96575f80fd5b50565b5f81359050612ca781612c83565b92915050565b5f60208284031215612cc257612cc1612be9565b5b5f612ccf84828501612c99565b91505092915050565b5f819050919050565b612cea81612cd8565b82525050565b5f602082019050612d035f830184612ce1565b92915050565b612d1281612cd8565b8114612d1c575f80fd5b50565b5f81359050612d2d81612d09565b92915050565b5f60208284031215612d4857612d47612be9565b5b5f612d5584828501612d1f565b91505092915050565b5f819050919050565b5f612d81612d7c612d7784612bed565b612d5e565b612bed565b9050919050565b5f612d9282612d67565b9050919050565b5f612da382612d88565b9050919050565b612db381612d99565b82525050565b5f602082019050612dcc5f830184612daa565b92915050565b5f8115159050919050565b612de681612dd2565b82525050565b5f602082019050612dff5f830184612ddd565b92915050565b5f612e0f82612d88565b9050919050565b612e1f81612e05565b82525050565b5f602082019050612e385f830184612e16565b92915050565b5f612e4882612d88565b9050919050565b612e5881612e3e565b82525050565b5f602082019050612e715f830184612e4f565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015612eae578082015181840152602081019050612e93565b5f8484015250505050565b5f601f19601f8301169050919050565b5f612ed382612e77565b612edd8185612e81565b9350612eed818560208601612e91565b612ef681612eb9565b840191505092915050565b5f604082019050612f145f830185612ddd565b8181036020830152612f268184612ec9565b90509392505050565b5f612f3982612d88565b9050919050565b612f4981612f2f565b82525050565b5f602082019050612f625f830184612f40565b92915050565b612f7181612dd2565b8114612f7b575f80fd5b50565b5f81359050612f8c81612f68565b92915050565b5f60208284031215612fa757612fa6612be9565b5b5f612fb484828501612f7e565b91505092915050565b612fc681612c0c565b82525050565b5f602082019050612fdf5f830184612fbd565b92915050565b5f82825260208201905092915050565b7f21746f6b656e00000000000000000000000000000000000000000000000000005f82015250565b5f613029600683612fe5565b915061303482612ff5565b602082019050919050565b5f6020820190508181035f8301526130568161301d565b9050919050565b5f8151905061306b81612d09565b92915050565b5f6020828403121561308657613085612be9565b5b5f6130938482850161305d565b91505092915050565b7f2162616c616e63650000000000000000000000000000000000000000000000005f82015250565b5f6130d0600883612fe5565b91506130db8261309c565b602082019050919050565b5f6020820190508181035f8301526130fd816130c4565b9050919050565b5f8151905061311281612c83565b92915050565b5f6020828403121561312d5761312c612be9565b5b5f61313a84828501613104565b91505092915050565b7f216d617841756374696f6e416d6f756e740000000000000000000000000000005f82015250565b5f613177601183612fe5565b915061318282613143565b602082019050919050565b5f6020820190508181035f8301526131a48161316b565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6131e282612cd8565b91506131ed83612cd8565b9250828201905080821115613205576132046131ab565b5b92915050565b7f216d696e427566666572000000000000000000000000000000000000000000005f82015250565b5f61323f600a83612fe5565b915061324a8261320b565b602082019050919050565b5f6020820190508181035f83015261326c81613233565b9050919050565b7f216d696e41756374696f6e5072696365427073000000000000000000000000005f82015250565b5f6132a7601383612fe5565b91506132b282613273565b602082019050919050565b5f6020820190508181035f8301526132d48161329b565b9050919050565b7f216d696e4d6178476173507269636500000000000000000000000000000000005f82015250565b5f61330f600f83612fe5565b915061331a826132db565b602082019050919050565b5f6020820190508181035f83015261333c81613303565b9050919050565b7f216d696e447573740000000000000000000000000000000000000000000000005f82015250565b5f613377600883612fe5565b915061338282613343565b602082019050919050565b5f6020820190508181035f8301526133a48161336b565b9050919050565b5f6040820190506133be5f830185612fbd565b6133cb6020830184612ce1565b9392505050565b7f2173656c660000000000000000000000000000000000000000000000000000005f82015250565b5f613406600583612fe5565b9150613411826133d2565b602082019050919050565b5f6020820190508181035f830152613433816133fa565b9050919050565b5f60408201905061344d5f830185612ce1565b61345a6020830184612ddd565b9392505050565b5f8151905061346f81612f68565b92915050565b5f6020828403121561348a57613489612be9565b5b5f61349784828501613461565b91505092915050565b5f6134aa82612cd8565b91506134b583612cd8565b92508282026134c381612cd8565b915082820484148315176134da576134d96131ab565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61351882612cd8565b915061352383612cd8565b925082613533576135326134e1565b5b828204905092915050565b5f61354882612cd8565b915061355383612cd8565b925082820390508181111561356b5761356a6131ab565b5b92915050565b7f6865616c7468436865636b0000000000000000000000000000000000000000005f82015250565b5f6135a5600b83612fe5565b91506135b082613571565b602082019050919050565b5f6020820190508181035f8301526135d281613599565b9050919050565b7f217a65726f2070726f66697400000000000000000000000000000000000000005f82015250565b5f61360d600c83612fe5565b9150613618826135d9565b602082019050919050565b5f6020820190508181035f83015261363a81613601565b9050919050565b7f21746f6f206869676800000000000000000000000000000000000000000000005f82015250565b5f613675600983612fe5565b915061368082613641565b602082019050919050565b5f6020820190508181035f8301526136a281613669565b9050919050565b5f80604083850312156136bf576136be612be9565b5b5f6136cc8582860161305d565b92505060206136dd85828601613461565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110613720575f80fd5b50565b5f8151905061373181613714565b92915050565b5f6020828403121561374c5761374b612be9565b5b5f61375984828501613723565b91505092915050565b7f216c6f7373206c696d69740000000000000000000000000000000000000000005f82015250565b5f613796600b83612fe5565b91506137a182613762565b602082019050919050565b5f6020820190508181035f8301526137c38161378a565b9050919050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f613824602a83612fe5565b915061382f826137ca565b604082019050919050565b5f6020820190508181035f83015261385181613818565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f6138b2602683612fe5565b91506138bd82613858565b604082019050919050565b5f6020820190508181035f8301526138df816138a6565b9050919050565b5f81905092915050565b5f6138fa82612e77565b61390481856138e6565b9350613914818560208601612e91565b80840191505092915050565b5f61392b82846138f0565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f61396a601d83612fe5565b915061397582613936565b602082019050919050565b5f6020820190508181035f8301526139978161395e565b9050919050565b5f81519050919050565b5f6139b28261399e565b6139bc8185612fe5565b93506139cc818560208601612e91565b6139d581612eb9565b840191505092915050565b5f6020820190508181035f8301526139f881846139a8565b90509291505056fea26469706673582212209b7946aff52db623e50113ae23778950974980fd18efb5abe970a5394dc43ea764736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002c5a85a3fd181857d02baff169d1e1cb220ead6d0000000000000000000000009cf12ccd6020b6888e4d4c4e4c7aca33c1eb91f8000000000000000000000000ba7fcb508c7195ee5ae823f37ee2c11d7ed52f8e0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001b5553446166205742544331382053746162696c69747920506f6f6c0000000000
-----Decoded View---------------
Arg [0] : _addressesRegistry (address): 0x2C5A85a3fd181857D02baff169D1e1cB220ead6d
Arg [1] : _asset (address): 0x9Cf12ccd6020b6888e4D4C4e4c7AcA33c1eB91f8
Arg [2] : _auctionFactory (address): 0xbA7FCb508c7195eE5AE823F37eE2c11D7ED52F8e
Arg [3] : _name (string): USDaf WBTC18 Stability Pool
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000002c5a85a3fd181857d02baff169d1e1cb220ead6d
Arg [1] : 0000000000000000000000009cf12ccd6020b6888e4d4c4e4c7aca33c1eb91f8
Arg [2] : 000000000000000000000000ba7fcb508c7195ee5ae823f37ee2c11d7ed52f8e
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [4] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [5] : 5553446166205742544331382053746162696c69747920506f6f6c0000000000
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.