Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
AppController
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
No with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {SignatureUtilsMixin} from "@eigenlayer-contracts/src/contracts/mixins/SignatureUtilsMixin.sol";
import {IPermissionController} from "@eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol";
import {PermissionControllerMixin} from "@eigenlayer-contracts/src/contracts/mixins/PermissionControllerMixin.sol";
import {
IReleaseManager, IReleaseManagerTypes
} from "@eigenlayer-contracts/src/contracts/interfaces/IReleaseManager.sol";
import {OperatorSet} from "@eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {IComputeAVSRegistrar} from "./interfaces/IComputeAVSRegistrar.sol";
import {IComputeOperator} from "./interfaces/IComputeOperator.sol";
import {AppControllerStorage} from "./storage/AppControllerStorage.sol";
import {IAppController} from "./interfaces/IAppController.sol";
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import {IApp} from "./interfaces/IApp.sol";
contract AppController is Initializable, SignatureUtilsMixin, PermissionControllerMixin, AppControllerStorage {
using EnumerableSet for EnumerableSet.AddressSet;
/// MODIFIERS
/// @notice Modifier to ensure app is not in the given status
modifier appIsActive(IApp app) {
require(_appConfigs[app].status != AppStatus.TERMINATED, InvalidAppStatus());
require(_appConfigs[app].status != AppStatus.NONE, InvalidAppStatus());
_;
}
/**
* @param _version The version string to use for this contract's domain separator
* @param _permissionController The PermissionController contract address
* @param _computeAVSRegistrar The ComputeAVSRegistrar contract address
* @param _computeOperator The ComputeOperator contract address
* @param _appBeacon The beacon for creating App proxies
*/
constructor(
string memory _version,
IPermissionController _permissionController,
IReleaseManager _releaseManager,
IComputeAVSRegistrar _computeAVSRegistrar,
IComputeOperator _computeOperator,
IBeacon _appBeacon
)
SignatureUtilsMixin(_version)
PermissionControllerMixin(_permissionController)
AppControllerStorage(_releaseManager, _computeOperator, _computeAVSRegistrar, _appBeacon)
{
_disableInitializers();
}
/// @inheritdoc IAppController
function initialize(address admin) external initializer {
// Accept the ComputeAVSRegistrar as an admin
permissionController.acceptAdmin(address(computeAVSRegistrar));
// Add this contract itself as an admin
permissionController.addPendingAdmin(address(this), address(this));
permissionController.acceptAdmin(address(this));
// Add the app controller as an admin
permissionController.addPendingAdmin(address(this), admin);
// Assign an initial operator set ID
uint32 operatorSetId = computeAVSRegistrar.assignOperatorSetId();
// Create the operator set
computeAVSRegistrar.createOperatorSet(operatorSetId);
// Add the compute operator to the allowlist
computeAVSRegistrar.addOperatorToAllowlist(
OperatorSet({avs: address(computeAVSRegistrar), id: operatorSetId}), address(computeOperator)
);
// Register the compute operator for the operator set
computeOperator.registerForOperatorSet(operatorSetId);
}
/// @inheritdoc IAppController
function setMaxActiveAppsPerUser(address user, uint32 limit) external checkCanCall(address(this)) {
_userConfigs[user].maxActiveApps = limit;
emit MaxActiveAppsSet(user, limit);
}
/// @inheritdoc IAppController
function setMaxGlobalActiveApps(uint32 limit) external checkCanCall(address(this)) {
maxGlobalActiveApps = limit;
emit GlobalMaxActiveAppsSet(limit);
}
/// @inheritdoc IAppController
function createApp(bytes32 salt, Release calldata release) external returns (IApp app) {
UserConfig storage userConfig = _userConfigs[msg.sender];
// Check global active app limit
require(globalActiveAppCount < maxGlobalActiveApps, GlobalMaxActiveAppsExceeded());
// Check user active app limit
require(userConfig.activeAppCount < userConfig.maxActiveApps, MaxActiveAppsExceeded());
// Increment active app counts
globalActiveAppCount++;
userConfig.activeAppCount++;
// Assign an operator set ID to the app
uint32 operatorSetId = computeAVSRegistrar.assignOperatorSetId();
// Publish the initial release metadata URI
releaseManager.publishMetadataURI(
OperatorSet({avs: address(computeAVSRegistrar), id: operatorSetId}), "https://eigencloud.xyz"
);
// Create app using BeaconProxy
app = IApp(Create2.deploy(0, _calculateAppMixedSalt(msg.sender, salt), _calculateAppInitCode(msg.sender)));
_appConfigs[app].operatorSetId = operatorSetId;
_appConfigs[app].latestReleaseBlockNumber = 0;
_appConfigs[app].creator = msg.sender;
_allApps.add(address(app));
emit AppCreated(msg.sender, app, operatorSetId);
// Upgrade the app with the initial release
_upgradeApp(app, release);
_startApp(app);
}
/// @inheritdoc IAppController
function upgradeApp(IApp app, Release calldata release)
external
checkCanCall(address(app))
appIsActive(app)
returns (uint256)
{
return _upgradeApp(app, release);
}
/// @inheritdoc IAppController
function startApp(IApp app) external checkCanCall(address(app)) {
_startApp(app);
}
/// @inheritdoc IAppController
function stopApp(IApp app) external checkCanCall(address(app)) {
AppConfig storage config = _appConfigs[app];
require(config.status == AppStatus.STARTED, InvalidAppStatus());
config.status = AppStatus.STOPPED;
emit AppStopped(app);
}
/// @inheritdoc IAppController
function terminateApp(IApp app) external checkCanCall(address(app)) appIsActive(app) {
_terminateApp(app);
}
/// @inheritdoc IAppController
function terminateAppByAdmin(IApp app) external checkCanCall(address(this)) appIsActive(app) {
_terminateApp(app);
emit AppTerminatedByAdmin(app);
}
/// INTERNAL FUNCTIONS
/**
* @notice Upgrades an app to a new release by publishing it through the release manager
* @param app The app instance to upgrade
* @param release The new release data containing artifacts and metadata
*/
function _upgradeApp(IApp app, Release calldata release) internal returns (uint256 releaseId) {
// Check that the release has exactly one artifact
require(release.rmsRelease.artifacts.length == 1, MoreThanOneArtifact());
releaseId = releaseManager.publishRelease(
OperatorSet({avs: address(computeAVSRegistrar), id: _appConfigs[app].operatorSetId}), release.rmsRelease
);
_appConfigs[app].latestReleaseBlockNumber = uint32(block.number);
emit AppUpgraded(app, releaseId, release);
}
/**
* @notice Starts an app and marks it as started
* @param app The app instance to start
*/
function _startApp(IApp app) internal {
_appConfigs[app].status = AppStatus.STARTED;
emit AppStarted(app);
}
/**
* @notice Terminates an app and decrements active app counters
* @param app The app instance to terminate
*/
function _terminateApp(IApp app) internal {
_appConfigs[app].status = AppStatus.TERMINATED;
// Decrement active app counts to free up capacity
globalActiveAppCount--;
// Decrement the creator's active app count
address appCreator = _appConfigs[app].creator;
_userConfigs[appCreator].activeAppCount--;
emit AppTerminated(app);
}
/**
* @notice Calculates a mixed salt for app deployment using deployer address and provided salt
* @param deployer The address of the app deployer
* @param salt The salt value
*/
function _calculateAppMixedSalt(address deployer, bytes32 salt) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(deployer, salt));
}
/**
* @notice Generates the initialization code for deploying a new app using beacon proxy pattern
* @param deployer The address that will be set as the app owner during initialization
*/
function _calculateAppInitCode(address deployer) internal view returns (bytes memory) {
return abi.encodePacked(
_BEACON_PROXY_BYTECODE, abi.encode(appBeacon, abi.encodeWithSelector(IApp.initialize.selector, deployer))
);
}
/// VIEW FUNCTIONS
/// @inheritdoc IAppController
function getMaxActiveAppsPerUser(address user) external view returns (uint32) {
return _userConfigs[user].maxActiveApps;
}
/// @inheritdoc IAppController
function getActiveAppCount(address user) external view returns (uint32) {
return _userConfigs[user].activeAppCount;
}
/// @inheritdoc IAppController
function calculateAppId(address deployer, bytes32 salt) external view returns (IApp) {
return IApp(
Create2.computeAddress(
_calculateAppMixedSalt(deployer, salt),
keccak256(_calculateAppInitCode(deployer)) //bytecode
)
);
}
/// @inheritdoc IAppController
function getAppStatus(IApp app) external view returns (AppStatus) {
return _appConfigs[app].status;
}
/// @inheritdoc IAppController
function getAppCreator(IApp app) external view returns (address) {
return _appConfigs[app].creator;
}
/// @inheritdoc IAppController
function getAppOperatorSetId(IApp app) external view returns (uint32) {
return _appConfigs[app].operatorSetId;
}
/// @inheritdoc IAppController
function getAppLatestReleaseBlockNumber(IApp app) external view returns (uint32) {
return _appConfigs[app].latestReleaseBlockNumber;
}
/// @inheritdoc IAppController
function getApps(uint256 offset, uint256 limit)
external
view
returns (IApp[] memory apps, AppConfig[] memory appConfigsMem)
{
uint256 totalApps = _allApps.length();
if (offset >= totalApps) return (new IApp[](0), new AppConfig[](0));
uint256 end = offset + limit > totalApps ? totalApps : offset + limit;
uint256 rangeSize = end - offset;
apps = new IApp[](rangeSize);
appConfigsMem = new AppConfig[](rangeSize);
for (uint256 i = 0; i < rangeSize; i++) {
apps[i] = IApp(_allApps.at(offset + i));
appConfigsMem[i] = _appConfigs[apps[i]];
}
}
/// @inheritdoc IAppController
function getAppsByDeveloper(address developer, uint256 offset, uint256 limit)
external
view
returns (IApp[] memory apps, AppConfig[] memory appConfigsMem)
{
uint256 totalApps = _allApps.length();
apps = new IApp[](limit);
appConfigsMem = new AppConfig[](limit);
uint256 skipped = 0;
uint256 found = 0;
for (uint256 i = 0; i < totalApps && found < limit; i++) {
IApp app = IApp(_allApps.at(i));
if (permissionController.isAdmin(address(app), developer)) {
if (skipped < offset) {
skipped++;
continue;
}
apps[found] = app;
appConfigsMem[found] = _appConfigs[app];
found++;
}
}
// Resize arrays to actual number found
assembly {
mstore(apps, found)
mstore(appConfigsMem, found)
}
}
/// @inheritdoc IAppController
function calculateApiPermissionDigestHash(bytes4 permission, uint256 expiry) external view returns (bytes32) {
return _calculateSignableDigest(keccak256(abi.encode(API_PERMISSION_TYPEHASH, permission, expiry)));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol)
pragma solidity ^0.8.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
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.
*
* ```solidity
* 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.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
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) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// 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;
/// @solidity memory-safe-assembly
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 in 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;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol";
import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol";
import "../interfaces/ISignatureUtilsMixin.sol";
import "./SemVerMixin.sol";
/// @dev The EIP-712 domain type hash used for computing the domain separator
/// See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
bytes32 constant EIP712_DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/// @title SignatureUtilsMixin
/// @notice A mixin contract that provides utilities for validating signatures according to EIP-712 and EIP-1271 standards.
/// @dev The domain name is hardcoded to "EigenLayer". This contract implements signature validation functionality that can be
/// inherited by other contracts. The domain separator uses the major version (e.g., "v1") to maintain EIP-712
/// signature compatibility across minor and patch version updates.
abstract contract SignatureUtilsMixin is ISignatureUtilsMixin, SemVerMixin {
using SignatureCheckerUpgradeable for address;
/// @notice Initializes the contract with a semantic version string.
/// @param _version The SemVer-formatted version string (e.g., "1.1.1") to use for this contract's domain separator.
/// @dev Version should follow SemVer 2.0.0 format with 'v' prefix: vMAJOR.MINOR.PATCH.
/// Only the major version component is used in the domain separator to maintain signature compatibility
/// across minor and patch version updates.
constructor(
string memory _version
) SemVerMixin(_version) {}
/// EXTERNAL FUNCTIONS ///
/// @inheritdoc ISignatureUtilsMixin
function domainSeparator() public view virtual returns (bytes32) {
// forgefmt: disable-next-item
return
keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes("EigenLayer")),
keccak256(bytes(_majorVersion())),
block.chainid,
address(this)
)
);
}
/// INTERNAL HELPERS ///
/// @notice Creates a digest that can be signed using EIP-712.
/// @dev Prepends the EIP-712 prefix ("\x19\x01") and domain separator to the input hash.
/// This follows the EIP-712 specification for creating structured data hashes.
/// See https://eips.ethereum.org/EIPS/eip-712#specification.
/// @param hash The hash of the typed data to be signed.
/// @return The complete digest that should be signed according to EIP-712.
function _calculateSignableDigest(
bytes32 hash
) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator(), hash));
}
/// @notice Validates a signature against a signer and digest, with an expiry timestamp.
/// @dev Reverts if the signature is invalid or expired. Uses EIP-1271 for smart contract signers.
/// For EOA signers, validates ECDSA signatures directly.
/// For contract signers, calls isValidSignature according to EIP-1271.
/// See https://eips.ethereum.org/EIPS/eip-1271#specification.
/// @param signer The address that should have signed the digest.
/// @param signableDigest The digest that was signed, created via _calculateSignableDigest.
/// @param signature The signature bytes to validate.
/// @param expiry The timestamp after which the signature is no longer valid.
function _checkIsValidSignatureNow(
address signer,
bytes32 signableDigest,
bytes memory signature,
uint256 expiry
) internal view {
// First, check if the signature has expired by comparing the expiry timestamp
// against the current block timestamp.
require(expiry >= block.timestamp, SignatureExpired());
// Next, verify that the signature is valid for the given signer and digest.
// For EOA signers, this performs standard ECDSA signature verification.
// For contract signers, this calls the EIP-1271 isValidSignature method.
require(signer.isValidSignatureNow(signableDigest, signature), InvalidSignature());
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "./ISemVerMixin.sol";
interface IPermissionControllerErrors {
/// @notice Thrown when a non-admin caller attempts to perform an admin-only action.
error NotAdmin();
/// @notice Thrown when attempting to remove an admin that does not exist.
error AdminNotSet();
/// @notice Thrown when attempting to set an appointee for a function that already has one.
error AppointeeAlreadySet();
/// @notice Thrown when attempting to interact with a non-existent appointee.
error AppointeeNotSet();
/// @notice Thrown when attempting to remove the last remaining admin.
error CannotHaveZeroAdmins();
/// @notice Thrown when attempting to set an admin that is already registered.
error AdminAlreadySet();
/// @notice Thrown when attempting to interact with an admin that is not in pending status.
error AdminNotPending();
/// @notice Thrown when attempting to add an admin that is already pending.
error AdminAlreadyPending();
}
interface IPermissionControllerEvents {
/// @notice Emitted when an appointee is set for an account to handle specific function calls.
event AppointeeSet(address indexed account, address indexed appointee, address target, bytes4 selector);
/// @notice Emitted when an appointee's permission to handle function calls for an account is revoked.
event AppointeeRemoved(address indexed account, address indexed appointee, address target, bytes4 selector);
/// @notice Emitted when an address is set as a pending admin for an account, requiring acceptance.
event PendingAdminAdded(address indexed account, address admin);
/// @notice Emitted when a pending admin status is removed for an account before acceptance.
event PendingAdminRemoved(address indexed account, address admin);
/// @notice Emitted when an address accepts and becomes an active admin for an account.
event AdminSet(address indexed account, address admin);
/// @notice Emitted when an admin's permissions are removed from an account.
event AdminRemoved(address indexed account, address admin);
}
interface IPermissionController is IPermissionControllerErrors, IPermissionControllerEvents, ISemVerMixin {
/**
* @notice Sets a pending admin for an account.
* @param account The account to set the pending admin for.
* @param admin The address to set as pending admin.
* @dev The pending admin must accept the role before becoming an active admin.
* @dev Multiple admins can be set for a single account.
*/
function addPendingAdmin(address account, address admin) external;
/**
* @notice Removes a pending admin from an account before they have accepted the role.
* @param account The account to remove the pending admin from.
* @param admin The pending admin address to remove.
* @dev Only an existing admin of the account can remove a pending admin.
*/
function removePendingAdmin(address account, address admin) external;
/**
* @notice Allows a pending admin to accept their admin role for an account.
* @param account The account to accept the admin role for.
* @dev Only addresses that were previously set as pending admins can accept the role.
*/
function acceptAdmin(
address account
) external;
/**
* @notice Removes an active admin from an account.
* @param account The account to remove the admin from.
* @param admin The admin address to remove.
* @dev Only an existing admin of the account can remove another admin.
* @dev Will revert if removing this admin would leave the account with zero admins.
*/
function removeAdmin(address account, address admin) external;
/**
* @notice Sets an appointee who can call specific functions on behalf of an account.
* @param account The account to set the appointee for.
* @param appointee The address to be given permission.
* @param target The contract address the appointee can interact with.
* @param selector The function selector the appointee can call.
* @dev Only an admin of the account can set appointees.
*/
function setAppointee(address account, address appointee, address target, bytes4 selector) external;
/**
* @notice Removes an appointee's permission to call a specific function.
* @param account The account to remove the appointee from.
* @param appointee The appointee address to remove.
* @param target The contract address to remove permissions for.
* @param selector The function selector to remove permissions for.
* @dev Only an admin of the account can remove appointees.
*/
function removeAppointee(address account, address appointee, address target, bytes4 selector) external;
/**
* @notice Checks if a given address is an admin of an account.
* @param account The account to check admin status for.
* @param caller The address to check.
* @dev If the account has no admins, returns true only if the caller is the account itself.
* @return Returns true if the caller is an admin, false otherwise.
*/
function isAdmin(address account, address caller) external view returns (bool);
/**
* @notice Checks if an address is currently a pending admin for an account.
* @param account The account to check pending admin status for.
* @param pendingAdmin The address to check.
* @return Returns true if the address is a pending admin, false otherwise.
*/
function isPendingAdmin(address account, address pendingAdmin) external view returns (bool);
/**
* @notice Retrieves all active admins for an account.
* @param account The account to get the admins for.
* @dev If the account has no admins, returns an array containing only the account address.
* @return An array of admin addresses.
*/
function getAdmins(
address account
) external view returns (address[] memory);
/**
* @notice Retrieves all pending admins for an account.
* @param account The account to get the pending admins for.
* @return An array of pending admin addresses.
*/
function getPendingAdmins(
address account
) external view returns (address[] memory);
/**
* @notice Checks if a caller has permission to call a specific function.
* @param account The account to check permissions for.
* @param caller The address attempting to make the call.
* @param target The contract address being called.
* @param selector The function selector being called.
* @dev Returns true if the caller is either an admin or an appointed caller.
* @dev Be mindful that upgrades to the contract may invalidate the appointee's permissions.
* This is only possible if a function's selector changes (e.g. if a function's parameters are modified).
* @return Returns true if the caller has permission, false otherwise.
*/
function canCall(address account, address caller, address target, bytes4 selector) external returns (bool);
/**
* @notice Retrieves all permissions granted to an appointee for a given account.
* @param account The account to check appointee permissions for.
* @param appointee The appointee address to check.
* @return Two arrays: target contract addresses and their corresponding function selectors.
*/
function getAppointeePermissions(
address account,
address appointee
) external returns (address[] memory, bytes4[] memory);
/**
* @notice Retrieves all appointees that can call a specific function for an account.
* @param account The account to get appointees for.
* @param target The contract address to check.
* @param selector The function selector to check.
* @dev Does not include admins in the returned list, even though they have calling permission.
* @return An array of appointee addresses.
*/
function getAppointees(address account, address target, bytes4 selector) external returns (address[] memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../interfaces/IPermissionController.sol";
abstract contract PermissionControllerMixin {
/// @dev Thrown when the caller is not allowed to call a function on behalf of an account.
error InvalidPermissions();
/// @notice Pointer to the permission controller contract.
IPermissionController public immutable permissionController;
constructor(
IPermissionController _permissionController
) {
permissionController = _permissionController;
}
/// @notice Checks if the caller (msg.sender) can call on behalf of an account.
modifier checkCanCall(
address account
) {
require(_checkCanCall(account), InvalidPermissions());
_;
}
/**
* @notice Checks if the caller is allowed to call a function on behalf of an account.
* @param account the account to check
* @dev `msg.sender` is the caller to check that can call the function on behalf of `account`.
* @dev Returns a bool, instead of reverting
*/
function _checkCanCall(
address account
) internal returns (bool) {
return permissionController.canCall(account, msg.sender, address(this), msg.sig);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "../libraries/OperatorSetLib.sol";
interface IReleaseManagerErrors {
/// @notice Thrown when a metadata URI must be published before publishing a release.
error MustPublishMetadataURI();
/// @notice Thrown when the upgrade by time is in the past.
error InvalidUpgradeByTime();
/// @notice Thrown when the metadata URI is empty.
error InvalidMetadataURI();
/// @notice Thrown when there are no releases for an operator set.
error NoReleases();
}
interface IReleaseManagerTypes {
/// @notice Represents a software artifact with its digest and registry URL.
/// @param digest The hash digest of the artifact.
/// @param registry Where the artifact can be found.
struct Artifact {
bytes32 digest;
string registry;
}
/// @notice Represents a release containing multiple artifacts and an upgrade deadline.
/// @param artifacts Array of artifacts included in this release.
/// @param upgradeByTime Timestamp by which operators must upgrade to this release. A value of 0 signals an instant upgrade requirement.
struct Release {
Artifact[] artifacts;
uint32 upgradeByTime;
}
}
interface IReleaseManagerEvents is IReleaseManagerTypes {
/// @notice Emitted when a new release is published.
/// @param operatorSet The operator set this release is for.
/// @param releaseId The id of the release that was published.
/// @param release The release that was published.
event ReleasePublished(OperatorSet indexed operatorSet, uint256 indexed releaseId, Release release);
/// @notice Emitted when a metadata URI is published.
/// @param operatorSet The operator set this metadata URI is for.
/// @param metadataURI The metadata URI that was published.
event MetadataURIPublished(OperatorSet indexed operatorSet, string metadataURI);
}
interface IReleaseManager is IReleaseManagerErrors, IReleaseManagerEvents {
/**
*
* WRITE FUNCTIONS
*
*/
/// @notice Publishes a new release for an operator set.
/// @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
/// @param operatorSet The operator set this release is for.
/// @param release The release that was published.
/// @return releaseId The index of the newly published release.
function publishRelease(
OperatorSet calldata operatorSet,
Release calldata release
) external returns (uint256 releaseId);
/// @notice Publishes a metadata URI for an operator set.
/// @param operatorSet The operator set this metadata URI is for.
/// @param metadataURI The metadata URI that was published.
function publishMetadataURI(OperatorSet calldata operatorSet, string calldata metadataURI) external;
/**
*
* VIEW FUNCTIONS
*
*/
/// @notice Returns the total number of releases for an operator set.
/// @param operatorSet The operator set to query.
/// @return The number of releases.
function getTotalReleases(
OperatorSet memory operatorSet
) external view returns (uint256);
/// @notice Returns a specific release by index.
/// @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
/// @param operatorSet The operator set to query.
/// @param releaseId The id of the release to get.
/// @return The release at the specified index.
function getRelease(OperatorSet memory operatorSet, uint256 releaseId) external view returns (Release memory);
/// @notice Returns the latest release for an operator set.
/// @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
/// @param operatorSet The operator set to query.
/// @return The id of the latest release.
/// @return The latest release.
function getLatestRelease(
OperatorSet memory operatorSet
) external view returns (uint256, Release memory);
/// @notice Returns the upgrade by time for the latest release.
/// @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
/// @param operatorSet The operator set to query.
/// @return The upgrade by time for the latest release.
function getLatestUpgradeByTime(
OperatorSet memory operatorSet
) external view returns (uint32);
/// @notice Returns true if the release is the latest release, false otherwise.
/// @param operatorSet The operator set to query.
/// @param releaseId The id of the release to check.
/// @return True if the release is the latest release, false otherwise.
function isValidRelease(OperatorSet memory operatorSet, uint256 releaseId) external view returns (bool);
/// @notice Returns the metadata URI for an operator set.
/// @param operatorSet The operator set to query.
/// @return The metadata URI for the operator set.
function getMetadataURI(
OperatorSet memory operatorSet
) external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
using OperatorSetLib for OperatorSet global;
/**
* @notice An operator set identified by the AVS address and an identifier
* @param avs The address of the AVS this operator set belongs to
* @param id The unique identifier for the operator set
*/
struct OperatorSet {
address avs;
uint32 id;
}
library OperatorSetLib {
function key(
OperatorSet memory os
) internal pure returns (bytes32) {
return bytes32(abi.encodePacked(os.avs, uint96(os.id)));
}
function decode(
bytes32 _key
) internal pure returns (OperatorSet memory) {
/// forgefmt: disable-next-item
return OperatorSet({
avs: address(uint160(uint256(_key) >> 96)),
id: uint32(uint256(_key) & type(uint96).max)
});
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import {IAVSRegistrar} from "@eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol";
import {IAllowlist} from "@eigenlayer-middleware/src/interfaces/IAllowlist.sol";
interface IComputeAVSRegistrar is IAVSRegistrar, IAllowlist {
/// @notice Thrown when the caller is not the AppController
error NotAppController();
/// @notice Thrown when trying to create an operator set with an unassigned ID
error OperatorSetIdNotAssigned();
/**
* @notice Initializes the ComputeAVSRegistrar
* @param metadataURI The metadata URI for the AVS
*/
function initialize(string calldata metadataURI) external;
/**
* @notice Assigns a unique operator set ID
* @return operatorSetId The ID of the assigned operator set
*/
function assignOperatorSetId() external returns (uint32);
/**
* @notice Creates and configures an operator set
* @param operatorSetId The ID of the operator set to create
*/
function createOperatorSet(uint32 operatorSetId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
interface IComputeOperator {
/// @notice Thrown when the caller is not the ComputeAVS
error NotComputeAVS();
/// @notice Thrown when the caller is not the AppController
error NotAppController();
/**
* @notice Initializes the ComputeOperator
* @param operatorMetadataURI The metadata URI for the operator
*/
function initialize(string calldata operatorMetadataURI) external;
/**
* @notice Registers this operator for a specified operator set
* @param operatorSetId The operator set ID within the app to register for
* @dev This function can only be called by the AppController
*/
function registerForOperatorSet(uint32 operatorSetId) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {IPermissionController} from "@eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol";
import {IReleaseManager} from "@eigenlayer-contracts/src/contracts/interfaces/IReleaseManager.sol";
import {IComputeOperator} from "../interfaces/IComputeOperator.sol";
import {IComputeAVSRegistrar} from "../interfaces/IComputeAVSRegistrar.sol";
import {IApp} from "../interfaces/IApp.sol";
import {IAppController} from "../interfaces/IAppController.sol";
import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
abstract contract AppControllerStorage is IAppController {
using EnumerableSet for EnumerableSet.AddressSet;
/// CONSTANTS & IMMUTABLES
/// @notice The EIP-712 typehash for the `DelegationApproval` struct used by the contract
bytes32 public constant API_PERMISSION_TYPEHASH = keccak256("ApiPermission(bytes4 permission,uint256 expiry)");
/**
* @notice Stored code of type(BeaconProxy).creationCode
* @dev Maintained as a constant to solve an edge case - changes to OpenZeppelin's BeaconProxy code should not cause
* addresses of Apps that are pre-computed with Create2 to change, even upon upgrading this contract, changing compiler version, etc.
*/
bytes internal constant _BEACON_PROXY_BYTECODE =
hex"608060405260405161090e38038061090e83398101604081905261002291610460565b61002e82826000610035565b505061058a565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610520565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610520565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108e7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053b565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c65782516103bf576001600160a01b0385163b6103bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d0565b6103d083836103d8565b949350505050565b8151156103e85781518083602001fd5b8060405162461bcd60e51b81526004016101699190610557565b80516001600160a01b038116811461041957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044f578181015183820152602001610437565b838111156100f95750506000910152565b6000806040838503121561047357600080fd5b61047c83610402565b60208401519092506001600160401b038082111561049957600080fd5b818501915085601f8301126104ad57600080fd5b8151818111156104bf576104bf61041e565b604051601f8201601f19908116603f011681019083821181831017156104e7576104e761041e565b8160405282815288602084870101111561050057600080fd5b610511836020830160208801610434565b80955050505050509250929050565b60006020828403121561053257600080fd5b6102c882610402565b6000825161054d818460208701610434565b9190910192915050565b6020815260008251806020840152610576816040850160208701610434565b601f01601f19169190910160400192915050565b61034e806105996000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f260279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb9190610249565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a2565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020d578251610206576001600160a01b0385163b6102065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610217565b610217838361021f565b949350505050565b81511561022f5781518083602001fd5b8060405162461bcd60e51b81526004016101fd91906102be565b60006020828403121561025b57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028d578181015183820152602001610275565b8381111561029c576000848401525b50505050565b600082516102b4818460208701610272565b9190910192915050565b60208152600082518060208401526102dd816040850160208701610272565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d51e81d3bc5ed20a26aeb05dce7e825c503b2061aa78628027300c8d65b9d89a64736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564";
/// @notice The ReleaseManager contract from EigenLayer
IReleaseManager public immutable releaseManager;
/// @notice The TEEOperator contract from EigenLayer
IComputeOperator public immutable computeOperator;
/// @notice The ComputeAVSRegistrar contract
IComputeAVSRegistrar public immutable computeAVSRegistrar;
/// @notice The beacon used for creating App proxies
IBeacon public immutable appBeacon;
/// @notice Set of all created apps
EnumerableSet.AddressSet internal _allApps;
/// @notice The mapping of app address to app storage
mapping(IApp => AppConfig) internal _appConfigs;
/// @notice User configuration and state
mapping(address => UserConfig) internal _userConfigs;
/// @inheritdoc IAppController
uint32 public maxGlobalActiveApps;
/// @inheritdoc IAppController
uint32 public globalActiveAppCount;
constructor(
IReleaseManager _releaseManager,
IComputeOperator _computeOperator,
IComputeAVSRegistrar _computeAVSRegistrar,
IBeacon _appBeacon
) {
releaseManager = _releaseManager;
computeOperator = _computeOperator;
computeAVSRegistrar = _computeAVSRegistrar;
appBeacon = _appBeacon;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import {IReleaseManagerTypes} from "@eigenlayer-contracts/src/contracts/interfaces/IReleaseManager.sol";
import {IApp} from "./IApp.sol";
interface IAppController {
/// @notice Thrown when trying to create an app that already exists
error AppAlreadyExists();
/// @notice Thrown when trying to access an app that does not exist
error AppDoesNotExist();
/// @notice Thrown when an invalid release metadata URI is provided
error InvalidReleaseMetadataURI();
/// @notice Thrown when a RMS release has more than one artifact
error MoreThanOneArtifact();
/// @notice Thrown when trying to operate on an app in the given status
error InvalidAppStatus();
/// @notice Thrown when an address has exceeded its maximum active app limit
error MaxActiveAppsExceeded();
/// @notice Thrown when global maximum active app limit has been reached
error GlobalMaxActiveAppsExceeded();
/// @notice Emitted when a new app is successfully created
event AppCreated(address indexed creator, IApp indexed app, uint32 operatorSetId);
/// @notice Emitted when an app is upgraded
event AppUpgraded(IApp indexed app, uint256 rmsReleaseId, Release release);
/// @notice Emitted when an app is started
event AppStarted(IApp indexed app);
/// @notice Emitted when an app is stopped
event AppStopped(IApp indexed app);
/// @notice Emitted when an app is terminated
event AppTerminated(IApp indexed app);
/// @notice Emitted when an app is terminated by admin
event AppTerminatedByAdmin(IApp indexed app);
/// @notice Emitted when the maximum active apps limit is set for an address
event MaxActiveAppsSet(address indexed user, uint32 limit);
/// @notice Emitted when the global maximum active apps limit is set
event GlobalMaxActiveAppsSet(uint32 limit);
/**
* @notice Enum for app status
*/
enum AppStatus {
NONE, // App has not been created yet
STARTED, // App is has been started
STOPPED, // App is has been stopped but can be restarted
TERMINATED // App is permanently terminated
}
/**
* @notice A struct containing a release and its environment
* @param rmsRelease The release to publish
* @param env The environment for the release
* @param encryptedSecrets The encrypted secrets for the release
*/
struct Release {
IReleaseManagerTypes.Release rmsRelease;
bytes publicEnv;
bytes encryptedEnv;
}
/// @notice The controller's config for an app
struct AppConfig {
address creator;
uint32 operatorSetId;
uint32 latestReleaseBlockNumber;
AppStatus status;
}
/// @notice User configuration and state
struct UserConfig {
uint32 maxActiveApps;
uint32 activeAppCount;
}
/**
* @notice Initialize the AppController contract
* @param admin The admin address for the contract
*/
function initialize(address admin) external;
/**
* @notice Sets the maximum active apps limit for a specific address
* @param user The address to set the limit for
* @param limit The maximum number of active apps the address can have
* @dev Caller must be UAM permissioned for the AppController
*/
function setMaxActiveAppsPerUser(address user, uint32 limit) external;
/**
* @notice Sets the global maximum active apps limit
* @param limit The maximum number of active apps globally
* @dev Caller must be UAM permissioned for the AppController
*/
function setMaxGlobalActiveApps(uint32 limit) external;
/**
* @notice Creates a new app instance
* @param salt The salt to use for the app
* @param release The release to upgrade to
* @return app The address of the newly created app
*/
function createApp(bytes32 salt, Release calldata release) external returns (IApp app);
/**
* @notice Upgrades an app with a new release to the ReleaseManager
* @param app The app to upgrade with the release
* @param release The release to upgrade to
* @return releaseId The unique identifier for the published release
* @dev Caller must be UAM permissioned for the app
* @dev The rms release must have exactly one artifact, with the digest being the docker
* image digest and the registry being the docker registry it is stored at.
* @dev The env must be a JSON marshalled bytes representing the public environment variables for the app.
* @dev The encryptedSecrets must be a JSON Web Encryption objects of the encrypted secrets for the app encrypted with
* the kms's public key.
* @dev The app must not be AppStatus.TERMINATED
*/
function upgradeApp(IApp app, Release calldata release) external returns (uint256);
/**
* @notice Starts an app, which starts the instance backing it
* @param app The app to start
* @dev Caller must be UAM permissioned for the app
* @dev App must be AppStatus.STOPPED
*/
function startApp(IApp app) external;
/**
* @notice Stops an app, which stops the instance backing it
* @param app The app to stop
* @dev Caller must be UAM permissioned for the app
* @dev App must be AppStatus.STARTED
*/
function stopApp(IApp app) external;
/**
* @notice Terminates an app permanently
* @param app The app to terminate
* @dev Caller must be UAM permissioned for the app
* @dev Once terminated, no further write operations are allowed
*/
function terminateApp(IApp app) external;
/**
* @notice Terminates an app permanently by admin
* @param app The app to terminate
* @dev Caller must be UAM permissioned for the AppController
* @dev Once terminated, no further write operations are allowed
*/
function terminateAppByAdmin(IApp app) external;
/**
* @notice Gets the maximum global active apps limit
* @return The maximum number of active apps globally
*/
function maxGlobalActiveApps() external view returns (uint32);
/**
* @notice Gets the current global active app count
* @return The current number of active apps globally
*/
function globalActiveAppCount() external view returns (uint32);
/**
* @notice Gets the maximum active apps for a user
* @param user The address to check
* @return The maximum number of active apps for the user
*/
function getMaxActiveAppsPerUser(address user) external view returns (uint32);
/**
* @notice Gets the current active app count for a user
* @param user The address to check
* @return The current number of active apps for the user
*/
function getActiveAppCount(address user) external view returns (uint32);
/**
* @notice Calculates the app id for a given deployer and salt
* @param deployer The address of the deployer
* @param salt The salt to use for the app
* @return The app id
*/
function calculateAppId(address deployer, bytes32 salt) external view returns (IApp);
/**
* @notice Gets the status for a given app
* @param app The app to get the status for
* @return The app status
*/
function getAppStatus(IApp app) external view returns (AppStatus);
/**
* @notice Gets the creator of an app
* @param app The app to check
* @return The address of the app creator
*/
function getAppCreator(IApp app) external view returns (address);
/**
* @notice Gets the operator set ID for a given app
* @param app The app to get the operator set ID for
* @return The operator set ID
*/
function getAppOperatorSetId(IApp app) external view returns (uint32);
/**
* @notice Gets the latest release block number for a given app
* @param app The app to get the latest release block number for
* @return The latest release block number
*/
function getAppLatestReleaseBlockNumber(IApp app) external view returns (uint32);
/**
* @notice Retrieves a paginated list of all apps and their configurations
* @param offset The starting index for pagination (0-based)
* @param limit The maximum number of apps to return in this page
* @return apps An array of app contract instances
* @return configs An array of corresponding app configurations
*/
function getApps(uint256 offset, uint256 limit) external view returns (IApp[] memory, AppConfig[] memory);
/**
* @notice Retrieves a paginated list of apps where the specified developer is an admin and their configurations
* @param developer The address of the developer
* @param offset The starting index for pagination (0-based)
* @param limit The maximum number of apps to return in this page
* @return apps An array of app contract instances
* @return configs An array of corresponding app configurations
*/
function getAppsByDeveloper(address developer, uint256 offset, uint256 limit)
external
view
returns (IApp[] memory, AppConfig[] memory);
/**
* @notice Calculates the digest hash for a given api permission
* @param permission The permission to calculate the digest hash for
* @param expiry The expiry of the api permission
* @return The digest hash
*/
function calculateApiPermissionDigestHash(bytes4 permission, uint256 expiry) external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)
pragma solidity ^0.8.0;
import "./IBeacon.sol";
import "../Proxy.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
*
* The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
* conflict with the storage layout of the implementation behind the proxy.
*
* _Available since v3.4._
*/
contract BeaconProxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
*/
constructor(address beacon, bytes memory data) payable {
_upgradeBeaconToAndCall(beacon, data, false);
}
/**
* @dev Returns the current beacon address.
*/
function _beacon() internal view virtual returns (address) {
return _getBeacon();
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_getBeacon()).implementation();
}
/**
* @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
*
* Requirements:
*
* - `beacon` must be a contract.
* - The implementation returned by `beacon` must be a contract.
*/
function _setBeacon(address beacon, bytes memory data) internal virtual {
_upgradeBeaconToAndCall(beacon, data, false);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
interface IApp {
/**
* @notice Initializes the App
* @param admin The UAM admin to be set for the app
*/
function initialize(address admin) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlotUpgradeable.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStringsUpgradeable {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlotUpgradeable.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSAUpgradeable.sol";
import "../../interfaces/IERC1271Upgradeable.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureCheckerUpgradeable {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSAUpgradeable.RecoverError error) = ECDSAUpgradeable.tryRecover(hash, signature);
return
(error == ECDSAUpgradeable.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271Upgradeable.isValidSignature.selector, hash, signature)
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271Upgradeable.isValidSignature.selector));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ISemVerMixin.sol";
interface ISignatureUtilsMixinErrors {
/// @notice Thrown when a signature is invalid.
error InvalidSignature();
/// @notice Thrown when a signature has expired.
error SignatureExpired();
}
interface ISignatureUtilsMixinTypes {
/// @notice Struct that bundles together a signature and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
/// @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithSaltAndExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the salt used to generate the signature
bytes32 salt;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
}
/**
* @title The interface for common signature utilities.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface ISignatureUtilsMixin is ISignatureUtilsMixinErrors, ISignatureUtilsMixinTypes, ISemVerMixin {
/// @notice Computes the EIP-712 domain separator used for signature validation.
/// @dev The domain separator is computed according to EIP-712 specification, using:
/// - The hardcoded name "EigenLayer"
/// - The contract's version string
/// - The current chain ID
/// - This contract's address
/// @return The 32-byte domain separator hash used in EIP-712 structured data signing.
/// @dev See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator.
function domainSeparator() external view returns (bytes32);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../interfaces/ISemVerMixin.sol";
import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol";
/// @title SemVerMixin
/// @notice A mixin contract that provides semantic versioning functionality.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/).
abstract contract SemVerMixin is ISemVerMixin {
using ShortStringsUpgradeable for *;
/// @notice The semantic version string for this contract, stored as a ShortString for gas efficiency.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/).
ShortString internal immutable _VERSION;
/// @notice Initializes the contract with a semantic version string.
/// @param _version The SemVer-formatted version string (e.g., "1.2.3")
/// @dev Version should follow SemVer 2.0.0 format: MAJOR.MINOR.PATCH
constructor(
string memory _version
) {
_VERSION = _version.toShortString();
}
/// @inheritdoc ISemVerMixin
function version() public view virtual returns (string memory) {
return _VERSION.toString();
}
/// @notice Returns the major version of the contract.
/// @dev Supports single digit major versions (e.g., "1" for version "1.2.3")
/// @return The major version string (e.g., "1" for version "1.2.3")
function _majorVersion() internal view returns (string memory) {
bytes memory v = bytes(_VERSION.toString());
return string(abi.encodePacked(v[0]));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
/// @title ISemVerMixin
/// @notice A mixin interface that provides semantic versioning functionality.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/)
interface ISemVerMixin {
/// @notice Returns the semantic version string of the contract.
/// @return The version string in SemVer format (e.g., "1.1.1")
function version() external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IAVSRegistrar {
/**
* @notice Called by the AllocationManager when an operator wants to register
* for one or more operator sets. This method should revert if registration
* is unsuccessful.
* @param operator the registering operator
* @param avs the AVS the operator is registering for. This should be the same as IAVSRegistrar.avs()
* @param operatorSetIds the list of operator set ids being registered for
* @param data arbitrary data the operator can provide as part of registration
*/
function registerOperator(
address operator,
address avs,
uint32[] calldata operatorSetIds,
bytes calldata data
) external;
/**
* @notice Called by the AllocationManager when an operator is deregistered from one or more operator sets
* @param operator the deregistering operator
* @param avs the AVS the operator is deregistering from. This should be the same as IAVSRegistrar.avs()
* @param operatorSetIds the list of operator set ids being deregistered from
*/
function deregisterOperator(address operator, address avs, uint32[] calldata operatorSetIds) external;
/**
* @notice Returns true if the AVS is supported by the registrar
* @param avs the AVS to check
* @return true if the AVS is supported, false otherwise
*/
function supportsAVS(
address avs
) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
interface IAllowlistErrors {
/// @notice Thrown when the operator is already in the allowlist
error OperatorAlreadyInAllowlist();
/// @notice Thrown when the operator is not in the allowlist
error OperatorNotInAllowlist();
}
interface IAllowlistEvents {
/// @notice Emitted when an operator is added to the allowlist
event OperatorAddedToAllowlist(OperatorSet indexed operatorSet, address indexed operator);
/// @notice Emitted when an operator is removed from the allowlist
event OperatorRemovedFromAllowlist(OperatorSet indexed operatorSet, address indexed operator);
}
interface IAllowlist is IAllowlistErrors, IAllowlistEvents {
/**
* @notice Adds an operator to the allowlist
* @param operatorSet The operator set to add the operator to
* @param operator The operator to add to the allowlist
* @dev Only callable by the owner
*/
function addOperatorToAllowlist(OperatorSet memory operatorSet, address operator) external;
/**
* @notice Removes an operator from the allowlist
* @param operatorSet The operator set to remove the operator from
* @param operator The operator to remove from the allowlist
* @dev If an operator is removed from the allowlist and is already registered, the avs
* must then handle state changes appropriately (ie. eject the operator)
* @dev Only callable by the owner
*/
function removeOperatorFromAllowlist(
OperatorSet memory operatorSet,
address operator
) external;
/**
* @notice Checks if an operator is in the allowlist
* @param operatorSet The operator set to check the operator in
* @param operator The operator to check
* @return True if the operator is in the allowlist, false otherwise
*/
function isOperatorAllowed(
OperatorSet memory operatorSet,
address operator
) external view returns (bool);
/**
* @notice Returns all operators in the allowlist
* @param operatorSet The operator set to get the allowed operators from
* @return An array of all operators in the allowlist
* @dev This function should be used with caution, as it can be expensive to call on-chain
*/
function getAllowedOperators(
OperatorSet memory operatorSet
) external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../StringsUpgradeable.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSAUpgradeable {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271Upgradeable {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @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] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@eigenlayer-middleware/=lib/eigenlayer-middleware/",
"@eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/",
"@openzeppelin/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/",
"@openzeppelin-upgrades/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/",
"ds-test/=lib/eigenlayer-middleware/lib/ds-test/src/",
"eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/",
"eigenlayer-middleware/=lib/eigenlayer-middleware/",
"erc4626-tests/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/",
"openzeppelin-contracts-upgradeable/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/",
"openzeppelin-contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/",
"openzeppelin/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/contracts/",
"zeus-templates/=lib/zeus-templates/src/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"_version","type":"string"},{"internalType":"contract IPermissionController","name":"_permissionController","type":"address"},{"internalType":"contract IReleaseManager","name":"_releaseManager","type":"address"},{"internalType":"contract IComputeAVSRegistrar","name":"_computeAVSRegistrar","type":"address"},{"internalType":"contract IComputeOperator","name":"_computeOperator","type":"address"},{"internalType":"contract IBeacon","name":"_appBeacon","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAlreadyExists","type":"error"},{"inputs":[],"name":"AppDoesNotExist","type":"error"},{"inputs":[],"name":"GlobalMaxActiveAppsExceeded","type":"error"},{"inputs":[],"name":"InvalidAppStatus","type":"error"},{"inputs":[],"name":"InvalidPermissions","type":"error"},{"inputs":[],"name":"InvalidReleaseMetadataURI","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"MaxActiveAppsExceeded","type":"error"},{"inputs":[],"name":"MoreThanOneArtifact","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"contract IApp","name":"app","type":"address"},{"indexed":false,"internalType":"uint32","name":"operatorSetId","type":"uint32"}],"name":"AppCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IApp","name":"app","type":"address"}],"name":"AppStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IApp","name":"app","type":"address"}],"name":"AppStopped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IApp","name":"app","type":"address"}],"name":"AppTerminated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IApp","name":"app","type":"address"}],"name":"AppTerminatedByAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IApp","name":"app","type":"address"},{"indexed":false,"internalType":"uint256","name":"rmsReleaseId","type":"uint256"},{"components":[{"components":[{"components":[{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"string","name":"registry","type":"string"}],"internalType":"struct IReleaseManagerTypes.Artifact[]","name":"artifacts","type":"tuple[]"},{"internalType":"uint32","name":"upgradeByTime","type":"uint32"}],"internalType":"struct IReleaseManagerTypes.Release","name":"rmsRelease","type":"tuple"},{"internalType":"bytes","name":"publicEnv","type":"bytes"},{"internalType":"bytes","name":"encryptedEnv","type":"bytes"}],"indexed":false,"internalType":"struct IAppController.Release","name":"release","type":"tuple"}],"name":"AppUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"limit","type":"uint32"}],"name":"GlobalMaxActiveAppsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint32","name":"limit","type":"uint32"}],"name":"MaxActiveAppsSet","type":"event"},{"inputs":[],"name":"API_PERMISSION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appBeacon","outputs":[{"internalType":"contract IBeacon","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"permission","type":"bytes4"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"calculateApiPermissionDigestHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"calculateAppId","outputs":[{"internalType":"contract IApp","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"computeAVSRegistrar","outputs":[{"internalType":"contract IComputeAVSRegistrar","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"computeOperator","outputs":[{"internalType":"contract IComputeOperator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"components":[{"components":[{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"string","name":"registry","type":"string"}],"internalType":"struct IReleaseManagerTypes.Artifact[]","name":"artifacts","type":"tuple[]"},{"internalType":"uint32","name":"upgradeByTime","type":"uint32"}],"internalType":"struct IReleaseManagerTypes.Release","name":"rmsRelease","type":"tuple"},{"internalType":"bytes","name":"publicEnv","type":"bytes"},{"internalType":"bytes","name":"encryptedEnv","type":"bytes"}],"internalType":"struct IAppController.Release","name":"release","type":"tuple"}],"name":"createApp","outputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getActiveAppCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"getAppCreator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"getAppLatestReleaseBlockNumber","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"getAppOperatorSetId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"getAppStatus","outputs":[{"internalType":"enum IAppController.AppStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getApps","outputs":[{"internalType":"contract IApp[]","name":"apps","type":"address[]"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint32","name":"operatorSetId","type":"uint32"},{"internalType":"uint32","name":"latestReleaseBlockNumber","type":"uint32"},{"internalType":"enum IAppController.AppStatus","name":"status","type":"uint8"}],"internalType":"struct IAppController.AppConfig[]","name":"appConfigsMem","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"developer","type":"address"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getAppsByDeveloper","outputs":[{"internalType":"contract IApp[]","name":"apps","type":"address[]"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint32","name":"operatorSetId","type":"uint32"},{"internalType":"uint32","name":"latestReleaseBlockNumber","type":"uint32"},{"internalType":"enum IAppController.AppStatus","name":"status","type":"uint8"}],"internalType":"struct IAppController.AppConfig[]","name":"appConfigsMem","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getMaxActiveAppsPerUser","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalActiveAppCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxGlobalActiveApps","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionController","outputs":[{"internalType":"contract IPermissionController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"releaseManager","outputs":[{"internalType":"contract IReleaseManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"limit","type":"uint32"}],"name":"setMaxActiveAppsPerUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"limit","type":"uint32"}],"name":"setMaxGlobalActiveApps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"startApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"stopApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"terminateApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"}],"name":"terminateAppByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IApp","name":"app","type":"address"},{"components":[{"components":[{"components":[{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"string","name":"registry","type":"string"}],"internalType":"struct IReleaseManagerTypes.Artifact[]","name":"artifacts","type":"tuple[]"},{"internalType":"uint32","name":"upgradeByTime","type":"uint32"}],"internalType":"struct IReleaseManagerTypes.Release","name":"rmsRelease","type":"tuple"},{"internalType":"bytes","name":"publicEnv","type":"bytes"},{"internalType":"bytes","name":"encryptedEnv","type":"bytes"}],"internalType":"struct IAppController.Release","name":"release","type":"tuple"}],"name":"upgradeApp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610140604052348015610010575f5ffd5b506040516159033803806159038339818101604052810190610032919061053c565b83828483888a806100488161017560201b60201c565b6080818152505050508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1681525050508373ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff166101008173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff166101208173ffffffffffffffffffffffffffffffffffffffff16815250505050505061016a6101da60201b60201c565b5050505050506107bd565b5f5f829050601f815111156101c157826040517f305a27a90000000000000000000000000000000000000000000000000000000081526004016101b89190610633565b60405180910390fd5b8051816101cd90610695565b5f1c175f1b915050919050565b5f60019054906101000a900460ff1615610229576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102209061076b565b60405180910390fd5b60ff80165f5f9054906101000a900460ff1660ff16146102965760ff5f5f6101000a81548160ff021916908360ff1602179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860ff60405161028d91906107a4565b60405180910390a15b565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6102f7826102b1565b810181811067ffffffffffffffff82111715610316576103156102c1565b5b80604052505050565b5f610328610298565b905061033482826102ee565b919050565b5f67ffffffffffffffff821115610353576103526102c1565b5b61035c826102b1565b9050602081019050919050565b8281835e5f83830152505050565b5f61038961038484610339565b61031f565b9050828152602081018484840111156103a5576103a46102ad565b5b6103b0848285610369565b509392505050565b5f82601f8301126103cc576103cb6102a9565b5b81516103dc848260208601610377565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61040e826103e5565b9050919050565b5f61041f82610404565b9050919050565b61042f81610415565b8114610439575f5ffd5b50565b5f8151905061044a81610426565b92915050565b5f61045a82610404565b9050919050565b61046a81610450565b8114610474575f5ffd5b50565b5f8151905061048581610461565b92915050565b5f61049582610404565b9050919050565b6104a58161048b565b81146104af575f5ffd5b50565b5f815190506104c08161049c565b92915050565b5f6104d082610404565b9050919050565b6104e0816104c6565b81146104ea575f5ffd5b50565b5f815190506104fb816104d7565b92915050565b5f61050b82610404565b9050919050565b61051b81610501565b8114610525575f5ffd5b50565b5f8151905061053681610512565b92915050565b5f5f5f5f5f5f60c08789031215610556576105556102a1565b5b5f87015167ffffffffffffffff811115610573576105726102a5565b5b61057f89828a016103b8565b965050602061059089828a0161043c565b95505060406105a189828a01610477565b94505060606105b289828a016104b2565b93505060806105c389828a016104ed565b92505060a06105d489828a01610528565b9150509295509295509295565b5f81519050919050565b5f82825260208201905092915050565b5f610605826105e1565b61060f81856105eb565b935061061f818560208601610369565b610628816102b1565b840191505092915050565b5f6020820190508181035f83015261064b81846105fb565b905092915050565b5f81519050919050565b5f819050602082019050919050565b5f819050919050565b5f610680825161066c565b80915050919050565b5f82821b905092915050565b5f61069f82610653565b826106a98461065d565b90506106b481610675565b925060208210156106f4576106ef7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802610689565b831692505b5050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320696e6974695f8201527f616c697a696e6700000000000000000000000000000000000000000000000000602082015250565b5f6107556027836105eb565b9150610760826106fb565b604082019050919050565b5f6020820190508181035f83015261078281610749565b9050919050565b5f60ff82169050919050565b61079e81610789565b82525050565b5f6020820190506107b75f830184610795565b92915050565b60805160a05160c05160e05161010051610120516150736108905f395f8181610887015261250401525f8181611050015281816111270152818161156701528181611768015281816117f80152818161187e015281816118c50152818161208c0152612be501525f81816106ac0152818161190b015261197601525f818161065d015281816110e00152612b9e01525f81816107270152818161152b015281816115d101528181611659015281816116df0152818161219801526125f701525f818161079d0152612dc401526150735ff3fe608060405234801561000f575f5ffd5b50600436106101cd575f3560e01c80639ffbdce611610102578063d49fec2b116100a0578063e70b81b11161006f578063e70b81b11461057a578063ef6d92c614610596578063f36618ac146105b4578063f698da25146105e5576101cd565b8063d49fec2b146104e2578063d5aae178146104fe578063d66f77711461052e578063d80a956b1461054a576101cd565b8063a60daa8f116100dc578063a60daa8f1461045c578063a8aa2bd31461048c578063b438c141146104aa578063c4d66de8146104c6576101cd565b80639ffbdce6146103dd578063a37e7e441461040d578063a46530a21461043e576101cd565b806354fd4d501161016f5780638a52d0b5116101495780638a52d0b5146103555780638a7f922c1461037357806390e2196b146103915780639690b7e7146103ad576101cd565b806354fd4d50146102d757806367962d48146102f55780636eb2099f14610325576101cd565b80633fc4cbfd116101ab5780633fc4cbfd1461024f57806340f70a9e1461026d5780634657e26a1461029d5780634dd8ef81146102bb576101cd565b80630c2199fb146101d15780630d78573e1461020157806336b188741461021f575b5f5ffd5b6101eb60048036038101906101e6919061301c565b610603565b6040516101f89190613065565b60405180910390f35b61020961065b565b60405161021691906130d9565b60405180910390f35b61023960048036038101906102349190613125565b61067f565b6040516102469190613183565b60405180910390f35b6102576106aa565b60405161026491906131bc565b60405180910390f35b6102876004803603810190610282919061301c565b6106ce565b6040516102949190613065565b60405180910390f35b6102a5610725565b6040516102b291906131f5565b60405180910390f35b6102d560048036038101906102d09190613249565b610749565b005b6102df610796565b6040516102ec91906132e4565b60405180910390f35b61030f600480360381019061030a9190613249565b6107c6565b60405161031c9190613313565b60405180910390f35b61033f600480360381019061033a9190613249565b61082d565b60405161034c9190613065565b60405180910390f35b61035d610885565b60405161036a919061334c565b60405180910390f35b61037b6108a9565b6040516103889190613374565b60405180910390f35b6103ab60048036038101906103a69190613249565b6108cd565b005b6103c760048036038101906103c29190613415565b610a6e565b6040516103d49190613374565b60405180910390f35b6103f760048036038101906103f29190613249565b610aca565b6040516104049190613065565b60405180910390f35b61042760048036038101906104229190613453565b610b22565b6040516104359291906136d4565b60405180910390f35b610446610ea2565b6040516104539190613065565b60405180910390f35b6104766004803603810190610471919061372b565b610eb7565b6040516104839190613183565b60405180910390f35b6104946113a1565b6040516104a19190613065565b60405180910390f35b6104c460048036038101906104bf91906137af565b6113b7565b005b6104e060048036038101906104db919061301c565b611452565b005b6104fc60048036038101906104f791906137da565b611a57565b005b61051860048036038101906105139190613249565b611b47565b6040516105259190613827565b60405180910390f35b61054860048036038101906105439190613249565b611b9c565b005b610564600480360381019061055f9190613840565b611d80565b60405161057191906138a9565b60405180910390f35b610594600480360381019061058f9190613249565b611f28565b005b61059e61208a565b6040516105ab91906138e2565b60405180910390f35b6105ce60048036038101906105c991906138fb565b6120ae565b6040516105dc9291906136d4565b60405180910390f35b6105ed612413565b6040516105fa9190613374565b60405180910390f35b5f60045f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160049054906101000a900463ffffffff169050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f6106a261068d84846124b2565b610696856124e4565b805190602001206125e0565b905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f60045f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900463ffffffff169050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b80610753816125f4565b610789576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610792826126be565b5050565b60606107c17f000000000000000000000000000000000000000000000000000000000000000061276c565b905090565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160149054906101000a900463ffffffff169050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7facd45e8bd36cea31aec6cd4552b994e6bfbda89766b3171349ace038b1b8267f81565b806108d7816125f4565b61090d576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816003808111156109215761092061358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff1660038111156109805761097f61358f565b5b036109b7576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60038111156109ca576109c961358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115610a2957610a2861358f565b5b03610a60576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a69836127de565b505050565b5f610ac27facd45e8bd36cea31aec6cd4552b994e6bfbda89766b3171349ace038b1b8267f8484604051602001610aa79392919061395a565b604051602081830303815290604052805190602001206129ad565b905092915050565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160189054906101000a900463ffffffff169050919050565b6060805f610b3060016129e5565b9050808510610be0575f67ffffffffffffffff811115610b5357610b5261398f565b5b604051908082528060200260200182016040528015610b815781602001602082028036833780820191505090505b505f67ffffffffffffffff811115610b9c57610b9b61398f565b5b604051908082528060200260200182016040528015610bd557816020015b610bc2612f62565b815260200190600190039081610bba5790505b509250925050610e9b565b5f818587610bee91906139e9565b11610c04578486610bff91906139e9565b610c06565b815b90505f8682610c159190613a1c565b90508067ffffffffffffffff811115610c3157610c3061398f565b5b604051908082528060200260200182016040528015610c5f5781602001602082028036833780820191505090505b5094508067ffffffffffffffff811115610c7c57610c7b61398f565b5b604051908082528060200260200182016040528015610cb557816020015b610ca2612f62565b815260200190600190039081610c9a5790505b5093505f5f90505b81811015610e9657610ce48189610cd491906139e9565b60016129f890919063ffffffff16565b868281518110610cf757610cf6613a4f565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060035f878381518110610d4757610d46613a4f565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160189054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f8201601c9054906101000a900460ff166003811115610e5557610e5461358f565b5b6003811115610e6757610e6661358f565b5b81525050858281518110610e7e57610e7d613a4f565b5b60200260200101819052508080600101915050610cbd565b505050505b9250929050565b60055f9054906101000a900463ffffffff1681565b5f5f60045f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20905060055f9054906101000a900463ffffffff1663ffffffff16600560049054906101000a900463ffffffff1663ffffffff1610610f60576040517f42ca568f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f015f9054906101000a900463ffffffff1663ffffffff16815f0160049054906101000a900463ffffffff1663ffffffff1610610fca576040517f82d7ade600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005600481819054906101000a900463ffffffff1680929190610fec90613a7c565b91906101000a81548163ffffffff021916908363ffffffff16021790555050805f01600481819054906101000a900463ffffffff168092919061102e90613a7c565b91906101000a81548163ffffffff021916908363ffffffff160217905550505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633a10eef76040518163ffffffff1660e01b81526004016020604051808303815f875af11580156110b8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110dc9190613abb565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634840a67c60405180604001604052807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020018463ffffffff168152506040518263ffffffff1660e01b81526004016111879190613b5d565b5f604051808303815f87803b15801561119e575f5ffd5b505af11580156111b0573d5f5f3e3d5ffd5b505050506111d05f6111c233886124b2565b6111cb336124e4565b612a0f565b92508060035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160146101000a81548163ffffffff021916908363ffffffff1602179055505f60035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160186101000a81548163ffffffff021916908363ffffffff1602179055503360035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061131f836001612b1690919063ffffffff16565b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fe9e6e5409b80e2dab7d38194fb370b2e8045a1af28177b94ddcf19d2495d75898360405161137d9190613065565b60405180910390a361138f8385612b43565b50611399836126be565b505092915050565b600560049054906101000a900463ffffffff1681565b306113c1816125f4565b6113f7576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160055f6101000a81548163ffffffff021916908363ffffffff1602179055507fc3c99803ad2e80be7382791ca0b23147a94739b9e66a656b9c8c47f9d6963414826040516114469190613065565b60405180910390a15050565b5f5f60019054906101000a900460ff16159050808015611482575060015f5f9054906101000a900460ff1660ff16105b806114af575061149130612d9a565b1580156114ae575060015f5f9054906101000a900460ff1660ff16145b5b6114ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e590613bf9565b60405180910390fd5b60015f5f6101000a81548160ff021916908360ff16021790555080156115295760015f60016101000a81548160ff0219169083151502179055505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663628806ef7f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016115a29190613313565b5f604051808303815f87803b1580156115b9575f5ffd5b505af11580156115cb573d5f5f3e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663eb5a4e8730306040518363ffffffff1660e01b815260040161162a929190613c17565b5f604051808303815f87803b158015611641575f5ffd5b505af1158015611653573d5f5f3e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663628806ef306040518263ffffffff1660e01b81526004016116b09190613313565b5f604051808303815f87803b1580156116c7575f5ffd5b505af11580156116d9573d5f5f3e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663eb5a4e8730846040518363ffffffff1660e01b8152600401611738929190613c17565b5f604051808303815f87803b15801561174f575f5ffd5b505af1158015611761573d5f5f3e3d5ffd5b505050505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633a10eef76040518163ffffffff1660e01b81526004016020604051808303815f875af11580156117d0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f49190613abb565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166374da4713826040518263ffffffff1660e01b815260040161184f9190613065565b5f604051808303815f87803b158015611866575f5ffd5b505af1158015611878573d5f5f3e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631017873a60405180604001604052807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020018463ffffffff168152507f00000000000000000000000000000000000000000000000000000000000000006040518363ffffffff1660e01b8152600401611947929190613c3e565b5f604051808303815f87803b15801561195e575f5ffd5b505af1158015611970573d5f5f3e3d5ffd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634ca62978826040518263ffffffff1660e01b81526004016119cd9190613065565b5f604051808303815f87803b1580156119e4575f5ffd5b505af11580156119f6573d5f5f3e3d5ffd5b50505050508015611a53575f5f60016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986001604051611a4a9190613caa565b60405180910390a15b5050565b30611a61816125f4565b611a97576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160045f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f6101000a81548163ffffffff021916908363ffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff167f708c955faa87ece750a9700c153a20797167e2fcbde9fca9186801f874663a9983604051611b3a9190613065565b60405180910390a2505050565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff169050919050565b30611ba6816125f4565b611bdc576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600380811115611bf057611bef61358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611c4f57611c4e61358f565b5b03611c86576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6003811115611c9957611c9861358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611cf857611cf761358f565b5b03611d2f576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d38836127de565b8273ffffffffffffffffffffffffffffffffffffffff167f4636ad9a0a072d9c8b05a5bcda7d33256c5401515e612c25c13273b378cb280960405160405180910390a2505050565b5f82611d8b816125f4565b611dc1576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600380811115611dd557611dd461358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611e3457611e3361358f565b5b03611e6b576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6003811115611e7e57611e7d61358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611edd57611edc61358f565b5b03611f14576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f1e8585612b43565b9250505092915050565b80611f32816125f4565b611f68576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60035f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20905060016003811115611fbc57611fbb61358f565b5b815f01601c9054906101000a900460ff166003811115611fdf57611fde61358f565b5b14612016576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002815f01601c6101000a81548160ff0219169083600381111561203d5761203c61358f565b5b02179055508273ffffffffffffffffffffffffffffffffffffffff167f143b9e3b5aa0fb8cf19b1bdb2eb8d7a94657d4b505070c667433d322b90b1f7860405160405180910390a2505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060805f6120bc60016129e5565b90508367ffffffffffffffff8111156120d8576120d761398f565b5b6040519080825280602002602001820160405280156121065781602001602082028036833780820191505090505b5092508367ffffffffffffffff8111156121235761212261398f565b5b60405190808252806020026020018201604052801561215c57816020015b612149612f62565b8152602001906001900390816121415790505b5091505f5f90505f5f90505f5f90505b838110801561217a57508682105b15612401575f6121948260016129f890919063ffffffff16565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166391006745828c6040518363ffffffff1660e01b81526004016121f1929190613c17565b602060405180830381865afa15801561220c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122309190613cf8565b156123ec578884101561225157838061224890613d23565b945050506123ee565b8087848151811061226557612264613a4f565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060035f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160189054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f8201601c9054906101000a900460ff1660038111156123a9576123a861358f565b5b60038111156123bb576123ba61358f565b5b815250508684815181106123d2576123d1613a4f565b5b602002602001018190525082806123e890613d23565b9350505b505b80806123f990613d23565b91505061216c565b50808552808452505050935093915050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6040518060400160405280600a81526020017f456967656e4c61796572000000000000000000000000000000000000000000008152508051906020012061247a612dbc565b805190602001204630604051602001612497959493929190613d6a565b60405160208183030381529060405280519060200120905090565b5f82826040516020016124c6929190613e20565b60405160208183030381529060405280519060200120905092915050565b606060405180610940016040528061090e815260200161473061090e91397f000000000000000000000000000000000000000000000000000000000000000063c4d66de860e01b8460405160240161253c9190613313565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516020016125aa929190613e9d565b6040516020818303038152906040526040516020016125ca929190613f05565b6040516020818303038152906040529050919050565b5f6125ec838330612e2d565b905092915050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663df595cb88333305f357fffffffff00000000000000000000000000000000000000000000000000000000166040518563ffffffff1660e01b81526004016126779493929190613f28565b6020604051808303815f875af1158015612693573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126b79190613cf8565b9050919050565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c6101000a81548160ff021916908360038111156127215761272061358f565b5b02179055508073ffffffffffffffffffffffffffffffffffffffff167f8426864999f5f9244a203f75107b05f8b474838bc43ff0d8abe18ee5f442751360405160405180910390a250565b60605f61277883612e57565b90505f602067ffffffffffffffff8111156127965761279561398f565b5b6040519080825280601f01601f1916602001820160405280156127c85781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b6003805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c6101000a81548160ff021916908360038111156128405761283f61358f565b5b02179055506005600481819054906101000a900463ffffffff168092919061286790613f6b565b91906101000a81548163ffffffff021916908363ffffffff160217905550505f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060045f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01600481819054906101000a900463ffffffff168092919061294790613f6b565b91906101000a81548163ffffffff021916908363ffffffff160217905550508173ffffffffffffffffffffffffffffffffffffffff167f2465e924a1e9a02843493e65702fd09152c8a631caf7b9b58e4b01ee20ced41660405160405180910390a25050565b5f6129b6612413565b826040516020016129c8929190613fe6565b604051602081830303815290604052805190602001209050919050565b5f6129f1825f01612ea5565b9050919050565b5f612a05835f0183612eb4565b5f1c905092915050565b5f83471015612a53576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a4a90614066565b60405180910390fd5b5f825103612a96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a8d906140ce565b60405180910390fd5b8282516020840186f590505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612b0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b0690614136565b60405180910390fd5b9392505050565b5f612b3b835f018373ffffffffffffffffffffffffffffffffffffffff165f1b612edb565b905092915050565b5f600182805f0190612b559190614160565b805f0190612b639190614187565b905014612b9c576040517f98c82cef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637c09ea8260405180604001604052807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815260200160035f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff1681525084805f0190612c879190614160565b6040518363ffffffff1660e01b8152600401612ca49291906144a7565b6020604051808303815f875af1158015612cc0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ce491906144e9565b90504360035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160186101000a81548163ffffffff021916908363ffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff167fb5d2b7df0352a87a587a430bfceab43859b3b3c404f0425c4c1ab0675ed57b948284604051612d8c92919061469c565b60405180910390a292915050565b5f5f8273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60605f612de87f000000000000000000000000000000000000000000000000000000000000000061276c565b9050805f81518110612dfd57612dfc613a4f565b5b602001015160f81c60f81b604051602001612e189190614715565b60405160208183030381529060405291505090565b5f604051836040820152846020820152828152600b810160ff815360558120925050509392505050565b5f5f60ff835f1c169050601f811115612e9c576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b5f815f01805490509050919050565b5f825f018281548110612eca57612ec9613a4f565b5b905f5260205f200154905092915050565b5f612ee68383612f42565b612f3857825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050612f3c565b5f90505b92915050565b5f5f836001015f8481526020019081526020015f20541415905092915050565b60405180608001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f63ffffffff1681526020015f63ffffffff1681526020015f6003811115612fb457612fb361358f565b5b81525090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612feb82612fc2565b9050919050565b612ffb81612fe1565b8114613005575f5ffd5b50565b5f8135905061301681612ff2565b92915050565b5f6020828403121561303157613030612fba565b5b5f61303e84828501613008565b91505092915050565b5f63ffffffff82169050919050565b61305f81613047565b82525050565b5f6020820190506130785f830184613056565b92915050565b5f819050919050565b5f6130a161309c61309784612fc2565b61307e565b612fc2565b9050919050565b5f6130b282613087565b9050919050565b5f6130c3826130a8565b9050919050565b6130d3816130b9565b82525050565b5f6020820190506130ec5f8301846130ca565b92915050565b5f819050919050565b613104816130f2565b811461310e575f5ffd5b50565b5f8135905061311f816130fb565b92915050565b5f5f6040838503121561313b5761313a612fba565b5b5f61314885828601613008565b925050602061315985828601613111565b9150509250929050565b5f61316d826130a8565b9050919050565b61317d81613163565b82525050565b5f6020820190506131965f830184613174565b92915050565b5f6131a6826130a8565b9050919050565b6131b68161319c565b82525050565b5f6020820190506131cf5f8301846131ad565b92915050565b5f6131df826130a8565b9050919050565b6131ef816131d5565b82525050565b5f6020820190506132085f8301846131e6565b92915050565b5f61321882612fe1565b9050919050565b6132288161320e565b8114613232575f5ffd5b50565b5f813590506132438161321f565b92915050565b5f6020828403121561325e5761325d612fba565b5b5f61326b84828501613235565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6132b682613274565b6132c0818561327e565b93506132d081856020860161328e565b6132d98161329c565b840191505092915050565b5f6020820190508181035f8301526132fc81846132ac565b905092915050565b61330d81612fe1565b82525050565b5f6020820190506133265f830184613304565b92915050565b5f613336826130a8565b9050919050565b6133468161332c565b82525050565b5f60208201905061335f5f83018461333d565b92915050565b61336e816130f2565b82525050565b5f6020820190506133875f830184613365565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6133c18161338d565b81146133cb575f5ffd5b50565b5f813590506133dc816133b8565b92915050565b5f819050919050565b6133f4816133e2565b81146133fe575f5ffd5b50565b5f8135905061340f816133eb565b92915050565b5f5f6040838503121561342b5761342a612fba565b5b5f613438858286016133ce565b925050602061344985828601613401565b9150509250929050565b5f5f6040838503121561346957613468612fba565b5b5f61347685828601613401565b925050602061348785828601613401565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6134c381613163565b82525050565b5f6134d483836134ba565b60208301905092915050565b5f602082019050919050565b5f6134f682613491565b613500818561349b565b935061350b836134ab565b805f5b8381101561353b57815161352288826134c9565b975061352d836134e0565b92505060018101905061350e565b5085935050505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61357a81612fe1565b82525050565b61358981613047565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106135cd576135cc61358f565b5b50565b5f8190506135dd826135bc565b919050565b5f6135ec826135d0565b9050919050565b6135fc816135e2565b82525050565b608082015f8201516136165f850182613571565b5060208201516136296020850182613580565b50604082015161363c6040850182613580565b50606082015161364f60608501826135f3565b50505050565b5f6136608383613602565b60808301905092915050565b5f602082019050919050565b5f61368282613548565b61368c8185613552565b935061369783613562565b805f5b838110156136c75781516136ae8882613655565b97506136b98361366c565b92505060018101905061369a565b5085935050505092915050565b5f6040820190508181035f8301526136ec81856134ec565b905081810360208301526137008184613678565b90509392505050565b5f5ffd5b5f6060828403121561372257613721613709565b5b81905092915050565b5f5f6040838503121561374157613740612fba565b5b5f61374e85828601613111565b925050602083013567ffffffffffffffff81111561376f5761376e612fbe565b5b61377b8582860161370d565b9150509250929050565b61378e81613047565b8114613798575f5ffd5b50565b5f813590506137a981613785565b92915050565b5f602082840312156137c4576137c3612fba565b5b5f6137d18482850161379b565b91505092915050565b5f5f604083850312156137f0576137ef612fba565b5b5f6137fd85828601613008565b925050602061380e8582860161379b565b9150509250929050565b613821816135e2565b82525050565b5f60208201905061383a5f830184613818565b92915050565b5f5f6040838503121561385657613855612fba565b5b5f61386385828601613235565b925050602083013567ffffffffffffffff81111561388457613883612fbe565b5b6138908582860161370d565b9150509250929050565b6138a3816133e2565b82525050565b5f6020820190506138bc5f83018461389a565b92915050565b5f6138cc826130a8565b9050919050565b6138dc816138c2565b82525050565b5f6020820190506138f55f8301846138d3565b92915050565b5f5f5f6060848603121561391257613911612fba565b5b5f61391f86828701613008565b935050602061393086828701613401565b925050604061394186828701613401565b9150509250925092565b6139548161338d565b82525050565b5f60608201905061396d5f830186613365565b61397a602083018561394b565b613987604083018461389a565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6139f3826133e2565b91506139fe836133e2565b9250828201905080821115613a1657613a156139bc565b5b92915050565b5f613a26826133e2565b9150613a31836133e2565b9250828203905081811115613a4957613a486139bc565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613a8682613047565b915063ffffffff8203613a9c57613a9b6139bc565b5b600182019050919050565b5f81519050613ab581613785565b92915050565b5f60208284031215613ad057613acf612fba565b5b5f613add84828501613aa7565b91505092915050565b604082015f820151613afa5f850182613571565b506020820151613b0d6020850182613580565b50505050565b7f68747470733a2f2f656967656e636c6f75642e78797a000000000000000000005f82015250565b5f613b4760168361327e565b9150613b5282613b13565b602082019050919050565b5f606082019050613b705f830184613ae6565b8181036040830152613b8181613b3b565b905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c7265615f8201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b5f613be3602e8361327e565b9150613bee82613b89565b604082019050919050565b5f6020820190508181035f830152613c1081613bd7565b9050919050565b5f604082019050613c2a5f830185613304565b613c376020830184613304565b9392505050565b5f606082019050613c515f830185613ae6565b613c5e6040830184613304565b9392505050565b5f819050919050565b5f60ff82169050919050565b5f613c94613c8f613c8a84613c65565b61307e565b613c6e565b9050919050565b613ca481613c7a565b82525050565b5f602082019050613cbd5f830184613c9b565b92915050565b5f8115159050919050565b613cd781613cc3565b8114613ce1575f5ffd5b50565b5f81519050613cf281613cce565b92915050565b5f60208284031215613d0d57613d0c612fba565b5b5f613d1a84828501613ce4565b91505092915050565b5f613d2d826133e2565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613d5f57613d5e6139bc565b5b600182019050919050565b5f60a082019050613d7d5f830188613365565b613d8a6020830187613365565b613d976040830186613365565b613da4606083018561389a565b613db16080830184613304565b9695505050505050565b5f8160601b9050919050565b5f613dd182613dbb565b9050919050565b5f613de282613dc7565b9050919050565b613dfa613df582612fe1565b613dd8565b82525050565b5f819050919050565b613e1a613e15826130f2565b613e00565b82525050565b5f613e2b8285613de9565b601482019150613e3b8284613e09565b6020820191508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f613e6f82613e4b565b613e798185613e55565b9350613e8981856020860161328e565b613e928161329c565b840191505092915050565b5f604082019050613eb05f83018561333d565b8181036020830152613ec28184613e65565b90509392505050565b5f81905092915050565b5f613edf82613e4b565b613ee98185613ecb565b9350613ef981856020860161328e565b80840191505092915050565b5f613f108285613ed5565b9150613f1c8284613ed5565b91508190509392505050565b5f608082019050613f3b5f830187613304565b613f486020830186613304565b613f556040830185613304565b613f62606083018461394b565b95945050505050565b5f613f7582613047565b91505f8203613f8757613f866139bc565b5b600182039050919050565b5f81905092915050565b7f19010000000000000000000000000000000000000000000000000000000000005f82015250565b5f613fd0600283613f92565b9150613fdb82613f9c565b600282019050919050565b5f613ff082613fc4565b9150613ffc8285613e09565b60208201915061400c8284613e09565b6020820191508190509392505050565b7f437265617465323a20696e73756666696369656e742062616c616e63650000005f82015250565b5f614050601d8361327e565b915061405b8261401c565b602082019050919050565b5f6020820190508181035f83015261407d81614044565b9050919050565b7f437265617465323a2062797465636f6465206c656e677468206973207a65726f5f82015250565b5f6140b860208361327e565b91506140c382614084565b602082019050919050565b5f6020820190508181035f8301526140e5816140ac565b9050919050565b7f437265617465323a204661696c6564206f6e206465706c6f79000000000000005f82015250565b5f61412060198361327e565b915061412b826140ec565b602082019050919050565b5f6020820190508181035f83015261414d81614114565b9050919050565b5f5ffd5b5f5ffd5b5f5ffd5b5f8235600160400383360303811261417b5761417a614154565b5b80830191505092915050565b5f5f833560016020038436030381126141a3576141a2614154565b5b80840192508235915067ffffffffffffffff8211156141c5576141c4614158565b5b6020830192506020820236038313156141e1576141e061415c565b5b509250929050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83356001602003843603038112614211576142106141f1565b5b83810192508235915060208301925067ffffffffffffffff821115614239576142386141e9565b5b60208202360383131561424f5761424e6141ed565b5b509250929050565b5f82825260208201905092915050565b5f819050919050565b5f61427e6020840184613111565b905092915050565b61428f816130f2565b82525050565b5f5f833560016020038436030381126142b1576142b06141f1565b5b83810192508235915060208301925067ffffffffffffffff8211156142d9576142d86141e9565b5b6001820236038313156142ef576142ee6141ed565b5b509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f61432083856142f7565b935061432d838584614307565b6143368361329c565b840190509392505050565b5f604083016143525f840184614270565b61435e5f860182614286565b5061436c6020840184614295565b858303602087015261437f838284614315565b925050508091505092915050565b5f6143988383614341565b905092915050565b5f823560016040038336030381126143bb576143ba6141f1565b5b82810191505092915050565b5f602082019050919050565b5f6143de8385614257565b9350836020840285016143f084614267565b805f5b8781101561443357848403895261440a82846143a0565b614414858261438d565b945061441f836143c7565b925060208a019950506001810190506143f3565b50829750879450505050509392505050565b5f614453602084018461379b565b905092915050565b5f6040830161446c5f8401846141f5565b8583035f87015261447e8382846143d3565b9250505061448f6020840184614445565b61449c6020860182613580565b508091505092915050565b5f6060820190506144ba5f830185613ae6565b81810360408301526144cc818461445b565b90509392505050565b5f815190506144e3816133eb565b92915050565b5f602082840312156144fe576144fd612fba565b5b5f61450b848285016144d5565b91505092915050565b5f8235600160400383360303811261452f5761452e6141f1565b5b82810191505092915050565b5f6040830161454c5f8401846141f5565b8583035f87015261455e8382846143d3565b9250505061456f6020840184614445565b61457c6020860182613580565b508091505092915050565b5f5f833560016020038436030381126145a3576145a26141f1565b5b83810192508235915060208301925067ffffffffffffffff8211156145cb576145ca6141e9565b5b6001820236038313156145e1576145e06141ed565b5b509250929050565b5f82825260208201905092915050565b5f61460483856145e9565b9350614611838584614307565b61461a8361329c565b840190509392505050565b5f606083016146365f840184614514565b8482035f860152614647828261453b565b9150506146576020840184614587565b858303602087015261466a8382846145f9565b9250505061467b6040840184614587565b858303604087015261468e8382846145f9565b925050508091505092915050565b5f6040820190506146af5f83018561389a565b81810360208301526146c18184614625565b90509392505050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f819050919050565b61470f61470a826146ca565b6146f5565b82525050565b5f61472082846146fe565b6001820191508190509291505056fe608060405260405161090e38038061090e83398101604081905261002291610460565b61002e82826000610035565b505061058a565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610520565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610520565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108e7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053b565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c65782516103bf576001600160a01b0385163b6103bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d0565b6103d083836103d8565b949350505050565b8151156103e85781518083602001fd5b8060405162461bcd60e51b81526004016101699190610557565b80516001600160a01b038116811461041957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044f578181015183820152602001610437565b838111156100f95750506000910152565b6000806040838503121561047357600080fd5b61047c83610402565b60208401519092506001600160401b038082111561049957600080fd5b818501915085601f8301126104ad57600080fd5b8151818111156104bf576104bf61041e565b604051601f8201601f19908116603f011681019083821181831017156104e7576104e761041e565b8160405282815288602084870101111561050057600080fd5b610511836020830160208801610434565b80955050505050509250929050565b60006020828403121561053257600080fd5b6102c882610402565b6000825161054d818460208701610434565b9190910192915050565b6020815260008251806020840152610576816040850160208701610434565b601f01601f19169190910160400192915050565b61034e806105996000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f260279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb9190610249565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a2565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020d578251610206576001600160a01b0385163b6102065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610217565b610217838361021f565b949350505050565b81511561022f5781518083602001fd5b8060405162461bcd60e51b81526004016101fd91906102be565b60006020828403121561025b57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028d578181015183820152602001610275565b8381111561029c576000848401525b50505050565b600082516102b4818460208701610272565b9190910192915050565b60208152600082518060208401526102dd816040850160208701610272565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d51e81d3bc5ed20a26aeb05dce7e825c503b2061aa78628027300c8d65b9d89a64736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207d531b50d1113e334f40451e3e8cd620d45d7589439e96c12188273537ac591464736f6c634300081b003300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e5000000000000000000000000eda3cad031c0cf367cf3f517ee0dc98f9ba80c8f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b000000000000000000000000801c1c2dfab0a6821ca38a08b78a7c7cc81d64d1000000000000000000000000c1e14f82c7f554b8582bb786728f669875b3fc530000000000000000000000000000000000000000000000000000000000000005312e302e34000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106101cd575f3560e01c80639ffbdce611610102578063d49fec2b116100a0578063e70b81b11161006f578063e70b81b11461057a578063ef6d92c614610596578063f36618ac146105b4578063f698da25146105e5576101cd565b8063d49fec2b146104e2578063d5aae178146104fe578063d66f77711461052e578063d80a956b1461054a576101cd565b8063a60daa8f116100dc578063a60daa8f1461045c578063a8aa2bd31461048c578063b438c141146104aa578063c4d66de8146104c6576101cd565b80639ffbdce6146103dd578063a37e7e441461040d578063a46530a21461043e576101cd565b806354fd4d501161016f5780638a52d0b5116101495780638a52d0b5146103555780638a7f922c1461037357806390e2196b146103915780639690b7e7146103ad576101cd565b806354fd4d50146102d757806367962d48146102f55780636eb2099f14610325576101cd565b80633fc4cbfd116101ab5780633fc4cbfd1461024f57806340f70a9e1461026d5780634657e26a1461029d5780634dd8ef81146102bb576101cd565b80630c2199fb146101d15780630d78573e1461020157806336b188741461021f575b5f5ffd5b6101eb60048036038101906101e6919061301c565b610603565b6040516101f89190613065565b60405180910390f35b61020961065b565b60405161021691906130d9565b60405180910390f35b61023960048036038101906102349190613125565b61067f565b6040516102469190613183565b60405180910390f35b6102576106aa565b60405161026491906131bc565b60405180910390f35b6102876004803603810190610282919061301c565b6106ce565b6040516102949190613065565b60405180910390f35b6102a5610725565b6040516102b291906131f5565b60405180910390f35b6102d560048036038101906102d09190613249565b610749565b005b6102df610796565b6040516102ec91906132e4565b60405180910390f35b61030f600480360381019061030a9190613249565b6107c6565b60405161031c9190613313565b60405180910390f35b61033f600480360381019061033a9190613249565b61082d565b60405161034c9190613065565b60405180910390f35b61035d610885565b60405161036a919061334c565b60405180910390f35b61037b6108a9565b6040516103889190613374565b60405180910390f35b6103ab60048036038101906103a69190613249565b6108cd565b005b6103c760048036038101906103c29190613415565b610a6e565b6040516103d49190613374565b60405180910390f35b6103f760048036038101906103f29190613249565b610aca565b6040516104049190613065565b60405180910390f35b61042760048036038101906104229190613453565b610b22565b6040516104359291906136d4565b60405180910390f35b610446610ea2565b6040516104539190613065565b60405180910390f35b6104766004803603810190610471919061372b565b610eb7565b6040516104839190613183565b60405180910390f35b6104946113a1565b6040516104a19190613065565b60405180910390f35b6104c460048036038101906104bf91906137af565b6113b7565b005b6104e060048036038101906104db919061301c565b611452565b005b6104fc60048036038101906104f791906137da565b611a57565b005b61051860048036038101906105139190613249565b611b47565b6040516105259190613827565b60405180910390f35b61054860048036038101906105439190613249565b611b9c565b005b610564600480360381019061055f9190613840565b611d80565b60405161057191906138a9565b60405180910390f35b610594600480360381019061058f9190613249565b611f28565b005b61059e61208a565b6040516105ab91906138e2565b60405180910390f35b6105ce60048036038101906105c991906138fb565b6120ae565b6040516105dc9291906136d4565b60405180910390f35b6105ed612413565b6040516105fa9190613374565b60405180910390f35b5f60045f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160049054906101000a900463ffffffff169050919050565b7f000000000000000000000000eda3cad031c0cf367cf3f517ee0dc98f9ba80c8f81565b5f6106a261068d84846124b2565b610696856124e4565b805190602001206125e0565b905092915050565b7f000000000000000000000000801c1c2dfab0a6821ca38a08b78a7c7cc81d64d181565b5f60045f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900463ffffffff169050919050565b7f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e581565b80610753816125f4565b610789576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610792826126be565b5050565b60606107c17f312e302e3400000000000000000000000000000000000000000000000000000561276c565b905090565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160149054906101000a900463ffffffff169050919050565b7f000000000000000000000000c1e14f82c7f554b8582bb786728f669875b3fc5381565b7facd45e8bd36cea31aec6cd4552b994e6bfbda89766b3171349ace038b1b8267f81565b806108d7816125f4565b61090d576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816003808111156109215761092061358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff1660038111156109805761097f61358f565b5b036109b7576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60038111156109ca576109c961358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115610a2957610a2861358f565b5b03610a60576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a69836127de565b505050565b5f610ac27facd45e8bd36cea31aec6cd4552b994e6bfbda89766b3171349ace038b1b8267f8484604051602001610aa79392919061395a565b604051602081830303815290604052805190602001206129ad565b905092915050565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160189054906101000a900463ffffffff169050919050565b6060805f610b3060016129e5565b9050808510610be0575f67ffffffffffffffff811115610b5357610b5261398f565b5b604051908082528060200260200182016040528015610b815781602001602082028036833780820191505090505b505f67ffffffffffffffff811115610b9c57610b9b61398f565b5b604051908082528060200260200182016040528015610bd557816020015b610bc2612f62565b815260200190600190039081610bba5790505b509250925050610e9b565b5f818587610bee91906139e9565b11610c04578486610bff91906139e9565b610c06565b815b90505f8682610c159190613a1c565b90508067ffffffffffffffff811115610c3157610c3061398f565b5b604051908082528060200260200182016040528015610c5f5781602001602082028036833780820191505090505b5094508067ffffffffffffffff811115610c7c57610c7b61398f565b5b604051908082528060200260200182016040528015610cb557816020015b610ca2612f62565b815260200190600190039081610c9a5790505b5093505f5f90505b81811015610e9657610ce48189610cd491906139e9565b60016129f890919063ffffffff16565b868281518110610cf757610cf6613a4f565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060035f878381518110610d4757610d46613a4f565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160189054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f8201601c9054906101000a900460ff166003811115610e5557610e5461358f565b5b6003811115610e6757610e6661358f565b5b81525050858281518110610e7e57610e7d613a4f565b5b60200260200101819052508080600101915050610cbd565b505050505b9250929050565b60055f9054906101000a900463ffffffff1681565b5f5f60045f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20905060055f9054906101000a900463ffffffff1663ffffffff16600560049054906101000a900463ffffffff1663ffffffff1610610f60576040517f42ca568f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f015f9054906101000a900463ffffffff1663ffffffff16815f0160049054906101000a900463ffffffff1663ffffffff1610610fca576040517f82d7ade600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005600481819054906101000a900463ffffffff1680929190610fec90613a7c565b91906101000a81548163ffffffff021916908363ffffffff16021790555050805f01600481819054906101000a900463ffffffff168092919061102e90613a7c565b91906101000a81548163ffffffff021916908363ffffffff160217905550505f7f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff16633a10eef76040518163ffffffff1660e01b81526004016020604051808303815f875af11580156110b8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110dc9190613abb565b90507f000000000000000000000000eda3cad031c0cf367cf3f517ee0dc98f9ba80c8f73ffffffffffffffffffffffffffffffffffffffff16634840a67c60405180604001604052807f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff1681526020018463ffffffff168152506040518263ffffffff1660e01b81526004016111879190613b5d565b5f604051808303815f87803b15801561119e575f5ffd5b505af11580156111b0573d5f5f3e3d5ffd5b505050506111d05f6111c233886124b2565b6111cb336124e4565b612a0f565b92508060035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160146101000a81548163ffffffff021916908363ffffffff1602179055505f60035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160186101000a81548163ffffffff021916908363ffffffff1602179055503360035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061131f836001612b1690919063ffffffff16565b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fe9e6e5409b80e2dab7d38194fb370b2e8045a1af28177b94ddcf19d2495d75898360405161137d9190613065565b60405180910390a361138f8385612b43565b50611399836126be565b505092915050565b600560049054906101000a900463ffffffff1681565b306113c1816125f4565b6113f7576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160055f6101000a81548163ffffffff021916908363ffffffff1602179055507fc3c99803ad2e80be7382791ca0b23147a94739b9e66a656b9c8c47f9d6963414826040516114469190613065565b60405180910390a15050565b5f5f60019054906101000a900460ff16159050808015611482575060015f5f9054906101000a900460ff1660ff16105b806114af575061149130612d9a565b1580156114ae575060015f5f9054906101000a900460ff1660ff16145b5b6114ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e590613bf9565b60405180910390fd5b60015f5f6101000a81548160ff021916908360ff16021790555080156115295760015f60016101000a81548160ff0219169083151502179055505b7f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e573ffffffffffffffffffffffffffffffffffffffff1663628806ef7f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b6040518263ffffffff1660e01b81526004016115a29190613313565b5f604051808303815f87803b1580156115b9575f5ffd5b505af11580156115cb573d5f5f3e3d5ffd5b505050507f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e573ffffffffffffffffffffffffffffffffffffffff1663eb5a4e8730306040518363ffffffff1660e01b815260040161162a929190613c17565b5f604051808303815f87803b158015611641575f5ffd5b505af1158015611653573d5f5f3e3d5ffd5b505050507f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e573ffffffffffffffffffffffffffffffffffffffff1663628806ef306040518263ffffffff1660e01b81526004016116b09190613313565b5f604051808303815f87803b1580156116c7575f5ffd5b505af11580156116d9573d5f5f3e3d5ffd5b505050507f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e573ffffffffffffffffffffffffffffffffffffffff1663eb5a4e8730846040518363ffffffff1660e01b8152600401611738929190613c17565b5f604051808303815f87803b15801561174f575f5ffd5b505af1158015611761573d5f5f3e3d5ffd5b505050505f7f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff16633a10eef76040518163ffffffff1660e01b81526004016020604051808303815f875af11580156117d0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f49190613abb565b90507f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff166374da4713826040518263ffffffff1660e01b815260040161184f9190613065565b5f604051808303815f87803b158015611866575f5ffd5b505af1158015611878573d5f5f3e3d5ffd5b505050507f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff16631017873a60405180604001604052807f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff1681526020018463ffffffff168152507f000000000000000000000000801c1c2dfab0a6821ca38a08b78a7c7cc81d64d16040518363ffffffff1660e01b8152600401611947929190613c3e565b5f604051808303815f87803b15801561195e575f5ffd5b505af1158015611970573d5f5f3e3d5ffd5b505050507f000000000000000000000000801c1c2dfab0a6821ca38a08b78a7c7cc81d64d173ffffffffffffffffffffffffffffffffffffffff16634ca62978826040518263ffffffff1660e01b81526004016119cd9190613065565b5f604051808303815f87803b1580156119e4575f5ffd5b505af11580156119f6573d5f5f3e3d5ffd5b50505050508015611a53575f5f60016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986001604051611a4a9190613caa565b60405180910390a15b5050565b30611a61816125f4565b611a97576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160045f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f6101000a81548163ffffffff021916908363ffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff167f708c955faa87ece750a9700c153a20797167e2fcbde9fca9186801f874663a9983604051611b3a9190613065565b60405180910390a2505050565b5f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff169050919050565b30611ba6816125f4565b611bdc576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600380811115611bf057611bef61358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611c4f57611c4e61358f565b5b03611c86576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6003811115611c9957611c9861358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611cf857611cf761358f565b5b03611d2f576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d38836127de565b8273ffffffffffffffffffffffffffffffffffffffff167f4636ad9a0a072d9c8b05a5bcda7d33256c5401515e612c25c13273b378cb280960405160405180910390a2505050565b5f82611d8b816125f4565b611dc1576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600380811115611dd557611dd461358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611e3457611e3361358f565b5b03611e6b576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6003811115611e7e57611e7d61358f565b5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c9054906101000a900460ff166003811115611edd57611edc61358f565b5b03611f14576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f1e8585612b43565b9250505092915050565b80611f32816125f4565b611f68576040517f932d94f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60035f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20905060016003811115611fbc57611fbb61358f565b5b815f01601c9054906101000a900460ff166003811115611fdf57611fde61358f565b5b14612016576040517f609749e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002815f01601c6101000a81548160ff0219169083600381111561203d5761203c61358f565b5b02179055508273ffffffffffffffffffffffffffffffffffffffff167f143b9e3b5aa0fb8cf19b1bdb2eb8d7a94657d4b505070c667433d322b90b1f7860405160405180910390a2505050565b7f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b81565b6060805f6120bc60016129e5565b90508367ffffffffffffffff8111156120d8576120d761398f565b5b6040519080825280602002602001820160405280156121065781602001602082028036833780820191505090505b5092508367ffffffffffffffff8111156121235761212261398f565b5b60405190808252806020026020018201604052801561215c57816020015b612149612f62565b8152602001906001900390816121415790505b5091505f5f90505f5f90505f5f90505b838110801561217a57508682105b15612401575f6121948260016129f890919063ffffffff16565b90507f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e573ffffffffffffffffffffffffffffffffffffffff166391006745828c6040518363ffffffff1660e01b81526004016121f1929190613c17565b602060405180830381865afa15801561220c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122309190613cf8565b156123ec578884101561225157838061224890613d23565b945050506123ee565b8087848151811061226557612264613a4f565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060035f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160189054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f8201601c9054906101000a900460ff1660038111156123a9576123a861358f565b5b60038111156123bb576123ba61358f565b5b815250508684815181106123d2576123d1613a4f565b5b602002602001018190525082806123e890613d23565b9350505b505b80806123f990613d23565b91505061216c565b50808552808452505050935093915050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6040518060400160405280600a81526020017f456967656e4c61796572000000000000000000000000000000000000000000008152508051906020012061247a612dbc565b805190602001204630604051602001612497959493929190613d6a565b60405160208183030381529060405280519060200120905090565b5f82826040516020016124c6929190613e20565b60405160208183030381529060405280519060200120905092915050565b606060405180610940016040528061090e815260200161473061090e91397f000000000000000000000000c1e14f82c7f554b8582bb786728f669875b3fc5363c4d66de860e01b8460405160240161253c9190613313565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516020016125aa929190613e9d565b6040516020818303038152906040526040516020016125ca929190613f05565b6040516020818303038152906040529050919050565b5f6125ec838330612e2d565b905092915050565b5f7f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e573ffffffffffffffffffffffffffffffffffffffff1663df595cb88333305f357fffffffff00000000000000000000000000000000000000000000000000000000166040518563ffffffff1660e01b81526004016126779493929190613f28565b6020604051808303815f875af1158015612693573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126b79190613cf8565b9050919050565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c6101000a81548160ff021916908360038111156127215761272061358f565b5b02179055508073ffffffffffffffffffffffffffffffffffffffff167f8426864999f5f9244a203f75107b05f8b474838bc43ff0d8abe18ee5f442751360405160405180910390a250565b60605f61277883612e57565b90505f602067ffffffffffffffff8111156127965761279561398f565b5b6040519080825280601f01601f1916602001820160405280156127c85781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b6003805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01601c6101000a81548160ff021916908360038111156128405761283f61358f565b5b02179055506005600481819054906101000a900463ffffffff168092919061286790613f6b565b91906101000a81548163ffffffff021916908363ffffffff160217905550505f60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060045f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f01600481819054906101000a900463ffffffff168092919061294790613f6b565b91906101000a81548163ffffffff021916908363ffffffff160217905550508173ffffffffffffffffffffffffffffffffffffffff167f2465e924a1e9a02843493e65702fd09152c8a631caf7b9b58e4b01ee20ced41660405160405180910390a25050565b5f6129b6612413565b826040516020016129c8929190613fe6565b604051602081830303815290604052805190602001209050919050565b5f6129f1825f01612ea5565b9050919050565b5f612a05835f0183612eb4565b5f1c905092915050565b5f83471015612a53576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a4a90614066565b60405180910390fd5b5f825103612a96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a8d906140ce565b60405180910390fd5b8282516020840186f590505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612b0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b0690614136565b60405180910390fd5b9392505050565b5f612b3b835f018373ffffffffffffffffffffffffffffffffffffffff165f1b612edb565b905092915050565b5f600182805f0190612b559190614160565b805f0190612b639190614187565b905014612b9c576040517f98c82cef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000eda3cad031c0cf367cf3f517ee0dc98f9ba80c8f73ffffffffffffffffffffffffffffffffffffffff16637c09ea8260405180604001604052807f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b73ffffffffffffffffffffffffffffffffffffffff16815260200160035f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff1681525084805f0190612c879190614160565b6040518363ffffffff1660e01b8152600401612ca49291906144a7565b6020604051808303815f875af1158015612cc0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ce491906144e9565b90504360035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160186101000a81548163ffffffff021916908363ffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff167fb5d2b7df0352a87a587a430bfceab43859b3b3c404f0425c4c1ab0675ed57b948284604051612d8c92919061469c565b60405180910390a292915050565b5f5f8273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60605f612de87f312e302e3400000000000000000000000000000000000000000000000000000561276c565b9050805f81518110612dfd57612dfc613a4f565b5b602001015160f81c60f81b604051602001612e189190614715565b60405160208183030381529060405291505090565b5f604051836040820152846020820152828152600b810160ff815360558120925050509392505050565b5f5f60ff835f1c169050601f811115612e9c576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b5f815f01805490509050919050565b5f825f018281548110612eca57612ec9613a4f565b5b905f5260205f200154905092915050565b5f612ee68383612f42565b612f3857825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050612f3c565b5f90505b92915050565b5f5f836001015f8481526020019081526020015f20541415905092915050565b60405180608001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f63ffffffff1681526020015f63ffffffff1681526020015f6003811115612fb457612fb361358f565b5b81525090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f612feb82612fc2565b9050919050565b612ffb81612fe1565b8114613005575f5ffd5b50565b5f8135905061301681612ff2565b92915050565b5f6020828403121561303157613030612fba565b5b5f61303e84828501613008565b91505092915050565b5f63ffffffff82169050919050565b61305f81613047565b82525050565b5f6020820190506130785f830184613056565b92915050565b5f819050919050565b5f6130a161309c61309784612fc2565b61307e565b612fc2565b9050919050565b5f6130b282613087565b9050919050565b5f6130c3826130a8565b9050919050565b6130d3816130b9565b82525050565b5f6020820190506130ec5f8301846130ca565b92915050565b5f819050919050565b613104816130f2565b811461310e575f5ffd5b50565b5f8135905061311f816130fb565b92915050565b5f5f6040838503121561313b5761313a612fba565b5b5f61314885828601613008565b925050602061315985828601613111565b9150509250929050565b5f61316d826130a8565b9050919050565b61317d81613163565b82525050565b5f6020820190506131965f830184613174565b92915050565b5f6131a6826130a8565b9050919050565b6131b68161319c565b82525050565b5f6020820190506131cf5f8301846131ad565b92915050565b5f6131df826130a8565b9050919050565b6131ef816131d5565b82525050565b5f6020820190506132085f8301846131e6565b92915050565b5f61321882612fe1565b9050919050565b6132288161320e565b8114613232575f5ffd5b50565b5f813590506132438161321f565b92915050565b5f6020828403121561325e5761325d612fba565b5b5f61326b84828501613235565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6132b682613274565b6132c0818561327e565b93506132d081856020860161328e565b6132d98161329c565b840191505092915050565b5f6020820190508181035f8301526132fc81846132ac565b905092915050565b61330d81612fe1565b82525050565b5f6020820190506133265f830184613304565b92915050565b5f613336826130a8565b9050919050565b6133468161332c565b82525050565b5f60208201905061335f5f83018461333d565b92915050565b61336e816130f2565b82525050565b5f6020820190506133875f830184613365565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6133c18161338d565b81146133cb575f5ffd5b50565b5f813590506133dc816133b8565b92915050565b5f819050919050565b6133f4816133e2565b81146133fe575f5ffd5b50565b5f8135905061340f816133eb565b92915050565b5f5f6040838503121561342b5761342a612fba565b5b5f613438858286016133ce565b925050602061344985828601613401565b9150509250929050565b5f5f6040838503121561346957613468612fba565b5b5f61347685828601613401565b925050602061348785828601613401565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6134c381613163565b82525050565b5f6134d483836134ba565b60208301905092915050565b5f602082019050919050565b5f6134f682613491565b613500818561349b565b935061350b836134ab565b805f5b8381101561353b57815161352288826134c9565b975061352d836134e0565b92505060018101905061350e565b5085935050505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61357a81612fe1565b82525050565b61358981613047565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106135cd576135cc61358f565b5b50565b5f8190506135dd826135bc565b919050565b5f6135ec826135d0565b9050919050565b6135fc816135e2565b82525050565b608082015f8201516136165f850182613571565b5060208201516136296020850182613580565b50604082015161363c6040850182613580565b50606082015161364f60608501826135f3565b50505050565b5f6136608383613602565b60808301905092915050565b5f602082019050919050565b5f61368282613548565b61368c8185613552565b935061369783613562565b805f5b838110156136c75781516136ae8882613655565b97506136b98361366c565b92505060018101905061369a565b5085935050505092915050565b5f6040820190508181035f8301526136ec81856134ec565b905081810360208301526137008184613678565b90509392505050565b5f5ffd5b5f6060828403121561372257613721613709565b5b81905092915050565b5f5f6040838503121561374157613740612fba565b5b5f61374e85828601613111565b925050602083013567ffffffffffffffff81111561376f5761376e612fbe565b5b61377b8582860161370d565b9150509250929050565b61378e81613047565b8114613798575f5ffd5b50565b5f813590506137a981613785565b92915050565b5f602082840312156137c4576137c3612fba565b5b5f6137d18482850161379b565b91505092915050565b5f5f604083850312156137f0576137ef612fba565b5b5f6137fd85828601613008565b925050602061380e8582860161379b565b9150509250929050565b613821816135e2565b82525050565b5f60208201905061383a5f830184613818565b92915050565b5f5f6040838503121561385657613855612fba565b5b5f61386385828601613235565b925050602083013567ffffffffffffffff81111561388457613883612fbe565b5b6138908582860161370d565b9150509250929050565b6138a3816133e2565b82525050565b5f6020820190506138bc5f83018461389a565b92915050565b5f6138cc826130a8565b9050919050565b6138dc816138c2565b82525050565b5f6020820190506138f55f8301846138d3565b92915050565b5f5f5f6060848603121561391257613911612fba565b5b5f61391f86828701613008565b935050602061393086828701613401565b925050604061394186828701613401565b9150509250925092565b6139548161338d565b82525050565b5f60608201905061396d5f830186613365565b61397a602083018561394b565b613987604083018461389a565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6139f3826133e2565b91506139fe836133e2565b9250828201905080821115613a1657613a156139bc565b5b92915050565b5f613a26826133e2565b9150613a31836133e2565b9250828203905081811115613a4957613a486139bc565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613a8682613047565b915063ffffffff8203613a9c57613a9b6139bc565b5b600182019050919050565b5f81519050613ab581613785565b92915050565b5f60208284031215613ad057613acf612fba565b5b5f613add84828501613aa7565b91505092915050565b604082015f820151613afa5f850182613571565b506020820151613b0d6020850182613580565b50505050565b7f68747470733a2f2f656967656e636c6f75642e78797a000000000000000000005f82015250565b5f613b4760168361327e565b9150613b5282613b13565b602082019050919050565b5f606082019050613b705f830184613ae6565b8181036040830152613b8181613b3b565b905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c7265615f8201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b5f613be3602e8361327e565b9150613bee82613b89565b604082019050919050565b5f6020820190508181035f830152613c1081613bd7565b9050919050565b5f604082019050613c2a5f830185613304565b613c376020830184613304565b9392505050565b5f606082019050613c515f830185613ae6565b613c5e6040830184613304565b9392505050565b5f819050919050565b5f60ff82169050919050565b5f613c94613c8f613c8a84613c65565b61307e565b613c6e565b9050919050565b613ca481613c7a565b82525050565b5f602082019050613cbd5f830184613c9b565b92915050565b5f8115159050919050565b613cd781613cc3565b8114613ce1575f5ffd5b50565b5f81519050613cf281613cce565b92915050565b5f60208284031215613d0d57613d0c612fba565b5b5f613d1a84828501613ce4565b91505092915050565b5f613d2d826133e2565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613d5f57613d5e6139bc565b5b600182019050919050565b5f60a082019050613d7d5f830188613365565b613d8a6020830187613365565b613d976040830186613365565b613da4606083018561389a565b613db16080830184613304565b9695505050505050565b5f8160601b9050919050565b5f613dd182613dbb565b9050919050565b5f613de282613dc7565b9050919050565b613dfa613df582612fe1565b613dd8565b82525050565b5f819050919050565b613e1a613e15826130f2565b613e00565b82525050565b5f613e2b8285613de9565b601482019150613e3b8284613e09565b6020820191508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f613e6f82613e4b565b613e798185613e55565b9350613e8981856020860161328e565b613e928161329c565b840191505092915050565b5f604082019050613eb05f83018561333d565b8181036020830152613ec28184613e65565b90509392505050565b5f81905092915050565b5f613edf82613e4b565b613ee98185613ecb565b9350613ef981856020860161328e565b80840191505092915050565b5f613f108285613ed5565b9150613f1c8284613ed5565b91508190509392505050565b5f608082019050613f3b5f830187613304565b613f486020830186613304565b613f556040830185613304565b613f62606083018461394b565b95945050505050565b5f613f7582613047565b91505f8203613f8757613f866139bc565b5b600182039050919050565b5f81905092915050565b7f19010000000000000000000000000000000000000000000000000000000000005f82015250565b5f613fd0600283613f92565b9150613fdb82613f9c565b600282019050919050565b5f613ff082613fc4565b9150613ffc8285613e09565b60208201915061400c8284613e09565b6020820191508190509392505050565b7f437265617465323a20696e73756666696369656e742062616c616e63650000005f82015250565b5f614050601d8361327e565b915061405b8261401c565b602082019050919050565b5f6020820190508181035f83015261407d81614044565b9050919050565b7f437265617465323a2062797465636f6465206c656e677468206973207a65726f5f82015250565b5f6140b860208361327e565b91506140c382614084565b602082019050919050565b5f6020820190508181035f8301526140e5816140ac565b9050919050565b7f437265617465323a204661696c6564206f6e206465706c6f79000000000000005f82015250565b5f61412060198361327e565b915061412b826140ec565b602082019050919050565b5f6020820190508181035f83015261414d81614114565b9050919050565b5f5ffd5b5f5ffd5b5f5ffd5b5f8235600160400383360303811261417b5761417a614154565b5b80830191505092915050565b5f5f833560016020038436030381126141a3576141a2614154565b5b80840192508235915067ffffffffffffffff8211156141c5576141c4614158565b5b6020830192506020820236038313156141e1576141e061415c565b5b509250929050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83356001602003843603038112614211576142106141f1565b5b83810192508235915060208301925067ffffffffffffffff821115614239576142386141e9565b5b60208202360383131561424f5761424e6141ed565b5b509250929050565b5f82825260208201905092915050565b5f819050919050565b5f61427e6020840184613111565b905092915050565b61428f816130f2565b82525050565b5f5f833560016020038436030381126142b1576142b06141f1565b5b83810192508235915060208301925067ffffffffffffffff8211156142d9576142d86141e9565b5b6001820236038313156142ef576142ee6141ed565b5b509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f61432083856142f7565b935061432d838584614307565b6143368361329c565b840190509392505050565b5f604083016143525f840184614270565b61435e5f860182614286565b5061436c6020840184614295565b858303602087015261437f838284614315565b925050508091505092915050565b5f6143988383614341565b905092915050565b5f823560016040038336030381126143bb576143ba6141f1565b5b82810191505092915050565b5f602082019050919050565b5f6143de8385614257565b9350836020840285016143f084614267565b805f5b8781101561443357848403895261440a82846143a0565b614414858261438d565b945061441f836143c7565b925060208a019950506001810190506143f3565b50829750879450505050509392505050565b5f614453602084018461379b565b905092915050565b5f6040830161446c5f8401846141f5565b8583035f87015261447e8382846143d3565b9250505061448f6020840184614445565b61449c6020860182613580565b508091505092915050565b5f6060820190506144ba5f830185613ae6565b81810360408301526144cc818461445b565b90509392505050565b5f815190506144e3816133eb565b92915050565b5f602082840312156144fe576144fd612fba565b5b5f61450b848285016144d5565b91505092915050565b5f8235600160400383360303811261452f5761452e6141f1565b5b82810191505092915050565b5f6040830161454c5f8401846141f5565b8583035f87015261455e8382846143d3565b9250505061456f6020840184614445565b61457c6020860182613580565b508091505092915050565b5f5f833560016020038436030381126145a3576145a26141f1565b5b83810192508235915060208301925067ffffffffffffffff8211156145cb576145ca6141e9565b5b6001820236038313156145e1576145e06141ed565b5b509250929050565b5f82825260208201905092915050565b5f61460483856145e9565b9350614611838584614307565b61461a8361329c565b840190509392505050565b5f606083016146365f840184614514565b8482035f860152614647828261453b565b9150506146576020840184614587565b858303602087015261466a8382846145f9565b9250505061467b6040840184614587565b858303604087015261468e8382846145f9565b925050508091505092915050565b5f6040820190506146af5f83018561389a565b81810360208301526146c18184614625565b90509392505050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f819050919050565b61470f61470a826146ca565b6146f5565b82525050565b5f61472082846146fe565b6001820191508190509291505056fe608060405260405161090e38038061090e83398101604081905261002291610460565b61002e82826000610035565b505061058a565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610520565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610520565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108e7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053b565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c65782516103bf576001600160a01b0385163b6103bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d0565b6103d083836103d8565b949350505050565b8151156103e85781518083602001fd5b8060405162461bcd60e51b81526004016101699190610557565b80516001600160a01b038116811461041957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044f578181015183820152602001610437565b838111156100f95750506000910152565b6000806040838503121561047357600080fd5b61047c83610402565b60208401519092506001600160401b038082111561049957600080fd5b818501915085601f8301126104ad57600080fd5b8151818111156104bf576104bf61041e565b604051601f8201601f19908116603f011681019083821181831017156104e7576104e761041e565b8160405282815288602084870101111561050057600080fd5b610511836020830160208801610434565b80955050505050509250929050565b60006020828403121561053257600080fd5b6102c882610402565b6000825161054d818460208701610434565b9190910192915050565b6020815260008251806020840152610576816040850160208701610434565b601f01601f19169190910160400192915050565b61034e806105996000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f260279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb9190610249565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a2565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020d578251610206576001600160a01b0385163b6102065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610217565b610217838361021f565b949350505050565b81511561022f5781518083602001fd5b8060405162461bcd60e51b81526004016101fd91906102be565b60006020828403121561025b57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028d578181015183820152602001610275565b8381111561029c576000848401525b50505050565b600082516102b4818460208701610272565b9190910192915050565b60208152600082518060208401526102dd816040850160208701610272565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d51e81d3bc5ed20a26aeb05dce7e825c503b2061aa78628027300c8d65b9d89a64736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207d531b50d1113e334f40451e3e8cd620d45d7589439e96c12188273537ac591464736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e5000000000000000000000000eda3cad031c0cf367cf3f517ee0dc98f9ba80c8f000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b000000000000000000000000801c1c2dfab0a6821ca38a08b78a7c7cc81d64d1000000000000000000000000c1e14f82c7f554b8582bb786728f669875b3fc530000000000000000000000000000000000000000000000000000000000000005312e302e34000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _version (string): 1.0.4
Arg [1] : _permissionController (address): 0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5
Arg [2] : _releaseManager (address): 0xeDA3CAd031c0cf367cF3f517Ee0DC98F9bA80C8F
Arg [3] : _computeAVSRegistrar (address): 0xaFE783e9BcEC2993898E70906434d5bC8de3357b
Arg [4] : _computeOperator (address): 0x801c1c2Dfab0A6821CA38a08b78A7c7CC81d64d1
Arg [5] : _appBeacon (address): 0xC1E14F82c7F554b8582BB786728f669875b3fC53
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [1] : 00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e5
Arg [2] : 000000000000000000000000eda3cad031c0cf367cf3f517ee0dc98f9ba80c8f
Arg [3] : 000000000000000000000000afe783e9bcec2993898e70906434d5bc8de3357b
Arg [4] : 000000000000000000000000801c1c2dfab0a6821ca38a08b78a7c7cc81d64d1
Arg [5] : 000000000000000000000000c1e14f82c7f554b8582bb786728f669875b3fc53
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [7] : 312e302e34000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.