Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 17417926 | 15 days ago | Contract Creation | 0 ETH |
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:
PluginRepo
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {ERC165CheckerUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165CheckerUpgradeable.sol";
import {IProtocolVersion} from "@aragon/osx-commons-contracts/src/utils/versioning/IProtocolVersion.sol";
import {ProtocolVersion} from "@aragon/osx-commons-contracts/src/utils/versioning/ProtocolVersion.sol";
import {IPluginSetup} from "@aragon/osx-commons-contracts/src/plugin/setup/IPluginSetup.sol";
import {PluginSetup} from "@aragon/osx-commons-contracts/src/plugin/setup/PluginSetup.sol";
import {PermissionManager} from "../../../core/permission/PermissionManager.sol";
import {IPluginRepo} from "./IPluginRepo.sol";
/// @title PluginRepo
/// @author Aragon X - 2020 - 2023
/// @notice The plugin repository contract required for managing and publishing different plugin versions within the Aragon DAO framework.
/// @custom:security-contact [email protected]
contract PluginRepo is
Initializable,
ERC165Upgradeable,
IPluginRepo,
UUPSUpgradeable,
ProtocolVersion,
PermissionManager
{
using AddressUpgradeable for address;
using ERC165CheckerUpgradeable for address;
/// @notice The struct describing the tag of a version obtained by a release and build number as `RELEASE.BUILD`.
/// @param release The release number.
/// @param build The build number
/// @dev Releases mark incompatible changes (e.g., the plugin interface, storage layout, or incompatible behavior) whereas builds mark compatible changes (e.g., patches and compatible feature additions).
struct Tag {
uint8 release;
uint16 build;
}
/// @notice The struct describing a plugin version (release and build).
/// @param tag The version tag.
/// @param pluginSetup The setup contract associated with this version.
/// @param buildMetadata The build metadata URI.
struct Version {
Tag tag;
address pluginSetup;
bytes buildMetadata;
}
/// @notice The ID of the permission required to call the `createVersion` function.
bytes32 public constant MAINTAINER_PERMISSION_ID = keccak256("MAINTAINER_PERMISSION");
/// @notice The ID of the permission required to call the `createVersion` function.
bytes32 public constant UPGRADE_REPO_PERMISSION_ID = keccak256("UPGRADE_REPO_PERMISSION");
/// @notice The mapping between release and build numbers.
mapping(uint8 => uint16) internal buildsPerRelease;
/// @notice The mapping between the version hash and the corresponding version information.
mapping(bytes32 => Version) internal versions;
/// @notice The mapping between the plugin setup address and its corresponding version hash.
mapping(address => bytes32) internal latestTagHashForPluginSetup;
/// @notice The ID of the latest release.
/// @dev The maximum release number is 255.
uint8 public latestRelease;
/// @notice Thrown if a version does not exist.
/// @param versionHash The tag hash.
error VersionHashDoesNotExist(bytes32 versionHash);
/// @notice Thrown if a plugin setup contract does not inherit from `PluginSetup`.
error InvalidPluginSetupInterface();
/// @notice Thrown if a release number is zero.
error ReleaseZeroNotAllowed();
/// @notice Thrown if a release number is incremented by more than one.
/// @param latestRelease The latest release number.
/// @param newRelease The new release number.
error InvalidReleaseIncrement(uint8 latestRelease, uint8 newRelease);
/// @notice Thrown if the same plugin setup contract exists already in a previous releases.
/// @param release The release number of the already existing plugin setup.
/// @param build The build number of the already existing plugin setup.
/// @param pluginSetup The plugin setup contract address.
error PluginSetupAlreadyInPreviousRelease(uint8 release, uint16 build, address pluginSetup);
/// @notice Thrown if the metadata URI is empty.
error EmptyReleaseMetadata();
/// @notice Thrown if release does not exist.
error ReleaseDoesNotExist();
/// @dev Used to disallow initializing the implementation contract by an attacker for extra safety.
constructor() {
_disableInitializers();
}
/// @notice Initializes the contract by
/// - initializing the permission manager
/// - granting the `MAINTAINER_PERMISSION_ID` permission to the initial owner.
/// @dev This method is required to support [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822).
function initialize(address initialOwner) external initializer {
__PermissionManager_init(initialOwner);
_grant(address(this), initialOwner, MAINTAINER_PERMISSION_ID);
_grant(address(this), initialOwner, UPGRADE_REPO_PERMISSION_ID);
}
/// @notice Initializes the pluginRepo after an upgrade from a previous protocol version.
/// @param _previousProtocolVersion The semantic protocol version number of the previous DAO implementation contract this upgrade is transitioning from.
/// @param _initData The initialization data to be passed to via `upgradeToAndCall` (see [ERC-1967](https://docs.openzeppelin.com/contracts/4.x/api/proxy#ERC1967Upgrade)).
/// @dev This function is a placeholder until we require reinitialization.
function initializeFrom(
uint8[3] calldata _previousProtocolVersion,
bytes calldata _initData
) external reinitializer(2) {
// Silences the unused function parameter warning.
_previousProtocolVersion;
_initData;
// Revert because this is a placeholder until this contract requires reinitialization.
revert();
}
/// @inheritdoc IPluginRepo
function createVersion(
uint8 _release,
address _pluginSetup,
bytes calldata _buildMetadata,
bytes calldata _releaseMetadata
) external auth(MAINTAINER_PERMISSION_ID) {
if (!_pluginSetup.supportsInterface(type(IPluginSetup).interfaceId)) {
revert InvalidPluginSetupInterface();
}
if (_release == 0) {
revert ReleaseZeroNotAllowed();
}
// Check that the release number is not incremented by more than one
if (_release - latestRelease > 1) {
revert InvalidReleaseIncrement({latestRelease: latestRelease, newRelease: _release});
}
if (_release > latestRelease) {
latestRelease = _release;
if (_releaseMetadata.length == 0) {
revert EmptyReleaseMetadata();
}
}
// Make sure the same plugin setup wasn't used in previous releases.
Version storage version = versions[latestTagHashForPluginSetup[_pluginSetup]];
if (version.tag.release != 0 && version.tag.release != _release) {
revert PluginSetupAlreadyInPreviousRelease(
version.tag.release,
version.tag.build,
_pluginSetup
);
}
uint16 build = ++buildsPerRelease[_release];
Tag memory tag = Tag(_release, build);
bytes32 _tagHash = tagHash(tag);
versions[_tagHash] = Version(tag, _pluginSetup, _buildMetadata);
latestTagHashForPluginSetup[_pluginSetup] = _tagHash;
emit VersionCreated({
release: _release,
build: build,
pluginSetup: _pluginSetup,
buildMetadata: _buildMetadata
});
if (_releaseMetadata.length > 0) {
emit ReleaseMetadataUpdated(_release, _releaseMetadata);
}
}
/// @inheritdoc IPluginRepo
function updateReleaseMetadata(
uint8 _release,
bytes calldata _releaseMetadata
) external auth(MAINTAINER_PERMISSION_ID) {
if (_release == 0) {
revert ReleaseZeroNotAllowed();
}
if (_release > latestRelease) {
revert ReleaseDoesNotExist();
}
if (_releaseMetadata.length == 0) {
revert EmptyReleaseMetadata();
}
emit ReleaseMetadataUpdated(_release, _releaseMetadata);
}
/// @notice Returns the latest version for a given release number.
/// @param _release The release number.
/// @return The latest version of this release.
function getLatestVersion(uint8 _release) public view returns (Version memory) {
uint16 latestBuild = uint16(buildsPerRelease[_release]);
return getVersion(tagHash(Tag(_release, latestBuild)));
}
/// @notice Returns the latest version for a given plugin setup.
/// @param _pluginSetup The plugin setup address
/// @return The latest version associated with the plugin Setup.
function getLatestVersion(address _pluginSetup) public view returns (Version memory) {
return getVersion(latestTagHashForPluginSetup[_pluginSetup]);
}
/// @notice Returns the version associated with a tag.
/// @param _tag The version tag.
/// @return The version associated with the tag.
function getVersion(Tag calldata _tag) public view returns (Version memory) {
return getVersion(tagHash(_tag));
}
/// @notice Returns the version for a tag hash.
/// @param _tagHash The tag hash.
/// @return The version associated with a tag hash.
function getVersion(bytes32 _tagHash) public view returns (Version memory) {
Version storage version = versions[_tagHash];
if (version.tag.release == 0) {
revert VersionHashDoesNotExist(_tagHash);
}
return version;
}
/// @notice Gets the total number of builds for a given release number.
/// @param _release The release number.
/// @return The number of builds of this release.
function buildCount(uint8 _release) public view returns (uint256) {
return buildsPerRelease[_release];
}
/// @notice The hash of the version tag obtained from the packed, bytes-encoded release and build number.
/// @param _tag The version tag.
/// @return The version tag hash.
function tagHash(Tag memory _tag) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_tag.release, _tag.build));
}
/// @notice Internal method authorizing the upgrade of the contract via the [upgradeability mechanism for UUPS proxies](https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable) (see [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822)).
/// @dev The caller must have the `UPGRADE_REPO_PERMISSION_ID` permission.
function _authorizeUpgrade(
address
) internal virtual override auth(UPGRADE_REPO_PERMISSION_ID) {}
/// @notice Checks if this or the parent contract supports an interface by its ID.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return
_interfaceId == type(IPluginRepo).interfaceId ||
_interfaceId == type(IProtocolVersion).interfaceId ||
super.supportsInterface(_interfaceId);
}
/// @notice 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 [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)).
uint256[46] 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 v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @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) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* 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. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @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/introspection/ERC165Checker.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165CheckerUpgradeable {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165Upgradeable).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*
* _Available since v3.4._
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeWithSelector(IERC165Upgradeable.supportsInterface.selector, interfaceId);
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.8; /// @title IProtocolVersion /// @author Aragon X - 2022-2023 /// @notice An interface defining the semantic Aragon OSx protocol version number. /// @custom:security-contact [email protected] interface IProtocolVersion { /// @notice Returns the semantic Aragon OSx protocol version number that the implementing contract is associated with. /// @return _version Returns the semantic Aragon OSx protocol version number. /// @dev This version number is not to be confused with the `release` and `build` numbers found in the `Version.Tag` struct inside the `PluginRepo` contract being used to version plugin setup and associated plugin implementation contracts. function protocolVersion() external view returns (uint8[3] memory _version); }
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {IProtocolVersion} from "./IProtocolVersion.sol";
/// @title ProtocolVersion
/// @author Aragon X - 2023
/// @notice An abstract, stateless, non-upgradeable contract providing the current Aragon OSx protocol version number.
/// @dev Do not add any new variables to this contract that would shift down storage in the inheritance chain.
/// @custom:security-contact [email protected]
abstract contract ProtocolVersion is IProtocolVersion {
// IMPORTANT: Do not add any storage variable, see the above notice.
/// @inheritdoc IProtocolVersion
function protocolVersion() public pure returns (uint8[3] memory) {
return [1, 4, 0];
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {PermissionLib} from "../../permission/PermissionLib.sol";
// solhint-disable-next-line no-unused-import
import {IDAO} from "../../dao/IDAO.sol";
/// @title IPluginSetup
/// @author Aragon X - 2022-2023
/// @notice The interface required for a plugin setup contract to be consumed by the `PluginSetupProcessor` for plugin installations, updates, and uninstallations.
/// @custom:security-contact [email protected]
interface IPluginSetup {
/// @notice The data associated with a prepared setup.
/// @param helpers The address array of helpers (contracts or EOAs) associated with this plugin version after the installation or update.
/// @param permissions The array of multi-targeted permission operations to be applied by the `PluginSetupProcessor` to the installing or updating DAO.
struct PreparedSetupData {
address[] helpers;
PermissionLib.MultiTargetPermission[] permissions;
}
/// @notice The payload for plugin updates and uninstallations containing the existing contracts as well as optional data to be consumed by the plugin setup.
/// @param plugin The address of the `Plugin`.
/// @param currentHelpers The address array of all current helpers (contracts or EOAs) associated with the plugin to update from.
/// @param data The bytes-encoded data containing the input parameters for the preparation of update/uninstall as specified in the corresponding ABI on the version's metadata.
struct SetupPayload {
address plugin;
address[] currentHelpers;
bytes data;
}
/// @notice Prepares the installation of a plugin.
/// @param _dao The address of the installing DAO.
/// @param _data The bytes-encoded data containing the input parameters for the installation as specified in the plugin's build metadata JSON file.
/// @return plugin The address of the `Plugin` contract being prepared for installation.
/// @return preparedSetupData The deployed plugin's relevant data which consists of helpers and permissions.
function prepareInstallation(
address _dao,
bytes calldata _data
) external returns (address plugin, PreparedSetupData memory preparedSetupData);
/// @notice Prepares the update of a plugin.
/// @param _dao The address of the updating DAO.
/// @param _fromBuild The build number of the plugin to update from.
/// @param _payload The relevant data necessary for the `prepareUpdate`. See above.
/// @return initData The initialization data to be passed to upgradeable contracts when the update is applied in the `PluginSetupProcessor`.
/// @return preparedSetupData The deployed plugin's relevant data which consists of helpers and permissions.
function prepareUpdate(
address _dao,
uint16 _fromBuild,
SetupPayload calldata _payload
) external returns (bytes memory initData, PreparedSetupData memory preparedSetupData);
/// @notice Prepares the uninstallation of a plugin.
/// @param _dao The address of the uninstalling DAO.
/// @param _payload The relevant data necessary for the `prepareUninstallation`. See above.
/// @return permissions The array of multi-targeted permission operations to be applied by the `PluginSetupProcessor` to the uninstalling DAO.
function prepareUninstallation(
address _dao,
SetupPayload calldata _payload
) external returns (PermissionLib.MultiTargetPermission[] memory permissions);
/// @notice Returns the plugin implementation address.
/// @return The address of the plugin implementation contract.
/// @dev The implementation can be instantiated via the `new` keyword, cloned via the minimal proxy pattern (see [ERC-1167](https://eips.ethereum.org/EIPS/eip-1167)), or proxied via the UUPS proxy pattern (see [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822)).
function implementation() external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IProtocolVersion} from "../../utils/versioning/IProtocolVersion.sol";
import {ProtocolVersion} from "../../utils/versioning/ProtocolVersion.sol";
import {IPluginSetup} from "./IPluginSetup.sol";
/// @title PluginSetup
/// @author Aragon X - 2022-2024
/// @notice An abstract contract to inherit from to implement the plugin setup for non-upgradeable plugins, i.e,
/// - `Plugin` being deployed via the `new` keyword
/// - `PluginCloneable` being deployed via the minimal proxy pattern (see [ERC-1167](https://eips.ethereum.org/EIPS/eip-1167)).
/// @custom:security-contact [email protected]
abstract contract PluginSetup is ERC165, IPluginSetup, ProtocolVersion {
/// @notice The address of the plugin implementation contract for initial block explorer verification and, in the case of `PluginClonable` implementations, to create [ERC-1167](https://eips.ethereum.org/EIPS/eip-1167) clones from.
address internal immutable IMPLEMENTATION;
/// @notice Thrown when attempting to prepare an update on a non-upgradeable plugin.
error NonUpgradeablePlugin();
/// @notice The contract constructor, that setting the plugin implementation contract.
/// @param _implementation The address of the plugin implementation contract.
constructor(address _implementation) {
IMPLEMENTATION = _implementation;
}
/// @inheritdoc IPluginSetup
/// @dev Since the underlying plugin is non-upgradeable, this non-virtual function must always revert.
function prepareUpdate(
address _dao,
uint16 _fromBuild,
SetupPayload calldata _payload
) external returns (bytes memory, PreparedSetupData memory) {
(_dao, _fromBuild, _payload);
revert NonUpgradeablePlugin();
}
/// @notice Checks if this or the parent contract supports an interface by its ID.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return
_interfaceId == type(IPluginSetup).interfaceId ||
_interfaceId == type(IProtocolVersion).interfaceId ||
super.supportsInterface(_interfaceId);
}
/// @inheritdoc IPluginSetup
function implementation() public view returns (address) {
return IMPLEMENTATION;
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {IPermissionCondition} from "@aragon/osx-commons-contracts/src/permission/condition/IPermissionCondition.sol";
import {PermissionCondition} from "@aragon/osx-commons-contracts/src/permission/condition/PermissionCondition.sol";
import {PermissionLib} from "@aragon/osx-commons-contracts/src/permission/PermissionLib.sol";
/// @title PermissionManager
/// @author Aragon X - 2021-2023
/// @notice The abstract permission manager used in a DAO, its associated plugins, and other framework-related components.
/// @custom:security-contact [email protected]
abstract contract PermissionManager is Initializable {
using AddressUpgradeable for address;
/// @notice The ID of the permission required to call the `grant`, `grantWithCondition`, `revoke`, and `bulk` function.
bytes32 public constant ROOT_PERMISSION_ID = keccak256("ROOT_PERMISSION");
/// @notice A special address encoding permissions that are valid for any address `who` or `where`.
address internal constant ANY_ADDR = address(type(uint160).max);
/// @notice A special address encoding if a permissions is not set and therefore not allowed.
address internal constant UNSET_FLAG = address(0);
/// @notice A special address encoding if a permission is allowed.
address internal constant ALLOW_FLAG = address(2);
/// @notice A mapping storing permissions as hashes (i.e., `permissionHash(where, who, permissionId)`) and their status encoded by an address (unset, allowed, or redirecting to a `PermissionCondition`).
mapping(bytes32 => address) internal permissionsHashed;
/// @notice Thrown if a call is unauthorized.
/// @param where The context in which the authorization reverted.
/// @param who The address (EOA or contract) missing the permission.
/// @param permissionId The permission identifier.
error Unauthorized(address where, address who, bytes32 permissionId);
/// @notice Thrown if a permission has been already granted with a different condition.
/// @dev This makes sure that condition on the same permission can not be overwriten by a different condition.
/// @param where The address of the target contract to grant `_who` permission to.
/// @param who The address (EOA or contract) to which the permission has already been granted.
/// @param permissionId The permission identifier.
/// @param currentCondition The current condition set for permissionId.
/// @param newCondition The new condition it tries to set for permissionId.
error PermissionAlreadyGrantedForDifferentCondition(
address where,
address who,
bytes32 permissionId,
address currentCondition,
address newCondition
);
/// @notice Thrown if a condition address is not a contract.
/// @param condition The address that is not a contract.
error ConditionNotAContract(IPermissionCondition condition);
/// @notice Thrown if a condition contract does not support the `IPermissionCondition` interface.
/// @param condition The address that is not a contract.
error ConditionInterfaceNotSupported(IPermissionCondition condition);
/// @notice Thrown for `ROOT_PERMISSION_ID` or `EXECUTE_PERMISSION_ID` permission grants where `who` or `where` is `ANY_ADDR`.
error PermissionsForAnyAddressDisallowed();
/// @notice Thrown for permission grants where `who` and `where` are both `ANY_ADDR`.
error AnyAddressDisallowedForWhoAndWhere();
/// @notice Thrown if `Operation.GrantWithCondition` is requested as an operation but the method does not support it.
error GrantWithConditionNotSupported();
/// @notice Emitted when a permission `permission` is granted in the context `here` to the address `_who` for the contract `_where`.
/// @param permissionId The permission identifier.
/// @param here The address of the context in which the permission is granted.
/// @param where The address of the target contract for which `_who` receives permission.
/// @param who The address (EOA or contract) receiving the permission.
/// @param condition The address `ALLOW_FLAG` for regular permissions or, alternatively, the `IPermissionCondition` contract implementation to be used.
event Granted(
bytes32 indexed permissionId,
address indexed here,
address where,
address indexed who,
address condition
);
/// @notice Emitted when a permission `permission` is revoked in the context `here` from the address `_who` for the contract `_where`.
/// @param permissionId The permission identifier.
/// @param here The address of the context in which the permission is revoked.
/// @param where The address of the target contract for which `_who` loses permission.
/// @param who The address (EOA or contract) losing the permission.
event Revoked(
bytes32 indexed permissionId,
address indexed here,
address where,
address indexed who
);
/// @notice A modifier to make functions on inheriting contracts authorized. Permissions to call the function are checked through this permission manager.
/// @param _permissionId The permission identifier required to call the method this modifier is applied to.
modifier auth(bytes32 _permissionId) {
_auth(_permissionId);
_;
}
/// @notice Initialization method to set the initial owner of the permission manager.
/// @dev The initial owner is granted the `ROOT_PERMISSION_ID` permission.
/// @param _initialOwner The initial owner of the permission manager.
function __PermissionManager_init(address _initialOwner) internal onlyInitializing {
_initializePermissionManager({_initialOwner: _initialOwner});
}
/// @notice Grants permission to an address to call methods in a contract guarded by an auth modifier with the specified permission identifier.
/// @dev Requires the `ROOT_PERMISSION_ID` permission.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) receiving the permission.
/// @param _permissionId The permission identifier.
/// @dev Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel.
function grant(
address _where,
address _who,
bytes32 _permissionId
) external virtual auth(ROOT_PERMISSION_ID) {
_grant({_where: _where, _who: _who, _permissionId: _permissionId});
}
/// @notice Grants permission to an address to call methods in a target contract guarded by an auth modifier with the specified permission identifier if the referenced condition permits it.
/// @dev Requires the `ROOT_PERMISSION_ID` permission
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) receiving the permission.
/// @param _permissionId The permission identifier.
/// @param _condition The `PermissionCondition` that will be asked for authorization on calls connected to the specified permission identifier.
/// @dev Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel.
function grantWithCondition(
address _where,
address _who,
bytes32 _permissionId,
IPermissionCondition _condition
) external virtual auth(ROOT_PERMISSION_ID) {
_grantWithCondition({
_where: _where,
_who: _who,
_permissionId: _permissionId,
_condition: _condition
});
}
/// @notice Revokes permission from an address to call methods in a target contract guarded by an auth modifier with the specified permission identifier.
/// @dev Requires the `ROOT_PERMISSION_ID` permission.
/// @param _where The address of the target contract for which `_who` loses permission.
/// @param _who The address (EOA or contract) losing the permission.
/// @param _permissionId The permission identifier.
/// @dev Note, that revoking permissions with `_who` or `_where` equal to `ANY_ADDR` does not revoke other permissions with specific `_who` and `_where` addresses that exist in parallel.
function revoke(
address _where,
address _who,
bytes32 _permissionId
) external virtual auth(ROOT_PERMISSION_ID) {
_revoke({_where: _where, _who: _who, _permissionId: _permissionId});
}
/// @notice Applies an array of permission operations on a single target contracts `_where`.
/// @param _where The address of the single target contract.
/// @param items The array of single-targeted permission operations to apply.
function applySingleTargetPermissions(
address _where,
PermissionLib.SingleTargetPermission[] calldata items
) external virtual auth(ROOT_PERMISSION_ID) {
for (uint256 i; i < items.length; ) {
PermissionLib.SingleTargetPermission memory item = items[i];
if (item.operation == PermissionLib.Operation.Grant) {
_grant({_where: _where, _who: item.who, _permissionId: item.permissionId});
} else if (item.operation == PermissionLib.Operation.Revoke) {
_revoke({_where: _where, _who: item.who, _permissionId: item.permissionId});
} else if (item.operation == PermissionLib.Operation.GrantWithCondition) {
revert GrantWithConditionNotSupported();
}
unchecked {
++i;
}
}
}
/// @notice Applies an array of permission operations on multiple target contracts `items[i].where`.
/// @param _items The array of multi-targeted permission operations to apply.
function applyMultiTargetPermissions(
PermissionLib.MultiTargetPermission[] calldata _items
) external virtual auth(ROOT_PERMISSION_ID) {
for (uint256 i; i < _items.length; ) {
PermissionLib.MultiTargetPermission memory item = _items[i];
if (item.operation == PermissionLib.Operation.Grant) {
// Ensure a non-zero condition isn't passed, as `_grant` can't handle conditions.
// This avoids the false impression that a conditional grant occurred,
// since the transaction would still succeed without conditions.
if (item.condition != address(0)) {
revert GrantWithConditionNotSupported();
}
_grant({_where: item.where, _who: item.who, _permissionId: item.permissionId});
} else if (item.operation == PermissionLib.Operation.Revoke) {
_revoke({_where: item.where, _who: item.who, _permissionId: item.permissionId});
} else if (item.operation == PermissionLib.Operation.GrantWithCondition) {
_grantWithCondition({
_where: item.where,
_who: item.who,
_permissionId: item.permissionId,
_condition: IPermissionCondition(item.condition)
});
}
unchecked {
++i;
}
}
}
/// @notice Checks if the caller address has permission on the target contract via a permission identifier and relays the answer to a condition contract if this was declared during the granting process.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) for which the permission is checked.
/// @param _permissionId The permission identifier.
/// @param _data Optional data to be passed to the set `PermissionCondition`.
/// @return Returns true if `_who` has the permissions on the target contract via the specified permission identifier.
function isGranted(
address _where,
address _who,
bytes32 _permissionId,
bytes memory _data
) public view virtual returns (bool) {
// Specific caller (`_who`) and target (`_where`) permission check
{
// This permission may have been granted directly via the `grant` function or with a condition via the `grantWithCondition` function.
address specificCallerTargetPermission = permissionsHashed[
permissionHash({_where: _where, _who: _who, _permissionId: _permissionId})
];
// If the permission was granted directly, return `true`.
if (specificCallerTargetPermission == ALLOW_FLAG) return true;
// If the permission was granted with a condition, check the condition and return the result.
if (specificCallerTargetPermission != UNSET_FLAG) {
return
_checkCondition({
_condition: specificCallerTargetPermission,
_where: _where,
_who: _who,
_permissionId: _permissionId,
_data: _data
});
}
// If this permission is not set, continue.
}
// Generic caller (`_who: ANY_ADDR`)
{
address genericCallerPermission = permissionsHashed[
permissionHash({_where: _where, _who: ANY_ADDR, _permissionId: _permissionId})
];
// If the permission was granted directly to (`_who: ANY_ADDR`), return `true`.
if (genericCallerPermission == ALLOW_FLAG) return true;
// If the permission was granted with a condition, check the condition and return the result.
if (genericCallerPermission != UNSET_FLAG) {
return
_checkCondition({
_condition: genericCallerPermission,
_where: _where,
_who: _who,
_permissionId: _permissionId,
_data: _data
});
}
// If this permission is not set, continue.
}
// Generic target (`_where: ANY_ADDR`) condition check
{
// This permission can only be granted in conjunction with a condition via the `grantWithCondition` function.
address genericTargetPermission = permissionsHashed[
permissionHash({_where: ANY_ADDR, _who: _who, _permissionId: _permissionId})
];
// If the permission was granted with a condition, check the condition and return the result.
if (genericTargetPermission != UNSET_FLAG) {
return
_checkCondition({
_condition: genericTargetPermission,
_where: _where,
_who: _who,
_permissionId: _permissionId,
_data: _data
});
}
// If this permission is not set, continue.
}
// No specific or generic permission applies to the `_who`, `_where`, `_permissionId`, so we return `false`.
return false;
}
/// @notice Relays the question if caller address has permission on target contract via a permission identifier to a condition contract.
/// @notice Checks a condition contract by doing an external call via try/catch.
/// @param _condition The condition contract that is called.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) owning the permission.
/// @param _permissionId The permission identifier.
/// @param _data Optional data to be passed to a referenced `PermissionCondition`.
/// @return Returns `true` if a caller (`_who`) has the permissions on the contract (`_where`) via the specified permission identifier.
/// @dev If the external call fails, we return `false`.
function _checkCondition(
address _condition,
address _where,
address _who,
bytes32 _permissionId,
bytes memory _data
) internal view virtual returns (bool) {
// Try-catch to skip failures
try
IPermissionCondition(_condition).isGranted({
_where: _where,
_who: _who,
_permissionId: _permissionId,
_data: _data
})
returns (bool result) {
if (result) {
return true;
}
} catch {}
return false;
}
/// @notice Grants the `ROOT_PERMISSION_ID` permission to the initial owner during initialization of the permission manager.
/// @param _initialOwner The initial owner of the permission manager.
function _initializePermissionManager(address _initialOwner) internal {
_grant({_where: address(this), _who: _initialOwner, _permissionId: ROOT_PERMISSION_ID});
}
/// @notice This method is used in the external `grant` method of the permission manager.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) owning the permission.
/// @param _permissionId The permission identifier.
/// @dev Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel.
function _grant(address _where, address _who, bytes32 _permissionId) internal virtual {
if (_where == ANY_ADDR) {
revert PermissionsForAnyAddressDisallowed();
}
if (_who == ANY_ADDR) {
if (
_permissionId == ROOT_PERMISSION_ID ||
isPermissionRestrictedForAnyAddr(_permissionId)
) {
revert PermissionsForAnyAddressDisallowed();
}
}
bytes32 permHash = permissionHash({
_where: _where,
_who: _who,
_permissionId: _permissionId
});
address currentFlag = permissionsHashed[permHash];
// Means permHash is not currently set.
if (currentFlag == UNSET_FLAG) {
permissionsHashed[permHash] = ALLOW_FLAG;
emit Granted({
permissionId: _permissionId,
here: msg.sender,
where: _where,
who: _who,
condition: ALLOW_FLAG
});
}
}
/// @notice This method is used in the external `grantWithCondition` method of the permission manager.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) owning the permission.
/// @param _permissionId The permission identifier.
/// @param _condition An address either resolving to a `PermissionCondition` contract address or being the `ALLOW_FLAG` address (`address(2)`).
/// @dev Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel.
function _grantWithCondition(
address _where,
address _who,
bytes32 _permissionId,
IPermissionCondition _condition
) internal virtual {
address conditionAddr = address(_condition);
if (!conditionAddr.isContract()) {
revert ConditionNotAContract(_condition);
}
if (
!PermissionCondition(conditionAddr).supportsInterface(
type(IPermissionCondition).interfaceId
)
) {
revert ConditionInterfaceNotSupported(_condition);
}
if (_where == ANY_ADDR && _who == ANY_ADDR) {
revert AnyAddressDisallowedForWhoAndWhere();
}
if (_where == ANY_ADDR || _who == ANY_ADDR) {
if (
_permissionId == ROOT_PERMISSION_ID ||
isPermissionRestrictedForAnyAddr(_permissionId)
) {
revert PermissionsForAnyAddressDisallowed();
}
}
bytes32 permHash = permissionHash({
_where: _where,
_who: _who,
_permissionId: _permissionId
});
address currentCondition = permissionsHashed[permHash];
// Means permHash is not currently set.
if (currentCondition == UNSET_FLAG) {
permissionsHashed[permHash] = conditionAddr;
emit Granted({
permissionId: _permissionId,
here: msg.sender,
where: _where,
who: _who,
condition: conditionAddr
});
} else if (currentCondition != conditionAddr) {
// Revert if `permHash` is already granted, but uses a different condition.
// If we don't revert, we either should:
// - allow overriding the condition on the same permission
// which could be confusing whoever granted the same permission first
// - or do nothing and succeed silently which could be confusing for the caller.
revert PermissionAlreadyGrantedForDifferentCondition({
where: _where,
who: _who,
permissionId: _permissionId,
currentCondition: currentCondition,
newCondition: conditionAddr
});
}
}
/// @notice This method is used in the public `revoke` method of the permission manager.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) owning the permission.
/// @param _permissionId The permission identifier.
/// @dev Note, that revoking permissions with `_who` or `_where` equal to `ANY_ADDR` does not revoke other permissions with specific `_who` and `_where` addresses that might have been granted in parallel.
function _revoke(address _where, address _who, bytes32 _permissionId) internal virtual {
bytes32 permHash = permissionHash({
_where: _where,
_who: _who,
_permissionId: _permissionId
});
if (permissionsHashed[permHash] != UNSET_FLAG) {
permissionsHashed[permHash] = UNSET_FLAG;
emit Revoked({permissionId: _permissionId, here: msg.sender, where: _where, who: _who});
}
}
/// @notice A private function to be used to check permissions on the permission manager contract (`address(this)`) itself.
/// @param _permissionId The permission identifier required to call the method this modifier is applied to.
function _auth(bytes32 _permissionId) internal view virtual {
if (!isGranted(address(this), msg.sender, _permissionId, msg.data)) {
revert Unauthorized({
where: address(this),
who: msg.sender,
permissionId: _permissionId
});
}
}
/// @notice Generates the hash for the `permissionsHashed` mapping obtained from the word "PERMISSION", the contract address, the address owning the permission, and the permission identifier.
/// @param _where The address of the target contract for which `_who` receives permission.
/// @param _who The address (EOA or contract) owning the permission.
/// @param _permissionId The permission identifier.
/// @return The permission hash.
function permissionHash(
address _where,
address _who,
bytes32 _permissionId
) internal pure virtual returns (bytes32) {
return keccak256(abi.encodePacked("PERMISSION", _who, _where, _permissionId));
}
/// @notice Decides if the granting permissionId is restricted when `_who == ANY_ADDR` or `_where == ANY_ADDR`.
/// @param _permissionId The permission identifier.
/// @return Whether or not the permission is restricted.
/// @dev By default, every permission is unrestricted and it is the derived contract's responsibility to override it. Note, that the `ROOT_PERMISSION_ID` is included and not required to be set it again.
function isPermissionRestrictedForAnyAddr(
bytes32 _permissionId
) internal view virtual returns (bool) {
(_permissionId); // silence the warning.
return false;
}
/// @notice 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 [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)).
uint256[49] private __gap;
}// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.8; /// @title IPluginRepo /// @author Aragon X - 2022-2023 /// @notice The interface required for a plugin repository. /// @custom:security-contact [email protected] interface IPluginRepo { /// @notice Updates the metadata for release with content `@fromHex(_releaseMetadata)`. /// @param _release The release number. /// @param _releaseMetadata The release metadata URI. function updateReleaseMetadata(uint8 _release, bytes calldata _releaseMetadata) external; /// @notice Creates a new plugin version as the latest build for an existing release number or the first build for a new release number for the provided `PluginSetup` contract address and metadata. /// @param _release The release number. /// @param _pluginSetupAddress The address of the plugin setup contract. /// @param _buildMetadata The build metadata URI. /// @param _releaseMetadata The release metadata URI. function createVersion( uint8 _release, address _pluginSetupAddress, bytes calldata _buildMetadata, bytes calldata _releaseMetadata ) external; /// @notice Emitted if the same plugin setup exists in previous releases. /// @param release The release number. /// @param build The build number. /// @param pluginSetup The address of the plugin setup contract. /// @param buildMetadata The build metadata URI. event VersionCreated( uint8 release, uint16 build, address indexed pluginSetup, bytes buildMetadata ); /// @notice Emitted when a release's metadata was updated. /// @param release The release number. /// @param releaseMetadata The release metadata URI. event ReleaseMetadataUpdated(uint8 release, bytes releaseMetadata); }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (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 IERC1822ProxiableUpgradeable {
/**
* @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) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/IERC1967Upgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import {Initializable} from "../utils/Initializable.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 ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
// 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;
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.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) {
AddressUpgradeable.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 (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(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 StorageSlotUpgradeable.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");
StorageSlotUpgradeable.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 StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.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) {
AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), 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: AGPL-3.0-or-later pragma solidity ^0.8.8; /// @title PermissionLib /// @author Aragon X - 2021-2023 /// @notice A library containing objects for permission processing. /// @custom:security-contact [email protected] library PermissionLib { /// @notice A constant expressing that no condition is applied to a permission. address public constant NO_CONDITION = address(0); /// @notice The types of permission operations available in the `PermissionManager`. /// @param Grant The grant operation setting a permission without a condition. /// @param Revoke The revoke operation removing a permission (that was granted with or without a condition). /// @param GrantWithCondition The grant operation setting a permission with a condition. enum Operation { Grant, Revoke, GrantWithCondition } /// @notice A struct containing the information for a permission to be applied on a single target contract without a condition. /// @param operation The permission operation type. /// @param who The address (EOA or contract) receiving the permission. /// @param permissionId The permission identifier. struct SingleTargetPermission { Operation operation; address who; bytes32 permissionId; } /// @notice A struct containing the information for a permission to be applied on multiple target contracts, optionally, with a condition. /// @param operation The permission operation type. /// @param where The address of the target contract for which `who` receives permission. /// @param who The address (EOA or contract) receiving the permission. /// @param condition The `PermissionCondition` that will be asked for authorization on calls connected to the specified permission identifier. /// @param permissionId The permission identifier. struct MultiTargetPermission { Operation operation; address where; address who; address condition; bytes32 permissionId; } }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.8; /// @title IDAO /// @author Aragon X - 2022-2024 /// @notice The interface required for DAOs within the Aragon App DAO framework. /// @custom:security-contact [email protected] interface IDAO { /// @notice Checks if an address has permission on a contract via a permission identifier and considers if `ANY_ADDRESS` was used in the granting process. /// @param _where The address of the contract. /// @param _who The address of a EOA or contract to give the permissions. /// @param _permissionId The permission identifier. /// @param _data The optional data passed to the `PermissionCondition` registered. /// @return Returns true if the address has permission, false if not. function hasPermission( address _where, address _who, bytes32 _permissionId, bytes memory _data ) external view returns (bool); /// @notice Updates the DAO metadata (e.g., an IPFS hash). /// @param _metadata The IPFS hash of the new metadata object. function setMetadata(bytes calldata _metadata) external; /// @notice Emitted when the DAO metadata is updated. /// @param metadata The IPFS hash of the new metadata object. event MetadataSet(bytes metadata); /// @notice Emitted when a standard callback is registered. /// @param interfaceId The ID of the interface. /// @param callbackSelector The selector of the callback function. /// @param magicNumber The magic number to be registered for the callback function selector. event StandardCallbackRegistered( bytes4 interfaceId, bytes4 callbackSelector, bytes4 magicNumber ); /// @notice Deposits (native) tokens to the DAO contract with a reference string. /// @param _token The address of the token or address(0) in case of the native token. /// @param _amount The amount of tokens to deposit. /// @param _reference The reference describing the deposit reason. function deposit(address _token, uint256 _amount, string calldata _reference) external payable; /// @notice Emitted when a token deposit has been made to the DAO. /// @param sender The address of the sender. /// @param token The address of the deposited token. /// @param amount The amount of tokens deposited. /// @param _reference The reference describing the deposit reason. event Deposited( address indexed sender, address indexed token, uint256 amount, string _reference ); /// @notice Emitted when a native token deposit has been made to the DAO. /// @dev This event is intended to be emitted in the `receive` function and is therefore bound by the gas limitations for `send`/`transfer` calls introduced by [ERC-2929](https://eips.ethereum.org/EIPS/eip-2929). /// @param sender The address of the sender. /// @param amount The amount of native tokens deposited. event NativeTokenDeposited(address sender, uint256 amount); /// @notice Setter for the trusted forwarder verifying the meta transaction. /// @param _trustedForwarder The trusted forwarder address. function setTrustedForwarder(address _trustedForwarder) external; /// @notice Getter for the trusted forwarder verifying the meta transaction. /// @return The trusted forwarder address. function getTrustedForwarder() external view returns (address); /// @notice Emitted when a new TrustedForwarder is set on the DAO. /// @param forwarder the new forwarder address. event TrustedForwarderSet(address forwarder); /// @notice Checks whether a signature is valid for a provided hash according to [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271). /// @param _hash The hash of the data to be signed. /// @param _signature The signature byte array associated with `_hash`. /// @return Returns the `bytes4` magic value `0x1626ba7e` if the signature is valid and `0xffffffff` if not. function isValidSignature(bytes32 _hash, bytes memory _signature) external returns (bytes4); /// @notice Registers an ERC standard having a callback by registering its [ERC-165](https://eips.ethereum.org/EIPS/eip-165) interface ID and callback function signature. /// @param _interfaceId The ID of the interface. /// @param _callbackSelector The selector of the callback function. /// @param _magicNumber The magic number to be registered for the function signature. function registerStandardCallback( bytes4 _interfaceId, bytes4 _callbackSelector, bytes4 _magicNumber ) external; /// @notice Removed function being left here to not corrupt the IDAO interface ID. Any call will revert. /// @dev Introduced in v1.0.0. Removed in v1.4.0. function setSignatureValidator(address) external; }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.8; /// @title IPermissionCondition /// @author Aragon X - 2021-2023 /// @notice An interface to be implemented to support custom permission logic. /// @dev To attach a condition to a permission, the `grantWithCondition` function must be used and refer to the implementing contract's address with the `condition` argument. /// @custom:security-contact [email protected] interface IPermissionCondition { /// @notice Checks if a call is permitted. /// @param _where The address of the target contract. /// @param _who The address (EOA or contract) for which the permissions are checked. /// @param _permissionId The permission identifier. /// @param _data Optional data passed to the `PermissionCondition` implementation. /// @return isPermitted Returns true if the call is permitted. function isGranted( address _where, address _who, bytes32 _permissionId, bytes calldata _data ) external view returns (bool isPermitted); }
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IProtocolVersion} from "../../utils/versioning/IProtocolVersion.sol";
import {ProtocolVersion} from "../../utils/versioning/ProtocolVersion.sol";
import {IPermissionCondition} from "./IPermissionCondition.sol";
/// @title PermissionCondition
/// @author Aragon X - 2023
/// @notice An abstract contract for non-upgradeable contracts instantiated via the `new` keyword to inherit from to support customary permissions depending on arbitrary on-chain state.
/// @custom:security-contact [email protected]
abstract contract PermissionCondition is ERC165, IPermissionCondition, ProtocolVersion {
/// @notice Checks if an interface is supported by this or its parent contract.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return
_interfaceId == type(IPermissionCondition).interfaceId ||
_interfaceId == type(IProtocolVersion).interfaceId ||
super.supportsInterface(_interfaceId);
}
}// 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 IBeaconUpgradeable {
/**
* @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
// 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 IERC1967Upgradeable {
/**
* @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.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 v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@aragon/osx/=lib/osx/packages/contracts/src/",
"@aragon/osx-commons-contracts/=lib/osx-commons/contracts/",
"@aragon/admin-plugin/=lib/admin-plugin/packages/contracts/src/",
"@aragon/multisig-plugin/=lib/multisig-plugin/packages/contracts/src/",
"@aragon/token-voting-plugin/=lib/token-voting-plugin/src/",
"@aragon/staged-proposal-processor-plugin/=lib/staged-proposal-processor-plugin/src/",
"@ensdomains/ens-contracts/=lib/ens-contracts/",
"@ensdomains/buffer/=lib/buffer/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin/openzeppelin-foundry-upgrades/=lib/staged-proposal-processor-plugin/node_modules/@openzeppelin/openzeppelin-foundry-upgrades/src/",
"admin-plugin/=lib/admin-plugin/",
"buffer/=lib/buffer/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"ens-contracts/=lib/ens-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"multisig-plugin/=lib/multisig-plugin/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"osx-commons/=lib/osx-commons/",
"osx/=lib/osx/",
"plugin-version-1.3/=lib/token-voting-plugin/lib/plugin-version-1.3/packages/contracts/src/",
"solidity-stringutils/=lib/staged-proposal-processor-plugin/node_modules/solidity-stringutils/",
"staged-proposal-processor-plugin/=lib/staged-proposal-processor-plugin/src/",
"token-voting-plugin/=lib/token-voting-plugin/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AnyAddressDisallowedForWhoAndWhere","type":"error"},{"inputs":[{"internalType":"contract IPermissionCondition","name":"condition","type":"address"}],"name":"ConditionInterfaceNotSupported","type":"error"},{"inputs":[{"internalType":"contract IPermissionCondition","name":"condition","type":"address"}],"name":"ConditionNotAContract","type":"error"},{"inputs":[],"name":"EmptyReleaseMetadata","type":"error"},{"inputs":[],"name":"GrantWithConditionNotSupported","type":"error"},{"inputs":[],"name":"InvalidPluginSetupInterface","type":"error"},{"inputs":[{"internalType":"uint8","name":"latestRelease","type":"uint8"},{"internalType":"uint8","name":"newRelease","type":"uint8"}],"name":"InvalidReleaseIncrement","type":"error"},{"inputs":[{"internalType":"address","name":"where","type":"address"},{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes32","name":"permissionId","type":"bytes32"},{"internalType":"address","name":"currentCondition","type":"address"},{"internalType":"address","name":"newCondition","type":"address"}],"name":"PermissionAlreadyGrantedForDifferentCondition","type":"error"},{"inputs":[],"name":"PermissionsForAnyAddressDisallowed","type":"error"},{"inputs":[{"internalType":"uint8","name":"release","type":"uint8"},{"internalType":"uint16","name":"build","type":"uint16"},{"internalType":"address","name":"pluginSetup","type":"address"}],"name":"PluginSetupAlreadyInPreviousRelease","type":"error"},{"inputs":[],"name":"ReleaseDoesNotExist","type":"error"},{"inputs":[],"name":"ReleaseZeroNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"where","type":"address"},{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes32","name":"permissionId","type":"bytes32"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"bytes32","name":"versionHash","type":"bytes32"}],"name":"VersionHashDoesNotExist","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"permissionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"here","type":"address"},{"indexed":false,"internalType":"address","name":"where","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"},{"indexed":false,"internalType":"address","name":"condition","type":"address"}],"name":"Granted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"release","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"releaseMetadata","type":"bytes"}],"name":"ReleaseMetadataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"permissionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"here","type":"address"},{"indexed":false,"internalType":"address","name":"where","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"release","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"build","type":"uint16"},{"indexed":true,"internalType":"address","name":"pluginSetup","type":"address"},{"indexed":false,"internalType":"bytes","name":"buildMetadata","type":"bytes"}],"name":"VersionCreated","type":"event"},{"inputs":[],"name":"MAINTAINER_PERMISSION_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROOT_PERMISSION_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_REPO_PERMISSION_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum PermissionLib.Operation","name":"operation","type":"uint8"},{"internalType":"address","name":"where","type":"address"},{"internalType":"address","name":"who","type":"address"},{"internalType":"address","name":"condition","type":"address"},{"internalType":"bytes32","name":"permissionId","type":"bytes32"}],"internalType":"struct PermissionLib.MultiTargetPermission[]","name":"_items","type":"tuple[]"}],"name":"applyMultiTargetPermissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_where","type":"address"},{"components":[{"internalType":"enum PermissionLib.Operation","name":"operation","type":"uint8"},{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes32","name":"permissionId","type":"bytes32"}],"internalType":"struct PermissionLib.SingleTargetPermission[]","name":"items","type":"tuple[]"}],"name":"applySingleTargetPermissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_release","type":"uint8"}],"name":"buildCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_release","type":"uint8"},{"internalType":"address","name":"_pluginSetup","type":"address"},{"internalType":"bytes","name":"_buildMetadata","type":"bytes"},{"internalType":"bytes","name":"_releaseMetadata","type":"bytes"}],"name":"createVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pluginSetup","type":"address"}],"name":"getLatestVersion","outputs":[{"components":[{"components":[{"internalType":"uint8","name":"release","type":"uint8"},{"internalType":"uint16","name":"build","type":"uint16"}],"internalType":"struct PluginRepo.Tag","name":"tag","type":"tuple"},{"internalType":"address","name":"pluginSetup","type":"address"},{"internalType":"bytes","name":"buildMetadata","type":"bytes"}],"internalType":"struct PluginRepo.Version","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_release","type":"uint8"}],"name":"getLatestVersion","outputs":[{"components":[{"components":[{"internalType":"uint8","name":"release","type":"uint8"},{"internalType":"uint16","name":"build","type":"uint16"}],"internalType":"struct PluginRepo.Tag","name":"tag","type":"tuple"},{"internalType":"address","name":"pluginSetup","type":"address"},{"internalType":"bytes","name":"buildMetadata","type":"bytes"}],"internalType":"struct PluginRepo.Version","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_tagHash","type":"bytes32"}],"name":"getVersion","outputs":[{"components":[{"components":[{"internalType":"uint8","name":"release","type":"uint8"},{"internalType":"uint16","name":"build","type":"uint16"}],"internalType":"struct PluginRepo.Tag","name":"tag","type":"tuple"},{"internalType":"address","name":"pluginSetup","type":"address"},{"internalType":"bytes","name":"buildMetadata","type":"bytes"}],"internalType":"struct PluginRepo.Version","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"release","type":"uint8"},{"internalType":"uint16","name":"build","type":"uint16"}],"internalType":"struct PluginRepo.Tag","name":"_tag","type":"tuple"}],"name":"getVersion","outputs":[{"components":[{"components":[{"internalType":"uint8","name":"release","type":"uint8"},{"internalType":"uint16","name":"build","type":"uint16"}],"internalType":"struct PluginRepo.Tag","name":"tag","type":"tuple"},{"internalType":"address","name":"pluginSetup","type":"address"},{"internalType":"bytes","name":"buildMetadata","type":"bytes"}],"internalType":"struct PluginRepo.Version","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_where","type":"address"},{"internalType":"address","name":"_who","type":"address"},{"internalType":"bytes32","name":"_permissionId","type":"bytes32"}],"name":"grant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_where","type":"address"},{"internalType":"address","name":"_who","type":"address"},{"internalType":"bytes32","name":"_permissionId","type":"bytes32"},{"internalType":"contract IPermissionCondition","name":"_condition","type":"address"}],"name":"grantWithCondition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[3]","name":"_previousProtocolVersion","type":"uint8[3]"},{"internalType":"bytes","name":"_initData","type":"bytes"}],"name":"initializeFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_where","type":"address"},{"internalType":"address","name":"_who","type":"address"},{"internalType":"bytes32","name":"_permissionId","type":"bytes32"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"isGranted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRelease","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolVersion","outputs":[{"internalType":"uint8[3]","name":"","type":"uint8[3]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_where","type":"address"},{"internalType":"address","name":"_who","type":"address"},{"internalType":"bytes32","name":"_permissionId","type":"bytes32"}],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_release","type":"uint8"},{"internalType":"bytes","name":"_releaseMetadata","type":"bytes"}],"name":"updateReleaseMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60a080604052346100da57306080525f549060ff8260081c16610088575060ff8082160361004e575b60405161272590816100df82396080518181816105ca015281816107b001526109740152f35b60ff90811916175f557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a15f610028565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a71461019457806309e56b141461018f57806322844d041461018a5780632675fdd01461018557806328375f67146101805780632ae9c6001461017b5780633659cfe61461017657806342d8e99e146101715780634f1ef2861461016c57806350abe9101461016757806352d1902d146101625780637be0ca5e1461015d5780639aaf9f08146101585780639af3e90914610153578063afe5eb781461014e578063c4d66de814610149578063c9dbc2a414610144578063cc98b8f51461013f578063d68bad2c1461013a578063d96054c414610135578063df1d6c4414610130578063e0589bd31461012b578063e978afe5146101265763fc05442714610121575f80fd5b610d9e565b610d43565b610ceb565b610cb5565b610c96565b610c77565b610c24565b610bda565b610ae4565b610abd565b610a64565b610a45565b610a25565b610962565b61090d565b610774565b610712565b6105a8565b61053b565b61047c565b6103dc565b61023d565b610205565b346102015760203660031901126102015760043563ffffffff60e01b811680910361020157602090630350c86d60e61b81149081156101f1575b81156101e0575b506040519015158152f35b6301ffc9a760e01b1490505f6101d5565b621574e360e91b811491506101ce565b5f80fd5b34610201575f3660031901126102015760206040515f5160206126905f395f51905f528152f35b6001600160a01b0381160361020157565b346102015760403660031901126102015760043561025a8161022c565b602435906001600160401b0382116102015736602383011215610201578160040135906001600160401b0382116102015736602460608402850101116102015760246102a7930190611062565b005b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b038211176102d857604052565b6102a9565b604081019081106001600160401b038211176102d857604052565b90601f801991011681019081106001600160401b038211176102d857604052565b604051906103286040836102f8565b565b604051906103286060836102f8565b6001600160401b0381116102d857601f01601f191660200190565b91909161036081610339565b61036d60405191826102f8565b809382825282116102015781815f9384602080950137010152565b92919261039482610339565b916103a260405193846102f8565b829481845281830111610201578281602093845f960137010152565b9080601f83011215610201578160206103d993359101610388565b90565b34610201576080366003190112610201576004356103f98161022c565b602435906104068261022c565b606435906044356001600160401b0383116102015760209361042f6104359436906004016103be565b926111d8565b6040519015158152f35b6004359060ff8216820361020157565b9181601f84011215610201578235916001600160401b038311610201576020838186019501011161020157565b346102015760403660031901126102015761049561043f565b6024356001600160401b038111610201576104b490369060040161044f565b916104bd611a4a565b60ff8116801561052c5760ff60cc54161061051d57821561050e576105097f8ff94c32efcef376eb02508cba5536e0634c1d6ad4b51ffa0f7306c78edaf5f793604051938493846112ab565b0390a1005b6388bc3fe760e01b5f5260045ffd5b6311c6e3ab60e01b5f5260045ffd5b633b7a97fd60e11b5f5260045ffd5b34610201575f36600319011261020157606060405161055a82826102f8565b369037604051610569816102bd565b60018152600460208201525f604082015260405190815f905b6003821061058f57606084f35b60208060019260ff865116815201930191019091610582565b34610201576020366003190112610201576004356105c58161022c565b61061c7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166105fe308214156112c5565b5f5160206126505f395f51905f52546001600160a01b031614611326565b610624611a9b565b602060405161063382826102f8565b5f8152601f19820136838301377f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156106755750506102a7906124c0565b6040516352d1902d60e01b81529180836004816001600160a01b0388165afa9283915f946106e3575b50506106c15760405162461bcd60e51b8152806106bd60048201612042565b0390fd5b6102a7926106de5f5160206126505f395f51905f525f9414611fe4565b6123db565b610703929450803d1061070b575b6106fb81836102f8565b810190611fd5565b915f8061069e565b503d6106f1565b346102015760803660031901126102015736606411610201576064356001600160401b0381116102015761074a90369060040161044f565b50506102015f5460ff8160081c16159081610766575b50611387565b6002915060ff16105f610760565b60403660031901126102015760043561078c8161022c565b6024356001600160401b038111610201576107ab9036906004016103be565b6107e47f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166105fe308214156112c5565b6107ec611a9b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561082057506102a7906124c0565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa5f9281610884575b506108665760405162461bcd60e51b8152806106bd60048201612042565b6102a7926106de5f5160206126505f395f51905f5260019414611fe4565b61089e91935060203d60201161070b576106fb81836102f8565b915f610848565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b60a060406103d9936020845261ffff6020825160ff8151168288015201511682850152600180841b03602082015116606085015201519160808082015201906108a5565b346102015760203660031901126102015760043561092a8161022c565b6109326113ea565b5060018060a01b03165f5260cb60205261095e61095260405f2054611454565b604051918291826108c9565b0390f35b34610201575f366003190112610201577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036109ba576040515f5160206126505f395f51905f528152602090f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608490fd5b34610201575f36600319011261020157602060ff60cc5416604051908152f35b346102015760203660031901126102015761095e610952600435611454565b3461020157604036600319011261020157610a7d6113ea565b50604051610a8a816102dd565b610a9261043f565b81526024359061ffff8216820361020157610ab88161095e936020610952940152612091565b611454565b34610201575f3660031901126102015760206040515f5160206126705f395f51905f528152f35b3461020157602036600319011261020157600435610b018161022c565b610b4e5f5491610b34610b1f610b1b8560ff9060081c1690565b1590565b80948195610bcc575b8115610bac5750611387565b82610b45600160ff195f5416175f55565b610b9557611570565b610b5457005b610b6261ff00195f54165f55565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498908060208101610509565b610ba761010061ff00195f5416175f55565b611570565b303b15915081610bbe575b505f610760565b60ff1660011490505f610bb7565b600160ff8216109150610b28565b34610201576080366003190112610201576102a7600435610bfa8161022c565b602435610c068161022c565b6044359060643592610c178461022c565b610c1f611aec565b6120d3565b34610201575f3660031901126102015760206040515f5160206126d05f395f51905f528152f35b606090600319011261020157600435610c638161022c565b90602435610c708161022c565b9060443590565b34610201576102a7610c8836610c4b565b91610c91611aec565b611d45565b34610201576102a7610ca736610c4b565b91610cb0611aec565b611b3d565b346102015760203660031901126102015760ff610cd061043f565b165f5260c9602052602061ffff60405f205416604051908152f35b346102015760203660031901126102015761095e610952610ab860ff610d0f61043f565b610d176113ea565b5016805f5260c960205261ffff60405f20541660405191610d37836102dd565b82526020820152612091565b34610201576020366003190112610201576004356001600160401b03811161020157366023820112156102015780600401356001600160401b0381116102015736602460a08302840101116102015760246102a792016116b9565b3461020157608036600319011261020157610db761043f565b602435610dc38161022c565b6044356001600160401b03811161020157610de290369060040161044f565b6064939193356001600160401b03811161020157610e0490369060040161044f565b949093610e0f611a4a565b610e1b610b1b826122f2565b6110535760ff8416801561052c5760cc5460ff16600160ff610e3d838961187c565b16116110375760ff16811161100f575b6001600160a01b0382165f90815260cb60205260409020610e7790545f5260ca60205260405f2090565b5460ff811691821515908382611004575b5050610fc8575050907feb4bce5025c5200f6a074dd28fe7754955dfdca0eb2dcbaa16ccc292655e666991610f8d610ecb8660ff165f5260c960205260405f2090565b94610ef5610ee3610ede885461ffff1690565b611895565b875461ffff191661ffff821617909755565b610efd610319565b60ff8816815261ffff87166020820152610f5b610f1982612091565b91610f2261032a565b9081526001600160a01b0386166020820152610f3f368589610388565b6040820152610f56835f5260ca60205260405f2090565b6118f7565b6001600160a01b0384165f90815260cb60205260409020556040516001600160a01b0390931695929384938885611a27565b0390a282610f9757005b6105097f8ff94c32efcef376eb02508cba5536e0634c1d6ad4b51ffa0f7306c78edaf5f793604051938493846112ab565b611001935060081c61ffff1660016218326360e21b03195f5260ff90911660045261ffff166024526001600160a01b0316604452606490565b5ffd5b141590505f80610e88565b6110238560ff1660ff1960cc54161760cc55565b86610e4d576388bc3fe760e01b5f5260045ffd5b6353db7b7b60e01b5f5260ff908116600452851660245260445ffd5b639d145ceb60e01b5f5260045ffd5b909161106c611aec565b5f5b81811061107b5750505050565b61108e611089828487611158565b61117a565b8051611099816111ba565b6110a2816111ba565b6110cf576020810151600192916110c9916040906001600160a01b03169101519086611d45565b0161106e565b600181516110dc816111ba565b6110e5816111ba565b036111125760208101516001929161110d916040906001600160a01b03169101519086611b3d565b6110c9565b6002905161111f816111ba565b611128816111ba565b14611135576001906110c9565b63d4d3bef760e01b5f5260045ffd5b634e487b7160e01b5f52603260045260245ffd5b9190811015611168576060020190565b611144565b3590600382101561020157565b606081360312610201576040805191611192836102bd565b61119b8161116d565b835260208101356111ab8161022c565b60208401520135604082015290565b600311156111c457565b634e487b7160e01b5f52602160045260245ffd5b9291906112076111fa6111ec848488611eb3565b5f52609760205260405f2090565b546001600160a01b031690565b6001600160a01b0381166002811461128057611276575061122e6111fa6111ec8487611e0f565b6001600160a01b038116600281146112805761127657506112556111fa6111ec8484611e64565b936001600160a01b03851661126d5750505050505f90565b6103d994611f2b565b936103d994611f2b565b505050505050600190565b908060209392818452848401375f828201840152601f01601f1916010190565b60409060ff6103d99593168152816020820152019161128b565b156112cc57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1561132d57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b1561138e57565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b604051906113f7826102bd565b60606040838151611407816102dd565b5f81525f602082015281525f60208201520152565b90600182811c9216801561144a575b602083101461143657565b634e487b7160e01b5f52602260045260245ffd5b91607f169161142b565b61145c6113ea565b50805f5260ca60205260405f2080549160ff831690811561155e57509060029161ffff6040519461148c866102bd565b60405192611499846102dd565b835260081c166020820152835260018060a01b0360018201541660208401520160405190815f8254926114cb8461141c565b808452936001811690811561153c57506001146114f8575b506114f0925003826102f8565b604082015290565b90505f9291925260205f20905f915b8183106115205750509060206114f0928201015f6114e3565b6020919350806001915483858801015201910190918392611507565b9050602092506114f094915060ff191682840152151560051b8201015f6114e3565b638d0aeeb160e01b5f5260045260245ffd5b60ff5f5460081c161561166057306001600160a01b0314611651576001600160a01b038181169190821461165157610328916115ba5f5160206126905f395f51905f528330611eb3565b5f8181526097602052604090206001600160a01b03906115d9906111fa565b16156115f2575b50506115ec8130611bcc565b30611c8c565b61160761161a915f52609760205260405f2090565b80546001600160a01b0319166002179055565b604080513081526002602082015233915f5160206126905f395f51905f52915f5160206126b05f395f51905f529190a45f806115e0565b6324159e5b60e01b5f5260045ffd5b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b906116c2611aec565b5f5b8181106116d057505050565b6116e36116de8284866117df565b6117ef565b9081516116ef816111ba565b6116f8816111ba565b61173d5760608201516001600160a01b03166111355760208201516040830151608090930151600193611737926001600160a01b039182169116611d45565b016116c4565b81600180935161174c816111ba565b611755816111ba565b0361178757602081015160408201516080909201516117829290916001600160a01b039182169116611b3d565b611737565b60028151611794816111ba565b61179d816111ba565b146117a9575b50611737565b6020810151604082015160808301516060909301516117d9936001600160a01b03918216939092821691166120d3565b5f6117a3565b91908110156111685760a0020190565b60a081360312610201576040519060a08201908282106001600160401b038311176102d8576080916040526118238161116d565b835260208101356118338161022c565b602084015260408101356118468161022c565b604084015260608101356118598161022c565b60608401520135608082015290565b634e487b7160e01b5f52601160045260245ffd5b9060ff8091169116039060ff821161189057565b611868565b61ffff1661ffff81146118905760010190565b601f82116118b557505050565b5f5260205f20906020601f840160051c830193106118ed575b601f0160051c01905b8181106118e2575050565b5f81556001016118d7565b90915081906118ce565b60026040919392936020855161191b60ff825116849060ff1660ff19825416179055565b0151815462ffff00191660089190911b62ffff001617815560208501516001820180546001600160a01b0319166001600160a01b0392909216919091179055019201519182516001600160401b0381116102d8576119838161197d845461141c565b846118a8565b6020601f82116001146119c25781906119b39394955f926119b7575b50508160011b915f199060031b1c19161790565b9055565b015190505f8061199f565b601f198216906119d5845f5260205f2090565b915f5b818110611a0f575095836001959697106119f7575b505050811b019055565b01515f1960f88460031b161c191690555f80806119ed565b9192602060018192868b0151815501940192016119d8565b61ffff6103d9959360ff606094168352166020820152816040820152019161128b565b611a6c611a573636610354565b5f5160206126705f395f51905f5233306111d8565b15611a7357565b631e09743f60e01b5f5230600452336024525f5160206126705f395f51905f5260445260645ffd5b611abd611aa83636610354565b5f5160206126d05f395f51905f5233306111d8565b15611ac457565b631e09743f60e01b5f5230600452336024525f5160206126d05f395f51905f5260445260645ffd5b611b0e611af93636610354565b5f5160206126905f395f51905f5233306111d8565b15611b1557565b631e09743f60e01b5f5230600452336024525f5160206126905f395f51905f5260445260645ffd5b90611b49838284611eb3565b5f818152609760205260409020546001600160a01b0316611b6b575b50505050565b5f52609760205260405f206001600160601b0360a01b81541690556040519160018060a01b0316825260018060a01b0316917f3ca48185ec3f6e47e24db18b13f1c65b1ce05da1659f9c1c4fe717dda5f6752460203393a45f808080611b65565b6001600160a01b0381811614611651576001600160a01b0382811692611c09915f5160206126705f395f51905f5291908514611c87575b83611eb3565b611c1b815f52609760205260405f2090565b546001600160a01b031615611c2f57505050565b611607611c44915f52609760205260405f2090565b604080516001600160a01b0390921682526002602083015233915f5160206126705f395f51905f52915f5160206126b05f395f51905f529190819081015b0390a4565b611c03565b6001600160a01b0381811614611651576001600160a01b0382811692611cc8915f5160206126d05f395f51905f5291908514611c875783611eb3565b611cda815f52609760205260405f2090565b546001600160a01b031615611cee57505050565b611607611d03915f52609760205260405f2090565b604080516001600160a01b0390921682526002602083015233915f5160206126d05f395f51905f52915f5160206126b05f395f51905f52919081908101611c82565b90916001600160a01b0380831614611651576001600160a01b03838116939082908514611de8575b611d779184611eb3565b611d89815f52609760205260405f2090565b546001600160a01b031615611d9e5750505050565b611607611db3915f52609760205260405f2090565b604080516001600160a01b039390931683526002602084015233925f5160206126b05f395f51905f529190a45f808080611b65565b5f5160206126905f395f51905f52148015611e08575b6116515781611d6d565b505f611dfe565b90604051906020820192692822a926a4a9a9a4a7a760b11b84526001600160601b0319602a8401526001600160601b03199060601b16603e830152605282015260528152611e5e6072826102f8565b51902090565b90604051906020820192692822a926a4a9a9a4a7a760b11b84526001600160601b03199060601b16602a8301526001600160601b0319603e830152605282015260528152611e5e6072826102f8565b9091604051916020830193692822a926a4a9a9a4a7a760b11b85526001600160601b03199060601b16602a8401526001600160601b03199060601b16603e830152605282015260528152611e5e6072826102f8565b90816020910312610201575180151581036102015790565b6040513d5f823e3d90fd5b6040516302675fdd60e41b81526001600160a01b03928316600482015292909116602483015260448201929092526080606482015291602091839182908190611f789060848301906108a5565b03916001600160a01b03165afa5f9181611fa4575b50611f9757505f90565b611f9f575f90565b600190565b611fc791925060203d602011611fce575b611fbf81836102f8565b810190611f08565b905f611f8d565b503d611fb5565b90816020910312610201575190565b15611feb57565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b805160209182015160405160f89290921b6001600160f81b03191692820192835260f01b6001600160f01b031916602182015260038152611e5e6023826102f8565b6001600160a01b0384169390929190843b156122d7576040516301ffc9a760e01b81526302675fdd60e41b6004820152602081602481895afa9081156122d2575f916122b3575b501561229857506001600160a01b03838116148080612286575b612277578015612265575b612233575b61214f828285611eb3565b6121646111fa825f52609760205260405f2090565b6001600160a01b038116806121e35750505f5160206126b05f395f51905f52916121bc8661219d611c82945f52609760205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b604080516001600160a01b0396871681529686166020880152941694339490918291820190565b8694925095909295036121f7575050505050565b6040516305cc3c4f60e11b81526001600160a01b039485166004820152948416602486015260448501528216606484015216608482015260a490fd5b5f5160206126905f395f51905f528214801561225e575b15612144576324159e5b60e01b5f5260045ffd5b505f61224a565b506001600160a01b038181161461213f565b6385f1ba9960e01b5f5260045ffd5b506001600160a01b0382811614612134565b636dd8243160e11b5f526001600160a01b031660045260245ffd5b6122cc915060203d602011611fce57611fbf81836102f8565b5f61211a565b611f20565b63241acd7b60e11b5f526001600160a01b031660045260245ffd5b60205f604051828101906301ffc9a760e01b82526301ffc9a760e01b6024820152602481526123226044826102f8565b519084617530fa903d5f5190836123cf575b50826123c5575b508161235e575b8161234b575090565b6103d9915063099718b560e41b90612557565b905060205f604051828101906301ffc9a760e01b825263ffffffff60e01b6024820152602481526123906044826102f8565b519084617530fa5f513d826123b9575b50816123af575b501590612342565b905015155f6123a7565b6020111591505f6123a0565b151591505f61233b565b6020111592505f612334565b916123e5836124c0565b6001600160a01b0383167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115908115916124b8575b50612428575050565b6124ad915f806040519361243d6060866102f8565b602785527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020860152660819985a5b195960ca1b6040860152602081519101845af43d156124b0573d9161249183610339565b9261249f60405194856102f8565b83523d5f602085013e6125b6565b50565b6060916125b6565b90505f61241f565b803b156124fc5760018060a01b03166001600160601b0360a01b5f5160206126505f395f51905f525416175f5160206126505f395f51905f5255565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b5f90602092604051848101916301ffc9a760e01b835263ffffffff60e01b1660248201526024815261258a6044826102f8565b5191617530fa5f513d826125aa575b50816125a3575090565b9050151590565b6020111591505f612599565b9192901561261857508151156125ca575090565b3b156125d35790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501561262b5750805190602001fd5b60405162461bcd60e51b8152602060048201529081906106bd9060248301906108a556fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0885006fe6672eeafd1deca6c67bcdc6dd79cfe2b157a98539ddf73cd8c04ea815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada330f579ad49235a8c1fd9041427e7067b1eb10926bbed380bf6fabc73e0e8076445aa4f06bdc18535eff05128093a2315c2c960a2722e20021cbff28da04760f5ba2646970667358221220e7349eb5dc5a1ce577990974f819d5fa228b489f861d2165035bae6e266b19bd64736f6c634300081c0033
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a71461019457806309e56b141461018f57806322844d041461018a5780632675fdd01461018557806328375f67146101805780632ae9c6001461017b5780633659cfe61461017657806342d8e99e146101715780634f1ef2861461016c57806350abe9101461016757806352d1902d146101625780637be0ca5e1461015d5780639aaf9f08146101585780639af3e90914610153578063afe5eb781461014e578063c4d66de814610149578063c9dbc2a414610144578063cc98b8f51461013f578063d68bad2c1461013a578063d96054c414610135578063df1d6c4414610130578063e0589bd31461012b578063e978afe5146101265763fc05442714610121575f80fd5b610d9e565b610d43565b610ceb565b610cb5565b610c96565b610c77565b610c24565b610bda565b610ae4565b610abd565b610a64565b610a45565b610a25565b610962565b61090d565b610774565b610712565b6105a8565b61053b565b61047c565b6103dc565b61023d565b610205565b346102015760203660031901126102015760043563ffffffff60e01b811680910361020157602090630350c86d60e61b81149081156101f1575b81156101e0575b506040519015158152f35b6301ffc9a760e01b1490505f6101d5565b621574e360e91b811491506101ce565b5f80fd5b34610201575f3660031901126102015760206040515f5160206126905f395f51905f528152f35b6001600160a01b0381160361020157565b346102015760403660031901126102015760043561025a8161022c565b602435906001600160401b0382116102015736602383011215610201578160040135906001600160401b0382116102015736602460608402850101116102015760246102a7930190611062565b005b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b038211176102d857604052565b6102a9565b604081019081106001600160401b038211176102d857604052565b90601f801991011681019081106001600160401b038211176102d857604052565b604051906103286040836102f8565b565b604051906103286060836102f8565b6001600160401b0381116102d857601f01601f191660200190565b91909161036081610339565b61036d60405191826102f8565b809382825282116102015781815f9384602080950137010152565b92919261039482610339565b916103a260405193846102f8565b829481845281830111610201578281602093845f960137010152565b9080601f83011215610201578160206103d993359101610388565b90565b34610201576080366003190112610201576004356103f98161022c565b602435906104068261022c565b606435906044356001600160401b0383116102015760209361042f6104359436906004016103be565b926111d8565b6040519015158152f35b6004359060ff8216820361020157565b9181601f84011215610201578235916001600160401b038311610201576020838186019501011161020157565b346102015760403660031901126102015761049561043f565b6024356001600160401b038111610201576104b490369060040161044f565b916104bd611a4a565b60ff8116801561052c5760ff60cc54161061051d57821561050e576105097f8ff94c32efcef376eb02508cba5536e0634c1d6ad4b51ffa0f7306c78edaf5f793604051938493846112ab565b0390a1005b6388bc3fe760e01b5f5260045ffd5b6311c6e3ab60e01b5f5260045ffd5b633b7a97fd60e11b5f5260045ffd5b34610201575f36600319011261020157606060405161055a82826102f8565b369037604051610569816102bd565b60018152600460208201525f604082015260405190815f905b6003821061058f57606084f35b60208060019260ff865116815201930191019091610582565b34610201576020366003190112610201576004356105c58161022c565b61061c7f0000000000000000000000006afc0d8ce9cdaf9d12815cc0314a0109341d98e66001600160a01b03166105fe308214156112c5565b5f5160206126505f395f51905f52546001600160a01b031614611326565b610624611a9b565b602060405161063382826102f8565b5f8152601f19820136838301377f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156106755750506102a7906124c0565b6040516352d1902d60e01b81529180836004816001600160a01b0388165afa9283915f946106e3575b50506106c15760405162461bcd60e51b8152806106bd60048201612042565b0390fd5b6102a7926106de5f5160206126505f395f51905f525f9414611fe4565b6123db565b610703929450803d1061070b575b6106fb81836102f8565b810190611fd5565b915f8061069e565b503d6106f1565b346102015760803660031901126102015736606411610201576064356001600160401b0381116102015761074a90369060040161044f565b50506102015f5460ff8160081c16159081610766575b50611387565b6002915060ff16105f610760565b60403660031901126102015760043561078c8161022c565b6024356001600160401b038111610201576107ab9036906004016103be565b6107e47f0000000000000000000000006afc0d8ce9cdaf9d12815cc0314a0109341d98e66001600160a01b03166105fe308214156112c5565b6107ec611a9b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561082057506102a7906124c0565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa5f9281610884575b506108665760405162461bcd60e51b8152806106bd60048201612042565b6102a7926106de5f5160206126505f395f51905f5260019414611fe4565b61089e91935060203d60201161070b576106fb81836102f8565b915f610848565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b60a060406103d9936020845261ffff6020825160ff8151168288015201511682850152600180841b03602082015116606085015201519160808082015201906108a5565b346102015760203660031901126102015760043561092a8161022c565b6109326113ea565b5060018060a01b03165f5260cb60205261095e61095260405f2054611454565b604051918291826108c9565b0390f35b34610201575f366003190112610201577f0000000000000000000000006afc0d8ce9cdaf9d12815cc0314a0109341d98e66001600160a01b031630036109ba576040515f5160206126505f395f51905f528152602090f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608490fd5b34610201575f36600319011261020157602060ff60cc5416604051908152f35b346102015760203660031901126102015761095e610952600435611454565b3461020157604036600319011261020157610a7d6113ea565b50604051610a8a816102dd565b610a9261043f565b81526024359061ffff8216820361020157610ab88161095e936020610952940152612091565b611454565b34610201575f3660031901126102015760206040515f5160206126705f395f51905f528152f35b3461020157602036600319011261020157600435610b018161022c565b610b4e5f5491610b34610b1f610b1b8560ff9060081c1690565b1590565b80948195610bcc575b8115610bac5750611387565b82610b45600160ff195f5416175f55565b610b9557611570565b610b5457005b610b6261ff00195f54165f55565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498908060208101610509565b610ba761010061ff00195f5416175f55565b611570565b303b15915081610bbe575b505f610760565b60ff1660011490505f610bb7565b600160ff8216109150610b28565b34610201576080366003190112610201576102a7600435610bfa8161022c565b602435610c068161022c565b6044359060643592610c178461022c565b610c1f611aec565b6120d3565b34610201575f3660031901126102015760206040515f5160206126d05f395f51905f528152f35b606090600319011261020157600435610c638161022c565b90602435610c708161022c565b9060443590565b34610201576102a7610c8836610c4b565b91610c91611aec565b611d45565b34610201576102a7610ca736610c4b565b91610cb0611aec565b611b3d565b346102015760203660031901126102015760ff610cd061043f565b165f5260c9602052602061ffff60405f205416604051908152f35b346102015760203660031901126102015761095e610952610ab860ff610d0f61043f565b610d176113ea565b5016805f5260c960205261ffff60405f20541660405191610d37836102dd565b82526020820152612091565b34610201576020366003190112610201576004356001600160401b03811161020157366023820112156102015780600401356001600160401b0381116102015736602460a08302840101116102015760246102a792016116b9565b3461020157608036600319011261020157610db761043f565b602435610dc38161022c565b6044356001600160401b03811161020157610de290369060040161044f565b6064939193356001600160401b03811161020157610e0490369060040161044f565b949093610e0f611a4a565b610e1b610b1b826122f2565b6110535760ff8416801561052c5760cc5460ff16600160ff610e3d838961187c565b16116110375760ff16811161100f575b6001600160a01b0382165f90815260cb60205260409020610e7790545f5260ca60205260405f2090565b5460ff811691821515908382611004575b5050610fc8575050907feb4bce5025c5200f6a074dd28fe7754955dfdca0eb2dcbaa16ccc292655e666991610f8d610ecb8660ff165f5260c960205260405f2090565b94610ef5610ee3610ede885461ffff1690565b611895565b875461ffff191661ffff821617909755565b610efd610319565b60ff8816815261ffff87166020820152610f5b610f1982612091565b91610f2261032a565b9081526001600160a01b0386166020820152610f3f368589610388565b6040820152610f56835f5260ca60205260405f2090565b6118f7565b6001600160a01b0384165f90815260cb60205260409020556040516001600160a01b0390931695929384938885611a27565b0390a282610f9757005b6105097f8ff94c32efcef376eb02508cba5536e0634c1d6ad4b51ffa0f7306c78edaf5f793604051938493846112ab565b611001935060081c61ffff1660016218326360e21b03195f5260ff90911660045261ffff166024526001600160a01b0316604452606490565b5ffd5b141590505f80610e88565b6110238560ff1660ff1960cc54161760cc55565b86610e4d576388bc3fe760e01b5f5260045ffd5b6353db7b7b60e01b5f5260ff908116600452851660245260445ffd5b639d145ceb60e01b5f5260045ffd5b909161106c611aec565b5f5b81811061107b5750505050565b61108e611089828487611158565b61117a565b8051611099816111ba565b6110a2816111ba565b6110cf576020810151600192916110c9916040906001600160a01b03169101519086611d45565b0161106e565b600181516110dc816111ba565b6110e5816111ba565b036111125760208101516001929161110d916040906001600160a01b03169101519086611b3d565b6110c9565b6002905161111f816111ba565b611128816111ba565b14611135576001906110c9565b63d4d3bef760e01b5f5260045ffd5b634e487b7160e01b5f52603260045260245ffd5b9190811015611168576060020190565b611144565b3590600382101561020157565b606081360312610201576040805191611192836102bd565b61119b8161116d565b835260208101356111ab8161022c565b60208401520135604082015290565b600311156111c457565b634e487b7160e01b5f52602160045260245ffd5b9291906112076111fa6111ec848488611eb3565b5f52609760205260405f2090565b546001600160a01b031690565b6001600160a01b0381166002811461128057611276575061122e6111fa6111ec8487611e0f565b6001600160a01b038116600281146112805761127657506112556111fa6111ec8484611e64565b936001600160a01b03851661126d5750505050505f90565b6103d994611f2b565b936103d994611f2b565b505050505050600190565b908060209392818452848401375f828201840152601f01601f1916010190565b60409060ff6103d99593168152816020820152019161128b565b156112cc57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1561132d57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b1561138e57565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b604051906113f7826102bd565b60606040838151611407816102dd565b5f81525f602082015281525f60208201520152565b90600182811c9216801561144a575b602083101461143657565b634e487b7160e01b5f52602260045260245ffd5b91607f169161142b565b61145c6113ea565b50805f5260ca60205260405f2080549160ff831690811561155e57509060029161ffff6040519461148c866102bd565b60405192611499846102dd565b835260081c166020820152835260018060a01b0360018201541660208401520160405190815f8254926114cb8461141c565b808452936001811690811561153c57506001146114f8575b506114f0925003826102f8565b604082015290565b90505f9291925260205f20905f915b8183106115205750509060206114f0928201015f6114e3565b6020919350806001915483858801015201910190918392611507565b9050602092506114f094915060ff191682840152151560051b8201015f6114e3565b638d0aeeb160e01b5f5260045260245ffd5b60ff5f5460081c161561166057306001600160a01b0314611651576001600160a01b038181169190821461165157610328916115ba5f5160206126905f395f51905f528330611eb3565b5f8181526097602052604090206001600160a01b03906115d9906111fa565b16156115f2575b50506115ec8130611bcc565b30611c8c565b61160761161a915f52609760205260405f2090565b80546001600160a01b0319166002179055565b604080513081526002602082015233915f5160206126905f395f51905f52915f5160206126b05f395f51905f529190a45f806115e0565b6324159e5b60e01b5f5260045ffd5b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b906116c2611aec565b5f5b8181106116d057505050565b6116e36116de8284866117df565b6117ef565b9081516116ef816111ba565b6116f8816111ba565b61173d5760608201516001600160a01b03166111355760208201516040830151608090930151600193611737926001600160a01b039182169116611d45565b016116c4565b81600180935161174c816111ba565b611755816111ba565b0361178757602081015160408201516080909201516117829290916001600160a01b039182169116611b3d565b611737565b60028151611794816111ba565b61179d816111ba565b146117a9575b50611737565b6020810151604082015160808301516060909301516117d9936001600160a01b03918216939092821691166120d3565b5f6117a3565b91908110156111685760a0020190565b60a081360312610201576040519060a08201908282106001600160401b038311176102d8576080916040526118238161116d565b835260208101356118338161022c565b602084015260408101356118468161022c565b604084015260608101356118598161022c565b60608401520135608082015290565b634e487b7160e01b5f52601160045260245ffd5b9060ff8091169116039060ff821161189057565b611868565b61ffff1661ffff81146118905760010190565b601f82116118b557505050565b5f5260205f20906020601f840160051c830193106118ed575b601f0160051c01905b8181106118e2575050565b5f81556001016118d7565b90915081906118ce565b60026040919392936020855161191b60ff825116849060ff1660ff19825416179055565b0151815462ffff00191660089190911b62ffff001617815560208501516001820180546001600160a01b0319166001600160a01b0392909216919091179055019201519182516001600160401b0381116102d8576119838161197d845461141c565b846118a8565b6020601f82116001146119c25781906119b39394955f926119b7575b50508160011b915f199060031b1c19161790565b9055565b015190505f8061199f565b601f198216906119d5845f5260205f2090565b915f5b818110611a0f575095836001959697106119f7575b505050811b019055565b01515f1960f88460031b161c191690555f80806119ed565b9192602060018192868b0151815501940192016119d8565b61ffff6103d9959360ff606094168352166020820152816040820152019161128b565b611a6c611a573636610354565b5f5160206126705f395f51905f5233306111d8565b15611a7357565b631e09743f60e01b5f5230600452336024525f5160206126705f395f51905f5260445260645ffd5b611abd611aa83636610354565b5f5160206126d05f395f51905f5233306111d8565b15611ac457565b631e09743f60e01b5f5230600452336024525f5160206126d05f395f51905f5260445260645ffd5b611b0e611af93636610354565b5f5160206126905f395f51905f5233306111d8565b15611b1557565b631e09743f60e01b5f5230600452336024525f5160206126905f395f51905f5260445260645ffd5b90611b49838284611eb3565b5f818152609760205260409020546001600160a01b0316611b6b575b50505050565b5f52609760205260405f206001600160601b0360a01b81541690556040519160018060a01b0316825260018060a01b0316917f3ca48185ec3f6e47e24db18b13f1c65b1ce05da1659f9c1c4fe717dda5f6752460203393a45f808080611b65565b6001600160a01b0381811614611651576001600160a01b0382811692611c09915f5160206126705f395f51905f5291908514611c87575b83611eb3565b611c1b815f52609760205260405f2090565b546001600160a01b031615611c2f57505050565b611607611c44915f52609760205260405f2090565b604080516001600160a01b0390921682526002602083015233915f5160206126705f395f51905f52915f5160206126b05f395f51905f529190819081015b0390a4565b611c03565b6001600160a01b0381811614611651576001600160a01b0382811692611cc8915f5160206126d05f395f51905f5291908514611c875783611eb3565b611cda815f52609760205260405f2090565b546001600160a01b031615611cee57505050565b611607611d03915f52609760205260405f2090565b604080516001600160a01b0390921682526002602083015233915f5160206126d05f395f51905f52915f5160206126b05f395f51905f52919081908101611c82565b90916001600160a01b0380831614611651576001600160a01b03838116939082908514611de8575b611d779184611eb3565b611d89815f52609760205260405f2090565b546001600160a01b031615611d9e5750505050565b611607611db3915f52609760205260405f2090565b604080516001600160a01b039390931683526002602084015233925f5160206126b05f395f51905f529190a45f808080611b65565b5f5160206126905f395f51905f52148015611e08575b6116515781611d6d565b505f611dfe565b90604051906020820192692822a926a4a9a9a4a7a760b11b84526001600160601b0319602a8401526001600160601b03199060601b16603e830152605282015260528152611e5e6072826102f8565b51902090565b90604051906020820192692822a926a4a9a9a4a7a760b11b84526001600160601b03199060601b16602a8301526001600160601b0319603e830152605282015260528152611e5e6072826102f8565b9091604051916020830193692822a926a4a9a9a4a7a760b11b85526001600160601b03199060601b16602a8401526001600160601b03199060601b16603e830152605282015260528152611e5e6072826102f8565b90816020910312610201575180151581036102015790565b6040513d5f823e3d90fd5b6040516302675fdd60e41b81526001600160a01b03928316600482015292909116602483015260448201929092526080606482015291602091839182908190611f789060848301906108a5565b03916001600160a01b03165afa5f9181611fa4575b50611f9757505f90565b611f9f575f90565b600190565b611fc791925060203d602011611fce575b611fbf81836102f8565b810190611f08565b905f611f8d565b503d611fb5565b90816020910312610201575190565b15611feb57565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b805160209182015160405160f89290921b6001600160f81b03191692820192835260f01b6001600160f01b031916602182015260038152611e5e6023826102f8565b6001600160a01b0384169390929190843b156122d7576040516301ffc9a760e01b81526302675fdd60e41b6004820152602081602481895afa9081156122d2575f916122b3575b501561229857506001600160a01b03838116148080612286575b612277578015612265575b612233575b61214f828285611eb3565b6121646111fa825f52609760205260405f2090565b6001600160a01b038116806121e35750505f5160206126b05f395f51905f52916121bc8661219d611c82945f52609760205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b604080516001600160a01b0396871681529686166020880152941694339490918291820190565b8694925095909295036121f7575050505050565b6040516305cc3c4f60e11b81526001600160a01b039485166004820152948416602486015260448501528216606484015216608482015260a490fd5b5f5160206126905f395f51905f528214801561225e575b15612144576324159e5b60e01b5f5260045ffd5b505f61224a565b506001600160a01b038181161461213f565b6385f1ba9960e01b5f5260045ffd5b506001600160a01b0382811614612134565b636dd8243160e11b5f526001600160a01b031660045260245ffd5b6122cc915060203d602011611fce57611fbf81836102f8565b5f61211a565b611f20565b63241acd7b60e11b5f526001600160a01b031660045260245ffd5b60205f604051828101906301ffc9a760e01b82526301ffc9a760e01b6024820152602481526123226044826102f8565b519084617530fa903d5f5190836123cf575b50826123c5575b508161235e575b8161234b575090565b6103d9915063099718b560e41b90612557565b905060205f604051828101906301ffc9a760e01b825263ffffffff60e01b6024820152602481526123906044826102f8565b519084617530fa5f513d826123b9575b50816123af575b501590612342565b905015155f6123a7565b6020111591505f6123a0565b151591505f61233b565b6020111592505f612334565b916123e5836124c0565b6001600160a01b0383167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2815115908115916124b8575b50612428575050565b6124ad915f806040519361243d6060866102f8565b602785527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020860152660819985a5b195960ca1b6040860152602081519101845af43d156124b0573d9161249183610339565b9261249f60405194856102f8565b83523d5f602085013e6125b6565b50565b6060916125b6565b90505f61241f565b803b156124fc5760018060a01b03166001600160601b0360a01b5f5160206126505f395f51905f525416175f5160206126505f395f51905f5255565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b5f90602092604051848101916301ffc9a760e01b835263ffffffff60e01b1660248201526024815261258a6044826102f8565b5191617530fa5f513d826125aa575b50816125a3575090565b9050151590565b6020111591505f612599565b9192901561261857508151156125ca575090565b3b156125d35790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501561262b5750805190602001fd5b60405162461bcd60e51b8152602060048201529081906106bd9060248301906108a556fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca0885006fe6672eeafd1deca6c67bcdc6dd79cfe2b157a98539ddf73cd8c04ea815fe80e4b37c8582a3b773d1d7071f983eacfd56b5965db654f3087c25ada330f579ad49235a8c1fd9041427e7067b1eb10926bbed380bf6fabc73e0e8076445aa4f06bdc18535eff05128093a2315c2c960a2722e20021cbff28da04760f5ba2646970667358221220e7349eb5dc5a1ce577990974f819d5fa228b489f861d2165035bae6e266b19bd64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.