Source Code
Latest 25 from a total of 57,042 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Update | 277962984 | 376 days ago | IN | 0 ETH | 0.00000246 | ||||
| Update | 277961603 | 376 days ago | IN | 0 ETH | 0.00000238 | ||||
| Update | 277961429 | 376 days ago | IN | 0 ETH | 0.00000246 | ||||
| Update | 277961312 | 376 days ago | IN | 0 ETH | 0.00000239 | ||||
| Update | 277960809 | 376 days ago | IN | 0 ETH | 0.00000238 | ||||
| Update | 277960357 | 376 days ago | IN | 0 ETH | 0.00000234 | ||||
| Update | 277959526 | 376 days ago | IN | 0 ETH | 0.00000233 | ||||
| Update | 277959345 | 376 days ago | IN | 0 ETH | 0.00000234 | ||||
| Update | 277958813 | 376 days ago | IN | 0 ETH | 0.00000233 | ||||
| Update | 277958500 | 376 days ago | IN | 0 ETH | 0.00000224 | ||||
| Update | 277954917 | 376 days ago | IN | 0 ETH | 0.00000254 | ||||
| Update | 277954692 | 376 days ago | IN | 0 ETH | 0.00000233 | ||||
| Update | 277953919 | 376 days ago | IN | 0 ETH | 0.00000238 | ||||
| Update | 277950323 | 376 days ago | IN | 0 ETH | 0.00000227 | ||||
| Update | 277949186 | 376 days ago | IN | 0 ETH | 0.00000221 | ||||
| Update | 277947688 | 376 days ago | IN | 0 ETH | 0.00000234 | ||||
| Update | 277943444 | 376 days ago | IN | 0 ETH | 0.0000025 | ||||
| Update | 277942713 | 376 days ago | IN | 0 ETH | 0.00000249 | ||||
| Update | 277942552 | 376 days ago | IN | 0 ETH | 0.00000249 | ||||
| Update | 277940316 | 376 days ago | IN | 0 ETH | 0.00000235 | ||||
| Update | 277939872 | 376 days ago | IN | 0 ETH | 0.00000235 | ||||
| Update | 277938475 | 376 days ago | IN | 0 ETH | 0.0000024 | ||||
| Update | 277937631 | 376 days ago | IN | 0 ETH | 0.00000238 | ||||
| Update | 277932718 | 376 days ago | IN | 0 ETH | 0.00000262 | ||||
| Update | 277931585 | 376 days ago | IN | 0 ETH | 0.00000262 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
AdrastiaCurrentAggregatorOracle
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@adrastia-oracle/adrastia-periphery/contracts/oracles/ManagedCurrentAggregatorOracle.sol";
import "../AdrastiaVersioning.sol";
contract AdrastiaCurrentAggregatorOracle is AdrastiaVersioning, ManagedCurrentAggregatorOracle {
string public name;
constructor(
string memory name_,
AbstractAggregatorOracleParams memory params,
uint256 updateThreshold_,
uint256 updateDelay_,
uint256 heartbeat_
) ManagedCurrentAggregatorOracle(params, updateThreshold_, updateDelay_, heartbeat_) {
name = name_;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
pragma experimental ABIEncoderV2;
import "@openzeppelin-v4/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin-v4/contracts/utils/math/SafeCast.sol";
import "../interfaces/IAccumulator.sol";
abstract contract AbstractAccumulator is IERC165, IAccumulator {
uint256 public immutable override changePrecision = 10 ** 8;
uint256 internal immutable theUpdateThreshold;
constructor(uint256 updateThreshold_) {
theUpdateThreshold = updateThreshold_;
}
function updateThreshold() external view virtual override returns (uint256) {
return _updateThreshold();
}
/// @inheritdoc IAccumulator
function updateThresholdSurpassed(bytes memory data) public view virtual override returns (bool) {
return changeThresholdSurpassed(data, _updateThreshold());
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
if (interfaceId == 0xffffffff) {
return false;
}
return interfaceId == type(IAccumulator).interfaceId || interfaceId == type(IERC165).interfaceId;
}
function _updateThreshold() internal view virtual returns (uint256) {
return theUpdateThreshold;
}
function calculateChange(uint256 a, uint256 b) internal view virtual returns (uint256 change, bool isInfinite) {
// Ensure a is never smaller than b
if (a < b) {
uint256 temp = a;
a = b;
b = temp;
}
// a >= b
if (a == 0) {
// a == b == 0 (since a >= b), therefore no change
return (0, false);
} else if (b == 0) {
// (a > 0 && b == 0) => change threshold passed
// Zero to non-zero always returns true
return (0, true);
}
unchecked {
uint256 delta = a - b; // a >= b, therefore no underflow
uint256 preciseDelta = delta * changePrecision;
// If the delta is so large that multiplying by CHANGE_PRECISION overflows, we assume that
// the change threshold has been surpassed.
// If our assumption is incorrect, the accumulator will be extra-up-to-date, which won't
// really break anything, but will cost more gas in keeping this accumulator updated.
if (preciseDelta < delta) return (0, true);
change = preciseDelta / b;
isInfinite = false;
}
}
function changeThresholdSurpassed(
uint256 a,
uint256 b,
uint256 changeThreshold
) internal view virtual returns (bool) {
(uint256 change, bool isInfinite) = calculateChange(a, b);
return isInfinite || change >= changeThreshold;
}
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
/**
* @title IAccumulator
* @notice An interface that defines an accumulator - that is, a contract that updates cumulative value(s) when the
* underlying value(s) change by more than the update threshold.
*/
abstract contract IAccumulator {
/// @notice Gets the scalar (as a power of 10) to be used for calculating changes in value.
/// @return The scalar to be used for calculating changes in value.
function changePrecision() external view virtual returns (uint256);
/// @notice Gets the threshold at which an update to the cumulative value(s) should be performed.
/// @return A percentage scaled by the change precision.
function updateThreshold() external view virtual returns (uint256);
/// @notice Gets the minimum delay between updates to the cumulative value(s).
/// @return The minimum delay between updates to the cumulative value(s), in seconds.
function updateDelay() external view virtual returns (uint256);
/// @notice Gets the maximum delay (target) between updates to the cumulative value(s), without requiring a change
/// past the update threshold.
/// @return The maximum delay (target) between updates to the cumulative value(s), in seconds.
function heartbeat() external view virtual returns (uint256);
/// @notice Determines whether the specified change threshold has been surpassed with respect to the specified
/// data.
/// @dev Calculates the change from the stored observation to the current observation.
/// @param data Amy data relating to the update.
/// @param changeThreshold The change threshold as a percentage multiplied by the change precision
/// (`changePrecision`). Ex: a 1% change is respresented as 0.01 * `changePrecision`.
/// @return surpassed True if the update threshold has been surpassed; false otherwise.
function changeThresholdSurpassed(bytes memory data, uint256 changeThreshold) public view virtual returns (bool);
/// @notice Determines whether the update threshold has been surpassed with respect to the specified data.
/// @dev Calculates the change from the stored observation to the current observation.
/// @param data Amy data relating to the update.
/// @return surpassed True if the update threshold has been surpassed; false otherwise.
function updateThresholdSurpassed(bytes memory data) public view virtual returns (bool);
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
import "../libraries/ObservationLibrary.sol";
/**
* @title IHistoricalOracle
* @notice An interface that defines an oracle contract that stores historical observations.
*/
interface IHistoricalOracle {
/// @notice Gets an observation for a token at a specific index.
/// @param token The address of the token to get the observation for.
/// @param index The index of the observation to get, where index 0 contains the latest observation, and the last
/// index contains the oldest observation (uses reverse chronological ordering).
/// @return observation The observation for the token at the specified index.
function getObservationAt(
address token,
uint256 index
) external view returns (ObservationLibrary.Observation memory);
/// @notice Gets the latest observations for a token.
/// @param token The address of the token to get the observations for.
/// @param amount The number of observations to get.
/// @return observations The latest observations for the token, in reverse chronological order, from newest to oldest.
function getObservations(
address token,
uint256 amount
) external view returns (ObservationLibrary.Observation[] memory);
/// @notice Gets the latest observations for a token.
/// @param token The address of the token to get the observations for.
/// @param amount The number of observations to get.
/// @param offset The index of the first observation to get (default: 0).
/// @param increment The increment between observations to get (default: 1).
/// @return observations The latest observations for the token, in reverse chronological order, from newest to oldest.
function getObservations(
address token,
uint256 amount,
uint256 offset,
uint256 increment
) external view returns (ObservationLibrary.Observation[] memory);
/// @notice Gets the number of observations for a token.
/// @param token The address of the token to get the number of observations for.
/// @return count The number of observations for the token.
function getObservationsCount(address token) external view returns (uint256);
/// @notice Gets the capacity of observations for a token.
/// @param token The address of the token to get the capacity of observations for.
/// @return capacity The capacity of observations for the token.
function getObservationsCapacity(address token) external view returns (uint256);
/// @notice Sets the capacity of observations for a token.
/// @param token The address of the token to set the capacity of observations for.
/// @param amount The new capacity of observations for the token.
function setObservationsCapacity(address token, uint256 amount) external;
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
import "./IUpdateable.sol";
import "./IQuoteToken.sol";
/**
* @title ILiquidityOracle
* @notice An interface that defines a liquidity oracle with a single quote token (or currency) and many exchange
* tokens.
*/
abstract contract ILiquidityOracle is IUpdateable, IQuoteToken {
/// @notice Gets the liquidity levels of the token and the quote token in the underlying pool.
/// @param token The token to get liquidity levels of (along with the quote token).
/// @return tokenLiquidity The amount of the token that is liquid in the underlying pool, in wei.
/// @return quoteTokenLiquidity The amount of the quote token that is liquid in the underlying pool, in wei.
function consultLiquidity(
address token
) public view virtual returns (uint112 tokenLiquidity, uint112 quoteTokenLiquidity);
/**
* @notice Gets the liquidity levels of the token and the quote token in the underlying pool, reverting if the
* quotation is older than the maximum allowable age.
* @dev Using maxAge of 0 can be gas costly and the returned data is easier to manipulate.
* @param token The token to get liquidity levels of (along with the quote token).
* @param maxAge The maximum age of the quotation, in seconds. If 0, the function gets the instant rates as of the
* latest block, straight from the source. WARNING: Using a maxAge of 0 is expensive and is generally insecure.
* @return tokenLiquidity The amount of the token that is liquid in the underlying pool, in wei.
* @return quoteTokenLiquidity The amount of the quote token that is liquid in the underlying pool, in wei.
*/
function consultLiquidity(
address token,
uint256 maxAge
) public view virtual returns (uint112 tokenLiquidity, uint112 quoteTokenLiquidity);
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
import "./IUpdateable.sol";
import "./ILiquidityOracle.sol";
import "./IPriceOracle.sol";
/**
* @title IOracle
* @notice An interface that defines a price and liquidity oracle.
*/
abstract contract IOracle is IUpdateable, IPriceOracle, ILiquidityOracle {
/**
* @notice Gets the price of a token in terms of the quote token along with the liquidity levels of the token
* andquote token in the underlying pool.
* @param token The token to get the price of.
* @return price The quote token denominated price for a whole token.
* @return tokenLiquidity The amount of the token that is liquid in the underlying pool, in wei.
* @return quoteTokenLiquidity The amount of the quote token that is liquid in the underlying pool, in wei.
*/
function consult(
address token
) public view virtual returns (uint112 price, uint112 tokenLiquidity, uint112 quoteTokenLiquidity);
/**
* @notice Gets the price of a token in terms of the quote token along with the liquidity levels of the token and
* quote token in the underlying pool, reverting if the quotation is older than the maximum allowable age.
* @dev Using maxAge of 0 can be gas costly and the returned data is easier to manipulate.
* @param token The token to get the price of.
* @param maxAge The maximum age of the quotation, in seconds. If 0, the function gets the instant rates as of the
* latest block, straight from the source. WARNING: Using a maxAge of 0 is expensive and is generally insecure.
* @return price The quote token denominated price for a whole token.
* @return tokenLiquidity The amount of the token that is liquid in the underlying pool, in wei.
* @return quoteTokenLiquidity The amount of the quote token that is liquid in the underlying pool, in wei.
*/
function consult(
address token,
uint256 maxAge
) public view virtual returns (uint112 price, uint112 tokenLiquidity, uint112 quoteTokenLiquidity);
function liquidityDecimals() public view virtual returns (uint8);
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
import "./IUpdateable.sol";
import "./IQuoteToken.sol";
/// @title IPriceOracle
/// @notice An interface that defines a price oracle with a single quote token (or currency) and many exchange tokens.
abstract contract IPriceOracle is IUpdateable, IQuoteToken {
/**
* @notice Gets the price of a token in terms of the quote token.
* @param token The token to get the price of.
* @return price The quote token denominated price for a whole token.
*/
function consultPrice(address token) public view virtual returns (uint112 price);
/**
* @notice Gets the price of a token in terms of the quote token, reverting if the quotation is older than the
* maximum allowable age.
* @dev Using maxAge of 0 can be gas costly and the returned data is easier to manipulate.
* @param token The token to get the price of.
* @param maxAge The maximum age of the quotation, in seconds. If 0, the function gets the instant rates as of the
* latest block, straight from the source. WARNING: Using a maxAge of 0 is expensive and is generally insecure.
* @return price The quote token denominated price for a whole token.
*/
function consultPrice(address token, uint256 maxAge) public view virtual returns (uint112 price);
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
/**
* @title IQuoteToken
* @notice An interface that defines a contract containing a quote token (or currency), providing the associated
* metadata.
*/
abstract contract IQuoteToken {
/// @notice Gets the quote token (or currency) name.
/// @return The name of the quote token (or currency).
function quoteTokenName() public view virtual returns (string memory);
/// @notice Gets the quote token address (if any).
/// @dev This may return address(0) if no specific quote token is used (such as an aggregate of quote tokens).
/// @return The address of the quote token, or address(0) if no specific quote token is used.
function quoteTokenAddress() public view virtual returns (address);
/// @notice Gets the quote token (or currency) symbol.
/// @return The symbol of the quote token (or currency).
function quoteTokenSymbol() public view virtual returns (string memory);
/// @notice Gets the number of decimal places that quote prices have.
/// @return The number of decimals of the quote token (or currency) that quote prices have.
function quoteTokenDecimals() public view virtual returns (uint8);
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
/// @title IUpdateByToken
/// @notice An interface that defines a contract that is updateable as per the input data.
abstract contract IUpdateable {
/// @notice Performs an update as per the input data.
/// @param data Any data needed for the update.
/// @return b True if anything was updated; false otherwise.
function update(bytes memory data) public virtual returns (bool b);
/// @notice Checks if an update needs to be performed.
/// @param data Any data relating to the update.
/// @return b True if an update needs to be performed; false otherwise.
function needsUpdate(bytes memory data) public view virtual returns (bool b);
/// @notice Check if an update can be performed by the caller (if needed).
/// @dev Tries to determine if the caller can call update with a valid observation being stored.
/// @dev This is not meant to be called by state-modifying functions.
/// @param data Any data relating to the update.
/// @return b True if an update can be performed by the caller; false otherwise.
function canUpdate(bytes memory data) public view virtual returns (bool b);
/// @notice Gets the timestamp of the last update.
/// @param data Any data relating to the update.
/// @return A unix timestamp.
function lastUpdateTime(bytes memory data) public view virtual returns (uint256);
/// @notice Gets the amount of time (in seconds) since the last update.
/// @param data Any data relating to the update.
/// @return Time in seconds.
function timeSinceLastUpdate(bytes memory data) public view virtual returns (uint256);
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
pragma experimental ABIEncoderV2;
library ObservationLibrary {
struct ObservationMetadata {
address oracle;
}
struct Observation {
uint112 price;
uint112 tokenLiquidity;
uint112 quoteTokenLiquidity;
uint32 timestamp;
}
struct MetaObservation {
ObservationMetadata metadata;
Observation data;
}
struct LiquidityObservation {
uint112 tokenLiquidity;
uint112 quoteTokenLiquidity;
uint32 timestamp;
}
struct PriceObservation {
uint112 price;
uint32 timestamp;
}
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.13;
library StringLibrary {
function bytes32ToString(bytes32 self) internal pure returns (string memory) {
// Calculate string length
uint256 i = 0;
while (i < 32 && self[i] != 0) ++i;
bytes memory bytesArray = new bytes(i);
// Extract characters
for (i = 0; i < 32 && self[i] != 0; ++i) bytesArray[i] = self[i];
return string(bytesArray);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "./IOracleAggregator.sol";
import "./AbstractOracle.sol";
import "./HistoricalOracle.sol";
import "../interfaces/IOracle.sol";
import "../utils/ExplicitQuotationMetadata.sol";
import "../strategies/validation/IValidationStrategy.sol";
abstract contract AbstractAggregatorOracle is
IOracleAggregator,
AbstractOracle,
HistoricalOracle,
ExplicitQuotationMetadata
{
struct TokenSpecificOracle {
address token;
address oracle;
}
/**
* @notice An event emitted when data is aggregated.
* @param token The token for which the data is aggregated.
* @param tick The identifier of the aggregation iteration (i.e. timestamp) at which the data is aggregated.
* @param numDataPoints The number of data points (i.e. underlying oracle responses) aggregated.
*/
event AggregationPerformed(address indexed token, uint256 indexed tick, uint256 numDataPoints);
IAggregationStrategy internal immutable generalAggregationStrategy;
IValidationStrategy internal immutable generalValidationStrategy;
/// @notice One whole unit of the quote token, in the quote token's smallest denomination.
uint256 internal immutable _quoteTokenWholeUnit;
uint8 internal immutable _liquidityDecimals;
Oracle[] internal oracles;
mapping(address => Oracle[]) internal tokenSpecificOracles;
mapping(address => bool) private oracleExists;
mapping(address => mapping(address => bool)) private oracleForExists;
/// @notice Emitted when an underlying oracle (or this oracle) throws an update error with a reason.
/// @param oracle The address or the oracle throwing the error.
/// @param token The token for which the oracle is throwing the error.
/// @param reason The reason for or description of the error.
event UpdateErrorWithReason(address indexed oracle, address indexed token, string reason);
/// @notice Emitted when an underlying oracle (or this oracle) throws an update error without a reason.
/// @param oracle The address or the oracle throwing the error.
/// @param token The token for which the oracle is throwing the error.
/// @param err Data corresponding with a low level error being thrown.
event UpdateError(address indexed oracle, address indexed token, bytes err);
struct AbstractAggregatorOracleParams {
IAggregationStrategy aggregationStrategy;
IValidationStrategy validationStrategy;
string quoteTokenName;
address quoteTokenAddress;
string quoteTokenSymbol;
uint8 quoteTokenDecimals;
uint8 liquidityDecimals;
address[] oracles;
TokenSpecificOracle[] tokenSpecificOracles;
}
constructor(
AbstractAggregatorOracleParams memory params
)
HistoricalOracle(1)
AbstractOracle(params.quoteTokenAddress)
ExplicitQuotationMetadata(
params.quoteTokenName,
params.quoteTokenAddress,
params.quoteTokenSymbol,
params.quoteTokenDecimals
)
{
if (
address(params.validationStrategy) != address(0) &&
params.validationStrategy.quoteTokenDecimals() != params.quoteTokenDecimals
) {
revert("AbstractAggregatorOracle: QUOTE_TOKEN_DECIMALS_MISMATCH");
}
generalAggregationStrategy = params.aggregationStrategy;
generalValidationStrategy = params.validationStrategy;
_quoteTokenWholeUnit = 10 ** params.quoteTokenDecimals;
_liquidityDecimals = params.liquidityDecimals;
// Setup general oracles
for (uint256 i = 0; i < params.oracles.length; ++i) {
require(!oracleExists[params.oracles[i]], "AbstractAggregatorOracle: DUPLICATE_ORACLE");
oracleExists[params.oracles[i]] = true;
oracles.push(
Oracle({
oracle: params.oracles[i],
priceDecimals: IOracle(params.oracles[i]).quoteTokenDecimals(),
liquidityDecimals: IOracle(params.oracles[i]).liquidityDecimals()
})
);
}
// Setup token-specific oracles
for (uint256 i = 0; i < params.tokenSpecificOracles.length; ++i) {
TokenSpecificOracle memory oracle = params.tokenSpecificOracles[i];
require(!oracleExists[oracle.oracle], "AbstractAggregatorOracle: DUPLICATE_ORACLE");
require(!oracleForExists[oracle.token][oracle.oracle], "AbstractAggregatorOracle: DUPLICATE_ORACLE");
oracleForExists[oracle.token][oracle.oracle] = true;
tokenSpecificOracles[oracle.token].push(
Oracle({
oracle: oracle.oracle,
priceDecimals: IOracle(oracle.oracle).quoteTokenDecimals(),
liquidityDecimals: IOracle(oracle.oracle).liquidityDecimals()
})
);
}
}
/// @inheritdoc IOracleAggregator
function aggregationStrategy(address token) external view virtual override returns (IAggregationStrategy) {
return _aggregationStrategy(token);
}
/// @inheritdoc IOracleAggregator
function validationStrategy(address token) external view virtual override returns (IValidationStrategy) {
return _validationStrategy(token);
}
/// @inheritdoc IOracleAggregator
function getOracles(address token) external view virtual override returns (Oracle[] memory) {
return _getOracles(token);
}
/// @inheritdoc IOracleAggregator
function minimumResponses(address token) external view virtual override returns (uint256) {
return _minimumResponses(token);
}
/// @inheritdoc IOracleAggregator
function maximumResponseAge(address token) external view virtual override returns (uint256) {
return _maximumResponseAge(token);
}
/// @inheritdoc ExplicitQuotationMetadata
function quoteTokenName()
public
view
virtual
override(ExplicitQuotationMetadata, IQuoteToken, SimpleQuotationMetadata)
returns (string memory)
{
return ExplicitQuotationMetadata.quoteTokenName();
}
/// @inheritdoc ExplicitQuotationMetadata
function quoteTokenAddress()
public
view
virtual
override(ExplicitQuotationMetadata, IQuoteToken, SimpleQuotationMetadata)
returns (address)
{
return ExplicitQuotationMetadata.quoteTokenAddress();
}
/// @inheritdoc ExplicitQuotationMetadata
function quoteTokenSymbol()
public
view
virtual
override(ExplicitQuotationMetadata, IQuoteToken, SimpleQuotationMetadata)
returns (string memory)
{
return ExplicitQuotationMetadata.quoteTokenSymbol();
}
/// @inheritdoc ExplicitQuotationMetadata
function quoteTokenDecimals()
public
view
virtual
override(ExplicitQuotationMetadata, IQuoteToken, SimpleQuotationMetadata)
returns (uint8)
{
return ExplicitQuotationMetadata.quoteTokenDecimals();
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ExplicitQuotationMetadata, AbstractOracle) returns (bool) {
return
interfaceId == type(IHistoricalOracle).interfaceId ||
interfaceId == type(IOracleAggregator).interfaceId ||
ExplicitQuotationMetadata.supportsInterface(interfaceId) ||
AbstractOracle.supportsInterface(interfaceId);
}
function canUpdate(bytes memory data) public view virtual override returns (bool) {
if (!needsUpdate(data)) {
return false;
}
if (canUpdateUnderlyingOracles(data)) {
return true;
}
address token = abi.decode(data, (address));
(, uint256 validResponses) = aggregateUnderlying(token, _maximumResponseAge(token));
// Only return true if we have reached the minimum number of valid underlying oracle consultations
return validResponses >= _minimumResponses(token);
}
/// @inheritdoc IOracle
function liquidityDecimals() public view virtual override returns (uint8) {
return _liquidityDecimals;
}
function getLatestObservation(
address token
) public view virtual override returns (ObservationLibrary.Observation memory observation) {
BufferMetadata storage meta = observationBufferMetadata[token];
if (meta.size == 0) {
// If the buffer is empty, return the default observation
return ObservationLibrary.Observation({price: 0, tokenLiquidity: 0, quoteTokenLiquidity: 0, timestamp: 0});
}
return observationBuffers[token][meta.end];
}
/// @notice Checks if any of the underlying oracles for the token need to be updated.
/// @dev This function is used to determine if the aggregator can be updated by updating one of the underlying
/// oracles. Please ensure updateUnderlyingOracles will update the underlying oracles if this function returns true.
/// @param data The encoded token address, along with any additional data required by the oracle.
/// @return True if any of the underlying oracles can be updated, false otherwise.
function canUpdateUnderlyingOracles(bytes memory data) internal view virtual returns (bool) {
address token = abi.decode(data, (address));
// Ensure all underlying oracles are up-to-date
Oracle[] memory theOracles = _getOracles(token);
for (uint256 i = 0; i < theOracles.length; ++i) {
if (IOracle(theOracles[i].oracle).canUpdate(data)) {
// We can update one of the underlying oracles
return true;
}
}
return false;
}
/// @notice Updates the underlying oracles for the token.
/// @dev This function is used to update the underlying oracles before consulting them.
/// @param data The encoded token address, along with any additional data required by the oracle.
/// @return True if any of the underlying oracles were updated, false otherwise.
function updateUnderlyingOracles(bytes memory data) internal virtual returns (bool) {
bool underlyingUpdated;
address token = abi.decode(data, (address));
// Ensure all underlying oracles are up-to-date
Oracle[] memory theOracles = _getOracles(token);
for (uint256 i = 0; i < theOracles.length; ++i) {
// We don't want any problematic underlying oracles to prevent this oracle from updating
// so we put update in a try-catch block
try IOracle(theOracles[i].oracle).update(data) returns (bool updated) {
underlyingUpdated = underlyingUpdated || updated;
} catch Error(string memory reason) {
emit UpdateErrorWithReason(theOracles[i].oracle, token, reason);
} catch (bytes memory err) {
emit UpdateError(theOracles[i].oracle, token, err);
}
}
return underlyingUpdated;
}
function _getOracles(address token) internal view virtual returns (Oracle[] memory) {
Oracle[] memory generalOracles = oracles;
Oracle[] memory specificOracles = tokenSpecificOracles[token];
uint256 generalOraclesCount = generalOracles.length;
uint256 specificOraclesCount = specificOracles.length;
Oracle[] memory allOracles = new Oracle[](generalOraclesCount + specificOraclesCount);
// Add the general oracles
for (uint256 i = 0; i < generalOraclesCount; ++i) allOracles[i] = generalOracles[i];
// Add the token specific oracles
for (uint256 i = 0; i < specificOraclesCount; ++i) allOracles[generalOraclesCount + i] = specificOracles[i];
return allOracles;
}
function performUpdate(bytes memory data) internal virtual returns (bool) {
bool underlyingUpdated = updateUnderlyingOracles(data);
address token = abi.decode(data, (address));
(ObservationLibrary.Observation memory observation, uint256 validResponses) = aggregateUnderlying(
token,
_maximumResponseAge(token)
);
if (validResponses >= _minimumResponses(token)) {
emit AggregationPerformed(token, block.timestamp, validResponses);
push(token, observation);
return true;
} else emit UpdateErrorWithReason(address(this), token, "AbstractAggregatorOracle: INVALID_NUM_CONSULTATIONS");
return underlyingUpdated;
}
function _minimumResponses(address token) internal view virtual returns (uint256);
function _maximumResponseAge(address token) internal view virtual returns (uint256);
function _aggregationStrategy(address token) internal view virtual returns (IAggregationStrategy) {
token; // silence unused variable warning. We let subclasses override this function to use the token parameter.
return generalAggregationStrategy;
}
function _validationStrategy(address token) internal view virtual returns (IValidationStrategy) {
token; // silence unused variable warning. We let subclasses override this function to use the token parameter.
return generalValidationStrategy;
}
function aggregateUnderlying(
address token,
uint256 maxAge
) internal view virtual returns (ObservationLibrary.Observation memory result, uint256 validResponses) {
uint256 pDecimals = quoteTokenDecimals();
uint256 lDecimals = liquidityDecimals();
Oracle[] memory theOracles = _getOracles(token);
ObservationLibrary.MetaObservation[] memory observations = new ObservationLibrary.MetaObservation[](
theOracles.length
);
uint256 oPrice;
uint256 oTokenLiquidity;
uint256 oQuoteTokenLiquidity;
IValidationStrategy validation = _validationStrategy(token);
for (uint256 i = 0; i < theOracles.length; ++i) {
// We don't want problematic underlying oracles to prevent us from calculating the aggregated
// results from the other working oracles, so we use a try-catch block.
try IOracle(theOracles[i].oracle).consult(token, maxAge) returns (
uint112 _price,
uint112 _tokenLiquidity,
uint112 _quoteTokenLiquidity
) {
// Promote returned data to uint256 to prevent scaling up from overflowing
oPrice = _price;
oTokenLiquidity = _tokenLiquidity;
oQuoteTokenLiquidity = _quoteTokenLiquidity;
} catch Error(string memory) {
continue;
} catch (bytes memory) {
continue;
}
// Fix differing quote token decimal places (for price)
if (theOracles[i].priceDecimals < pDecimals) {
// Scale up
uint256 scalar = 10 ** (pDecimals - theOracles[i].priceDecimals);
oPrice *= scalar;
} else if (theOracles[i].priceDecimals > pDecimals) {
// Scale down
uint256 scalar = 10 ** (theOracles[i].priceDecimals - pDecimals);
oPrice /= scalar;
}
// Fix differing liquidity decimal places
if (theOracles[i].liquidityDecimals < lDecimals) {
// Scale up
uint256 scalar = 10 ** (lDecimals - theOracles[i].liquidityDecimals);
oTokenLiquidity *= scalar;
oQuoteTokenLiquidity *= scalar;
} else if (theOracles[i].liquidityDecimals > lDecimals) {
// Scale down
uint256 scalar = 10 ** (theOracles[i].liquidityDecimals - lDecimals);
oTokenLiquidity /= scalar;
oQuoteTokenLiquidity /= scalar;
}
if (
// Check that the values are not too large
oPrice <= type(uint112).max &&
oTokenLiquidity <= type(uint112).max &&
oQuoteTokenLiquidity <= type(uint112).max
) {
ObservationLibrary.MetaObservation memory observation;
{
bytes memory updateData = abi.encode(token);
uint256 timestamp = IOracle(theOracles[i].oracle).lastUpdateTime(updateData);
observation = ObservationLibrary.MetaObservation({
metadata: ObservationLibrary.ObservationMetadata({oracle: theOracles[i].oracle}),
data: ObservationLibrary.Observation({
price: uint112(oPrice),
tokenLiquidity: uint112(oTokenLiquidity),
quoteTokenLiquidity: uint112(oQuoteTokenLiquidity),
timestamp: uint32(timestamp)
})
});
}
if (address(validation) == address(0) || validation.validateObservation(token, observation)) {
// The observation is valid, so we add it to the array
observations[validResponses++] = observation;
}
}
}
if (validResponses == 0) {
return (
ObservationLibrary.Observation({price: 0, tokenLiquidity: 0, quoteTokenLiquidity: 0, timestamp: 0}),
0
);
}
result = _aggregationStrategy(token).aggregateObservations(token, observations, 0, validResponses - 1);
if (address(validation) != address(0)) {
// Validate the aggregated result
ObservationLibrary.MetaObservation memory metaResult = ObservationLibrary.MetaObservation({
metadata: ObservationLibrary.ObservationMetadata({oracle: address(this)}),
data: result
});
if (!validation.validateObservation(token, metaResult)) {
return (
ObservationLibrary.Observation({price: 0, tokenLiquidity: 0, quoteTokenLiquidity: 0, timestamp: 0}),
0
);
}
}
}
/// @inheritdoc AbstractOracle
function instantFetch(
address token
) internal view virtual override returns (uint112 price, uint112 tokenLiquidity, uint112 quoteTokenLiquidity) {
(ObservationLibrary.Observation memory result, uint256 validResponses) = aggregateUnderlying(token, 0);
uint256 minResponses = _minimumResponses(token);
require(validResponses >= minResponses, "AbstractAggregatorOracle: INVALID_NUM_CONSULTATIONS");
price = result.price;
tokenLiquidity = result.tokenLiquidity;
quoteTokenLiquidity = result.quoteTokenLiquidity;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@openzeppelin-v4/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin-v4/contracts/utils/introspection/IERC165.sol";
import "../interfaces/IOracle.sol";
import "../libraries/ObservationLibrary.sol";
import "../utils/SimpleQuotationMetadata.sol";
abstract contract AbstractOracle is IERC165, IOracle, SimpleQuotationMetadata {
constructor(address quoteToken_) SimpleQuotationMetadata(quoteToken_) {}
/// @param data The encoded address of the token for which to perform the update.
/// @inheritdoc IUpdateable
function update(bytes memory data) public virtual override returns (bool);
/// @param data The encoded address of the token for which to perform the update.
/// @inheritdoc IUpdateable
function needsUpdate(bytes memory data) public view virtual override returns (bool);
/// @param data The encoded address of the token for which to perform the update.
/// @inheritdoc IUpdateable
function canUpdate(bytes memory data) public view virtual override returns (bool);
function getLatestObservation(
address token
) public view virtual returns (ObservationLibrary.Observation memory observation);
/// @param data The encoded address of the token for which the update relates to.
/// @inheritdoc IUpdateable
function lastUpdateTime(bytes memory data) public view virtual override returns (uint256) {
address token = abi.decode(data, (address));
return getLatestObservation(token).timestamp;
}
/// @param data The encoded address of the token for which the update relates to.
/// @inheritdoc IUpdateable
function timeSinceLastUpdate(bytes memory data) public view virtual override returns (uint256) {
return block.timestamp - lastUpdateTime(data);
}
function consultPrice(address token) public view virtual override returns (uint112 price) {
if (token == quoteTokenAddress()) return uint112(10 ** quoteTokenDecimals());
ObservationLibrary.Observation memory observation = getLatestObservation(token);
require(observation.timestamp != 0, "AbstractOracle: MISSING_OBSERVATION");
return observation.price;
}
/// @inheritdoc IPriceOracle
function consultPrice(address token, uint256 maxAge) public view virtual override returns (uint112 price) {
if (token == quoteTokenAddress()) return uint112(10 ** quoteTokenDecimals());
if (maxAge == 0) {
(price, , ) = instantFetch(token);
return price;
}
ObservationLibrary.Observation memory observation = getLatestObservation(token);
require(observation.timestamp != 0, "AbstractOracle: MISSING_OBSERVATION");
require(block.timestamp <= observation.timestamp + maxAge, "AbstractOracle: RATE_TOO_OLD");
return observation.price;
}
/// @inheritdoc ILiquidityOracle
function consultLiquidity(
address token
) public view virtual override returns (uint112 tokenLiquidity, uint112 quoteTokenLiquidity) {
if (token == quoteTokenAddress()) return (0, 0);
ObservationLibrary.Observation memory observation = getLatestObservation(token);
require(observation.timestamp != 0, "AbstractOracle: MISSING_OBSERVATION");
tokenLiquidity = observation.tokenLiquidity;
quoteTokenLiquidity = observation.quoteTokenLiquidity;
}
/// @inheritdoc ILiquidityOracle
function consultLiquidity(
address token,
uint256 maxAge
) public view virtual override returns (uint112 tokenLiquidity, uint112 quoteTokenLiquidity) {
if (token == quoteTokenAddress()) return (0, 0);
if (maxAge == 0) {
(, tokenLiquidity, quoteTokenLiquidity) = instantFetch(token);
return (tokenLiquidity, quoteTokenLiquidity);
}
ObservationLibrary.Observation memory observation = getLatestObservation(token);
require(observation.timestamp != 0, "AbstractOracle: MISSING_OBSERVATION");
require(block.timestamp <= observation.timestamp + maxAge, "AbstractOracle: RATE_TOO_OLD");
tokenLiquidity = observation.tokenLiquidity;
quoteTokenLiquidity = observation.quoteTokenLiquidity;
}
/// @inheritdoc IOracle
function consult(
address token
) public view virtual override returns (uint112 price, uint112 tokenLiquidity, uint112 quoteTokenLiquidity) {
if (token == quoteTokenAddress()) return (uint112(10 ** quoteTokenDecimals()), 0, 0);
ObservationLibrary.Observation memory observation = getLatestObservation(token);
require(observation.timestamp != 0, "AbstractOracle: MISSING_OBSERVATION");
price = observation.price;
tokenLiquidity = observation.tokenLiquidity;
quoteTokenLiquidity = observation.quoteTokenLiquidity;
}
/// @inheritdoc IOracle
function consult(
address token,
uint256 maxAge
) public view virtual override returns (uint112 price, uint112 tokenLiquidity, uint112 quoteTokenLiquidity) {
if (token == quoteTokenAddress()) return (uint112(10 ** quoteTokenDecimals()), 0, 0);
if (maxAge == 0) return instantFetch(token);
ObservationLibrary.Observation memory observation = getLatestObservation(token);
require(observation.timestamp != 0, "AbstractOracle: MISSING_OBSERVATION");
require(block.timestamp <= observation.timestamp + maxAge, "AbstractOracle: RATE_TOO_OLD");
price = observation.price;
tokenLiquidity = observation.tokenLiquidity;
quoteTokenLiquidity = observation.quoteTokenLiquidity;
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(SimpleQuotationMetadata, IERC165) returns (bool) {
return
interfaceId == type(IOracle).interfaceId ||
interfaceId == type(IUpdateable).interfaceId ||
interfaceId == type(IPriceOracle).interfaceId ||
interfaceId == type(ILiquidityOracle).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Fetches the instant rates as of the latest block, straight from the source.
* @dev This is costly in gas and the rates are easier to manipulate.
* @param token The token to get the rates for.
* @return price The quote token denominated price for a whole token.
* @return tokenLiquidity The amount of the token that is liquid in the underlying pool, in wei.
* @return quoteTokenLiquidity The amount of the quote token that is liquid in the underlying pool, in wei.
*/
function instantFetch(
address token
) internal view virtual returns (uint112 price, uint112 tokenLiquidity, uint112 quoteTokenLiquidity);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "./AbstractAggregatorOracle.sol";
import "../accumulators/AbstractAccumulator.sol";
/**
* @title CurrentAggregatorOracle
* @notice An aggregator oracle that updates when the price changes by a certain threshold.
* @dev This oracle doesn't update the underlying oracles, so ensure that the underlying oracles are kept up-to-date.
*/
contract CurrentAggregatorOracle is AbstractAccumulator, AbstractAggregatorOracle {
/// @notice The minimum delay between updates, in seconds.
uint256 internal immutable minUpdateDelay;
/// @notice The (optimistic) maximum delay between updates, in seconds.
uint256 internal immutable maxUpdateDelay;
/// @notice An error that is thrown when the minimum update delay is greater than the maximum update delay.
/// @param minUpdateDelay The minimum update delay.
/// @param maxUpdateDelay The maximum update delay.
error InvalidUpdateDelays(uint256 minUpdateDelay, uint256 maxUpdateDelay);
/**
* @notice Constructor for the CurrentAggregatorOracle contract.
* @param params The parameters for the abstract aggregator oracle.
* @param updateThreshold_ The threshold for the price change that triggers an update. The threshold is expressed as
* a percentage of the current price and scaled by AbstractAccumulator#changePrecision.
* @param minUpdateDelay_ The minimum delay between updates, in seconds.
* @param maxUpdateDelay_ The (optimistic) maximum delay between updates, in seconds. Also known as the heartbeat.
*/
constructor(
AbstractAggregatorOracleParams memory params,
uint256 updateThreshold_,
uint256 minUpdateDelay_,
uint256 maxUpdateDelay_
) AbstractAggregatorOracle(params) AbstractAccumulator(updateThreshold_) {
if (maxUpdateDelay_ < minUpdateDelay_) revert InvalidUpdateDelays(minUpdateDelay_, maxUpdateDelay_);
minUpdateDelay = minUpdateDelay_;
maxUpdateDelay = maxUpdateDelay_;
}
/// @inheritdoc IAccumulator
function updateDelay() external view virtual override returns (uint256) {
return _updateDelay();
}
/// @inheritdoc IAccumulator
function heartbeat() external view virtual override returns (uint256) {
return _heartbeat();
}
/// @inheritdoc AbstractOracle
function update(bytes memory data) public virtual override returns (bool) {
if (needsUpdate(data)) return performUpdate(data);
return false;
}
/// @inheritdoc IAccumulator
function changeThresholdSurpassed(
bytes memory data,
uint256 changeThreshold
) public view virtual override returns (bool) {
address token = abi.decode(data, (address));
uint256 maxAge = _maximumResponseAge(token);
(ObservationLibrary.Observation memory currentObservation, uint256 responses) = aggregateUnderlying(
token,
maxAge
);
uint256 requiredResponses = _minimumResponses(token);
if (responses < requiredResponses) {
// Not enough responses to update
return false;
}
ObservationLibrary.Observation memory lastObservation = getLatestObservation(token);
return changeThresholdSurpassed(currentObservation.price, lastObservation.price, changeThreshold);
}
/**
* @notice Checks whether the oracle needs to be updated.
* @dev This oracle needs to be updated if the price change threshold is surpassed or if the time since the last
* update has exceeded the maximum update delay.
* @param data The encoded token address.
* @return True if the oracle needs to be updated, false otherwise.
*/
function needsUpdate(bytes memory data) public view virtual override returns (bool) {
uint256 deltaTime = timeSinceLastUpdate(data);
if (deltaTime < _updateDelay()) {
// Ensures updates occur at most once every minUpdateDelay (seconds)
return false;
} else if (deltaTime >= _heartbeat()) {
// Ensures updates occur (optimistically) at least once every heartbeat (seconds)
return true;
}
return updateThresholdSurpassed(data);
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(AbstractAccumulator, AbstractAggregatorOracle) returns (bool) {
return
AbstractAccumulator.supportsInterface(interfaceId) ||
AbstractAggregatorOracle.supportsInterface(interfaceId);
}
function _updateDelay() internal view virtual returns (uint256) {
return minUpdateDelay;
}
function _heartbeat() internal view virtual returns (uint256) {
return maxUpdateDelay;
}
function _minimumResponses(address) internal view virtual override returns (uint256) {
return 1;
}
function _maximumResponseAge(address) internal view virtual override returns (uint256) {
return _heartbeat() + 30 minutes;
}
/// @inheritdoc AbstractAggregatorOracle
/// @dev This oracle won't update its underlying oracles.
function canUpdateUnderlyingOracles(bytes memory) internal view virtual override returns (bool) {
return false;
}
/// @inheritdoc AbstractAggregatorOracle
/// @dev This oracle won't update its underlying oracles.
function updateUnderlyingOracles(bytes memory) internal virtual override returns (bool) {
return false;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "../interfaces/IHistoricalOracle.sol";
import "../libraries/ObservationLibrary.sol";
abstract contract HistoricalOracle is IHistoricalOracle {
struct BufferMetadata {
uint16 start;
uint16 end;
uint16 size;
uint16 maxSize;
uint16 flags; // Bit flags for future use
uint112 __reserved; // Reserved for future use
uint64 extra; // For user extensions
}
mapping(address => BufferMetadata) internal observationBufferMetadata;
mapping(address => ObservationLibrary.Observation[]) internal observationBuffers;
uint16 internal immutable initialCapacity;
/// @notice Emitted when a stored quotation is updated.
/// @param token The address of the token that the quotation is for.
/// @param price The quote token denominated price for a whole token.
/// @param tokenLiquidity The amount of the token that is liquid in the underlying pool, in wei.
/// @param quoteTokenLiquidity The amount of the quote token that is liquid in the underlying pool, in wei.
/// @param timestamp The epoch timestamp of the quotation (in seconds).
event Updated(
address indexed token,
uint256 price,
uint256 tokenLiquidity,
uint256 quoteTokenLiquidity,
uint256 timestamp
);
/// @notice Event emitted when an observation buffer's capacity is increased past the initial capacity.
/// @dev Buffer initialization does not emit an event.
/// @param token The token for which the observation buffer's capacity was increased.
/// @param oldCapacity The previous capacity of the observation buffer.
/// @param newCapacity The new capacity of the observation buffer.
event ObservationCapacityIncreased(address indexed token, uint256 oldCapacity, uint256 newCapacity);
/// @notice Event emitted when an observation buffer's capacity is initialized.
/// @param token The token for which the observation buffer's capacity was initialized.
/// @param capacity The capacity of the observation buffer.
event ObservationCapacityInitialized(address indexed token, uint256 capacity);
/// @notice An error that is thrown if we try to initialize an observation buffer that has already been initialized.
/// @param token The token for which we tried to initialize the observation buffer.
error BufferAlreadyInitialized(address token);
/// @notice An error that is thrown if we try to retrieve an observation at an invalid index.
/// @param token The token for which we tried to retrieve the observation.
/// @param index The index of the observation that we tried to retrieve.
/// @param size The size of the observation buffer.
error InvalidIndex(address token, uint256 index, uint256 size);
/// @notice An error that is thrown if we try to decrease the capacity of an observation buffer.
/// @param token The token for which we tried to decrease the capacity of the observation buffer.
/// @param amount The capacity that we tried to decrease the observation buffer to.
/// @param currentCapacity The current capacity of the observation buffer.
error CapacityCannotBeDecreased(address token, uint256 amount, uint256 currentCapacity);
/// @notice An error that is thrown if we try to increase the capacity of an observation buffer past the maximum capacity.
/// @param token The token for which we tried to increase the capacity of the observation buffer.
/// @param amount The capacity that we tried to increase the observation buffer to.
/// @param maxCapacity The maximum capacity of the observation buffer.
error CapacityTooLarge(address token, uint256 amount, uint256 maxCapacity);
/// @notice An error that is thrown if we try to retrieve more observations than are available in the observation buffer.
/// @param token The token for which we tried to retrieve the observations.
/// @param size The size of the observation buffer.
/// @param minSizeRequired The minimum size of the observation buffer that we require.
error InsufficientData(address token, uint256 size, uint256 minSizeRequired);
constructor(uint16 initialCapacity_) {
initialCapacity = initialCapacity_;
}
/// @inheritdoc IHistoricalOracle
function getObservationAt(
address token,
uint256 index
) external view virtual override returns (ObservationLibrary.Observation memory) {
BufferMetadata memory meta = observationBufferMetadata[token];
if (index >= meta.size) {
revert InvalidIndex(token, index, meta.size);
}
uint256 bufferIndex = meta.end < index ? meta.end + meta.size - index : meta.end - index;
return observationBuffers[token][bufferIndex];
}
/// @inheritdoc IHistoricalOracle
function getObservations(
address token,
uint256 amount
) external view virtual override returns (ObservationLibrary.Observation[] memory) {
return getObservationsInternal(token, amount, 0, 1);
}
/// @inheritdoc IHistoricalOracle
function getObservations(
address token,
uint256 amount,
uint256 offset,
uint256 increment
) external view virtual returns (ObservationLibrary.Observation[] memory) {
return getObservationsInternal(token, amount, offset, increment);
}
/// @inheritdoc IHistoricalOracle
function getObservationsCount(address token) external view override returns (uint256) {
return observationBufferMetadata[token].size;
}
/// @inheritdoc IHistoricalOracle
function getObservationsCapacity(address token) external view virtual override returns (uint256) {
uint256 maxSize = observationBufferMetadata[token].maxSize;
if (maxSize == 0) return initialCapacity;
return maxSize;
}
/// @inheritdoc IHistoricalOracle
/// @param amount The new capacity of observations for the token. Must be greater than the current capacity, but
/// less than 65536.
function setObservationsCapacity(address token, uint256 amount) external virtual override {
BufferMetadata storage meta = observationBufferMetadata[token];
if (meta.maxSize == 0) {
// Buffer is not initialized yet
initializeBuffers(token);
}
if (amount < meta.maxSize) revert CapacityCannotBeDecreased(token, amount, meta.maxSize);
if (amount > type(uint16).max) revert CapacityTooLarge(token, amount, type(uint16).max);
ObservationLibrary.Observation[] storage observationBuffer = observationBuffers[token];
// Add new slots to the buffer
uint256 capacityToAdd = amount - meta.maxSize;
for (uint256 i = 0; i < capacityToAdd; ++i) {
// Push a dummy observation with non-zero values to put most of the gas cost on the caller
observationBuffer.push(
ObservationLibrary.Observation({price: 1, tokenLiquidity: 1, quoteTokenLiquidity: 1, timestamp: 1})
);
}
if (meta.maxSize != amount) {
emit ObservationCapacityIncreased(token, meta.maxSize, amount);
// Update the metadata
meta.maxSize = uint16(amount);
}
}
function getObservationsInternal(
address token,
uint256 amount,
uint256 offset,
uint256 increment
) internal view virtual returns (ObservationLibrary.Observation[] memory) {
if (amount == 0) return new ObservationLibrary.Observation[](0);
BufferMetadata memory meta = observationBufferMetadata[token];
if (meta.size <= (amount - 1) * increment + offset)
revert InsufficientData(token, meta.size, (amount - 1) * increment + offset + 1);
ObservationLibrary.Observation[] memory observations = new ObservationLibrary.Observation[](amount);
uint256 count = 0;
for (
uint256 i = meta.end < offset ? meta.end + meta.size - offset : meta.end - offset;
count < amount;
i = (i < increment) ? (i + meta.size) - increment : i - increment
) {
observations[count++] = observationBuffers[token][i];
}
return observations;
}
function initializeBuffers(address token) internal virtual {
if (observationBuffers[token].length != 0) {
revert BufferAlreadyInitialized(token);
}
BufferMetadata storage meta = observationBufferMetadata[token];
// Initialize the buffers
ObservationLibrary.Observation[] storage observationBuffer = observationBuffers[token];
for (uint256 i = 0; i < initialCapacity; ++i) {
observationBuffer.push();
}
// Initialize the metadata
meta.start = 0;
meta.end = 0;
meta.size = 0;
meta.maxSize = initialCapacity;
emit ObservationCapacityInitialized(token, meta.maxSize);
}
function push(address token, ObservationLibrary.Observation memory observation) internal virtual {
BufferMetadata storage meta = observationBufferMetadata[token];
if (meta.size == 0) {
if (meta.maxSize == 0) {
// Initialize the buffers
initializeBuffers(token);
}
} else {
meta.end = (meta.end + 1) % meta.maxSize;
}
observationBuffers[token][meta.end] = observation;
emit Updated(
token,
observation.price,
observation.tokenLiquidity,
observation.quoteTokenLiquidity,
block.timestamp
);
if (meta.size < meta.maxSize && meta.end == meta.size) {
// We are at the end of the array and we have not yet filled it
meta.size++;
} else {
// start was just overwritten
meta.start = (meta.start + 1) % meta.size;
}
}
}//SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "../strategies/aggregation/IAggregationStrategy.sol";
import "../strategies/validation/IValidationStrategy.sol";
/**
* @title IOracleAggregator
* @notice This interface defines the functions for an aggregator oracle. An aggregator oracle collects and processes
* data from multiple underlying oracles to provide a single source of truth that is accurate and reliable.
*/
interface IOracleAggregator {
/**
* @dev Struct representing an individual oracle.
* Contains the following properties:
* - oracle: The address of the oracle (160 bits)
* - priceDecimals: The number of decimals in the oracle's price data
* - liquidityDecimals: The number of decimals in the oracle's liquidity data
*/
struct Oracle {
address oracle; // The oracle address, 160 bits
uint8 priceDecimals; // The number of decimals of the price
uint8 liquidityDecimals; // The number of decimals of the liquidity
}
/**
* @notice Returns the aggregation strategy being used by the aggregator oracle for a given token.
* @dev The aggregation strategy is used to aggregate the data from the underlying oracles.
* @param token The address of the token for which the aggregation strategy is being requested.
* @return strategy The instance of the IAggregationStrategy being used.
*/
function aggregationStrategy(address token) external view returns (IAggregationStrategy strategy);
/**
* @notice Returns the validation strategy being used by the aggregator oracle for a given token.
* @dev The validation strategy is used to validate the data from the underlying oracles before it is aggregated.
* Results from the underlying oracles that do not pass validation will be ignored.
* @param token The address of the token for which the validation strategy is being requested.
* @return strategy The instance of the IValidationStrategy being used, or the zero address if no validation
* strategy is being used.
*/
function validationStrategy(address token) external view returns (IValidationStrategy strategy);
/**
* @notice Returns an array of Oracle structs representing the underlying oracles for a given token.
* @param token The address of the token for which oracles are being requested.
* @return oracles An array of Oracle structs for the given token.
*/
function getOracles(address token) external view returns (Oracle[] memory oracles);
/**
* @notice Returns the minimum number of oracle responses required for the aggregator to push a new observation.
* @param token The address of the token for which the minimum number of responses is being requested.
* @return minimumResponses The minimum number of responses required.
*/
function minimumResponses(address token) external view returns (uint256 minimumResponses);
/**
* @notice Returns the maximum age (in seconds) of an underlying oracle response for it to be considered valid.
* @dev The maximum response age is used to prevent stale data from being aggregated.
* @param token The address of the token for which the maximum response age is being requested.
* @return maximumResponseAge The maximum response age in seconds.
*/
function maximumResponseAge(address token) external view returns (uint256 maximumResponseAge);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
import "../../libraries/ObservationLibrary.sol";
/**
* @title IAggregationStrategy
* @notice Interface for implementing a strategy to aggregate data from a series of observations
* within a specified range. This can be useful when working with time-weighted average prices,
* volume-weighted average prices, or any other custom aggregation logic.
*
* Implementations of this interface can be used in a variety of scenarios, such as DeFi
* protocols, on-chain analytics, and other smart contract applications.
*/
interface IAggregationStrategy {
/**
* @notice Aggregate the observations within the specified range and return the result
* as a single Observation.
*
* The aggregation strategy can be customized to include various forms of logic,
* such as calculating the median, mean, or mode of the observations.
*
* @dev The implementation of this function should perform input validation, such as
* ensuring the provided range is valid (i.e., 'from' <= 'to'), and that the input
* array of observations is not empty.
*
* @param token The address of the token for which to aggregate observations.
* @param observations An array of MetaObservation structs containing the data to aggregate.
* @param from The starting index (inclusive) of the range to aggregate from the observations array.
* @param to The ending index (inclusive) of the range to aggregate from the observations array.
*
* @return ObservationLibrary.Observation memory An Observation struct containing the result
* of the aggregation.
*/
function aggregateObservations(
address token,
ObservationLibrary.MetaObservation[] calldata observations,
uint256 from,
uint256 to
) external view returns (ObservationLibrary.Observation memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;
import "../../libraries/ObservationLibrary.sol";
/**
* @title IValidationStrategy
* @notice Interface for implementing validation strategies for observation data in a token pair.
*/
interface IValidationStrategy {
/**
* @notice Returns the number of decimals of the quote token.
* @dev This is useful for validations involving prices, which are always expressed in the quote token.
* @return The number of decimals for the quote token.
*/
function quoteTokenDecimals() external view returns (uint8);
/**
* @notice Validates the given observation data for a token pair.
* @param token The address of the token for which the observation data is being validated.
* @param observation The observation data to be validated.
* @return True if the observation passes validation; false otherwise.
*/
function validateObservation(
address token,
ObservationLibrary.MetaObservation calldata observation
) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@openzeppelin-v4/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin-v4/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../interfaces/IQuoteToken.sol";
contract ExplicitQuotationMetadata is IQuoteToken, IERC165 {
string internal _quoteTokenName;
string internal _quoteTokenSymbol;
address internal immutable _quoteTokenAddress;
uint8 internal immutable _quoteTokenDecimals;
constructor(
string memory quoteTokenName_,
address quoteTokenAddress_,
string memory quoteTokenSymbol_,
uint8 quoteTokenDecimals_
) {
_quoteTokenName = quoteTokenName_;
_quoteTokenSymbol = quoteTokenSymbol_;
_quoteTokenAddress = quoteTokenAddress_;
_quoteTokenDecimals = quoteTokenDecimals_;
}
/// @inheritdoc IQuoteToken
function quoteTokenName() public view virtual override returns (string memory) {
return _quoteTokenName;
}
/// @inheritdoc IQuoteToken
function quoteTokenAddress() public view virtual override returns (address) {
return _quoteTokenAddress;
}
/// @inheritdoc IQuoteToken
function quoteTokenSymbol() public view virtual override returns (string memory) {
return _quoteTokenSymbol;
}
/// @inheritdoc IQuoteToken
function quoteTokenDecimals() public view virtual override returns (uint8) {
return _quoteTokenDecimals;
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IQuoteToken).interfaceId;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@openzeppelin-v4/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin-v4/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../interfaces/IQuoteToken.sol";
import "../libraries/StringLibrary.sol";
contract SimpleQuotationMetadata is IQuoteToken, IERC165 {
using StringLibrary for bytes32;
address public immutable quoteToken;
constructor(address quoteToken_) {
quoteToken = quoteToken_;
}
/// @inheritdoc IQuoteToken
function quoteTokenName() public view virtual override returns (string memory) {
return getStringOrBytes32(quoteToken, IERC20Metadata.name.selector);
}
/// @inheritdoc IQuoteToken
function quoteTokenAddress() public view virtual override returns (address) {
return quoteToken;
}
/// @inheritdoc IQuoteToken
function quoteTokenSymbol() public view virtual override returns (string memory) {
return getStringOrBytes32(quoteToken, IERC20Metadata.symbol.selector);
}
/// @inheritdoc IQuoteToken
function quoteTokenDecimals() public view virtual override returns (uint8) {
(bool success, bytes memory result) = quoteToken.staticcall(
abi.encodeWithSelector(IERC20Metadata.decimals.selector)
);
if (!success) return 18; // Return 18 by default
return abi.decode(result, (uint8));
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IQuoteToken).interfaceId;
}
function getStringOrBytes32(address contractAddress, bytes4 selector) internal view returns (string memory) {
(bool success, bytes memory result) = contractAddress.staticcall(abi.encodeWithSelector(selector));
if (!success) return "";
return result.length == 32 ? (bytes32(result)).bytes32ToString() : abi.decode(result, (string));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0 <0.9.0;
library Roles {
bytes32 public constant ADMIN = keccak256("ADMIN_ROLE");
bytes32 public constant UPDATER_ADMIN = keccak256("UPDATER_ADMIN_ROLE");
bytes32 public constant ORACLE_UPDATER = keccak256("ORACLE_UPDATER_ROLE");
bytes32 public constant RATE_ADMIN = keccak256("RATE_ADMIN_ROLE");
bytes32 public constant UPDATE_PAUSE_ADMIN = keccak256("UPDATE_PAUSE_ADMIN_ROLE");
bytes32 public constant CONFIG_ADMIN = keccak256("CONFIG_ADMIN_ROLE");
bytes32 public constant TARGET_ADMIN = keccak256("TARGET_ADMIN_ROLE");
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@adrastia-oracle/adrastia-core/contracts/oracles/CurrentAggregatorOracle.sol";
import "./bases/ManagedCurrentAggregatorOracleBase.sol";
contract ManagedCurrentAggregatorOracle is CurrentAggregatorOracle, ManagedCurrentAggregatorOracleBase {
constructor(
AbstractAggregatorOracleParams memory params,
uint256 updateThreshold_,
uint256 updateDelay_,
uint256 heartbeat_
)
CurrentAggregatorOracle(params, updateThreshold_, updateDelay_, heartbeat_)
ManagedCurrentAggregatorOracleBase(uint32(updateThreshold_), uint32(updateDelay_), uint32(heartbeat_))
{}
function setUpdatesPaused(address token, bool paused) external virtual onlyRole(Roles.UPDATE_PAUSE_ADMIN) {
uint16 flags = observationBufferMetadata[token].flags;
bool currentlyPaused = (flags & PAUSE_FLAG_MASK) != 0;
if (currentlyPaused != paused) {
if (paused) {
flags |= PAUSE_FLAG_MASK;
} else {
flags &= ~PAUSE_FLAG_MASK;
}
observationBufferMetadata[token].flags = flags;
emit PauseStatusChanged(token, paused);
} else {
revert PauseStatusUnchanged(token, paused);
}
}
function areUpdatesPaused(address token) external view virtual returns (bool) {
return _areUpdatesPaused(token);
}
function canUpdate(bytes memory data) public view virtual override returns (bool) {
// Return false if the message sender is missing the required role
if (!hasRole(Roles.ORACLE_UPDATER, address(0)) && !hasRole(Roles.ORACLE_UPDATER, msg.sender)) return false;
address token = abi.decode(data, (address));
if (_areUpdatesPaused(token)) return false;
return super.canUpdate(data);
}
function update(bytes memory data) public virtual override onlyRoleOrOpenRole(Roles.ORACLE_UPDATER) returns (bool) {
address token = abi.decode(data, (address));
if (_areUpdatesPaused(token)) revert UpdatesArePaused(token);
return super.update(data);
}
function quoteTokenDecimals()
public
view
virtual
override(AbstractAggregatorOracle, ManagedAggregatorOracleBase)
returns (uint8)
{
return AbstractAggregatorOracle.quoteTokenDecimals();
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(AccessControlEnumerable, CurrentAggregatorOracle) returns (bool) {
return
AccessControlEnumerable.supportsInterface(interfaceId) ||
CurrentAggregatorOracle.supportsInterface(interfaceId);
}
function _updateThreshold() internal view virtual override returns (uint256) {
return config.updateThreshold;
}
function _updateDelay() internal view virtual override returns (uint256) {
return config.updateDelay;
}
function _heartbeat() internal view virtual override returns (uint256) {
return config.heartbeat;
}
function _minimumResponses(address token) internal view virtual override returns (uint256) {
IOracleAggregatorTokenConfig tokenConfig = tokenConfigs[token];
if (address(tokenConfig) != address(0)) {
return tokenConfig.minimumResponses();
}
return super._minimumResponses(token);
}
function _aggregationStrategy(address token) internal view virtual override returns (IAggregationStrategy) {
IOracleAggregatorTokenConfig tokenConfig = tokenConfigs[token];
if (address(tokenConfig) != address(0)) {
return tokenConfig.aggregationStrategy();
}
return super._aggregationStrategy(token);
}
function _validationStrategy(address token) internal view virtual override returns (IValidationStrategy) {
IOracleAggregatorTokenConfig tokenConfig = tokenConfigs[token];
if (address(tokenConfig) != address(0)) {
return tokenConfig.validationStrategy();
}
return super._validationStrategy(token);
}
function _getOracles(address token) internal view virtual override returns (Oracle[] memory oracles) {
IOracleAggregatorTokenConfig tokenConfig = tokenConfigs[token];
if (address(tokenConfig) != address(0)) {
return tokenConfig.oracles();
}
return super._getOracles(token);
}
function _areUpdatesPaused(address token) internal view virtual returns (bool) {
return (observationBufferMetadata[token].flags & PAUSE_FLAG_MASK) != 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "./ManagedOracleBase.sol";
import "../configs/IOracleAggregatorTokenConfig.sol";
/// @title ManagedAggregatorOracleBase
/// @notice A base contract for aggregators that are managed by access control with support for token-specific
/// configurations.
abstract contract ManagedAggregatorOracleBase is ManagedOracleBase {
uint256 internal constant ERROR_MISSING_ORACLES = 1;
uint256 internal constant ERROR_INVALID_MINIMUM_RESPONSES = 2;
uint256 internal constant ERROR_INVALID_AGGREGATION_STRATEGY = 3;
uint256 internal constant ERROR_DUPLICATE_ORACLES = 4;
uint256 internal constant ERROR_QUOTE_TOKEN_DECIMALS_MISMATCH = 5;
uint256 internal constant ERROR_MINIMUM_RESPONSES_TOO_LARGE = 6;
uint256 internal constant ERROR_INVALID_ORACLE = 7;
/// @notice A mapping of token addresses to their configurations.
mapping(address => IOracleAggregatorTokenConfig) internal tokenConfigs;
/// @notice Emitted when a token's configuration is updated.
/// @param token The token whose configuration was updated.
/// @param oldConfig The old configuration address.
/// @param newConfig The new configuration address.
event TokenConfigUpdated(
address indexed token,
IOracleAggregatorTokenConfig oldConfig,
IOracleAggregatorTokenConfig newConfig
);
error InvalidTokenConfig(IOracleAggregatorTokenConfig config, uint256 errorCode);
/// @notice An error thrown when attempting to set a new token configuration that is the same as the current
/// configuration (using a only shallow check to allow for implementation changes).
/// @dev This is thrown to make it more noticeable when nothing changes. It's probably a mistake.
/// @param token The token whose configuration was unchanged.
/// @param config The unchanged configuration.
error TokenConfigUnchanged(address token, IOracleAggregatorTokenConfig config);
/// @notice Constructs a new ManagedAggregatorOracleBase.
constructor() ManagedOracleBase() {}
/**
* @notice Sets a new configuration for a specific token.
* @dev This configuration is for the strategies, minimum responses, and underlying oracles.
* @param token The token to set the configuration for.
* @param newConfig The new token configuration.
*/
function setTokenConfig(
address token,
IOracleAggregatorTokenConfig newConfig
) external onlyRole(Roles.CONFIG_ADMIN) {
if (address(newConfig) != address(0)) {
IOracleAggregator.Oracle[] memory oracles = newConfig.oracles();
// Validate that newConfig.oracles().length > 0
if (oracles.length == 0) revert InvalidTokenConfig(newConfig, ERROR_MISSING_ORACLES);
// Validate that newConfig.minimumResponses() > 0
uint256 minResponses = newConfig.minimumResponses();
if (minResponses == 0) revert InvalidTokenConfig(newConfig, ERROR_INVALID_MINIMUM_RESPONSES);
if (minResponses > newConfig.oracles().length)
revert InvalidTokenConfig(newConfig, ERROR_MINIMUM_RESPONSES_TOO_LARGE);
// Validate that newConfig.aggregationStrategy() != address(0)
if (address(newConfig.aggregationStrategy()) == address(0))
revert InvalidTokenConfig(newConfig, ERROR_INVALID_AGGREGATION_STRATEGY);
// Validate that there are no duplicate oracles and that no oracle is the zero address
for (uint256 i = 0; i < oracles.length; ++i) {
if (address(oracles[i].oracle) == address(0))
revert InvalidTokenConfig(newConfig, ERROR_INVALID_ORACLE);
for (uint256 j = i + 1; j < oracles.length; ++j) {
if (address(oracles[i].oracle) == address(oracles[j].oracle))
revert InvalidTokenConfig(newConfig, ERROR_DUPLICATE_ORACLES);
}
}
// Validate that the validation strategy's quote token decimals match our quote token decimals
// (if the validation strategy is set)
IValidationStrategy validationStrategy = newConfig.validationStrategy();
if (address(validationStrategy) != address(0)) {
if (validationStrategy.quoteTokenDecimals() != quoteTokenDecimals())
revert InvalidTokenConfig(newConfig, ERROR_QUOTE_TOKEN_DECIMALS_MISMATCH);
}
}
IOracleAggregatorTokenConfig oldConfig = tokenConfigs[token];
// Ensure that the new config is different from the current config
if (oldConfig == newConfig) revert TokenConfigUnchanged(token, newConfig);
tokenConfigs[token] = newConfig;
emit TokenConfigUpdated(token, oldConfig, newConfig);
}
function quoteTokenDecimals() public view virtual returns (uint8);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "./ManagedAggregatorOracleBase.sol";
/// @title ManagedCurrentAggregatorOracleBase
/// @notice A base contract for aggregators that are managed by access control with support for token-specific
/// configurations.
abstract contract ManagedCurrentAggregatorOracleBase is ManagedAggregatorOracleBase {
struct Config {
uint32 updateThreshold;
uint32 updateDelay;
uint32 heartbeat;
}
uint256 internal constant ERROR_UPDATE_DELAY_TOO_HIGH = 100;
uint256 internal constant ERROR_UPDATE_THRESHOLD_ZERO = 101;
uint256 internal constant ERROR_HEARTBEAT_ZERO = 101;
/// @notice Emitted when the configuration is updated.
/// @param oldConfig The old configuration.
/// @param newConfig The new configuration.
event ConfigUpdated(Config oldConfig, Config newConfig);
/// @notice An error thrown when attempting to set an invalid configuration.
/// @param config The invalid configuration.
/// @param errorCode The error code.
error InvalidConfig(Config config, uint256 errorCode);
/// @notice An error thrown when attempting to set a new configuration that is the same as the current
/// configuration.
/// @dev This is thrown to make it more noticeable when nothing changes. It's probably a mistake.
/// @param config The unchanged configuration.
error ConfigUnchanged(Config config);
/// @notice The current configuration for the update threshold, update delay, and heartbeat.
Config internal config;
/// @notice Constructs a new ManagedCurrentAggregatorOracleBase with the given configuration values.
/// @param updateThreshold_ The initial value for the update threshold.
/// @param updateDelay_ The initial value for the update delay.
/// @param heartbeat_ The initial value for the heartbeat.
constructor(uint32 updateThreshold_, uint32 updateDelay_, uint32 heartbeat_) ManagedAggregatorOracleBase() {
config.updateThreshold = updateThreshold_;
config.updateDelay = updateDelay_;
config.heartbeat = heartbeat_;
}
/**
* @notice Sets a new configuration that applies to all tokens.
* @dev This configuration is for the update threshold, update delay, and heartbeat.
* @param newConfig The new config.
* @custom:throws InvalidConfig if the new configuration is invalid.
*/
function setConfig(Config calldata newConfig) external onlyRole(Roles.CONFIG_ADMIN) {
// Ensure that updateDelay is not greater than heartbeat
if (newConfig.updateDelay > newConfig.heartbeat) revert InvalidConfig(newConfig, ERROR_UPDATE_DELAY_TOO_HIGH);
// Ensure that the update threshold is not zero
if (newConfig.updateThreshold == 0) revert InvalidConfig(newConfig, ERROR_UPDATE_THRESHOLD_ZERO);
// Ensure that the heartbeat is not zero
if (newConfig.heartbeat == 0) revert InvalidConfig(newConfig, ERROR_HEARTBEAT_ZERO);
Config memory oldConfig = config;
// Ensure that the new config is different from the current config
if (
oldConfig.updateThreshold == newConfig.updateThreshold &&
oldConfig.updateDelay == newConfig.updateDelay &&
oldConfig.heartbeat == newConfig.heartbeat
) {
revert ConfigUnchanged(newConfig);
}
config = newConfig;
emit ConfigUpdated(oldConfig, newConfig);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@openzeppelin-v4/contracts/access/AccessControlEnumerable.sol";
import "../../access/Roles.sol";
abstract contract ManagedOracleBase is AccessControlEnumerable {
uint16 internal constant PAUSE_FLAG_MASK = 1;
/// @notice Event emitted when the pause status of updates for a token is changed.
/// @param token The token for which the pause status of updates was changed.
/// @param areUpdatesPaused Whether updates are paused for the token.
event PauseStatusChanged(address indexed token, bool areUpdatesPaused);
/// @notice An error that is thrown when we try to change the pause state for a token, but the current pause state
/// is the same as the new pause state.
/// @dev This error is thrown to make it easier to notice when we try to change the pause state but nothing changes.
/// This is useful in preventing human error, in the case that we expect a change when there is none.
/// @param token The token for which we tried to change the pause state.
/// @param paused The pause state we tried to set.
error PauseStatusUnchanged(address token, bool paused);
/// @notice An error that is thrown when updates are paused for a token.
/// @param token The token for which updates are paused.
error UpdatesArePaused(address token);
/// @notice An error thrown when attempting to call a function that requires a certain role.
/// @param account The account that is missing the role.
/// @param role The role that is missing.
error MissingRole(address account, bytes32 role);
constructor() {
initializeRoles();
}
/**
* @notice Modifier to make a function callable only by a certain role. In addition to checking the sender's role,
* `address(0)` 's role is also considered. Granting a role to `address(0)` is equivalent to enabling this role for
* everyone.
* @param role The role to check.
*/
modifier onlyRoleOrOpenRole(bytes32 role) {
if (!hasRole(role, address(0))) {
if (!hasRole(role, msg.sender)) revert MissingRole(msg.sender, role);
}
_;
}
function initializeRoles() internal virtual {
// Setup admin role, setting msg.sender as admin
_setupRole(Roles.ADMIN, msg.sender);
_setRoleAdmin(Roles.ADMIN, Roles.ADMIN);
// CONFIG_ADMIN is managed by ADMIN
_setRoleAdmin(Roles.CONFIG_ADMIN, Roles.ADMIN);
// UPDATER_ADMIN is managed by ADMIN
_setRoleAdmin(Roles.UPDATER_ADMIN, Roles.ADMIN);
// ORACLE_UPDATER is managed by UPDATER_ADMIN
_setRoleAdmin(Roles.ORACLE_UPDATER, Roles.UPDATER_ADMIN);
// UPDATE_PAUSE_ADMIN is managed by ADMIN
_setRoleAdmin(Roles.UPDATE_PAUSE_ADMIN, Roles.ADMIN);
// Hierarchy:
// ADMIN
// - CONFIG_ADMIN
// - UPDATER_ADMIN
// - ORACLE_UPDATER
// - UPDATE_PAUSE_ADMIN
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
import "@adrastia-oracle/adrastia-core/contracts/oracles/IOracleAggregator.sol";
interface IOracleAggregatorTokenConfig {
function aggregationStrategy() external view returns (IAggregationStrategy);
function validationStrategy() external view returns (IValidationStrategy);
function minimumResponses() external view returns (uint256);
function oracles() external view returns (IOracleAggregator.Oracle[] memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_roleMembers[role].remove(account);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.13;
contract AdrastiaVersioning {
string public constant ADRASTIA_CORE_VERSION = "v4.7.1";
string public constant ADRASTIA_PERIPHERY_VERSION = "v4.7.2";
string public constant ADRASTIA_PROTOCOL_VERSION = "v0.1.0";
}{
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"components":[{"internalType":"contract IAggregationStrategy","name":"aggregationStrategy","type":"address"},{"internalType":"contract IValidationStrategy","name":"validationStrategy","type":"address"},{"internalType":"string","name":"quoteTokenName","type":"string"},{"internalType":"address","name":"quoteTokenAddress","type":"address"},{"internalType":"string","name":"quoteTokenSymbol","type":"string"},{"internalType":"uint8","name":"quoteTokenDecimals","type":"uint8"},{"internalType":"uint8","name":"liquidityDecimals","type":"uint8"},{"internalType":"address[]","name":"oracles","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"oracle","type":"address"}],"internalType":"struct AbstractAggregatorOracle.TokenSpecificOracle[]","name":"tokenSpecificOracles","type":"tuple[]"}],"internalType":"struct AbstractAggregatorOracle.AbstractAggregatorOracleParams","name":"params","type":"tuple"},{"internalType":"uint256","name":"updateThreshold_","type":"uint256"},{"internalType":"uint256","name":"updateDelay_","type":"uint256"},{"internalType":"uint256","name":"heartbeat_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"BufferAlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"currentCapacity","type":"uint256"}],"name":"CapacityCannotBeDecreased","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maxCapacity","type":"uint256"}],"name":"CapacityTooLarge","type":"error"},{"inputs":[{"components":[{"internalType":"uint32","name":"updateThreshold","type":"uint32"},{"internalType":"uint32","name":"updateDelay","type":"uint32"},{"internalType":"uint32","name":"heartbeat","type":"uint32"}],"internalType":"struct ManagedCurrentAggregatorOracleBase.Config","name":"config","type":"tuple"}],"name":"ConfigUnchanged","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"minSizeRequired","type":"uint256"}],"name":"InsufficientData","type":"error"},{"inputs":[{"components":[{"internalType":"uint32","name":"updateThreshold","type":"uint32"},{"internalType":"uint32","name":"updateDelay","type":"uint32"},{"internalType":"uint32","name":"heartbeat","type":"uint32"}],"internalType":"struct ManagedCurrentAggregatorOracleBase.Config","name":"config","type":"tuple"},{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"InvalidConfig","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"InvalidIndex","type":"error"},{"inputs":[{"internalType":"contract IOracleAggregatorTokenConfig","name":"config","type":"address"},{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"InvalidTokenConfig","type":"error"},{"inputs":[{"internalType":"uint256","name":"minUpdateDelay","type":"uint256"},{"internalType":"uint256","name":"maxUpdateDelay","type":"uint256"}],"name":"InvalidUpdateDelays","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"MissingRole","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"paused","type":"bool"}],"name":"PauseStatusUnchanged","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"contract IOracleAggregatorTokenConfig","name":"config","type":"address"}],"name":"TokenConfigUnchanged","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"UpdatesArePaused","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"tick","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numDataPoints","type":"uint256"}],"name":"AggregationPerformed","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"updateThreshold","type":"uint32"},{"internalType":"uint32","name":"updateDelay","type":"uint32"},{"internalType":"uint32","name":"heartbeat","type":"uint32"}],"indexed":false,"internalType":"struct ManagedCurrentAggregatorOracleBase.Config","name":"oldConfig","type":"tuple"},{"components":[{"internalType":"uint32","name":"updateThreshold","type":"uint32"},{"internalType":"uint32","name":"updateDelay","type":"uint32"},{"internalType":"uint32","name":"heartbeat","type":"uint32"}],"indexed":false,"internalType":"struct ManagedCurrentAggregatorOracleBase.Config","name":"newConfig","type":"tuple"}],"name":"ConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCapacity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCapacity","type":"uint256"}],"name":"ObservationCapacityIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"capacity","type":"uint256"}],"name":"ObservationCapacityInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"areUpdatesPaused","type":"bool"}],"name":"PauseStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"contract IOracleAggregatorTokenConfig","name":"oldConfig","type":"address"},{"indexed":false,"internalType":"contract IOracleAggregatorTokenConfig","name":"newConfig","type":"address"}],"name":"TokenConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bytes","name":"err","type":"bytes"}],"name":"UpdateError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"UpdateErrorWithReason","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteTokenLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Updated","type":"event"},{"inputs":[],"name":"ADRASTIA_CORE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ADRASTIA_PERIPHERY_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ADRASTIA_PROTOCOL_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"aggregationStrategy","outputs":[{"internalType":"contract IAggregationStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"areUpdatesPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"canUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"changePrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"changeThreshold","type":"uint256"}],"name":"changeThresholdSurpassed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"consult","outputs":[{"internalType":"uint112","name":"price","type":"uint112"},{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxAge","type":"uint256"}],"name":"consult","outputs":[{"internalType":"uint112","name":"price","type":"uint112"},{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"consultLiquidity","outputs":[{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxAge","type":"uint256"}],"name":"consultLiquidity","outputs":[{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxAge","type":"uint256"}],"name":"consultPrice","outputs":[{"internalType":"uint112","name":"price","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"consultPrice","outputs":[{"internalType":"uint112","name":"price","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getLatestObservation","outputs":[{"components":[{"internalType":"uint112","name":"price","type":"uint112"},{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct ObservationLibrary.Observation","name":"observation","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getObservationAt","outputs":[{"components":[{"internalType":"uint112","name":"price","type":"uint112"},{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct ObservationLibrary.Observation","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getObservations","outputs":[{"components":[{"internalType":"uint112","name":"price","type":"uint112"},{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct ObservationLibrary.Observation[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"increment","type":"uint256"}],"name":"getObservations","outputs":[{"components":[{"internalType":"uint112","name":"price","type":"uint112"},{"internalType":"uint112","name":"tokenLiquidity","type":"uint112"},{"internalType":"uint112","name":"quoteTokenLiquidity","type":"uint112"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct ObservationLibrary.Observation[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getObservationsCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getObservationsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getOracles","outputs":[{"components":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint8","name":"priceDecimals","type":"uint8"},{"internalType":"uint8","name":"liquidityDecimals","type":"uint8"}],"internalType":"struct IOracleAggregator.Oracle[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"heartbeat","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maximumResponseAge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"minimumResponses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"needsUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteTokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteTokenName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteTokenSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"updateThreshold","type":"uint32"},{"internalType":"uint32","name":"updateDelay","type":"uint32"},{"internalType":"uint32","name":"heartbeat","type":"uint32"}],"internalType":"struct ManagedCurrentAggregatorOracleBase.Config","name":"newConfig","type":"tuple"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setObservationsCapacity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"contract IOracleAggregatorTokenConfig","name":"newConfig","type":"address"}],"name":"setTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"paused","type":"bool"}],"name":"setUpdatesPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"timeSinceLastUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"update","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"updateThresholdSurpassed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"validationStrategy","outputs":[{"internalType":"contract IValidationStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6102006040526305f5e1006080523480156200001a57600080fd5b5060405162006808380380620068088339810160408190526200003d9162000e9d565b60408401516060850151608086015160a080880151908790526001600160a01b03831660c052600160e052835188948894889488948794879487948b9488948894889488949093909290916200009b90600290602087019062000b48565b508151620000b190600390602085019062000b48565b506001600160a01b039283166101005260ff16610120525060208301511615801591506200015157508060a0015160ff1681602001516001600160a01b03166327624b076040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000125573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200014b91906200102d565b60ff1614155b15620001ca5760405162461bcd60e51b815260206004820152603760248201527f416273747261637441676772656761746f724f7261636c653a2051554f54455f60448201527f544f4b454e5f444543494d414c535f4d49534d4154434800000000000000000060648201526084015b60405180910390fd5b80516001600160a01b03908116610140526020820151166101605260a0810151620001f790600a6200115e565b6101805260c081015160ff166101a05260005b8160e0015151811015620004d557600660008360e0015183815181106200023557620002356200116f565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1615620002ad5760405162461bcd60e51b815260206004820152602a6024820152600080516020620067c88339815191526044820152694154455f4f5241434c4560b01b6064820152608401620001c1565b6001600660008460e001518481518110620002cc57620002cc6200116f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550600460405180606001604052808460e0015184815181106200033157620003316200116f565b60200260200101516001600160a01b031681526020018460e0015184815181106200036057620003606200116f565b60200260200101516001600160a01b03166327624b076040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003a6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003cc91906200102d565b60ff1681526020018460e001518481518110620003ed57620003ed6200116f565b60200260200101516001600160a01b031663bfe1dba86040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200045991906200102d565b60ff90811690915282546001810184556000938452602093849020835191018054948401516040909401518316600160a81b0260ff60a81b1994909316600160a01b026001600160a81b03199095166001600160a01b03909216919091179390931791909116179055620004cd8162001185565b90506200020a565b5060005b81610100015151811015620007ac57600082610100015182815181106200050457620005046200116f565b602090810291909101810151808201516001600160a01b03166000908152600690925260409091205490915060ff1615620005845760405162461bcd60e51b815260206004820152602a6024820152600080516020620067c88339815191526044820152694154455f4f5241434c4560b01b6064820152608401620001c1565b80516001600160a01b039081166000908152600760209081526040808320828601519094168352929052205460ff1615620006045760405162461bcd60e51b815260206004820152602a6024820152600080516020620067c88339815191526044820152694154455f4f5241434c4560b01b6064820152608401620001c1565b80516001600160a01b039081166000908152600760209081526040808320828601805186168552908352818420805460ff1916600117905585518516845260058352928190208151606081018352845186168152935182516327624b0760e01b815292519195858501949116926327624b0792600480830193928290030181865afa15801562000698573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006be91906200102d565b60ff16815260200183602001516001600160a01b031663bfe1dba86040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000709573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200072f91906200102d565b60ff90811690915282546001810184556000938452602093849020835191018054948401516040909401518316600160a81b0260ff60a81b1994909316600160a01b026001600160a81b03199095166001600160a01b0390921691909117939093179190911617905550620007a48162001185565b9050620004d9565b505081811015620007db5760405163e811617b60e01b81526004810183905260248101829052604401620001c1565b6101c0919091526101e05250620007f3905062000861565b600b805463ffffffff9485166001600160401b031990911617640100000000938516939093029290921763ffffffff60401b191668010000000000000000919093160291909117905550508651620008559250600c9150602088019062000b48565b505050505050620011dd565b6200087c600080516020620067e88339815191523362000994565b62000897600080516020620067e883398151915280620009a4565b620008d27fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af600080516020620067e8833981519152620009a4565b6200090c7ef7280a0db925c0d1e88a56cb8ae89369595b41df40ca283519b9b197f5fed0600080516020620067e8833981519152620009a4565b620009577f9792fdc19ab98adfa72ab2fa98d342618c661e01c406979c105b31eda87f5e6f7ef7280a0db925c0d1e88a56cb8ae89369595b41df40ca283519b9b197f5fed0620009a4565b620009927f71a9d0bd0e16f5720ede57dbd96d9c682aa5147a3f584ae2cb6be366f74f8789600080516020620067e8833981519152620009a4565b565b620009a08282620009ef565b5050565b600082815260086020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b62000a06828262000a3260201b620025f81760201c565b600082815260096020908152604090912062000a2d9183906200269a62000ad6821b17901c565b505050565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff16620009a05760008281526008602090815260408083206001600160a01b03851684529091529020805460ff1916600117905562000a923390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000aed836001600160a01b03841662000af6565b90505b92915050565b600081815260018301602052604081205462000b3f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000af0565b50600062000af0565b82805462000b5690620011a1565b90600052602060002090601f01602090048101928262000b7a576000855562000bc5565b82601f1062000b9557805160ff191683800117855562000bc5565b8280016001018555821562000bc5579182015b8281111562000bc557825182559160200191906001019062000ba8565b5062000bd392915062000bd7565b5090565b5b8082111562000bd3576000815560010162000bd8565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171562000c295762000c2962000bee565b60405290565b60405161012081016001600160401b038111828210171562000c295762000c2962000bee565b604051601f8201601f191681016001600160401b038111828210171562000c805762000c8062000bee565b604052919050565b600082601f83011262000c9a57600080fd5b81516001600160401b0381111562000cb65762000cb662000bee565b602062000ccc601f8301601f1916820162000c55565b828152858284870101111562000ce157600080fd5b60005b8381101562000d0157858101830151828201840152820162000ce4565b8381111562000d135760008385840101525b5095945050505050565b6001600160a01b038116811462000d3357600080fd5b50565b805162000d438162000d1d565b919050565b805160ff8116811462000d4357600080fd5b60006001600160401b0382111562000d765762000d7662000bee565b5060051b60200190565b600082601f83011262000d9257600080fd5b8151602062000dab62000da58362000d5a565b62000c55565b82815260059290921b8401810191818101908684111562000dcb57600080fd5b8286015b8481101562000df357805162000de58162000d1d565b835291830191830162000dcf565b509695505050505050565b600082601f83011262000e1057600080fd5b8151602062000e2362000da58362000d5a565b82815260069290921b8401810191818101908684111562000e4357600080fd5b8286015b8481101562000df3576040818903121562000e625760008081fd5b62000e6c62000c04565b815162000e798162000d1d565b81528185015162000e8a8162000d1d565b8186015283529183019160400162000e47565b600080600080600060a0868803121562000eb657600080fd5b85516001600160401b038082111562000ece57600080fd5b62000edc89838a0162000c88565b9650602088015191508082111562000ef357600080fd5b90870190610120828a03121562000f0957600080fd5b62000f1362000c2f565b62000f1e8362000d36565b815262000f2e6020840162000d36565b602082015260408301518281111562000f4657600080fd5b62000f548b82860162000c88565b60408301525062000f686060840162000d36565b606082015260808301518281111562000f8057600080fd5b62000f8e8b82860162000c88565b60808301525062000fa260a0840162000d48565b60a082015262000fb560c0840162000d48565b60c082015260e08301518281111562000fcd57600080fd5b62000fdb8b82860162000d80565b60e083015250610100808401518381111562000ff657600080fd5b620010048c82870162000dfe565b9183019190915250604089015160608a01516080909a0151989b919a5098979650945050505050565b6000602082840312156200104057600080fd5b62000aed8262000d48565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620010a25781600019048211156200108657620010866200104b565b808516156200109457918102915b93841c939080029062001066565b509250929050565b600082620010bb5750600162000af0565b81620010ca5750600062000af0565b8160018114620010e35760028114620010ee576200110e565b600191505062000af0565b60ff8411156200110257620011026200104b565b50506001821b62000af0565b5060208310610133831016604e8410600b841016171562001133575081810a62000af0565b6200113f838362001061565b80600019048211156200115657620011566200104b565b029392505050565b600062000aed60ff841683620010aa565b634e487b7160e01b600052603260045260246000fd5b6000600182016200119a576200119a6200104b565b5060010190565b600181811c90821680620011b657607f821691505b602082108103620011d757634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e0516154f5620012d360003960005050600050506000818161077f0152613003015260005050600061278e015260006138a901526000818161047701528181610ce00152818161121e015281816115670152818161191301528181611a930152612fdf01526000818161074601528181610ca4015281816113d00152818161152b015281816118d701528181611a570152611b380152600081816120a90152818161283201526128930152600061040f015260005050600081816106f4015261405701526154f56000f3fe608060405234801561001057600080fd5b506004361061034c5760003560e01c80639aae129d116101bd578063cd92f13d116100f9578063e5a7b1ef116100a2578063f368c0431161007c578063f368c043146108a0578063f8d0b6c8146108b3578063fb5e8315146108c6578063fc46c859146108d957600080fd5b8063e5a7b1ef14610867578063ee7b54741461087a578063f2f5c8e71461088d57600080fd5b8063e06df80b116100d3578063e06df80b14610837578063e25437421461083f578063e3e717e91461084757600080fd5b8063cd92f13d146107fe578063d47ba53814610811578063d547741f1461082457600080fd5b8063afbe528211610166578063bfe1dba811610140578063bfe1dba81461077d578063c14ce674146107a3578063c43ed2c8146107d8578063ca15c873146107eb57600080fd5b8063afbe528214610731578063bad3462014610744578063bdbdf2851461076a57600080fd5b80639f6024d8116101975780639f6024d8146106ef578063a217fddf14610716578063ab54b64d1461071e57600080fd5b80639aae129d1461068d5780639b4a95e0146106c95780639b7405d3146106dc57600080fd5b806336568abe1161028c5780636d6a08c2116102355780638e7492811161020f5780638e749281146106195780639010d07c1461063957806391d148541461064c5780639407f5cb1461068557600080fd5b80636d6a08c2146105d35780638194fe9e146105f3578063820a16801461060657600080fd5b80634fd23d2d116102665780634fd23d2d1461057f578063554f94db1461059257806357611cac146105a857600080fd5b806336568abe1461053f5780633ddac953146105525780633defb9621461056557600080fd5b8063234398bd116102f9578063283583c6116102d3578063283583c6146104a95780632f2ff15d146104e6578063343e2874146104f957806335a0bf5c1461050c57600080fd5b8063234398bd14610431578063248a9ca31461044457806327624b071461047557600080fd5b80630d6f01f31161032a5780630d6f01f3146103b95780630e6159db146103ce578063217a4b701461040a57600080fd5b806301ffc9a71461035157806306fdde03146103795780630ac900421461038e575b600080fd5b61036461035f36600461478c565b610915565b60405190151581526020015b60405180910390f35b610381610935565b6040516103709190614812565b6103a161039c36600461483a565b6109c3565b6040516001600160a01b039091168152602001610370565b6103cc6103c7366004614857565b6109ce565b005b6103816040518060400160405280600681526020017f76342e372e31000000000000000000000000000000000000000000000000000081525081565b6103a17f000000000000000000000000000000000000000000000000000000000000000081565b61036461043f366004614960565b610c84565b610467610452366004614995565b60009081526008602052604090206001015490565b604051908152602001610370565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff9091168152602001610370565b6104bc6104b736600461483a565b610c9e565b604080516001600160701b0394851681529284166020840152921691810191909152606001610370565b6103cc6104f43660046149ae565b610da5565b6103cc6105073660046149de565b610dcf565b61051f61051a36600461483a565b6113cb565b604080516001600160701b03938416815292909116602083015201610370565b6103cc61054d3660046149ae565b611499565b6104bc610560366004614857565b611525565b600b5468010000000000000000900463ffffffff16610467565b6103cc61058d366004614a0c565b6116ad565b600b54640100000000900463ffffffff16610467565b6105bb6105b6366004614857565b6118d3565b6040516001600160701b039091168152602001610370565b6105e66105e1366004614857565b611a3c565b6040516103709190614a1e565b6105bb61060136600461483a565b611a53565b61051f610614366004614857565b611b33565b61062c61062736600461483a565b611c86565b6040516103709190614aa2565b6103a1610647366004614b0b565b611c91565b61036461065a3660046149ae565b60009182526008602090815260408084206001600160a01b0393909316845291905290205460ff1690565b610467611ca9565b6103816040518060400160405280600681526020017f76302e312e30000000000000000000000000000000000000000000000000000081525081565b6103646106d7366004614960565b611cba565b6103646106ea36600461483a565b611d17565b6104677f000000000000000000000000000000000000000000000000000000000000000081565b610467600081565b6103cc61072c366004614b3b565b611d46565b61046761073f366004614960565b611e8f565b7f00000000000000000000000000000000000000000000000000000000000000006103a1565b610467610778366004614960565b611ea4565b7f0000000000000000000000000000000000000000000000000000000000000000610497565b6104676107b136600461483a565b6001600160a01b0316600090815260208190526040902054640100000000900461ffff1690565b6103646107e6366004614960565b611ed7565b6104676107f9366004614995565b612044565b6105e661080c366004614b69565b61205b565b61046761081f36600461483a565b612074565b6103cc6108323660046149ae565b6120ce565b6103816120f3565b6103816120fd565b61085a610855366004614857565b612107565b6040516103709190614ba4565b61046761087536600461483a565b61232a565b610364610888366004614be8565b612335565b61046761089b36600461483a565b6123ce565b61085a6108ae36600461483a565b6123d9565b6103a16108c136600461483a565b6124f7565b6103646108d4366004614960565b612502565b6103816040518060400160405280600681526020017f76342e372e32000000000000000000000000000000000000000000000000000081525081565b6000610920826126af565b8061092f575061092f826126ed565b92915050565b600c805461094290614c2d565b80601f016020809104026020016040519081016040528092919081815260200182805461096e90614c2d565b80156109bb5780601f10610990576101008083540402835291602001916109bb565b820191906000526020600020905b81548152906001019060200180831161099e57829003601f168201915b505050505081565b600061092f82612707565b6001600160a01b038216600090815260208190526040812080549091660100000000000090910461ffff169003610a0857610a08836127b2565b80546601000000000000900461ffff16821015610a7e5780546040517f82f747b50000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101849052660100000000000090910461ffff1660448201526064015b60405180910390fd5b61ffff821115610ad4576040517f35a0bb670000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810183905261ffff6044820152606401610a75565b6001600160a01b03831660009081526001602052604081208254909190610b09906601000000000000900461ffff1685614c77565b905060005b81811015610bdc5760408051608081018252600180825260208083018281529383018281526060840183815288548085018a5560008a81529390932094516002909302909401805495516001600160701b039081166e0100000000000000000000000000009081026001600160e01b031990981694821694909417969096178155905192018054935163ffffffff169091027fffffffffffffffffffffffffffff0000000000000000000000000000000000009093169190931617179055610bd581614c8e565b9050610b0e565b5082546601000000000000900461ffff168414610c7d57825460408051660100000000000090920461ffff168252602082018690526001600160a01b038716917fcc3b38181883e2a866ba9fc2e4a8e9c79315090f9e0f219887a547c4329ea4cb910160405180910390a282547fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff16660100000000000061ffff8616021783555b5050505050565b600061092f82610888600b5463ffffffff1690565b905090565b600080807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031603610d1457610d067f0000000000000000000000000000000000000000000000000000000000000000600a614d8c565b600080925092509250610d9e565b6000610d1f856123d9565b9050806060015163ffffffff16600003610d875760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b806000015193508060200151925080604001519150505b9193909250565b600082815260086020526040902060010154610dc081612905565b610dca8383612912565b505050565b7fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af610df981612905565b6001600160a01b038216156112d9576000826001600160a01b0316632857373a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e48573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e709190810190614db1565b90508051600003610ea65760405163108a7c4960e01b81526001600160a01b038416600482015260016024820152604401610a75565b6000836001600160a01b03166354bcd7ff6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0a9190614ea5565b905080600003610f3f5760405163108a7c4960e01b81526001600160a01b038516600482015260026024820152604401610a75565b836001600160a01b0316632857373a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fa59190810190614db1565b51811115610fd85760405163108a7c4960e01b81526001600160a01b038516600482015260066024820152604401610a75565b60006001600160a01b0316846001600160a01b0316636ae5cec26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611021573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110459190614ebe565b6001600160a01b03160361107e5760405163108a7c4960e01b81526001600160a01b038516600482015260036024820152604401610a75565b60005b82518110156111a65760006001600160a01b03168382815181106110a7576110a7614edb565b6020026020010151600001516001600160a01b0316036110ec5760405163108a7c4960e01b81526001600160a01b038616600482015260076024820152604401610a75565b60006110f9826001614ef1565b90505b83518110156111955783818151811061111757611117614edb565b6020026020010151600001516001600160a01b031684838151811061113e5761113e614edb565b6020026020010151600001516001600160a01b0316036111855760405163108a7c4960e01b81526001600160a01b0387166004828101919091526024820152604401610a75565b61118e81614c8e565b90506110fc565b5061119f81614c8e565b9050611081565b506000846001600160a01b0316631d0e44606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120b9190614ebe565b90506001600160a01b038116156112d5577f000000000000000000000000000000000000000000000000000000000000000060ff16816001600160a01b03166327624b076040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a29190614f09565b60ff16146112d55760405163108a7c4960e01b81526001600160a01b038616600482015260056024820152604401610a75565b5050505b6001600160a01b038084166000908152600a602052604090205481169083168103611343576040517f80336a320000000000000000000000000000000000000000000000000000000081526001600160a01b03808616600483015284166024820152604401610a75565b6001600160a01b038481166000818152600a602090815260409182902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016888616908117909155825194861685529084015290917f2aad6d1b86aa2648ffd8f6850ce9fa7c364ceddae29234268102a5ffed873b3d910160405180910390a250505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03160361141257506000928392509050565b600061141d846123d9565b9050806060015163ffffffff166000036114855760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b806020015192508060400151915050915091565b6001600160a01b03811633146115175760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610a75565b6115218282612934565b5050565b600080807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b03160361159b5761158d7f0000000000000000000000000000000000000000000000000000000000000000600a614d8c565b6000809250925092506116a6565b836000036115b7576115ac85612956565b9250925092506116a6565b60006115c2866123d9565b9050806060015163ffffffff1660000361162a5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b84816060015163ffffffff166116409190614ef1565b42111561168f5760405162461bcd60e51b815260206004820152601c60248201527f41627374726163744f7261636c653a20524154455f544f4f5f4f4c44000000006044820152606401610a75565b806000015193508060200151925080604001519150505b9250925092565b7fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af6116d781612905565b6116e76060830160408401614f36565b63ffffffff166116fd6040840160208501614f36565b63ffffffff161115611727578160646040516378ceac6f60e01b8152600401610a75929190614f9c565b6117346020830183614f36565b63ffffffff1660000361175f578160656040516378ceac6f60e01b8152600401610a75929190614f9c565b61176f6060830160408401614f36565b63ffffffff1660000361179a578160656040516378ceac6f60e01b8152600401610a75929190614f9c565b60408051606081018252600b5463ffffffff808216835264010000000082048116602080850191909152680100000000000000009092041692820192909252906117e690840184614f36565b63ffffffff16816000015163ffffffff16148015611822575061180f6040840160208501614f36565b63ffffffff16816020015163ffffffff16145b801561184c57506118396060840160408501614f36565b63ffffffff16816040015163ffffffff16145b1561188557826040517f6c90ab44000000000000000000000000000000000000000000000000000000008152600401610a759190614fb7565b82600b6118928282614fc5565b9050507fd8a61dbcfb5d6c4bf580fec4f5edcbabfedb79848780c5a08783b258349710d981846040516118c6929190615084565b60405180910390a1505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603611940576119397f0000000000000000000000000000000000000000000000000000000000000000600a614d8c565b905061092f565b8160000361195c5761195183612956565b5090915061092f9050565b6000611967846123d9565b9050806060015163ffffffff166000036119cf5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b82816060015163ffffffff166119e59190614ef1565b421115611a345760405162461bcd60e51b815260206004820152601c60248201527f41627374726163744f7261636c653a20524154455f544f4f5f4f4c44000000006044820152606401610a75565b519392505050565b6060611a4c838360006001612a0b565b9392505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031603611ab95761092f7f0000000000000000000000000000000000000000000000000000000000000000600a614d8c565b6000611ac4836123d9565b9050806060015163ffffffff16600003611b2c5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b5192915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031603611b7a57506000905080611c7f565b82600003611b9757611b8b84612956565b9093509150611c7f9050565b6000611ba2856123d9565b9050806060015163ffffffff16600003611c0a5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b83816060015163ffffffff16611c209190614ef1565b421115611c6f5760405162461bcd60e51b815260206004820152601c60248201527f41627374726163744f7261636c653a20524154455f544f4f5f4f4c44000000006044820152606401610a75565b8060200151925080604001519150505b9250929050565b606061092f82612d9c565b6000828152600960205260408120611a4c9083612e2f565b6000610c99600b5463ffffffff1690565b600080611cc683611e8f565b600b54909150640100000000900463ffffffff16811015611cea5750600092915050565b600b5468010000000000000000900463ffffffff168110611d0e5750600192915050565b611a4c83610c84565b6001600160a01b038116600090815260208190526040812054680100000000000000009004600116151561092f565b7f71a9d0bd0e16f5720ede57dbd96d9c682aa5147a3f584ae2cb6be366f74f8789611d7081612905565b6001600160a01b03831660009081526020819052604090205468010000000000000000900461ffff81169060011615158315158114611e4a578315611dba57600182179150611dc2565b600119821691505b6001600160a01b0385166000818152602081815260409182902080547fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff166801000000000000000061ffff881602179055905186151581527f06c32dc5449a43f80c90d607b256e2d2ce23677068c6edd70ef64297053a247d910160405180910390a2610c7d565b6040517f701455670000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201528415156024820152604401610a75565b6000611e9a82611ea4565b61092f9042614c77565b60008082806020019051810190611ebb9190614ebe565b9050611ec6816123d9565b6060015163ffffffff169392505050565b60008080527fff854284463209d6bcc2eef3b33c69d39b62bf9f40ef94df8bdd0b45a566e9a16020527fb80d84a45535a249aaaa06f547327bc7aa3214dace3852eb6dcdba1ff6720e13547f9792fdc19ab98adfa72ab2fa98d342618c661e01c406979c105b31eda87f5e6f9060ff16611fa757600081815260086020908152604080832033845290915290205460ff16611fa7576040517f0161a64a00000000000000000000000000000000000000000000000000000000815233600482015260248101829052604401610a75565b600083806020019051810190611fbd9190614ebe565b9050611fef816001600160a01b0316600090815260208190526040902054680100000000000000009004600116151590565b15612031576040517fd3f2201a0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610a75565b61203a84612e3b565b9250505b50919050565b600081815260096020526040812061092f90612e5c565b606061206985858585612a0b565b90505b949350505050565b6001600160a01b0381166000908152602081905260408120546601000000000000900461ffff1680820361092f57505061ffff7f000000000000000000000000000000000000000000000000000000000000000016919050565b6000828152600860205260409020600101546120e981612905565b610dca8383612934565b6060610c99612e66565b6060610c99612ef8565b6040805160808101825260008082526020820181905291810182905260608101919091526001600160a01b03831660009081526020818152604091829020825160e081018452905461ffff808216835262010000820481169383019390935264010000000081048316938201849052660100000000000081048316606083015268010000000000000000810490921660808201526a010000000000000000000082046001600160701b031660a0820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1660c082015290831061223e5760408082015190517f3a2a4a0b0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810185905261ffff9091166044820152606401610a75565b600083826020015161ffff16106122685783826020015161ffff166122639190614c77565b61228b565b838260400151836020015161227d91906150bd565b61ffff1661228b9190614c77565b6001600160a01b0386166000908152600160205260409020805491925090829081106122b9576122b9614edb565b60009182526020918290206040805160808101825260029390930290910180546001600160701b0380821685526e010000000000000000000000000000918290048116958501959095526001909101549384169183019190915290910463ffffffff16606082015295945050505050565b600061092f82612f07565b6000808380602001905181019061234c9190614ebe565b9050600061235982612f93565b90506000806123688484612fb7565b91509150600061237785612f07565b90508082101561238f5760009550505050505061092f565b600061239a866123d9565b90506123c184600001516001600160701b031682600001516001600160701b03168a61381d565b9998505050505050505050565b600061092f82612f93565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b0385168252819052918220805491929091640100000000900461ffff169003612452575050604080516080810182526000808252602082018190529181018290526060810191909152919050565b6001600160a01b0383166000908152600160205260409020815481546201000090910461ffff1690811061248857612488614edb565b60009182526020918290206040805160808101825260029390930290910180546001600160701b0380821685526e010000000000000000000000000000918290048116958501959095526001909101549384169183019190915290910463ffffffff1660608201529392505050565b600061092f82613846565b60008080527fff854284463209d6bcc2eef3b33c69d39b62bf9f40ef94df8bdd0b45a566e9a16020527fb80d84a45535a249aaaa06f547327bc7aa3214dace3852eb6dcdba1ff6720e135460ff1615801561258c57503360009081527fff854284463209d6bcc2eef3b33c69d39b62bf9f40ef94df8bdd0b45a566e9a1602052604090205460ff16155b1561259957506000919050565b6000828060200190518101906125af9190614ebe565b90506125e1816001600160a01b0316600090815260208190526040902054680100000000000000009004600116151590565b156125ef5750600092915050565b611a4c836138cd565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff166115215760008281526008602090815260408083206001600160a01b03851684529091529020805460ff191660011790556126563390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611a4c836001600160a01b038416613925565b60006001600160e01b031982167f5a05180f00000000000000000000000000000000000000000000000000000000148061092f575061092f82613974565b60006126f8826139db565b8061092f575061092f82613a5d565b6001600160a01b038082166000908152600a6020526040812054909116801561278c57806001600160a01b0316631d0e44606040518163ffffffff1660e01b8152600401602060405180830381865afa158015612768573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c9190614ebe565b7f0000000000000000000000000000000000000000000000000000000000000000611a4c565b6001600160a01b0381166000908152600160205260409020541561280d576040517f1690fa400000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610a75565b6001600160a01b0381166000908152602081815260408083206001909252822090915b7f000000000000000000000000000000000000000000000000000000000000000061ffff168110156128785781546001018255600082905261287181614c8e565b9050612830565b50815467ffffffffffffffff1916660100000000000061ffff7f0000000000000000000000000000000000000000000000000000000000000000811682029290921780855560405191900490911681526001600160a01b038416907fc4913fc151d71f6929a713bd2f607375acc4e952a83c8b69a4b04362d735cbd29060200160405180910390a2505050565b61290f8133613b03565b50565b61291c82826125f8565b6000828152600960205260409020610dca908261269a565b61293e8282613b83565b6000828152600960205260409020610dca9082613c06565b6000806000806000612969866000612fb7565b91509150600061297887612f07565b9050808210156129f05760405162461bcd60e51b815260206004820152603360248201527f416273747261637441676772656761746f724f7261636c653a20494e56414c4960448201527f445f4e554d5f434f4e53554c544154494f4e53000000000000000000000000006064820152608401610a75565b50508051602082015160409092015190969195509350915050565b606083600003612a67576040805160008082526020820190925290612a5f565b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181612a2b5790505b50905061206c565b6001600160a01b03851660009081526020818152604091829020825160e081018452905461ffff80821683526201000082048116938301939093526401000000008104831693820193909352660100000000000083048216606082015268010000000000000000830490911660808201526a010000000000000000000082046001600160701b031660a0820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1660c08201528383612b2d600188614c77565b612b3791906150e3565b612b419190614ef1565b816040015161ffff1611612bd057604081015186908585612b6360018a614c77565b612b6d91906150e3565b612b779190614ef1565b612b82906001614ef1565b6040517f50a48eae0000000000000000000000000000000000000000000000000000000081526001600160a01b03909316600484015261ffff90911660248301526044820152606401610a75565b60008567ffffffffffffffff811115612beb57612beb614883565b604051908082528060200260200182016040528015612c3d57816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181612c095790505b50905060008086846020015161ffff1610612c6b5786846020015161ffff16612c669190614c77565b612c8e565b8684604001518560200151612c8091906150bd565b61ffff16612c8e9190614c77565b90505b87821015612d8f576001600160a01b0389166000908152600160205260409020805482908110612cc357612cc3614edb565b60009182526020918290206040805160808101825260029390930290910180546001600160701b0380821685526e010000000000000000000000000000918290048116958501959095526001909101549384169183019190915290910463ffffffff1660608201528383612d3681614c8e565b945081518110612d4857612d48614edb565b6020026020010181905250858110612d6957612d648682614c77565b612d88565b85846040015161ffff1682612d7e9190614ef1565b612d889190614c77565b9050612c91565b5090979650505050505050565b6001600160a01b038082166000908152600a6020526040902054606091168015612e2657806001600160a01b0316632857373a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612dfe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a4c9190810190614db1565b611a4c83613c1b565b6000611a4c8383613eaf565b6000612e4682611cba565b15612e545761092f82613ed9565b506000919050565b600061092f825490565b606060038054612e7590614c2d565b80601f0160208091040260200160405190810160405280929190818152602001828054612ea190614c2d565b8015612eee5780601f10612ec357610100808354040283529160200191612eee565b820191906000526020600020905b815481529060010190602001808311612ed157829003601f168201915b5050505050905090565b606060028054612e7590614c2d565b6001600160a01b038082166000908152600a60205260408120549091168015612f8c57806001600160a01b03166354bcd7ff6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c9190614ea5565b6001611a4c565b600b5460009068010000000000000000900463ffffffff1661092f90610708614ef1565b60408051608081018252600080825260208201819052918101829052606081018290529060ff7f00000000000000000000000000000000000000000000000000000000000000008116907f0000000000000000000000000000000000000000000000000000000000000000168261302d87612d9c565b90506000815167ffffffffffffffff81111561304b5761304b614883565b6040519080825280602002602001820160405280156130b157816020015b60408051606080820183526000828401818152835283516080810185528181526020808201839052948101829052918201528282015282526000199092019101816130695790505b5090506000806000806130c38c612707565b905060005b865181101561365e578681815181106130e3576130e3614edb565b6020908102919091010151516040517f3ddac9530000000000000000000000000000000000000000000000000000000081526001600160a01b038f81166004830152602482018f905290911690633ddac95390604401606060405180830381865afa925050508015613172575060408051601f3d908101601f1916820190925261316f91810190615119565b60015b6131db5761317e61515c565b806308c379a0036131a35750613192615178565b8061319d57506131a5565b5061364e565b505b3d8080156131cf576040519150601f19603f3d011682016040523d82523d6000602084013e6131d4565b606091505b505061364e565b6001600160701b03928316975090821695501692508887828151811061320357613203614edb565b60200260200101516020015160ff16101561326557600087828151811061322c5761322c614edb565b60200260200101516020015160ff168a6132469190614c77565b61325190600a615220565b905061325d81876150e3565b9550506132d6565b8887828151811061327857613278614edb565b60200260200101516020015160ff1611156132d6576000898883815181106132a2576132a2614edb565b60200260200101516020015160ff166132bb9190614c77565b6132c690600a615220565b90506132d28187615242565b9550505b878782815181106132e9576132e9614edb565b60200260200101516040015160ff16101561335757600087828151811061331257613312614edb565b60200260200101516040015160ff168961332c9190614c77565b61333790600a615220565b905061334381866150e3565b945061334f81856150e3565b9350506133d4565b8787828151811061336a5761336a614edb565b60200260200101516040015160ff1611156133d45760008888838151811061339457613394614edb565b60200260200101516040015160ff166133ad9190614c77565b6133b890600a615220565b90506133c48186615242565b94506133d08185615242565b9350505b6001600160701b0385118015906133f257506001600160701b038411155b801561340557506001600160701b038311155b1561364e5760408051606080820183526000828401818152835283516080810185528181526020808201839052948101829052918201529181019190915260008e60405160200161346591906001600160a01b0391909116815260200190565b6040516020818303038152906040529050600089848151811061348a5761348a614edb565b6020026020010151600001516001600160a01b031663bdbdf285836040518263ffffffff1660e01b81526004016134c19190614812565b602060405180830381865afa1580156134de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135029190614ea5565b9050604051806040016040528060405180602001604052808d888151811061352c5761352c614edb565b6020026020010151600001516001600160a01b0316815250815260200160405180608001604052808b6001600160701b031681526020018a6001600160701b03168152602001896001600160701b031681526020018463ffffffff168152508152509250505060006001600160a01b0316836001600160a01b0316148061361d5750826001600160a01b031663950ee1e28f836040518363ffffffff1660e01b81526004016135dc9291906152ac565b602060405180830381865afa1580156135f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061361d91906152c9565b1561364c5780878c61362e81614c8e565b9d508151811061364057613640614edb565b60200260200101819052505b505b61365781614c8e565b90506130c8565b508860000361369c575050604080516080810182526000808252602082018190529181018290526060810182905298509650611c7f95505050505050565b6136a58c613846565b6001600160a01b031663bef24ea38d8760006136c260018f614c77565b6040518563ffffffff1660e01b81526004016136e194939291906152e6565b608060405180830381865afa1580156136fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137229190615350565b99506001600160a01b0381161561380e57600060405180604001604052806040518060200160405280306001600160a01b031681525081526020018c8152509050816001600160a01b031663950ee1e28e836040518363ffffffff1660e01b81526004016137919291906152ac565b602060405180830381865afa1580156137ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d291906152c9565b61380c575050604080516080810182526000808252602082018190529181018290526060810182905299509750611c7f9650505050505050565b505b50505050505050509250929050565b600080600061382c868661401c565b91509150808061383c5750838210155b9695505050505050565b6001600160a01b038082166000908152600a602052604081205490911680156138a757806001600160a01b0316636ae5cec26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612768573d6000803e3d6000fd5b7f0000000000000000000000000000000000000000000000000000000000000000611a4c565b60006138d882611cba565b6138e457506000919050565b6000828060200190518101906138fa9190614ebe565b905060006139108261390b84612f93565b612fb7565b91505061391c82612f07565b11159392505050565b600081815260018301602052604081205461396c5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561092f565b50600061092f565b60006001600160e01b031982167f7965db0b00000000000000000000000000000000000000000000000000000000148061092f57507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b031983161461092f565b60006001600160e01b031980831690036139f757506000919050565b6001600160e01b031982167faeff306300000000000000000000000000000000000000000000000000000000148061092f57506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60006001600160e01b031982167f5b47aca9000000000000000000000000000000000000000000000000000000001480613ac057506001600160e01b031982167f6b3f5d0300000000000000000000000000000000000000000000000000000000145b80613af457507f9f88c26e000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b8061092f575061092f826140ac565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff1661152157613b41816001600160a01b031660146141af565b613b4c8360206141af565b604051602001613b5d9291906153cf565b60408051601f198184030181529082905262461bcd60e51b8252610a7591600401614812565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff16156115215760008281526008602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611a4c836001600160a01b0384166143d8565b606060006004805480602002602001604051908101604052809291908181526020016000905b82821015613cbb57600084815260209081902060408051606081018252918501546001600160a01b038116835260ff74010000000000000000000000000000000000000000820481168486015275010000000000000000000000000000000000000000009091041690820152825260019092019101613c41565b5050506001600160a01b03851660009081526005602090815260408083208054825181850281018501909352808352959650929490935090849084015b82821015613d7257600084815260209081902060408051606081018252918501546001600160a01b038116835260ff74010000000000000000000000000000000000000000820481168486015275010000000000000000000000000000000000000000009091041690820152825260019092019101613cf8565b50508451835193945092915060009050613d8c8284614ef1565b67ffffffffffffffff811115613da457613da4614883565b604051908082528060200260200182016040528015613def57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181613dc25790505b50905060005b83811015613e4557858181518110613e0f57613e0f614edb565b6020026020010151828281518110613e2957613e29614edb565b602002602001018190525080613e3e90614c8e565b9050613df5565b5060005b82811015613ea457848181518110613e6357613e63614edb565b6020026020010151828286613e789190614ef1565b81518110613e8857613e88614edb565b602002602001018190525080613e9d90614c8e565b9050613e49565b509695505050505050565b6000826000018281548110613ec657613ec6614edb565b9060005260206000200154905092915050565b600080600083806020019051810190613ef29190614ebe565b9050600080613f048361390b85612f93565b91509150613f1183612f07565b8110613f715742836001600160a01b03167f14a871ab15e169a114a18fffaac6d4992e7035193d8410862d72b9ee39b04b2383604051613f5391815260200190565b60405180910390a3613f6583836144cb565b50600195945050505050565b826001600160a01b0316306001600160a01b03167f3e930f884cdf7675c76ade43623c05ac440890e8f5f9e6a281bfb483dd9feb0c60405161400a9060208082526033908201527f416273747261637441676772656761746f724f7261636c653a20494e56414c4960408201527f445f4e554d5f434f4e53554c544154494f4e5300000000000000000000000000606082015260800190565b60405180910390a35091949350505050565b6000808284101561402b579192915b8360000361403e57506000905080611c7f565b826000036140525750600090506001611c7f565b8284037f000000000000000000000000000000000000000000000000000000000000000081028181101561408f5760006001935093505050611c7f565b84818161409e5761409e61522c565b049660009650945050505050565b60006001600160e01b031982167faa0e913d00000000000000000000000000000000000000000000000000000000148061410f57506001600160e01b031982167fb629643a00000000000000000000000000000000000000000000000000000000145b8061414357506001600160e01b031982167fd6f5e23200000000000000000000000000000000000000000000000000000000145b8061417757506001600160e01b031982167fb7aaa9dc00000000000000000000000000000000000000000000000000000000145b8061092f57507f9f88c26e000000000000000000000000000000000000000000000000000000006001600160e01b031983161461092f565b606060006141be8360026150e3565b6141c9906002614ef1565b67ffffffffffffffff8111156141e1576141e1614883565b6040519080825280601f01601f19166020018201604052801561420b576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061424257614242614edb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106142a5576142a5614edb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006142e18460026150e3565b6142ec906001614ef1565b90505b6001811115614389577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061432d5761432d614edb565b1a60f81b82828151811061434357614343614edb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361438281615450565b90506142ef565b508315611a4c5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a75565b600081815260018301602052604081205480156144c15760006143fc600183614c77565b855490915060009061441090600190614c77565b905081811461447557600086600001828154811061443057614430614edb565b906000526020600020015490508087600001848154811061445357614453614edb565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061448657614486615467565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061092f565b600091505061092f565b6001600160a01b03821660009081526020819052604081208054909164010000000090910461ffff16900361451f5780546601000000000000900461ffff1660000361451a5761451a836127b2565b614584565b805461ffff6601000000000000820481169161454491620100009091041660016150bd565b61454e919061547d565b815461ffff9190911662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff9091161781555b6001600160a01b03831660009081526001602052604090208154815484929162010000900461ffff169081106145bc576145bc614edb565b60009182526020918290208351600292909202018054848401516001600160701b039384166001600160e01b0319909216919091176e0100000000000000000000000000009184168202178255604080860151600190930180546060978801519486167fffffffffffffffffffffffffffff0000000000000000000000000000000000009091161763ffffffff909416909202929092179055855186840151878301518351928516835290841694820194909452929091169082015242918101919091526001600160a01b038416907ffc74cea824f39db3e95982ad65b1fdb44455998f02934dfd18b83e32b81426d79060800160405180910390a2805461ffff660100000000000082048116640100000000909204161080156146f55750805462010000810461ffff90811664010000000090920416145b15614734578054640100000000900461ffff168160046147148361549e565b91906101000a81548161ffff021916908361ffff16021790555050505050565b805461ffff6401000000008204811691614750911660016150bd565b61475a919061547d565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff919091161790555050565b60006020828403121561479e57600080fd5b81356001600160e01b031981168114611a4c57600080fd5b60005b838110156147d15781810151838201526020016147b9565b838111156147e0576000848401525b50505050565b600081518084526147fe8160208601602086016147b6565b601f01601f19169290920160200192915050565b602081526000611a4c60208301846147e6565b6001600160a01b038116811461290f57600080fd5b60006020828403121561484c57600080fd5b8135611a4c81614825565b6000806040838503121561486a57600080fd5b823561487581614825565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6060810181811067ffffffffffffffff821117156148b9576148b9614883565b60405250565b601f19601f830116810181811067ffffffffffffffff821117156148e5576148e5614883565b6040525050565b600082601f8301126148fd57600080fd5b813567ffffffffffffffff81111561491757614917614883565b60405161492e6020601f19601f85011601826148bf565b81815284602083860101111561494357600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561497257600080fd5b813567ffffffffffffffff81111561498957600080fd5b61206c848285016148ec565b6000602082840312156149a757600080fd5b5035919050565b600080604083850312156149c157600080fd5b8235915060208301356149d381614825565b809150509250929050565b600080604083850312156149f157600080fd5b82356149fc81614825565b915060208301356149d381614825565b60006060828403121561203e57600080fd5b6020808252825182820181905260009190848201906040850190845b81811015614a9657614a838385516001600160701b038082511683528060208301511660208401528060408301511660408401525063ffffffff60608201511660608301525050565b9284019260809290920191600101614a3a565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b82811015614afe57815180516001600160a01b031685528681015160ff9081168887015290860151168585015260609093019290850190600101614abf565b5091979650505050505050565b60008060408385031215614b1e57600080fd5b50508035926020909101359150565b801515811461290f57600080fd5b60008060408385031215614b4e57600080fd5b8235614b5981614825565b915060208301356149d381614b2d565b60008060008060808587031215614b7f57600080fd5b8435614b8a81614825565b966020860135965060408601359560600135945092505050565b6080810161092f82846001600160701b038082511683528060208301511660208401528060408301511660408401525063ffffffff60608201511660608301525050565b60008060408385031215614bfb57600080fd5b823567ffffffffffffffff811115614c1257600080fd5b614c1e858286016148ec565b95602094909401359450505050565b600181811c90821680614c4157607f821691505b60208210810361203e57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082821015614c8957614c89614c61565b500390565b60006000198203614ca157614ca1614c61565b5060010190565b600181815b80851115614ce3578160001904821115614cc957614cc9614c61565b80851615614cd657918102915b93841c9390800290614cad565b509250929050565b600082614cfa5750600161092f565b81614d075750600061092f565b8160018114614d1d5760028114614d2757614d43565b600191505061092f565b60ff841115614d3857614d38614c61565b50506001821b61092f565b5060208310610133831016604e8410600b8410161715614d66575081810a61092f565b614d708383614ca8565b8060001904821115614d8457614d84614c61565b029392505050565b6000611a4c60ff841683614ceb565b805160ff81168114614dac57600080fd5b919050565b60006020808385031215614dc457600080fd5b825167ffffffffffffffff80821115614ddc57600080fd5b818501915085601f830112614df057600080fd5b815181811115614e0257614e02614883565b604091508151614e17858360051b01826148bf565b818152606091820284018501918582019089841115614e3557600080fd5b948601945b83861015614e975780868b031215614e525760008081fd5b8451614e5d81614899565b8651614e6881614825565b8152614e75878901614d9b565b88820152614e84868801614d9b565b8187015282529485019490860190614e3a565b509098975050505050505050565b600060208284031215614eb757600080fd5b5051919050565b600060208284031215614ed057600080fd5b8151611a4c81614825565b634e487b7160e01b600052603260045260246000fd5b60008219821115614f0457614f04614c61565b500190565b600060208284031215614f1b57600080fd5b611a4c82614d9b565b63ffffffff8116811461290f57600080fd5b600060208284031215614f4857600080fd5b8135611a4c81614f24565b8035614f5e81614f24565b63ffffffff9081168352602082013590614f7782614f24565b9081166020840152604082013590614f8e82614f24565b808216604085015250505050565b60808101614faa8285614f53565b8260608301529392505050565b6060810161092f8284614f53565b8135614fd081614f24565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008216178355602084013561501081614f24565b67ffffffff000000008160201b169050808367ffffffffffffffff19841617178455604085013561504081614f24565b6bffffffff00000000000000008160401b16847fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008516178317178555505050505050565b600060c08201905063ffffffff80855116835280602086015116602084015280604086015116604084015250611a4c6060830184614f53565b600061ffff8083168185168083038211156150da576150da614c61565b01949350505050565b60008160001904831182151516156150fd576150fd614c61565b500290565b80516001600160701b0381168114614dac57600080fd5b60008060006060848603121561512e57600080fd5b61513784615102565b925061514560208501615102565b915061515360408501615102565b90509250925092565b600060033d11156151755760046000803e5060005160e01c5b90565b600060443d10156151865790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156151d457505050505090565b82850191508151818111156151ec5750505050505090565b843d87010160208285010111156152065750505050505090565b615215602082860101876148bf565b509095945050505050565b6000611a4c8383614ceb565b634e487b7160e01b600052601260045260246000fd5b6000826152515761525161522c565b500490565b6001600160a01b038151511682526020810151610dca60208401826001600160701b038082511683528060208301511660208401528060408301511660408401525063ffffffff60608201511660608301525050565b6001600160a01b038316815260c08101611a4c6020830184615256565b6000602082840312156152db57600080fd5b8151611a4c81614b2d565b6000608082016001600160a01b0387168352602060808185015281875180845260a09350838601915082890160005b8281101561533857615328848351615256565b9285019290840190600101615315565b50505060408501969096525050506060015292915050565b60006080828403121561536257600080fd5b6040516080810181811067ffffffffffffffff8211171561538557615385614883565b60405261539183615102565b815261539f60208401615102565b60208201526153b060408401615102565b604082015260608301516153c381614f24565b60608201529392505050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516154078160178501602088016147b6565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516154448160288401602088016147b6565b01602801949350505050565b60008161545f5761545f614c61565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600061ffff808416806154925761549261522c565b92169190910692915050565b600061ffff8083168181036154b5576154b5614c61565b600101939250505056fea2646970667358221220077e1b8e92d8fa9f243f0f0df5aba4bcc77629cfe03f76d3ee7ecc453e51026364736f6c634300080d0033416273747261637441676772656761746f724f7261636c653a204455504c4943a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000184c69717569646174696f6e204f7261636c652028555344290000000000000000000000000000000000000000c7e8e1dab09e7e29cda87c32dbdf34b8e285900300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e400000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000009555320446f6c6c617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061034c5760003560e01c80639aae129d116101bd578063cd92f13d116100f9578063e5a7b1ef116100a2578063f368c0431161007c578063f368c043146108a0578063f8d0b6c8146108b3578063fb5e8315146108c6578063fc46c859146108d957600080fd5b8063e5a7b1ef14610867578063ee7b54741461087a578063f2f5c8e71461088d57600080fd5b8063e06df80b116100d3578063e06df80b14610837578063e25437421461083f578063e3e717e91461084757600080fd5b8063cd92f13d146107fe578063d47ba53814610811578063d547741f1461082457600080fd5b8063afbe528211610166578063bfe1dba811610140578063bfe1dba81461077d578063c14ce674146107a3578063c43ed2c8146107d8578063ca15c873146107eb57600080fd5b8063afbe528214610731578063bad3462014610744578063bdbdf2851461076a57600080fd5b80639f6024d8116101975780639f6024d8146106ef578063a217fddf14610716578063ab54b64d1461071e57600080fd5b80639aae129d1461068d5780639b4a95e0146106c95780639b7405d3146106dc57600080fd5b806336568abe1161028c5780636d6a08c2116102355780638e7492811161020f5780638e749281146106195780639010d07c1461063957806391d148541461064c5780639407f5cb1461068557600080fd5b80636d6a08c2146105d35780638194fe9e146105f3578063820a16801461060657600080fd5b80634fd23d2d116102665780634fd23d2d1461057f578063554f94db1461059257806357611cac146105a857600080fd5b806336568abe1461053f5780633ddac953146105525780633defb9621461056557600080fd5b8063234398bd116102f9578063283583c6116102d3578063283583c6146104a95780632f2ff15d146104e6578063343e2874146104f957806335a0bf5c1461050c57600080fd5b8063234398bd14610431578063248a9ca31461044457806327624b071461047557600080fd5b80630d6f01f31161032a5780630d6f01f3146103b95780630e6159db146103ce578063217a4b701461040a57600080fd5b806301ffc9a71461035157806306fdde03146103795780630ac900421461038e575b600080fd5b61036461035f36600461478c565b610915565b60405190151581526020015b60405180910390f35b610381610935565b6040516103709190614812565b6103a161039c36600461483a565b6109c3565b6040516001600160a01b039091168152602001610370565b6103cc6103c7366004614857565b6109ce565b005b6103816040518060400160405280600681526020017f76342e372e31000000000000000000000000000000000000000000000000000081525081565b6103a17f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e481565b61036461043f366004614960565b610c84565b610467610452366004614995565b60009081526008602052604090206001015490565b604051908152602001610370565b7f00000000000000000000000000000000000000000000000000000000000000085b60405160ff9091168152602001610370565b6104bc6104b736600461483a565b610c9e565b604080516001600160701b0394851681529284166020840152921691810191909152606001610370565b6103cc6104f43660046149ae565b610da5565b6103cc6105073660046149de565b610dcf565b61051f61051a36600461483a565b6113cb565b604080516001600160701b03938416815292909116602083015201610370565b6103cc61054d3660046149ae565b611499565b6104bc610560366004614857565b611525565b600b5468010000000000000000900463ffffffff16610467565b6103cc61058d366004614a0c565b6116ad565b600b54640100000000900463ffffffff16610467565b6105bb6105b6366004614857565b6118d3565b6040516001600160701b039091168152602001610370565b6105e66105e1366004614857565b611a3c565b6040516103709190614a1e565b6105bb61060136600461483a565b611a53565b61051f610614366004614857565b611b33565b61062c61062736600461483a565b611c86565b6040516103709190614aa2565b6103a1610647366004614b0b565b611c91565b61036461065a3660046149ae565b60009182526008602090815260408084206001600160a01b0393909316845291905290205460ff1690565b610467611ca9565b6103816040518060400160405280600681526020017f76302e312e30000000000000000000000000000000000000000000000000000081525081565b6103646106d7366004614960565b611cba565b6103646106ea36600461483a565b611d17565b6104677f0000000000000000000000000000000000000000000000000000000005f5e10081565b610467600081565b6103cc61072c366004614b3b565b611d46565b61046761073f366004614960565b611e8f565b7f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46103a1565b610467610778366004614960565b611ea4565b7f0000000000000000000000000000000000000000000000000000000000000000610497565b6104676107b136600461483a565b6001600160a01b0316600090815260208190526040902054640100000000900461ffff1690565b6103646107e6366004614960565b611ed7565b6104676107f9366004614995565b612044565b6105e661080c366004614b69565b61205b565b61046761081f36600461483a565b612074565b6103cc6108323660046149ae565b6120ce565b6103816120f3565b6103816120fd565b61085a610855366004614857565b612107565b6040516103709190614ba4565b61046761087536600461483a565b61232a565b610364610888366004614be8565b612335565b61046761089b36600461483a565b6123ce565b61085a6108ae36600461483a565b6123d9565b6103a16108c136600461483a565b6124f7565b6103646108d4366004614960565b612502565b6103816040518060400160405280600681526020017f76342e372e32000000000000000000000000000000000000000000000000000081525081565b6000610920826126af565b8061092f575061092f826126ed565b92915050565b600c805461094290614c2d565b80601f016020809104026020016040519081016040528092919081815260200182805461096e90614c2d565b80156109bb5780601f10610990576101008083540402835291602001916109bb565b820191906000526020600020905b81548152906001019060200180831161099e57829003601f168201915b505050505081565b600061092f82612707565b6001600160a01b038216600090815260208190526040812080549091660100000000000090910461ffff169003610a0857610a08836127b2565b80546601000000000000900461ffff16821015610a7e5780546040517f82f747b50000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101849052660100000000000090910461ffff1660448201526064015b60405180910390fd5b61ffff821115610ad4576040517f35a0bb670000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810183905261ffff6044820152606401610a75565b6001600160a01b03831660009081526001602052604081208254909190610b09906601000000000000900461ffff1685614c77565b905060005b81811015610bdc5760408051608081018252600180825260208083018281529383018281526060840183815288548085018a5560008a81529390932094516002909302909401805495516001600160701b039081166e0100000000000000000000000000009081026001600160e01b031990981694821694909417969096178155905192018054935163ffffffff169091027fffffffffffffffffffffffffffff0000000000000000000000000000000000009093169190931617179055610bd581614c8e565b9050610b0e565b5082546601000000000000900461ffff168414610c7d57825460408051660100000000000090920461ffff168252602082018690526001600160a01b038716917fcc3b38181883e2a866ba9fc2e4a8e9c79315090f9e0f219887a547c4329ea4cb910160405180910390a282547fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff16660100000000000061ffff8616021783555b5050505050565b600061092f82610888600b5463ffffffff1690565b905090565b600080807f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46001600160a01b0316846001600160a01b031603610d1457610d067f0000000000000000000000000000000000000000000000000000000000000008600a614d8c565b600080925092509250610d9e565b6000610d1f856123d9565b9050806060015163ffffffff16600003610d875760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b806000015193508060200151925080604001519150505b9193909250565b600082815260086020526040902060010154610dc081612905565b610dca8383612912565b505050565b7fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af610df981612905565b6001600160a01b038216156112d9576000826001600160a01b0316632857373a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e48573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e709190810190614db1565b90508051600003610ea65760405163108a7c4960e01b81526001600160a01b038416600482015260016024820152604401610a75565b6000836001600160a01b03166354bcd7ff6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0a9190614ea5565b905080600003610f3f5760405163108a7c4960e01b81526001600160a01b038516600482015260026024820152604401610a75565b836001600160a01b0316632857373a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fa59190810190614db1565b51811115610fd85760405163108a7c4960e01b81526001600160a01b038516600482015260066024820152604401610a75565b60006001600160a01b0316846001600160a01b0316636ae5cec26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611021573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110459190614ebe565b6001600160a01b03160361107e5760405163108a7c4960e01b81526001600160a01b038516600482015260036024820152604401610a75565b60005b82518110156111a65760006001600160a01b03168382815181106110a7576110a7614edb565b6020026020010151600001516001600160a01b0316036110ec5760405163108a7c4960e01b81526001600160a01b038616600482015260076024820152604401610a75565b60006110f9826001614ef1565b90505b83518110156111955783818151811061111757611117614edb565b6020026020010151600001516001600160a01b031684838151811061113e5761113e614edb565b6020026020010151600001516001600160a01b0316036111855760405163108a7c4960e01b81526001600160a01b0387166004828101919091526024820152604401610a75565b61118e81614c8e565b90506110fc565b5061119f81614c8e565b9050611081565b506000846001600160a01b0316631d0e44606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120b9190614ebe565b90506001600160a01b038116156112d5577f000000000000000000000000000000000000000000000000000000000000000860ff16816001600160a01b03166327624b076040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a29190614f09565b60ff16146112d55760405163108a7c4960e01b81526001600160a01b038616600482015260056024820152604401610a75565b5050505b6001600160a01b038084166000908152600a602052604090205481169083168103611343576040517f80336a320000000000000000000000000000000000000000000000000000000081526001600160a01b03808616600483015284166024820152604401610a75565b6001600160a01b038481166000818152600a602090815260409182902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016888616908117909155825194861685529084015290917f2aad6d1b86aa2648ffd8f6850ce9fa7c364ceddae29234268102a5ffed873b3d910160405180910390a250505050565b6000807f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46001600160a01b0316836001600160a01b03160361141257506000928392509050565b600061141d846123d9565b9050806060015163ffffffff166000036114855760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b806020015192508060400151915050915091565b6001600160a01b03811633146115175760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610a75565b6115218282612934565b5050565b600080807f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46001600160a01b0316856001600160a01b03160361159b5761158d7f0000000000000000000000000000000000000000000000000000000000000008600a614d8c565b6000809250925092506116a6565b836000036115b7576115ac85612956565b9250925092506116a6565b60006115c2866123d9565b9050806060015163ffffffff1660000361162a5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b84816060015163ffffffff166116409190614ef1565b42111561168f5760405162461bcd60e51b815260206004820152601c60248201527f41627374726163744f7261636c653a20524154455f544f4f5f4f4c44000000006044820152606401610a75565b806000015193508060200151925080604001519150505b9250925092565b7fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af6116d781612905565b6116e76060830160408401614f36565b63ffffffff166116fd6040840160208501614f36565b63ffffffff161115611727578160646040516378ceac6f60e01b8152600401610a75929190614f9c565b6117346020830183614f36565b63ffffffff1660000361175f578160656040516378ceac6f60e01b8152600401610a75929190614f9c565b61176f6060830160408401614f36565b63ffffffff1660000361179a578160656040516378ceac6f60e01b8152600401610a75929190614f9c565b60408051606081018252600b5463ffffffff808216835264010000000082048116602080850191909152680100000000000000009092041692820192909252906117e690840184614f36565b63ffffffff16816000015163ffffffff16148015611822575061180f6040840160208501614f36565b63ffffffff16816020015163ffffffff16145b801561184c57506118396060840160408501614f36565b63ffffffff16816040015163ffffffff16145b1561188557826040517f6c90ab44000000000000000000000000000000000000000000000000000000008152600401610a759190614fb7565b82600b6118928282614fc5565b9050507fd8a61dbcfb5d6c4bf580fec4f5edcbabfedb79848780c5a08783b258349710d981846040516118c6929190615084565b60405180910390a1505050565b60007f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46001600160a01b0316836001600160a01b031603611940576119397f0000000000000000000000000000000000000000000000000000000000000008600a614d8c565b905061092f565b8160000361195c5761195183612956565b5090915061092f9050565b6000611967846123d9565b9050806060015163ffffffff166000036119cf5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b82816060015163ffffffff166119e59190614ef1565b421115611a345760405162461bcd60e51b815260206004820152601c60248201527f41627374726163744f7261636c653a20524154455f544f4f5f4f4c44000000006044820152606401610a75565b519392505050565b6060611a4c838360006001612a0b565b9392505050565b60007f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46001600160a01b0316826001600160a01b031603611ab95761092f7f0000000000000000000000000000000000000000000000000000000000000008600a614d8c565b6000611ac4836123d9565b9050806060015163ffffffff16600003611b2c5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b5192915050565b6000807f000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e46001600160a01b0316846001600160a01b031603611b7a57506000905080611c7f565b82600003611b9757611b8b84612956565b9093509150611c7f9050565b6000611ba2856123d9565b9050806060015163ffffffff16600003611c0a5760405162461bcd60e51b815260206004820152602360248201527f41627374726163744f7261636c653a204d495353494e475f4f4253455256415460448201526224a7a760e91b6064820152608401610a75565b83816060015163ffffffff16611c209190614ef1565b421115611c6f5760405162461bcd60e51b815260206004820152601c60248201527f41627374726163744f7261636c653a20524154455f544f4f5f4f4c44000000006044820152606401610a75565b8060200151925080604001519150505b9250929050565b606061092f82612d9c565b6000828152600960205260408120611a4c9083612e2f565b6000610c99600b5463ffffffff1690565b600080611cc683611e8f565b600b54909150640100000000900463ffffffff16811015611cea5750600092915050565b600b5468010000000000000000900463ffffffff168110611d0e5750600192915050565b611a4c83610c84565b6001600160a01b038116600090815260208190526040812054680100000000000000009004600116151561092f565b7f71a9d0bd0e16f5720ede57dbd96d9c682aa5147a3f584ae2cb6be366f74f8789611d7081612905565b6001600160a01b03831660009081526020819052604090205468010000000000000000900461ffff81169060011615158315158114611e4a578315611dba57600182179150611dc2565b600119821691505b6001600160a01b0385166000818152602081815260409182902080547fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff166801000000000000000061ffff881602179055905186151581527f06c32dc5449a43f80c90d607b256e2d2ce23677068c6edd70ef64297053a247d910160405180910390a2610c7d565b6040517f701455670000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201528415156024820152604401610a75565b6000611e9a82611ea4565b61092f9042614c77565b60008082806020019051810190611ebb9190614ebe565b9050611ec6816123d9565b6060015163ffffffff169392505050565b60008080527fff854284463209d6bcc2eef3b33c69d39b62bf9f40ef94df8bdd0b45a566e9a16020527fb80d84a45535a249aaaa06f547327bc7aa3214dace3852eb6dcdba1ff6720e13547f9792fdc19ab98adfa72ab2fa98d342618c661e01c406979c105b31eda87f5e6f9060ff16611fa757600081815260086020908152604080832033845290915290205460ff16611fa7576040517f0161a64a00000000000000000000000000000000000000000000000000000000815233600482015260248101829052604401610a75565b600083806020019051810190611fbd9190614ebe565b9050611fef816001600160a01b0316600090815260208190526040902054680100000000000000009004600116151590565b15612031576040517fd3f2201a0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610a75565b61203a84612e3b565b9250505b50919050565b600081815260096020526040812061092f90612e5c565b606061206985858585612a0b565b90505b949350505050565b6001600160a01b0381166000908152602081905260408120546601000000000000900461ffff1680820361092f57505061ffff7f000000000000000000000000000000000000000000000000000000000000000116919050565b6000828152600860205260409020600101546120e981612905565b610dca8383612934565b6060610c99612e66565b6060610c99612ef8565b6040805160808101825260008082526020820181905291810182905260608101919091526001600160a01b03831660009081526020818152604091829020825160e081018452905461ffff808216835262010000820481169383019390935264010000000081048316938201849052660100000000000081048316606083015268010000000000000000810490921660808201526a010000000000000000000082046001600160701b031660a0820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1660c082015290831061223e5760408082015190517f3a2a4a0b0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810185905261ffff9091166044820152606401610a75565b600083826020015161ffff16106122685783826020015161ffff166122639190614c77565b61228b565b838260400151836020015161227d91906150bd565b61ffff1661228b9190614c77565b6001600160a01b0386166000908152600160205260409020805491925090829081106122b9576122b9614edb565b60009182526020918290206040805160808101825260029390930290910180546001600160701b0380821685526e010000000000000000000000000000918290048116958501959095526001909101549384169183019190915290910463ffffffff16606082015295945050505050565b600061092f82612f07565b6000808380602001905181019061234c9190614ebe565b9050600061235982612f93565b90506000806123688484612fb7565b91509150600061237785612f07565b90508082101561238f5760009550505050505061092f565b600061239a866123d9565b90506123c184600001516001600160701b031682600001516001600160701b03168a61381d565b9998505050505050505050565b600061092f82612f93565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b0385168252819052918220805491929091640100000000900461ffff169003612452575050604080516080810182526000808252602082018190529181018290526060810191909152919050565b6001600160a01b0383166000908152600160205260409020815481546201000090910461ffff1690811061248857612488614edb565b60009182526020918290206040805160808101825260029390930290910180546001600160701b0380821685526e010000000000000000000000000000918290048116958501959095526001909101549384169183019190915290910463ffffffff1660608201529392505050565b600061092f82613846565b60008080527fff854284463209d6bcc2eef3b33c69d39b62bf9f40ef94df8bdd0b45a566e9a16020527fb80d84a45535a249aaaa06f547327bc7aa3214dace3852eb6dcdba1ff6720e135460ff1615801561258c57503360009081527fff854284463209d6bcc2eef3b33c69d39b62bf9f40ef94df8bdd0b45a566e9a1602052604090205460ff16155b1561259957506000919050565b6000828060200190518101906125af9190614ebe565b90506125e1816001600160a01b0316600090815260208190526040902054680100000000000000009004600116151590565b156125ef5750600092915050565b611a4c836138cd565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff166115215760008281526008602090815260408083206001600160a01b03851684529091529020805460ff191660011790556126563390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611a4c836001600160a01b038416613925565b60006001600160e01b031982167f5a05180f00000000000000000000000000000000000000000000000000000000148061092f575061092f82613974565b60006126f8826139db565b8061092f575061092f82613a5d565b6001600160a01b038082166000908152600a6020526040812054909116801561278c57806001600160a01b0316631d0e44606040518163ffffffff1660e01b8152600401602060405180830381865afa158015612768573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c9190614ebe565b7f0000000000000000000000000000000000000000000000000000000000000000611a4c565b6001600160a01b0381166000908152600160205260409020541561280d576040517f1690fa400000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610a75565b6001600160a01b0381166000908152602081815260408083206001909252822090915b7f000000000000000000000000000000000000000000000000000000000000000161ffff168110156128785781546001018255600082905261287181614c8e565b9050612830565b50815467ffffffffffffffff1916660100000000000061ffff7f0000000000000000000000000000000000000000000000000000000000000001811682029290921780855560405191900490911681526001600160a01b038416907fc4913fc151d71f6929a713bd2f607375acc4e952a83c8b69a4b04362d735cbd29060200160405180910390a2505050565b61290f8133613b03565b50565b61291c82826125f8565b6000828152600960205260409020610dca908261269a565b61293e8282613b83565b6000828152600960205260409020610dca9082613c06565b6000806000806000612969866000612fb7565b91509150600061297887612f07565b9050808210156129f05760405162461bcd60e51b815260206004820152603360248201527f416273747261637441676772656761746f724f7261636c653a20494e56414c4960448201527f445f4e554d5f434f4e53554c544154494f4e53000000000000000000000000006064820152608401610a75565b50508051602082015160409092015190969195509350915050565b606083600003612a67576040805160008082526020820190925290612a5f565b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181612a2b5790505b50905061206c565b6001600160a01b03851660009081526020818152604091829020825160e081018452905461ffff80821683526201000082048116938301939093526401000000008104831693820193909352660100000000000083048216606082015268010000000000000000830490911660808201526a010000000000000000000082046001600160701b031660a0820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1660c08201528383612b2d600188614c77565b612b3791906150e3565b612b419190614ef1565b816040015161ffff1611612bd057604081015186908585612b6360018a614c77565b612b6d91906150e3565b612b779190614ef1565b612b82906001614ef1565b6040517f50a48eae0000000000000000000000000000000000000000000000000000000081526001600160a01b03909316600484015261ffff90911660248301526044820152606401610a75565b60008567ffffffffffffffff811115612beb57612beb614883565b604051908082528060200260200182016040528015612c3d57816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181612c095790505b50905060008086846020015161ffff1610612c6b5786846020015161ffff16612c669190614c77565b612c8e565b8684604001518560200151612c8091906150bd565b61ffff16612c8e9190614c77565b90505b87821015612d8f576001600160a01b0389166000908152600160205260409020805482908110612cc357612cc3614edb565b60009182526020918290206040805160808101825260029390930290910180546001600160701b0380821685526e010000000000000000000000000000918290048116958501959095526001909101549384169183019190915290910463ffffffff1660608201528383612d3681614c8e565b945081518110612d4857612d48614edb565b6020026020010181905250858110612d6957612d648682614c77565b612d88565b85846040015161ffff1682612d7e9190614ef1565b612d889190614c77565b9050612c91565b5090979650505050505050565b6001600160a01b038082166000908152600a6020526040902054606091168015612e2657806001600160a01b0316632857373a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612dfe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a4c9190810190614db1565b611a4c83613c1b565b6000611a4c8383613eaf565b6000612e4682611cba565b15612e545761092f82613ed9565b506000919050565b600061092f825490565b606060038054612e7590614c2d565b80601f0160208091040260200160405190810160405280929190818152602001828054612ea190614c2d565b8015612eee5780601f10612ec357610100808354040283529160200191612eee565b820191906000526020600020905b815481529060010190602001808311612ed157829003601f168201915b5050505050905090565b606060028054612e7590614c2d565b6001600160a01b038082166000908152600a60205260408120549091168015612f8c57806001600160a01b03166354bcd7ff6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c9190614ea5565b6001611a4c565b600b5460009068010000000000000000900463ffffffff1661092f90610708614ef1565b60408051608081018252600080825260208201819052918101829052606081018290529060ff7f00000000000000000000000000000000000000000000000000000000000000088116907f0000000000000000000000000000000000000000000000000000000000000000168261302d87612d9c565b90506000815167ffffffffffffffff81111561304b5761304b614883565b6040519080825280602002602001820160405280156130b157816020015b60408051606080820183526000828401818152835283516080810185528181526020808201839052948101829052918201528282015282526000199092019101816130695790505b5090506000806000806130c38c612707565b905060005b865181101561365e578681815181106130e3576130e3614edb565b6020908102919091010151516040517f3ddac9530000000000000000000000000000000000000000000000000000000081526001600160a01b038f81166004830152602482018f905290911690633ddac95390604401606060405180830381865afa925050508015613172575060408051601f3d908101601f1916820190925261316f91810190615119565b60015b6131db5761317e61515c565b806308c379a0036131a35750613192615178565b8061319d57506131a5565b5061364e565b505b3d8080156131cf576040519150601f19603f3d011682016040523d82523d6000602084013e6131d4565b606091505b505061364e565b6001600160701b03928316975090821695501692508887828151811061320357613203614edb565b60200260200101516020015160ff16101561326557600087828151811061322c5761322c614edb565b60200260200101516020015160ff168a6132469190614c77565b61325190600a615220565b905061325d81876150e3565b9550506132d6565b8887828151811061327857613278614edb565b60200260200101516020015160ff1611156132d6576000898883815181106132a2576132a2614edb565b60200260200101516020015160ff166132bb9190614c77565b6132c690600a615220565b90506132d28187615242565b9550505b878782815181106132e9576132e9614edb565b60200260200101516040015160ff16101561335757600087828151811061331257613312614edb565b60200260200101516040015160ff168961332c9190614c77565b61333790600a615220565b905061334381866150e3565b945061334f81856150e3565b9350506133d4565b8787828151811061336a5761336a614edb565b60200260200101516040015160ff1611156133d45760008888838151811061339457613394614edb565b60200260200101516040015160ff166133ad9190614c77565b6133b890600a615220565b90506133c48186615242565b94506133d08185615242565b9350505b6001600160701b0385118015906133f257506001600160701b038411155b801561340557506001600160701b038311155b1561364e5760408051606080820183526000828401818152835283516080810185528181526020808201839052948101829052918201529181019190915260008e60405160200161346591906001600160a01b0391909116815260200190565b6040516020818303038152906040529050600089848151811061348a5761348a614edb565b6020026020010151600001516001600160a01b031663bdbdf285836040518263ffffffff1660e01b81526004016134c19190614812565b602060405180830381865afa1580156134de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135029190614ea5565b9050604051806040016040528060405180602001604052808d888151811061352c5761352c614edb565b6020026020010151600001516001600160a01b0316815250815260200160405180608001604052808b6001600160701b031681526020018a6001600160701b03168152602001896001600160701b031681526020018463ffffffff168152508152509250505060006001600160a01b0316836001600160a01b0316148061361d5750826001600160a01b031663950ee1e28f836040518363ffffffff1660e01b81526004016135dc9291906152ac565b602060405180830381865afa1580156135f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061361d91906152c9565b1561364c5780878c61362e81614c8e565b9d508151811061364057613640614edb565b60200260200101819052505b505b61365781614c8e565b90506130c8565b508860000361369c575050604080516080810182526000808252602082018190529181018290526060810182905298509650611c7f95505050505050565b6136a58c613846565b6001600160a01b031663bef24ea38d8760006136c260018f614c77565b6040518563ffffffff1660e01b81526004016136e194939291906152e6565b608060405180830381865afa1580156136fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137229190615350565b99506001600160a01b0381161561380e57600060405180604001604052806040518060200160405280306001600160a01b031681525081526020018c8152509050816001600160a01b031663950ee1e28e836040518363ffffffff1660e01b81526004016137919291906152ac565b602060405180830381865afa1580156137ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d291906152c9565b61380c575050604080516080810182526000808252602082018190529181018290526060810182905299509750611c7f9650505050505050565b505b50505050505050509250929050565b600080600061382c868661401c565b91509150808061383c5750838210155b9695505050505050565b6001600160a01b038082166000908152600a602052604081205490911680156138a757806001600160a01b0316636ae5cec26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612768573d6000803e3d6000fd5b7f000000000000000000000000c7e8e1dab09e7e29cda87c32dbdf34b8e2859003611a4c565b60006138d882611cba565b6138e457506000919050565b6000828060200190518101906138fa9190614ebe565b905060006139108261390b84612f93565b612fb7565b91505061391c82612f07565b11159392505050565b600081815260018301602052604081205461396c5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561092f565b50600061092f565b60006001600160e01b031982167f7965db0b00000000000000000000000000000000000000000000000000000000148061092f57507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b031983161461092f565b60006001600160e01b031980831690036139f757506000919050565b6001600160e01b031982167faeff306300000000000000000000000000000000000000000000000000000000148061092f57506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60006001600160e01b031982167f5b47aca9000000000000000000000000000000000000000000000000000000001480613ac057506001600160e01b031982167f6b3f5d0300000000000000000000000000000000000000000000000000000000145b80613af457507f9f88c26e000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b8061092f575061092f826140ac565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff1661152157613b41816001600160a01b031660146141af565b613b4c8360206141af565b604051602001613b5d9291906153cf565b60408051601f198184030181529082905262461bcd60e51b8252610a7591600401614812565b60008281526008602090815260408083206001600160a01b038516845290915290205460ff16156115215760008281526008602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611a4c836001600160a01b0384166143d8565b606060006004805480602002602001604051908101604052809291908181526020016000905b82821015613cbb57600084815260209081902060408051606081018252918501546001600160a01b038116835260ff74010000000000000000000000000000000000000000820481168486015275010000000000000000000000000000000000000000009091041690820152825260019092019101613c41565b5050506001600160a01b03851660009081526005602090815260408083208054825181850281018501909352808352959650929490935090849084015b82821015613d7257600084815260209081902060408051606081018252918501546001600160a01b038116835260ff74010000000000000000000000000000000000000000820481168486015275010000000000000000000000000000000000000000009091041690820152825260019092019101613cf8565b50508451835193945092915060009050613d8c8284614ef1565b67ffffffffffffffff811115613da457613da4614883565b604051908082528060200260200182016040528015613def57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181613dc25790505b50905060005b83811015613e4557858181518110613e0f57613e0f614edb565b6020026020010151828281518110613e2957613e29614edb565b602002602001018190525080613e3e90614c8e565b9050613df5565b5060005b82811015613ea457848181518110613e6357613e63614edb565b6020026020010151828286613e789190614ef1565b81518110613e8857613e88614edb565b602002602001018190525080613e9d90614c8e565b9050613e49565b509695505050505050565b6000826000018281548110613ec657613ec6614edb565b9060005260206000200154905092915050565b600080600083806020019051810190613ef29190614ebe565b9050600080613f048361390b85612f93565b91509150613f1183612f07565b8110613f715742836001600160a01b03167f14a871ab15e169a114a18fffaac6d4992e7035193d8410862d72b9ee39b04b2383604051613f5391815260200190565b60405180910390a3613f6583836144cb565b50600195945050505050565b826001600160a01b0316306001600160a01b03167f3e930f884cdf7675c76ade43623c05ac440890e8f5f9e6a281bfb483dd9feb0c60405161400a9060208082526033908201527f416273747261637441676772656761746f724f7261636c653a20494e56414c4960408201527f445f4e554d5f434f4e53554c544154494f4e5300000000000000000000000000606082015260800190565b60405180910390a35091949350505050565b6000808284101561402b579192915b8360000361403e57506000905080611c7f565b826000036140525750600090506001611c7f565b8284037f0000000000000000000000000000000000000000000000000000000005f5e10081028181101561408f5760006001935093505050611c7f565b84818161409e5761409e61522c565b049660009650945050505050565b60006001600160e01b031982167faa0e913d00000000000000000000000000000000000000000000000000000000148061410f57506001600160e01b031982167fb629643a00000000000000000000000000000000000000000000000000000000145b8061414357506001600160e01b031982167fd6f5e23200000000000000000000000000000000000000000000000000000000145b8061417757506001600160e01b031982167fb7aaa9dc00000000000000000000000000000000000000000000000000000000145b8061092f57507f9f88c26e000000000000000000000000000000000000000000000000000000006001600160e01b031983161461092f565b606060006141be8360026150e3565b6141c9906002614ef1565b67ffffffffffffffff8111156141e1576141e1614883565b6040519080825280601f01601f19166020018201604052801561420b576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061424257614242614edb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106142a5576142a5614edb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006142e18460026150e3565b6142ec906001614ef1565b90505b6001811115614389577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061432d5761432d614edb565b1a60f81b82828151811061434357614343614edb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361438281615450565b90506142ef565b508315611a4c5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a75565b600081815260018301602052604081205480156144c15760006143fc600183614c77565b855490915060009061441090600190614c77565b905081811461447557600086600001828154811061443057614430614edb565b906000526020600020015490508087600001848154811061445357614453614edb565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061448657614486615467565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061092f565b600091505061092f565b6001600160a01b03821660009081526020819052604081208054909164010000000090910461ffff16900361451f5780546601000000000000900461ffff1660000361451a5761451a836127b2565b614584565b805461ffff6601000000000000820481169161454491620100009091041660016150bd565b61454e919061547d565b815461ffff9190911662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff9091161781555b6001600160a01b03831660009081526001602052604090208154815484929162010000900461ffff169081106145bc576145bc614edb565b60009182526020918290208351600292909202018054848401516001600160701b039384166001600160e01b0319909216919091176e0100000000000000000000000000009184168202178255604080860151600190930180546060978801519486167fffffffffffffffffffffffffffff0000000000000000000000000000000000009091161763ffffffff909416909202929092179055855186840151878301518351928516835290841694820194909452929091169082015242918101919091526001600160a01b038416907ffc74cea824f39db3e95982ad65b1fdb44455998f02934dfd18b83e32b81426d79060800160405180910390a2805461ffff660100000000000082048116640100000000909204161080156146f55750805462010000810461ffff90811664010000000090920416145b15614734578054640100000000900461ffff168160046147148361549e565b91906101000a81548161ffff021916908361ffff16021790555050505050565b805461ffff6401000000008204811691614750911660016150bd565b61475a919061547d565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff919091161790555050565b60006020828403121561479e57600080fd5b81356001600160e01b031981168114611a4c57600080fd5b60005b838110156147d15781810151838201526020016147b9565b838111156147e0576000848401525b50505050565b600081518084526147fe8160208601602086016147b6565b601f01601f19169290920160200192915050565b602081526000611a4c60208301846147e6565b6001600160a01b038116811461290f57600080fd5b60006020828403121561484c57600080fd5b8135611a4c81614825565b6000806040838503121561486a57600080fd5b823561487581614825565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6060810181811067ffffffffffffffff821117156148b9576148b9614883565b60405250565b601f19601f830116810181811067ffffffffffffffff821117156148e5576148e5614883565b6040525050565b600082601f8301126148fd57600080fd5b813567ffffffffffffffff81111561491757614917614883565b60405161492e6020601f19601f85011601826148bf565b81815284602083860101111561494357600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561497257600080fd5b813567ffffffffffffffff81111561498957600080fd5b61206c848285016148ec565b6000602082840312156149a757600080fd5b5035919050565b600080604083850312156149c157600080fd5b8235915060208301356149d381614825565b809150509250929050565b600080604083850312156149f157600080fd5b82356149fc81614825565b915060208301356149d381614825565b60006060828403121561203e57600080fd5b6020808252825182820181905260009190848201906040850190845b81811015614a9657614a838385516001600160701b038082511683528060208301511660208401528060408301511660408401525063ffffffff60608201511660608301525050565b9284019260809290920191600101614a3a565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b82811015614afe57815180516001600160a01b031685528681015160ff9081168887015290860151168585015260609093019290850190600101614abf565b5091979650505050505050565b60008060408385031215614b1e57600080fd5b50508035926020909101359150565b801515811461290f57600080fd5b60008060408385031215614b4e57600080fd5b8235614b5981614825565b915060208301356149d381614b2d565b60008060008060808587031215614b7f57600080fd5b8435614b8a81614825565b966020860135965060408601359560600135945092505050565b6080810161092f82846001600160701b038082511683528060208301511660208401528060408301511660408401525063ffffffff60608201511660608301525050565b60008060408385031215614bfb57600080fd5b823567ffffffffffffffff811115614c1257600080fd5b614c1e858286016148ec565b95602094909401359450505050565b600181811c90821680614c4157607f821691505b60208210810361203e57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082821015614c8957614c89614c61565b500390565b60006000198203614ca157614ca1614c61565b5060010190565b600181815b80851115614ce3578160001904821115614cc957614cc9614c61565b80851615614cd657918102915b93841c9390800290614cad565b509250929050565b600082614cfa5750600161092f565b81614d075750600061092f565b8160018114614d1d5760028114614d2757614d43565b600191505061092f565b60ff841115614d3857614d38614c61565b50506001821b61092f565b5060208310610133831016604e8410600b8410161715614d66575081810a61092f565b614d708383614ca8565b8060001904821115614d8457614d84614c61565b029392505050565b6000611a4c60ff841683614ceb565b805160ff81168114614dac57600080fd5b919050565b60006020808385031215614dc457600080fd5b825167ffffffffffffffff80821115614ddc57600080fd5b818501915085601f830112614df057600080fd5b815181811115614e0257614e02614883565b604091508151614e17858360051b01826148bf565b818152606091820284018501918582019089841115614e3557600080fd5b948601945b83861015614e975780868b031215614e525760008081fd5b8451614e5d81614899565b8651614e6881614825565b8152614e75878901614d9b565b88820152614e84868801614d9b565b8187015282529485019490860190614e3a565b509098975050505050505050565b600060208284031215614eb757600080fd5b5051919050565b600060208284031215614ed057600080fd5b8151611a4c81614825565b634e487b7160e01b600052603260045260246000fd5b60008219821115614f0457614f04614c61565b500190565b600060208284031215614f1b57600080fd5b611a4c82614d9b565b63ffffffff8116811461290f57600080fd5b600060208284031215614f4857600080fd5b8135611a4c81614f24565b8035614f5e81614f24565b63ffffffff9081168352602082013590614f7782614f24565b9081166020840152604082013590614f8e82614f24565b808216604085015250505050565b60808101614faa8285614f53565b8260608301529392505050565b6060810161092f8284614f53565b8135614fd081614f24565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008216178355602084013561501081614f24565b67ffffffff000000008160201b169050808367ffffffffffffffff19841617178455604085013561504081614f24565b6bffffffff00000000000000008160401b16847fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008516178317178555505050505050565b600060c08201905063ffffffff80855116835280602086015116602084015280604086015116604084015250611a4c6060830184614f53565b600061ffff8083168185168083038211156150da576150da614c61565b01949350505050565b60008160001904831182151516156150fd576150fd614c61565b500290565b80516001600160701b0381168114614dac57600080fd5b60008060006060848603121561512e57600080fd5b61513784615102565b925061514560208501615102565b915061515360408501615102565b90509250925092565b600060033d11156151755760046000803e5060005160e01c5b90565b600060443d10156151865790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156151d457505050505090565b82850191508151818111156151ec5750505050505090565b843d87010160208285010111156152065750505050505090565b615215602082860101876148bf565b509095945050505050565b6000611a4c8383614ceb565b634e487b7160e01b600052601260045260246000fd5b6000826152515761525161522c565b500490565b6001600160a01b038151511682526020810151610dca60208401826001600160701b038082511683528060208301511660208401528060408301511660408401525063ffffffff60608201511660608301525050565b6001600160a01b038316815260c08101611a4c6020830184615256565b6000602082840312156152db57600080fd5b8151611a4c81614b2d565b6000608082016001600160a01b0387168352602060808185015281875180845260a09350838601915082890160005b8281101561533857615328848351615256565b9285019290840190600101615315565b50505060408501969096525050506060015292915050565b60006080828403121561536257600080fd5b6040516080810181811067ffffffffffffffff8211171561538557615385614883565b60405261539183615102565b815261539f60208401615102565b60208201526153b060408401615102565b604082015260608301516153c381614f24565b60608201529392505050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516154078160178501602088016147b6565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516154448160288401602088016147b6565b01602801949350505050565b60008161545f5761545f614c61565b506000190190565b634e487b7160e01b600052603160045260246000fd5b600061ffff808416806154925761549261522c565b92169190910692915050565b600061ffff8083168181036154b5576154b5614c61565b600101939250505056fea2646970667358221220077e1b8e92d8fa9f243f0f0df5aba4bcc77629cfe03f76d3ee7ecc453e51026364736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000184c69717569646174696f6e204f7261636c652028555344290000000000000000000000000000000000000000c7e8e1dab09e7e29cda87c32dbdf34b8e285900300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e400000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000009555320446f6c6c617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : name_ (string): Liquidation Oracle (USD)
Arg [1] : params (tuple):
Arg [1] : aggregationStrategy (address): 0xC7E8e1daB09e7E29cda87C32DBDf34b8E2859003
Arg [2] : validationStrategy (address): 0x0000000000000000000000000000000000000000
Arg [3] : quoteTokenName (string): US Dollar
Arg [4] : quoteTokenAddress (address): 0xEe4c4dcF5C9Ec793860E9D18d9daf037926098e4
Arg [5] : quoteTokenSymbol (string): USD
Arg [6] : quoteTokenDecimals (uint8): 8
Arg [7] : liquidityDecimals (uint8): 0
Arg [2] : updateThreshold_ (uint256): 100000
Arg [3] : updateDelay_ (uint256): 0
Arg [4] : heartbeat_ (uint256): 86400
-----Encoded View---------------
22 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000186a0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [6] : 4c69717569646174696f6e204f7261636c652028555344290000000000000000
Arg [7] : 000000000000000000000000c7e8e1dab09e7e29cda87c32dbdf34b8e2859003
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [10] : 000000000000000000000000ee4c4dcf5c9ec793860e9d18d9daf037926098e4
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [14] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [15] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [17] : 555320446f6c6c61720000000000000000000000000000000000000000000000
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [19] : 5553440000000000000000000000000000000000000000000000000000000000
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.