Source Code
Latest 25 from a total of 45 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add | 59427212 | 483 days ago | IN | 0 POL | 0.00493983 | ||||
| Add | 57029915 | 544 days ago | IN | 0 POL | 0.00648618 | ||||
| Add | 57026287 | 544 days ago | IN | 0 POL | 0.00331961 | ||||
| Add | 52152228 | 671 days ago | IN | 0 POL | 0.00461813 | ||||
| Multicall | 50743350 | 707 days ago | IN | 0 POL | 0.04606166 | ||||
| Add | 49941906 | 727 days ago | IN | 0 POL | 0.00968193 | ||||
| Remove | 49941537 | 727 days ago | IN | 0 POL | 0.00338928 | ||||
| Add | 49941365 | 727 days ago | IN | 0 POL | 0.00795026 | ||||
| Add | 48085138 | 775 days ago | IN | 0 POL | 0.01079608 | ||||
| Add | 48048542 | 776 days ago | IN | 0 POL | 0.00895222 | ||||
| Add | 48048087 | 776 days ago | IN | 0 POL | 0.01067272 | ||||
| Add | 47729957 | 784 days ago | IN | 0 POL | 0.01496155 | ||||
| Add | 47729911 | 784 days ago | IN | 0 POL | 0.01438402 | ||||
| Add | 47729863 | 784 days ago | IN | 0 POL | 0.01524398 | ||||
| Add | 47729765 | 784 days ago | IN | 0 POL | 0.01897744 | ||||
| Add | 47576833 | 788 days ago | IN | 0 POL | 0.025344 | ||||
| Add | 47576794 | 788 days ago | IN | 0 POL | 0.02319196 | ||||
| Add | 47576748 | 788 days ago | IN | 0 POL | 0.02345152 | ||||
| Add | 47576704 | 788 days ago | IN | 0 POL | 0.02627592 | ||||
| Multicall | 46681911 | 810 days ago | IN | 0 POL | 0.01653017 | ||||
| Multicall | 45769451 | 833 days ago | IN | 0 POL | 0.0206458 | ||||
| Multicall | 45737512 | 834 days ago | IN | 0 POL | 0.01739863 | ||||
| Multicall | 45734312 | 834 days ago | IN | 0 POL | 0.01443651 | ||||
| Remove | 45223757 | 847 days ago | IN | 0 POL | 0.00455654 | ||||
| Multicall | 45219484 | 847 days ago | IN | 0 POL | 0.02775737 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
TWMultichainRegistryRouter
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 300 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
// ========== Internal imports ==========
import "../extension/PermissionsEnumerableLogic.sol";
import "../extension/ERC2771ContextLogic.sol";
import "../../extension/Multicall.sol";
import "../../extension/plugin/Router.sol";
/**
*
* "Inherited by entrypoint" extensions.
* - PermissionsEnumerable
* - ERC2771Context
* - Multicall
*
* "NOT inherited by entrypoint" extensions.
* - TWMultichainRegistry
*/
contract TWMultichainRegistryRouter is PermissionsEnumerableLogic, ERC2771ContextLogic, Router {
/*///////////////////////////////////////////////////////////////
Constructor + initializer logic
//////////////////////////////////////////////////////////////*/
constructor(address _pluginMap, address[] memory _trustedForwarders)
ERC2771ContextLogic(_trustedForwarders)
Router(_pluginMap)
{
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/*///////////////////////////////////////////////////////////////
Overridable Permissions
//////////////////////////////////////////////////////////////*/
/// @dev Returns whether plug-in can be set in the given execution context.
function _canSetPlugin() internal view override returns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
function _msgSender() internal view override(ERC2771ContextLogic, PermissionsLogic) returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return msg.sender;
}
}
function _msgData() internal view override(ERC2771ContextLogic, PermissionsLogic) returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return msg.data;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./interface/IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-165).
*
* 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
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* 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) (utils/Multicall.sol)
pragma solidity ^0.8.0;
import "../lib/TWAddress.sol";
import "./interface/IMulticall.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
contract Multicall is IMulticall {
/**
* @notice Receives and executes a batch of function calls on this contract.
* @dev Receives and executes a batch of function calls on this contract.
*
* @param data The bytes data that makes up the batch of function calls to execute.
* @return results The bytes data that makes up the result of the batch of function calls executed.
*/
function multicall(bytes[] calldata data) external virtual override returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = TWAddress.functionDelegateCall(address(this), data[i]);
}
return results;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
interface IMulticall {
/**
* @dev Receives and executes a batch of function calls on this contract.
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IPermissions {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./IPermissions.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IPermissionsEnumerable is IPermissions {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296)
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
interface IPluginMap {
/**
* @notice An interface to describe a plug-in.
*
* @param functionSelector 4-byte function selector.
* @param functionSignature Function representation as a string. E.g. "transfer(address,address,uint256)"
* @param pluginAddress Address of the contract containing the function.
*/
struct Plugin {
bytes4 functionSelector;
string functionSignature;
address pluginAddress;
}
/// @dev Emitted when a function selector is mapped to a particular plug-in smart contract, during construction of Map.
event PluginSet(bytes4 indexed functionSelector, string indexed functionSignature, address indexed pluginAddress);
/// @dev Returns the plug-in contract for a given function.
function getPluginForFunction(bytes4 functionSelector) external view returns (address);
/// @dev Returns all functions that are mapped to the given plug-in contract.
function getAllFunctionsOfPlugin(address pluginAddress) external view returns (bytes4[] memory);
/// @dev Returns all plug-ins known by Map.
function getAllPlugins() external view returns (Plugin[] memory);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
import "./IPluginMap.sol";
interface IRouter is IPluginMap {
/// @dev Emitted when a functionality is added, or plugged-in.
event PluginAdded(bytes4 indexed functionSelector, address indexed pluginAddress);
/// @dev Emitted when a functionality is updated or overridden.
event PluginUpdated(
bytes4 indexed functionSelector,
address indexed oldPluginAddress,
address indexed newPluginAddress
);
/// @dev Emitted when a functionality is removed.
event PluginRemoved(bytes4 indexed functionSelector, address indexed pluginAddress);
/// @dev Add a new plugin to the contract.
function addPlugin(Plugin memory plugin) external;
/// @dev Update / override an existing plugin.
function updatePlugin(Plugin memory plugin) external;
/// @dev Remove an existing plugin from the contract.
function removePlugin(bytes4 functionSelector) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "../interface/plugin/IRouter.sol";
import "../../extension/Multicall.sol";
import "../../eip/ERC165.sol";
import "../../openzeppelin-presets/utils/EnumerableSet.sol";
library RouterStorage {
bytes32 public constant ROUTER_STORAGE_POSITION = keccak256("router.storage");
struct Data {
EnumerableSet.Bytes32Set allSelectors;
mapping(address => EnumerableSet.Bytes32Set) selectorsForPlugin;
mapping(bytes4 => IPluginMap.Plugin) pluginForSelector;
}
function routerStorage() internal pure returns (Data storage routerData) {
bytes32 position = ROUTER_STORAGE_POSITION;
assembly {
routerData.slot := position
}
}
}
abstract contract Router is Multicall, ERC165, IRouter {
using EnumerableSet for EnumerableSet.Bytes32Set;
/*///////////////////////////////////////////////////////////////
State variables
//////////////////////////////////////////////////////////////*/
address public immutable pluginMap;
/*///////////////////////////////////////////////////////////////
Constructor + initializer logic
//////////////////////////////////////////////////////////////*/
constructor(address _pluginMap) {
pluginMap = _pluginMap;
}
/*///////////////////////////////////////////////////////////////
ERC 165
//////////////////////////////////////////////////////////////*/
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IRouter).interfaceId || super.supportsInterface(interfaceId);
}
/*///////////////////////////////////////////////////////////////
Generic contract logic
//////////////////////////////////////////////////////////////*/
fallback() external payable virtual {
address _pluginAddress = _getPluginForFunction(msg.sig);
if (_pluginAddress == address(0)) {
_pluginAddress = IPluginMap(pluginMap).getPluginForFunction(msg.sig);
}
_delegate(_pluginAddress);
}
receive() external payable {}
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @dev Add functionality to the contract.
function addPlugin(Plugin memory _plugin) external {
require(_canSetPlugin(), "Router: Not authorized");
_addPlugin(_plugin);
}
/// @dev Update or override existing functionality.
function updatePlugin(Plugin memory _plugin) external {
require(_canSetPlugin(), "Map: Not authorized");
_updatePlugin(_plugin);
}
/// @dev Remove existing functionality from the contract.
function removePlugin(bytes4 _selector) external {
require(_canSetPlugin(), "Map: Not authorized");
_removePlugin(_selector);
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @dev View address of the plugged-in functionality contract for a given function signature.
function getPluginForFunction(bytes4 _selector) public view returns (address) {
address pluginAddress = _getPluginForFunction(_selector);
return pluginAddress != address(0) ? pluginAddress : IPluginMap(pluginMap).getPluginForFunction(_selector);
}
/// @dev View all funtionality as list of function signatures.
function getAllFunctionsOfPlugin(address _pluginAddress) external view returns (bytes4[] memory registered) {
RouterStorage.Data storage data = RouterStorage.routerStorage();
EnumerableSet.Bytes32Set storage selectorsForPlugin = data.selectorsForPlugin[_pluginAddress];
bytes4[] memory defaultSelectors = IPluginMap(pluginMap).getAllFunctionsOfPlugin(_pluginAddress);
uint256 len = defaultSelectors.length;
uint256 count = selectorsForPlugin.length() + defaultSelectors.length;
for (uint256 i = 0; i < len; i += 1) {
if (selectorsForPlugin.contains(defaultSelectors[i])) {
count -= 1;
defaultSelectors[i] = bytes4(0);
}
}
registered = new bytes4[](count);
uint256 index;
for (uint256 i = 0; i < len; i += 1) {
if (defaultSelectors[i] != bytes4(0)) {
registered[index++] = defaultSelectors[i];
}
}
len = selectorsForPlugin.length();
for (uint256 i = 0; i < len; i += 1) {
registered[index++] = bytes4(data.selectorsForPlugin[_pluginAddress].at(i));
}
}
/// @dev View all funtionality existing on the contract.
function getAllPlugins() external view returns (Plugin[] memory registered) {
RouterStorage.Data storage data = RouterStorage.routerStorage();
EnumerableSet.Bytes32Set storage overrideSelectors = data.allSelectors;
Plugin[] memory defaultPlugins = IPluginMap(pluginMap).getAllPlugins();
uint256 overrideSelectorsLen = overrideSelectors.length();
uint256 defaultPluginsLen = defaultPlugins.length;
uint256 totalCount = overrideSelectorsLen + defaultPluginsLen;
for (uint256 i = 0; i < overrideSelectorsLen; i += 1) {
for (uint256 j = 0; j < defaultPluginsLen; j += 1) {
if (bytes4(overrideSelectors.at(i)) == defaultPlugins[j].functionSelector) {
totalCount -= 1;
defaultPlugins[j].functionSelector = bytes4(0);
}
}
}
registered = new Plugin[](totalCount);
uint256 index;
for (uint256 i = 0; i < defaultPluginsLen; i += 1) {
if (defaultPlugins[i].functionSelector != bytes4(0)) {
registered[index] = defaultPlugins[i];
index += 1;
}
}
for (uint256 i = 0; i < overrideSelectorsLen; i += 1) {
registered[index] = data.pluginForSelector[bytes4(overrideSelectors.at(i))];
index += 1;
}
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev View address of the plugged-in functionality contract for a given function signature.
function _getPluginForFunction(bytes4 _selector) public view returns (address) {
RouterStorage.Data storage data = RouterStorage.routerStorage();
address _pluginAddress = data.pluginForSelector[_selector].pluginAddress;
return _pluginAddress;
}
/// @dev Add functionality to the contract.
function _addPlugin(Plugin memory _plugin) internal {
RouterStorage.Data storage data = RouterStorage.routerStorage();
// Revert: default plugin exists for function; use updatePlugin instead.
try IPluginMap(pluginMap).getPluginForFunction(_plugin.functionSelector) returns (address) {
revert("Router: default plugin exists for function.");
} catch {
require(data.allSelectors.add(bytes32(_plugin.functionSelector)), "Router: plugin exists for function.");
}
require(
_plugin.functionSelector == bytes4(keccak256(abi.encodePacked(_plugin.functionSignature))),
"Router: fn selector and signature mismatch."
);
data.pluginForSelector[_plugin.functionSelector] = _plugin;
data.selectorsForPlugin[_plugin.pluginAddress].add(bytes32(_plugin.functionSelector));
emit PluginAdded(_plugin.functionSelector, _plugin.pluginAddress);
}
/// @dev Update or override existing functionality.
function _updatePlugin(Plugin memory _plugin) internal {
address currentPlugin = getPluginForFunction(_plugin.functionSelector);
require(
_plugin.functionSelector == bytes4(keccak256(abi.encodePacked(_plugin.functionSignature))),
"Router: fn selector and signature mismatch."
);
RouterStorage.Data storage data = RouterStorage.routerStorage();
data.allSelectors.add(bytes32(_plugin.functionSelector));
data.pluginForSelector[_plugin.functionSelector] = _plugin;
data.selectorsForPlugin[currentPlugin].remove(bytes32(_plugin.functionSelector));
data.selectorsForPlugin[_plugin.pluginAddress].add(bytes32(_plugin.functionSelector));
emit PluginUpdated(_plugin.functionSelector, currentPlugin, _plugin.pluginAddress);
}
/// @dev Remove existing functionality from the contract.
function _removePlugin(bytes4 _selector) internal {
RouterStorage.Data storage data = RouterStorage.routerStorage();
address currentPlugin = _getPluginForFunction(_selector);
require(currentPlugin != address(0), "Router: No plugin available for selector");
delete data.pluginForSelector[_selector];
data.allSelectors.remove(_selector);
data.selectorsForPlugin[currentPlugin].remove(bytes32(_selector));
emit PluginRemoved(_selector, currentPlugin);
}
function _canSetPlugin() internal view virtual returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library TWAddress {
/**
* @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
* ====
*
* [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.
*
* [EIP1884](https://eips.ethereum.org/EIPS/eip-1884) 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library TWStrings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./ERC2771ContextStorage.sol";
/**
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771ContextLogic {
constructor(address[] memory trustedForwarder) {
ERC2771ContextStorage.Data storage data = ERC2771ContextStorage.erc2771ContextStorage();
for (uint256 i = 0; i < trustedForwarder.length; i++) {
data._trustedForwarder[trustedForwarder[i]] = true;
}
}
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
ERC2771ContextStorage.Data storage data = ERC2771ContextStorage.erc2771ContextStorage();
return data._trustedForwarder[forwarder];
}
function _msgSender() internal view virtual returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return msg.sender;
}
}
function _msgData() internal view virtual returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return msg.data;
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
library ERC2771ContextStorage {
bytes32 public constant ERC2771_CONTEXT_STORAGE_POSITION = keccak256("erc2771.context.storage");
struct Data {
mapping(address => bool) _trustedForwarder;
}
function erc2771ContextStorage() internal pure returns (Data storage erc2771ContextData) {
bytes32 position = ERC2771_CONTEXT_STORAGE_POSITION;
assembly {
erc2771ContextData.slot := position
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./PermissionsEnumerableStorage.sol";
import "./PermissionsLogic.sol";
/**
* @title PermissionsEnumerable
* @dev This contracts provides extending-contracts with role-based access control mechanisms.
* Also provides interfaces to view all members with a given role, and total count of members.
*/
contract PermissionsEnumerableLogic is IPermissionsEnumerable, PermissionsLogic {
/**
* @notice Returns the role-member from a list of members for a role,
* at a given index.
* @dev Returns `member` who has `role`, at `index` of role-members list.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param index Index in list of current members for the role.
*
* @return member Address of account that has `role`
*/
function getRoleMember(bytes32 role, uint256 index) external view override returns (address member) {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 currentIndex = data.roleMembers[role].index;
uint256 check;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (data.roleMembers[role].members[i] != address(0)) {
if (check == index) {
member = data.roleMembers[role].members[i];
return member;
}
check += 1;
} else if (hasRole(role, address(0)) && i == data.roleMembers[role].indexOf[address(0)]) {
check += 1;
}
}
}
/**
* @notice Returns total number of accounts that have a role.
* @dev Returns `count` of accounts that have `role`.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*
* @return count Total number of accounts that have `role`
*/
function getRoleMemberCount(bytes32 role) external view override returns (uint256 count) {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 currentIndex = data.roleMembers[role].index;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (data.roleMembers[role].members[i] != address(0)) {
count += 1;
}
}
if (hasRole(role, address(0))) {
count += 1;
}
}
/// @dev Revokes `role` from `account`, and removes `account` from {roleMembers}
/// See {_removeMember}
function _revokeRole(bytes32 role, address account) internal override {
super._revokeRole(role, account);
_removeMember(role, account);
}
/// @dev Grants `role` to `account`, and adds `account` to {roleMembers}
/// See {_addMember}
function _setupRole(bytes32 role, address account) internal override {
super._setupRole(role, account);
_addMember(role, account);
}
/// @dev adds `account` to {roleMembers}, for `role`
function _addMember(bytes32 role, address account) internal {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 idx = data.roleMembers[role].index;
data.roleMembers[role].index += 1;
data.roleMembers[role].members[idx] = account;
data.roleMembers[role].indexOf[account] = idx;
}
/// @dev removes `account` from {roleMembers}, for `role`
function _removeMember(bytes32 role, address account) internal {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 idx = data.roleMembers[role].indexOf[account];
delete data.roleMembers[role].members[idx];
delete data.roleMembers[role].indexOf[account];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "../../extension/interface/IPermissionsEnumerable.sol";
library PermissionsEnumerableStorage {
bytes32 public constant PERMISSIONS_ENUMERABLE_STORAGE_POSITION = keccak256("permissions.enumerable.storage");
/**
* @notice A data structure to store data of members for a given role.
*
* @param index Current index in the list of accounts that have a role.
* @param members map from index => address of account that has a role
* @param indexOf map from address => index which the account has.
*/
struct RoleMembers {
uint256 index;
mapping(uint256 => address) members;
mapping(address => uint256) indexOf;
}
struct Data {
/// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}.
mapping(bytes32 => RoleMembers) roleMembers;
}
function permissionsEnumerableStorage() internal pure returns (Data storage permissionsEnumerableData) {
bytes32 position = PERMISSIONS_ENUMERABLE_STORAGE_POSITION;
assembly {
permissionsEnumerableData.slot := position
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "../../extension/interface/IPermissions.sol";
import "./PermissionsStorage.sol";
import "../../lib/TWStrings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/
contract PermissionsLogic is IPermissions {
/// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @dev Modifier that checks if an account has the specified role; reverts otherwise.
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @notice Checks whether an account has a particular role.
* @dev Returns `true` if `account` has been granted `role`.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
return data._hasRole[role][account];
}
/**
* @notice Checks whether an account has a particular role;
* role restrictions can be swtiched on and off.
*
* @dev Returns `true` if `account` has been granted `role`.
* Role restrictions can be swtiched on and off:
* - If address(0) has ROLE, then the ROLE restrictions
* don't apply.
* - If address(0) does not have ROLE, then the ROLE
* restrictions will apply.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
if (!data._hasRole[role][address(0)]) {
return data._hasRole[role][account];
}
return true;
}
/**
* @notice Returns the admin role that controls the specified role.
* @dev See {grantRole} and {revokeRole}.
* To change a role's admin, use {_setRoleAdmin}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
return data._getRoleAdmin[role];
}
/**
* @notice Grants a role to an account, if not previously granted.
* @dev Caller must have admin role for the `role`.
* Emits {RoleGranted Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account to which the role is being granted.
*/
function grantRole(bytes32 role, address account) public virtual override {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
_checkRole(data._getRoleAdmin[role], _msgSender());
if (data._hasRole[role][account]) {
revert("Can only grant to non holders");
}
_setupRole(role, account);
}
/**
* @notice Revokes role from an account.
* @dev Caller must have admin role for the `role`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function revokeRole(bytes32 role, address account) public virtual override {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
_checkRole(data._getRoleAdmin[role], _msgSender());
_revokeRole(role, account);
}
/**
* @notice Revokes role from the account.
* @dev Caller must have the `role`, with caller being the same as `account`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function renounceRole(bytes32 role, address account) public virtual override {
if (_msgSender() != account) {
revert("Can only renounce for self");
}
_revokeRole(role, account);
}
/// @dev Sets `adminRole` as `role`'s admin role.
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
bytes32 previousAdminRole = data._getRoleAdmin[role];
data._getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
data._hasRole[role][account] = true;
emit RoleGranted(role, account, _msgSender());
}
/// @dev Revokes `role` from `account`
function _revokeRole(bytes32 role, address account) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
_checkRole(role, account);
delete data._hasRole[role][account];
emit RoleRevoked(role, account, _msgSender());
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRole(bytes32 role, address account) internal view virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
if (!data._hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
function _msgSender() internal view virtual returns (address sender) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
library PermissionsStorage {
bytes32 public constant PERMISSIONS_STORAGE_POSITION = keccak256("permissions.storage");
struct Data {
/// @dev Map from keccak256 hash of a role => a map from address => whether address has role.
mapping(bytes32 => mapping(address => bool)) _hasRole;
/// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.
mapping(bytes32 => bytes32) _getRoleAdmin;
}
function permissionsStorage() internal pure returns (Data storage permissionsData) {
bytes32 position = PERMISSIONS_STORAGE_POSITION;
assembly {
permissionsData.slot := position
}
}
}{
"optimizer": {
"enabled": true,
"runs": 300
},
"evmVersion": "london",
"remappings": [
":@chainlink/contracts/src/=node_modules/@chainlink/contracts/src/",
":@ds-test/=lib/ds-test/src/",
":@openzeppelin/=node_modules/@openzeppelin/",
":@std/=lib/forge-std/src/",
":contracts/=contracts/",
":ds-test/=lib/ds-test/src/",
":erc721a-upgradeable/=node_modules/erc721a-upgradeable/",
":erc721a/=node_modules/erc721a/",
":forge-std/=lib/forge-std/src/"
],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_pluginMap","type":"address"},{"internalType":"address[]","name":"_trustedForwarders","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"address","name":"pluginAddress","type":"address"}],"name":"PluginAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"address","name":"pluginAddress","type":"address"}],"name":"PluginRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"string","name":"functionSignature","type":"string"},{"indexed":true,"internalType":"address","name":"pluginAddress","type":"address"}],"name":"PluginSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"address","name":"oldPluginAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newPluginAddress","type":"address"}],"name":"PluginUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"_getPluginForFunction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"},{"internalType":"address","name":"pluginAddress","type":"address"}],"internalType":"struct IPluginMap.Plugin","name":"_plugin","type":"tuple"}],"name":"addPlugin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pluginAddress","type":"address"}],"name":"getAllFunctionsOfPlugin","outputs":[{"internalType":"bytes4[]","name":"registered","type":"bytes4[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllPlugins","outputs":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"},{"internalType":"address","name":"pluginAddress","type":"address"}],"internalType":"struct IPluginMap.Plugin[]","name":"registered","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"getPluginForFunction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"member","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRoleWithSwitch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pluginMap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"removePlugin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"},{"internalType":"address","name":"pluginAddress","type":"address"}],"internalType":"struct IPluginMap.Plugin","name":"_plugin","type":"tuple"}],"name":"updatePlugin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a06040523480156200001157600080fd5b5060405162002f9c38038062002f9c83398101604081905262000034916200032c565b818160006200004d620000ed60201b620013031760201c565b905060005b8251811015620000c057600182600001600085848151811062000079576200007962000415565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620000b78162000441565b91505062000052565b5050506001600160a01b0316608052620000e56000620000df62000111565b62000136565b50506200047a565b7fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c90565b60006200011e336200015d565b1562000131575060131936013560601c90565b503390565b6200014d82826200019860201b620013271760201c565b6200015982826200022b565b5050565b60008062000175620000ed60201b620013031760201c565b6001600160a01b0390931660009081526020939093525050604090205460ff1690565b6000620001af620002b160201b620013b21760201c565b6000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790559050620001e662000111565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4505050565b600062000242620002d560201b620013c41760201c565b600084815260208290526040812080549293506001916200026483856200045f565b909155505060009384526020918252604080852082865260018101845281862080546001600160a01b039096166001600160a01b0319909616861790559385526002909301909152912055565b7fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed590565b7f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c90565b80516001600160a01b03811681146200031157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200034057600080fd5b6200034b83620002f9565b602084810151919350906001600160401b03808211156200036b57600080fd5b818601915086601f8301126200038057600080fd5b81518181111562000395576200039562000316565b8060051b604051601f19603f83011681018181108582111715620003bd57620003bd62000316565b604052918252848201925083810185019189831115620003dc57600080fd5b938501935b828510156200040557620003f585620002f9565b84529385019392850192620003e1565b8096505050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156200045857620004586200042b565b5060010190565b600082198211156200047557620004756200042b565b500190565b608051612ae3620004b960003960008181610172015281816104b80152818161082201528181610ad80152818161104f015261141f0152612ae36000f3fe6080604052600436106101235760003560e01c806391d14854116100a0578063ac9650d811610064578063ac9650d814610479578063b48912da146104a6578063c511f8fb146104da578063ca15c873146104fa578063d547741f1461051a5761012a565b806391d14854146103e4578063a217fddf14610404578063a32fa5b314610419578063a520a38a14610439578063a5342fdf146104595761012a565b80634cb5d8fd116100e75780634cb5d8fd146102e5578063572b6c05146103055780635c573f2e1461035d5780636b86400e1461038a5780639010d07c146103ac5761012a565b806301ffc9a7146101f45780631ab6b70514610229578063248a9ca31461024b5780632f2ff15d146102a557806336568abe146102c55761012a565b3661012a57005b60006101416000356001600160e01b03191661053a565b90506001600160a01b0381166101e85760405163529051c560e11b81526000356001600160e01b03191660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a520a38a90602401602060405180830381865afa1580156101c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e5919061218a565b90505b6101f181610581565b50005b34801561020057600080fd5b5061021461020f3660046121bd565b6105aa565b60405190151581526020015b60405180910390f35b34801561023557600080fd5b5061024961024436600461227d565b6105e1565b005b34801561025757600080fd5b5061029761026636600461234e565b60009081527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed6602052604090205490565b604051908152602001610220565b3480156102b157600080fd5b506102496102c0366004612367565b610646565b3480156102d157600080fd5b506102496102e0366004612367565b610710565b3480156102f157600080fd5b5061024961030036600461227d565b610786565b34801561031157600080fd5b50610214610320366004612397565b6001600160a01b031660009081527fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c602052604090205460ff1690565b34801561036957600080fd5b5061037d610378366004612397565b6107d9565b60405161022091906123b4565b34801561039657600080fd5b5061039f610ab7565b604051610220919061245e565b3480156103b857600080fd5b506103cc6103c73660046124f4565b610e7e565b6040516001600160a01b039091168152602001610220565b3480156103f057600080fd5b506102146103ff366004612367565b610f7a565b34801561041057600080fd5b50610297600081565b34801561042557600080fd5b50610214610434366004612367565b610fb2565b34801561044557600080fd5b506103cc6104543660046121bd565b611014565b34801561046557600080fd5b506102496104743660046121bd565b6110d0565b34801561048557600080fd5b50610499610494366004612516565b611123565b604051610220919061258b565b3480156104b257600080fd5b506103cc7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e657600080fd5b506103cc6104f53660046121bd565b61053a565b34801561050657600080fd5b5061029761051536600461234e565b611218565b34801561052657600080fd5b50610249610535366004612367565b6112af565b6001600160e01b03191660009081527f1a3e4131826bb378aa43abb34a33a366bc4a35b55ab18a884fa205b59285ec4860205260409020600201546001600160a01b031690565b3660008037600080366000845af43d6000803e8080156105a0573d6000f35b3d6000fd5b505050565b60006001600160e01b0319821663f337402760e01b14806105db57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6105e96113d6565b61063a5760405162461bcd60e51b815260206004820152601660248201527f526f757465723a204e6f7420617574686f72697a65640000000000000000000060448201526064015b60405180910390fd5b610643816113e9565b50565b60008281527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed66020526040902054600080516020612a4783398151915290610695906106906116a5565b6116ee565b6000838152602082815260408083206001600160a01b038616845290915290205460ff16156107065760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610631565b6105a5838361177c565b806001600160a01b03166107226116a5565b6001600160a01b0316146107785760405162461bcd60e51b815260206004820152601a60248201527f43616e206f6e6c792072656e6f756e636520666f722073656c660000000000006044820152606401610631565b6107828282611790565b5050565b61078e6113d6565b6107d05760405162461bcd60e51b815260206004820152601360248201527213585c0e88139bdd08185d5d1a1bdc9a5e9959606a1b6044820152606401610631565b610643816117f4565b60606000600080516020612a278339815191526001600160a01b0384811660008181526002840160205260408082209051632e2b9f9760e11b81526004810193909352939450917f00000000000000000000000000000000000000000000000000000000000000001690635c573f2e90602401600060405180830381865afa158015610869573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108919190810190612611565b80519091506000816108a2856119b1565b6108ac91906126c1565b905060005b82811015610944576108ef8482815181106108ce576108ce6126d9565b60200260200101516001600160e01b031916866119bb90919063ffffffff16565b15610932576108ff6001836126ef565b9150600060e01b848281518110610918576109186126d9565b6001600160e01b0319909216602092830291909101909101525b61093d6001826126c1565b90506108b1565b508067ffffffffffffffff81111561095e5761095e6121da565b604051908082528060200260200182016040528015610987578160200160208202803683370190505b5095506000805b83811015610a285784516000908690839081106109ad576109ad6126d9565b60200260200101516001600160e01b03191614610a16578481815181106109d6576109d66126d9565b60200260200101518883806109ea90612706565b9450815181106109fc576109fc6126d9565b6001600160e01b0319909216602092830291909101909101525b610a216001826126c1565b905061098e565b50610a32856119b1565b925060005b83811015610aab576001600160a01b03891660009081526002880160205260409020610a6390826119d3565b8883610a6e81612706565b945081518110610a8057610a806126d9565b6001600160e01b031990921660209283029190910190910152610aa46001826126c1565b9050610a37565b50505050505050919050565b60606000600080516020612a278339815191529050600081600001905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636b86400e6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b34573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b5c9190810190612721565b90506000610b69836119b1565b82519091506000610b7a82846126c1565b905060005b83811015610c375760005b83811015610c2457858181518110610ba457610ba46126d9565b6020908102919091010151516001600160e01b031916610bc488846119d3565b6001600160e01b0319161415610c1257610bdf6001846126ef565b9250600060e01b868281518110610bf857610bf86126d9565b60209081029190910101516001600160e01b031990911690525b610c1d6001826126c1565b9050610b8a565b50610c306001826126c1565b9050610b7f565b508067ffffffffffffffff811115610c5157610c516121da565b604051908082528060200260200182016040528015610ca157816020015b60408051606080820183526000808352602083019190915291810191909152815260200190600190039081610c6f5790505b5096506000805b83811015610d39578551600090879083908110610cc757610cc76126d9565b6020026020010151600001516001600160e01b03191614610d2757858181518110610cf457610cf46126d9565b6020026020010151898381518110610d0e57610d0e6126d9565b6020908102919091010152610d246001836126c1565b91505b610d326001826126c1565b9050610ca8565b5060005b84811015610e7357600388016000610d5589846119d3565b6001600160e01b031990811682526020808301939093526040918201600020825160608101909352805460e01b90911682526001810180549293919291840191610d9e90612862565b80601f0160208091040260200160405190810160405280929190818152602001828054610dca90612862565b8015610e175780601f10610dec57610100808354040283529160200191610e17565b820191906000526020600020905b815481529060010190602001808311610dfa57829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015289518a9084908110610e4957610e496126d9565b6020908102919091010152610e5f6001836126c1565b9150610e6c6001826126c1565b9050610d3d565b505050505050505090565b6000828152600080516020612a8e8339815191526020819052604082205482805b82811015610f70576000878152602085815260408083208484526001019091529020546001600160a01b031615610f1b5785821415610f09576000878152602094855260408082209282526001909201909452909220546001600160a01b031692506105db915050565b610f146001836126c1565b9150610f5e565b610f26876000610f7a565b8015610f4b575060008781526020858152604080832083805260020190915290205481145b15610f5e57610f5b6001836126c1565b91505b610f696001826126c1565b9050610e9f565b5050505092915050565b6000918252600080516020612a47833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000828152600080516020612a478339815191526020818152604080842084805290915282205460ff1661100a576000848152602091825260408082206001600160a01b0386168352909252205460ff1690506105db565b5060019392505050565b6000806110208361053a565b90506001600160a01b0381166110c75760405163529051c560e11b81526001600160e01b0319841660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a520a38a90602401602060405180830381865afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c2919061218a565b6110c9565b805b9392505050565b6110d86113d6565b61111a5760405162461bcd60e51b815260206004820152601360248201527213585c0e88139bdd08185d5d1a1bdc9a5e9959606a1b6044820152606401610631565b610643816119df565b60608167ffffffffffffffff81111561113e5761113e6121da565b60405190808252806020026020018201604052801561117157816020015b606081526020019060019003908161115c5790505b50905060005b82811015611211576111e130858584818110611195576111956126d9565b90506020028101906111a7919061289d565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b3192505050565b8282815181106111f3576111f36126d9565b6020026020010181905250808061120990612706565b915050611177565b5092915050565b6000818152600080516020612a8e83398151915260208190526040822054825b81811015611289576000858152602084815260408083208484526001019091529020546001600160a01b031615611277576112746001856126c1565b93505b6112826001826126c1565b9050611238565b50611295846000610f7a565b156112a8576112a56001846126c1565b92505b5050919050565b60008281527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed66020526040902054600080516020612a47833981519152906112f9906106906116a5565b6105a58383611790565b7fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c90565b6000600080516020612a478339815191526000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055905061136d6116a5565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4505050565b600080516020612a4783398151915290565b600080516020612a8e83398151915290565b60006113e4816103ff6116a5565b905090565b6000600080516020612a27833981519152825160405163529051c560e11b81526001600160e01b031990911660048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a520a38a90602401602060405180830381865afa92505050801561148a575060408051601f3d908101601f191682019092526114879181019061218a565b60015b6115025781516114a59082906001600160e01b031916611b56565b6114fd5760405162461bcd60e51b815260206004820152602360248201527f526f757465723a20706c7567696e2065786973747320666f722066756e63746960448201526237b71760e91b6064820152608401610631565b61155e565b60405162461bcd60e51b815260206004820152602b60248201527f526f757465723a2064656661756c7420706c7567696e2065786973747320666f60448201526a3910333ab731ba34b7b71760a91b6064820152608401610631565b60208083015160405161157192016128eb565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916146115bd5760405162461bcd60e51b815260040161063190612907565b81516001600160e01b031916600090815260038201602090815260409091208351815463ffffffff191660e09190911c1781558184015180518593611609926001850192910190612096565b50604091820151600291820180546001600160a01b0319166001600160a01b039283161790558451858401519091166000908152918401602052919020611659916001600160e01b031916611b56565b50604080830151835191516001600160a01b03909116916001600160e01b031916907fe0e70d6cf2eef8321d38ecb6a3a5a107eaaf5e5f8b1976b462146a34e28f7dc290600090a35050565b3360009081527fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c602052604081205460ff16156116e9575060131936013560601c90565b503390565b6000828152600080516020612a47833981519152602081815260408084206001600160a01b03861685529091529091205460ff166105a55761173a826001600160a01b03166014611b62565b611745846020611b62565b604051602001611756929190612952565b60408051601f198184030181529082905262461bcd60e51b8252610631916004016129c7565b6117868282611327565b6107828282611cfe565b61179a8282611d7a565b6000828152600080516020612a8e833981519152602090815260408083206001600160a01b03851680855260028201808552838620805487526001909301855292852080546001600160a01b031916905584529152555050565b60006118038260000151611014565b9050816020015160405160200161181a91906128eb565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916146118665760405162461bcd60e51b815260040161063190612907565b8151600080516020612a278339815191529061188d9082906001600160e01b031916611b56565b5082516001600160e01b031916600090815260038201602090815260409091208451815463ffffffff191660e09190911c17815581850151805186936118da926001850192910190612096565b50604091820151600291820180546001600160a01b0319166001600160a01b0392831617905585519085166000908152918401602052919020611926916001600160e01b031916611e08565b5082516040808501516001600160a01b031660009081526002840160205220611958916001600160e01b031916611b56565b5082604001516001600160a01b0316826001600160a01b031684600001516001600160e01b0319167fcc8adca15b14349a258731182baaa1a066ed6e039d88e217beefdd9d400bb20560405160405180910390a4505050565b60006105db825490565b600081815260018301602052604081205415156110c9565b60006110c98383611e14565b600080516020612a2783398151915260006119f98361053a565b90506001600160a01b038116611a625760405162461bcd60e51b815260206004820152602860248201527f526f757465723a204e6f20706c7567696e20617661696c61626c6520666f722060448201526739b2b632b1ba37b960c11b6064820152608401610631565b6001600160e01b0319831660009081526003830160205260408120805463ffffffff1916815590611a96600183018261211a565b5060020180546001600160a01b0319169055611abc826001600160e01b03198516611e08565b506001600160a01b03811660009081526002830160205260409020611aeb906001600160e01b03198516611e08565b506040516001600160a01b038216906001600160e01b03198516907f35abc8f71d3b64d5ac2bf726bfcc6c2c4311e2882a30b10d56536b6747f310c490600090a3505050565b60606110c98383604051806060016040528060278152602001612a6760279139611e3e565b60006110c98383611f1b565b60606000611b718360026129da565b611b7c9060026126c1565b67ffffffffffffffff811115611b9457611b946121da565b6040519080825280601f01601f191660200182016040528015611bbe576020820181803683370190505b509050600360fc1b81600081518110611bd957611bd96126d9565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611c0857611c086126d9565b60200101906001600160f81b031916908160001a9053506000611c2c8460026129da565b611c379060016126c1565b90505b6001811115611caf576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611c6b57611c6b6126d9565b1a60f81b828281518110611c8157611c816126d9565b60200101906001600160f81b031916908160001a90535060049490941c93611ca8816129f9565b9050611c3a565b5083156110c95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610631565b6000828152600080516020612a8e8339815191526020819052604082208054919260019190611d2d83856126c1565b909155505060009384526020918252604080852082865260018101845281862080546001600160a01b039096166001600160a01b0319909616861790559385526002909301909152912055565b600080516020612a47833981519152611d9383836116ee565b6000838152602082815260408083206001600160a01b03861684529091529020805460ff19169055611dc36116a5565b6001600160a01b0316826001600160a01b0316847ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a4505050565b60006110c98383611f6a565b6000826000018281548110611e2b57611e2b6126d9565b9060005260206000200154905092915050565b60606001600160a01b0384163b611ea65760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610631565b600080856001600160a01b031685604051611ec191906128eb565b600060405180830381855af49150503d8060008114611efc576040519150601f19603f3d011682016040523d82523d6000602084013e611f01565b606091505b5091509150611f1182828661205d565b9695505050505050565b6000818152600183016020526040812054611f62575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105db565b5060006105db565b60008181526001830160205260408120548015612053576000611f8e6001836126ef565b8554909150600090611fa2906001906126ef565b9050818114612007576000866000018281548110611fc257611fc26126d9565b9060005260206000200154905080876000018481548110611fe557611fe56126d9565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061201857612018612a10565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105db565b60009150506105db565b6060831561206c5750816110c9565b82511561207c5782518084602001fd5b8160405162461bcd60e51b815260040161063191906129c7565b8280546120a290612862565b90600052602060002090601f0160209004810192826120c4576000855561210a565b82601f106120dd57805160ff191683800117855561210a565b8280016001018555821561210a579182015b8281111561210a5782518255916020019190600101906120ef565b50612116929150612150565b5090565b50805461212690612862565b6000825580601f10612136575050565b601f01602090049060005260206000209081019061064391905b5b808211156121165760008155600101612151565b6001600160a01b038116811461064357600080fd5b805161218581612165565b919050565b60006020828403121561219c57600080fd5b81516110c981612165565b6001600160e01b03198116811461064357600080fd5b6000602082840312156121cf57600080fd5b81356110c9816121a7565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715612213576122136121da565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612242576122426121da565b604052919050565b600067ffffffffffffffff821115612264576122646121da565b50601f01601f191660200190565b803561218581612165565b6000602080838503121561229057600080fd5b823567ffffffffffffffff808211156122a857600080fd5b90840190606082870312156122bc57600080fd5b6122c46121f0565b82356122cf816121a7565b815282840135828111156122e257600080fd5b83019150601f820187136122f557600080fd5b81356123086123038261224a565b612219565b818152888683860101111561231c57600080fd5b818685018783013760008683830101528086840152505061233f60408401612272565b60408201529695505050505050565b60006020828403121561236057600080fd5b5035919050565b6000806040838503121561237a57600080fd5b82359150602083013561238c81612165565b809150509250929050565b6000602082840312156123a957600080fd5b81356110c981612165565b6020808252825182820181905260009190848201906040850190845b818110156123f65783516001600160e01b031916835292840192918401916001016123d0565b50909695505050505050565b60005b8381101561241d578181015183820152602001612405565b8381111561242c576000848401525b50505050565b6000815180845261244a816020860160208601612402565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156124e657888303603f19018552815180516001600160e01b0319168452878101516060898601819052906124bf82870182612432565b928901516001600160a01b0316958901959095525094870194925090860190600101612485565b509098975050505050505050565b6000806040838503121561250757600080fd5b50508035926020909101359150565b6000806020838503121561252957600080fd5b823567ffffffffffffffff8082111561254157600080fd5b818501915085601f83011261255557600080fd5b81358181111561256457600080fd5b8660208260051b850101111561257957600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156125e057603f198886030184526125ce858351612432565b945092850192908501906001016125b2565b5092979650505050505050565b600067ffffffffffffffff821115612607576126076121da565b5060051b60200190565b6000602080838503121561262457600080fd5b825167ffffffffffffffff81111561263b57600080fd5b8301601f8101851361264c57600080fd5b805161265a612303826125ed565b81815260059190911b8201830190838101908783111561267957600080fd5b928401925b828410156126a0578351612691816121a7565b8252928401929084019061267e565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156126d4576126d46126ab565b500190565b634e487b7160e01b600052603260045260246000fd5b600082821015612701576127016126ab565b500390565b600060001982141561271a5761271a6126ab565b5060010190565b6000602080838503121561273457600080fd5b825167ffffffffffffffff8082111561274c57600080fd5b818501915085601f83011261276057600080fd5b815161276e612303826125ed565b81815260059190911b8301840190848101908883111561278d57600080fd5b8585015b83811015612855578051858111156127a857600080fd5b86016060818c03601f190112156127bf5760008081fd5b6127c76121f0565b888201516127d4816121a7565b8152604082810151888111156127ea5760008081fd5b8301603f81018e136127fc5760008081fd5b8a81015161280c6123038261224a565b8181528f848385010111156128215760008081fd5b612830828e8301868601612402565b848d01525061284390506060840161217a565b90820152845250918601918601612791565b5098975050505050505050565b600181811c9082168061287657607f821691505b6020821081141561289757634e487b7160e01b600052602260045260246000fd5b50919050565b6000808335601e198436030181126128b457600080fd5b83018035915067ffffffffffffffff8211156128cf57600080fd5b6020019150368190038213156128e457600080fd5b9250929050565b600082516128fd818460208701612402565b9190910192915050565b6020808252602b908201527f526f757465723a20666e2073656c6563746f7220616e64207369676e6174757260408201526a329036b4b9b6b0ba31b41760a91b606082015260800190565b7f5065726d697373696f6e733a206163636f756e7420000000000000000000000081526000835161298a816015850160208801612402565b7001034b99036b4b9b9b4b733903937b6329607d1b60159184019182015283516129bb816026840160208801612402565b01602601949350505050565b6020815260006110c96020830184612432565b60008160001904831182151516156129f4576129f46126ab565b500290565b600081612a0857612a086126ab565b506000190190565b634e487b7160e01b600052603160045260246000fdfe1a3e4131826bb378aa43abb34a33a366bc4a35b55ab18a884fa205b59285ec45d0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0ca264697066735822122053598aa548bade4238687fba586eafd190668a03d9014ada77a09280b6bda94f64736f6c634300080c003300000000000000000000000017134ecfda7081439794ce7fb9e928e2283a573800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ebc1977d1ac2fe1f6daaf584e2957f7c436fcdef
Deployed Bytecode
0x6080604052600436106101235760003560e01c806391d14854116100a0578063ac9650d811610064578063ac9650d814610479578063b48912da146104a6578063c511f8fb146104da578063ca15c873146104fa578063d547741f1461051a5761012a565b806391d14854146103e4578063a217fddf14610404578063a32fa5b314610419578063a520a38a14610439578063a5342fdf146104595761012a565b80634cb5d8fd116100e75780634cb5d8fd146102e5578063572b6c05146103055780635c573f2e1461035d5780636b86400e1461038a5780639010d07c146103ac5761012a565b806301ffc9a7146101f45780631ab6b70514610229578063248a9ca31461024b5780632f2ff15d146102a557806336568abe146102c55761012a565b3661012a57005b60006101416000356001600160e01b03191661053a565b90506001600160a01b0381166101e85760405163529051c560e11b81526000356001600160e01b03191660048201527f00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a57386001600160a01b03169063a520a38a90602401602060405180830381865afa1580156101c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e5919061218a565b90505b6101f181610581565b50005b34801561020057600080fd5b5061021461020f3660046121bd565b6105aa565b60405190151581526020015b60405180910390f35b34801561023557600080fd5b5061024961024436600461227d565b6105e1565b005b34801561025757600080fd5b5061029761026636600461234e565b60009081527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed6602052604090205490565b604051908152602001610220565b3480156102b157600080fd5b506102496102c0366004612367565b610646565b3480156102d157600080fd5b506102496102e0366004612367565b610710565b3480156102f157600080fd5b5061024961030036600461227d565b610786565b34801561031157600080fd5b50610214610320366004612397565b6001600160a01b031660009081527fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c602052604090205460ff1690565b34801561036957600080fd5b5061037d610378366004612397565b6107d9565b60405161022091906123b4565b34801561039657600080fd5b5061039f610ab7565b604051610220919061245e565b3480156103b857600080fd5b506103cc6103c73660046124f4565b610e7e565b6040516001600160a01b039091168152602001610220565b3480156103f057600080fd5b506102146103ff366004612367565b610f7a565b34801561041057600080fd5b50610297600081565b34801561042557600080fd5b50610214610434366004612367565b610fb2565b34801561044557600080fd5b506103cc6104543660046121bd565b611014565b34801561046557600080fd5b506102496104743660046121bd565b6110d0565b34801561048557600080fd5b50610499610494366004612516565b611123565b604051610220919061258b565b3480156104b257600080fd5b506103cc7f00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a573881565b3480156104e657600080fd5b506103cc6104f53660046121bd565b61053a565b34801561050657600080fd5b5061029761051536600461234e565b611218565b34801561052657600080fd5b50610249610535366004612367565b6112af565b6001600160e01b03191660009081527f1a3e4131826bb378aa43abb34a33a366bc4a35b55ab18a884fa205b59285ec4860205260409020600201546001600160a01b031690565b3660008037600080366000845af43d6000803e8080156105a0573d6000f35b3d6000fd5b505050565b60006001600160e01b0319821663f337402760e01b14806105db57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6105e96113d6565b61063a5760405162461bcd60e51b815260206004820152601660248201527f526f757465723a204e6f7420617574686f72697a65640000000000000000000060448201526064015b60405180910390fd5b610643816113e9565b50565b60008281527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed66020526040902054600080516020612a4783398151915290610695906106906116a5565b6116ee565b6000838152602082815260408083206001600160a01b038616845290915290205460ff16156107065760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610631565b6105a5838361177c565b806001600160a01b03166107226116a5565b6001600160a01b0316146107785760405162461bcd60e51b815260206004820152601a60248201527f43616e206f6e6c792072656e6f756e636520666f722073656c660000000000006044820152606401610631565b6107828282611790565b5050565b61078e6113d6565b6107d05760405162461bcd60e51b815260206004820152601360248201527213585c0e88139bdd08185d5d1a1bdc9a5e9959606a1b6044820152606401610631565b610643816117f4565b60606000600080516020612a278339815191526001600160a01b0384811660008181526002840160205260408082209051632e2b9f9760e11b81526004810193909352939450917f00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a57381690635c573f2e90602401600060405180830381865afa158015610869573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108919190810190612611565b80519091506000816108a2856119b1565b6108ac91906126c1565b905060005b82811015610944576108ef8482815181106108ce576108ce6126d9565b60200260200101516001600160e01b031916866119bb90919063ffffffff16565b15610932576108ff6001836126ef565b9150600060e01b848281518110610918576109186126d9565b6001600160e01b0319909216602092830291909101909101525b61093d6001826126c1565b90506108b1565b508067ffffffffffffffff81111561095e5761095e6121da565b604051908082528060200260200182016040528015610987578160200160208202803683370190505b5095506000805b83811015610a285784516000908690839081106109ad576109ad6126d9565b60200260200101516001600160e01b03191614610a16578481815181106109d6576109d66126d9565b60200260200101518883806109ea90612706565b9450815181106109fc576109fc6126d9565b6001600160e01b0319909216602092830291909101909101525b610a216001826126c1565b905061098e565b50610a32856119b1565b925060005b83811015610aab576001600160a01b03891660009081526002880160205260409020610a6390826119d3565b8883610a6e81612706565b945081518110610a8057610a806126d9565b6001600160e01b031990921660209283029190910190910152610aa46001826126c1565b9050610a37565b50505050505050919050565b60606000600080516020612a278339815191529050600081600001905060007f00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a57386001600160a01b0316636b86400e6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b34573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b5c9190810190612721565b90506000610b69836119b1565b82519091506000610b7a82846126c1565b905060005b83811015610c375760005b83811015610c2457858181518110610ba457610ba46126d9565b6020908102919091010151516001600160e01b031916610bc488846119d3565b6001600160e01b0319161415610c1257610bdf6001846126ef565b9250600060e01b868281518110610bf857610bf86126d9565b60209081029190910101516001600160e01b031990911690525b610c1d6001826126c1565b9050610b8a565b50610c306001826126c1565b9050610b7f565b508067ffffffffffffffff811115610c5157610c516121da565b604051908082528060200260200182016040528015610ca157816020015b60408051606080820183526000808352602083019190915291810191909152815260200190600190039081610c6f5790505b5096506000805b83811015610d39578551600090879083908110610cc757610cc76126d9565b6020026020010151600001516001600160e01b03191614610d2757858181518110610cf457610cf46126d9565b6020026020010151898381518110610d0e57610d0e6126d9565b6020908102919091010152610d246001836126c1565b91505b610d326001826126c1565b9050610ca8565b5060005b84811015610e7357600388016000610d5589846119d3565b6001600160e01b031990811682526020808301939093526040918201600020825160608101909352805460e01b90911682526001810180549293919291840191610d9e90612862565b80601f0160208091040260200160405190810160405280929190818152602001828054610dca90612862565b8015610e175780601f10610dec57610100808354040283529160200191610e17565b820191906000526020600020905b815481529060010190602001808311610dfa57829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015289518a9084908110610e4957610e496126d9565b6020908102919091010152610e5f6001836126c1565b9150610e6c6001826126c1565b9050610d3d565b505050505050505090565b6000828152600080516020612a8e8339815191526020819052604082205482805b82811015610f70576000878152602085815260408083208484526001019091529020546001600160a01b031615610f1b5785821415610f09576000878152602094855260408082209282526001909201909452909220546001600160a01b031692506105db915050565b610f146001836126c1565b9150610f5e565b610f26876000610f7a565b8015610f4b575060008781526020858152604080832083805260020190915290205481145b15610f5e57610f5b6001836126c1565b91505b610f696001826126c1565b9050610e9f565b5050505092915050565b6000918252600080516020612a47833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000828152600080516020612a478339815191526020818152604080842084805290915282205460ff1661100a576000848152602091825260408082206001600160a01b0386168352909252205460ff1690506105db565b5060019392505050565b6000806110208361053a565b90506001600160a01b0381166110c75760405163529051c560e11b81526001600160e01b0319841660048201527f00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a57386001600160a01b03169063a520a38a90602401602060405180830381865afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c2919061218a565b6110c9565b805b9392505050565b6110d86113d6565b61111a5760405162461bcd60e51b815260206004820152601360248201527213585c0e88139bdd08185d5d1a1bdc9a5e9959606a1b6044820152606401610631565b610643816119df565b60608167ffffffffffffffff81111561113e5761113e6121da565b60405190808252806020026020018201604052801561117157816020015b606081526020019060019003908161115c5790505b50905060005b82811015611211576111e130858584818110611195576111956126d9565b90506020028101906111a7919061289d565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b3192505050565b8282815181106111f3576111f36126d9565b6020026020010181905250808061120990612706565b915050611177565b5092915050565b6000818152600080516020612a8e83398151915260208190526040822054825b81811015611289576000858152602084815260408083208484526001019091529020546001600160a01b031615611277576112746001856126c1565b93505b6112826001826126c1565b9050611238565b50611295846000610f7a565b156112a8576112a56001846126c1565b92505b5050919050565b60008281527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed66020526040902054600080516020612a47833981519152906112f9906106906116a5565b6105a58383611790565b7fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c90565b6000600080516020612a478339815191526000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055905061136d6116a5565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4505050565b600080516020612a4783398151915290565b600080516020612a8e83398151915290565b60006113e4816103ff6116a5565b905090565b6000600080516020612a27833981519152825160405163529051c560e11b81526001600160e01b031990911660048201529091507f00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a57386001600160a01b03169063a520a38a90602401602060405180830381865afa92505050801561148a575060408051601f3d908101601f191682019092526114879181019061218a565b60015b6115025781516114a59082906001600160e01b031916611b56565b6114fd5760405162461bcd60e51b815260206004820152602360248201527f526f757465723a20706c7567696e2065786973747320666f722066756e63746960448201526237b71760e91b6064820152608401610631565b61155e565b60405162461bcd60e51b815260206004820152602b60248201527f526f757465723a2064656661756c7420706c7567696e2065786973747320666f60448201526a3910333ab731ba34b7b71760a91b6064820152608401610631565b60208083015160405161157192016128eb565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916146115bd5760405162461bcd60e51b815260040161063190612907565b81516001600160e01b031916600090815260038201602090815260409091208351815463ffffffff191660e09190911c1781558184015180518593611609926001850192910190612096565b50604091820151600291820180546001600160a01b0319166001600160a01b039283161790558451858401519091166000908152918401602052919020611659916001600160e01b031916611b56565b50604080830151835191516001600160a01b03909116916001600160e01b031916907fe0e70d6cf2eef8321d38ecb6a3a5a107eaaf5e5f8b1976b462146a34e28f7dc290600090a35050565b3360009081527fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c602052604081205460ff16156116e9575060131936013560601c90565b503390565b6000828152600080516020612a47833981519152602081815260408084206001600160a01b03861685529091529091205460ff166105a55761173a826001600160a01b03166014611b62565b611745846020611b62565b604051602001611756929190612952565b60408051601f198184030181529082905262461bcd60e51b8252610631916004016129c7565b6117868282611327565b6107828282611cfe565b61179a8282611d7a565b6000828152600080516020612a8e833981519152602090815260408083206001600160a01b03851680855260028201808552838620805487526001909301855292852080546001600160a01b031916905584529152555050565b60006118038260000151611014565b9050816020015160405160200161181a91906128eb565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916146118665760405162461bcd60e51b815260040161063190612907565b8151600080516020612a278339815191529061188d9082906001600160e01b031916611b56565b5082516001600160e01b031916600090815260038201602090815260409091208451815463ffffffff191660e09190911c17815581850151805186936118da926001850192910190612096565b50604091820151600291820180546001600160a01b0319166001600160a01b0392831617905585519085166000908152918401602052919020611926916001600160e01b031916611e08565b5082516040808501516001600160a01b031660009081526002840160205220611958916001600160e01b031916611b56565b5082604001516001600160a01b0316826001600160a01b031684600001516001600160e01b0319167fcc8adca15b14349a258731182baaa1a066ed6e039d88e217beefdd9d400bb20560405160405180910390a4505050565b60006105db825490565b600081815260018301602052604081205415156110c9565b60006110c98383611e14565b600080516020612a2783398151915260006119f98361053a565b90506001600160a01b038116611a625760405162461bcd60e51b815260206004820152602860248201527f526f757465723a204e6f20706c7567696e20617661696c61626c6520666f722060448201526739b2b632b1ba37b960c11b6064820152608401610631565b6001600160e01b0319831660009081526003830160205260408120805463ffffffff1916815590611a96600183018261211a565b5060020180546001600160a01b0319169055611abc826001600160e01b03198516611e08565b506001600160a01b03811660009081526002830160205260409020611aeb906001600160e01b03198516611e08565b506040516001600160a01b038216906001600160e01b03198516907f35abc8f71d3b64d5ac2bf726bfcc6c2c4311e2882a30b10d56536b6747f310c490600090a3505050565b60606110c98383604051806060016040528060278152602001612a6760279139611e3e565b60006110c98383611f1b565b60606000611b718360026129da565b611b7c9060026126c1565b67ffffffffffffffff811115611b9457611b946121da565b6040519080825280601f01601f191660200182016040528015611bbe576020820181803683370190505b509050600360fc1b81600081518110611bd957611bd96126d9565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611c0857611c086126d9565b60200101906001600160f81b031916908160001a9053506000611c2c8460026129da565b611c379060016126c1565b90505b6001811115611caf576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611c6b57611c6b6126d9565b1a60f81b828281518110611c8157611c816126d9565b60200101906001600160f81b031916908160001a90535060049490941c93611ca8816129f9565b9050611c3a565b5083156110c95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610631565b6000828152600080516020612a8e8339815191526020819052604082208054919260019190611d2d83856126c1565b909155505060009384526020918252604080852082865260018101845281862080546001600160a01b039096166001600160a01b0319909616861790559385526002909301909152912055565b600080516020612a47833981519152611d9383836116ee565b6000838152602082815260408083206001600160a01b03861684529091529020805460ff19169055611dc36116a5565b6001600160a01b0316826001600160a01b0316847ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a4505050565b60006110c98383611f6a565b6000826000018281548110611e2b57611e2b6126d9565b9060005260206000200154905092915050565b60606001600160a01b0384163b611ea65760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610631565b600080856001600160a01b031685604051611ec191906128eb565b600060405180830381855af49150503d8060008114611efc576040519150601f19603f3d011682016040523d82523d6000602084013e611f01565b606091505b5091509150611f1182828661205d565b9695505050505050565b6000818152600183016020526040812054611f62575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105db565b5060006105db565b60008181526001830160205260408120548015612053576000611f8e6001836126ef565b8554909150600090611fa2906001906126ef565b9050818114612007576000866000018281548110611fc257611fc26126d9565b9060005260206000200154905080876000018481548110611fe557611fe56126d9565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061201857612018612a10565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105db565b60009150506105db565b6060831561206c5750816110c9565b82511561207c5782518084602001fd5b8160405162461bcd60e51b815260040161063191906129c7565b8280546120a290612862565b90600052602060002090601f0160209004810192826120c4576000855561210a565b82601f106120dd57805160ff191683800117855561210a565b8280016001018555821561210a579182015b8281111561210a5782518255916020019190600101906120ef565b50612116929150612150565b5090565b50805461212690612862565b6000825580601f10612136575050565b601f01602090049060005260206000209081019061064391905b5b808211156121165760008155600101612151565b6001600160a01b038116811461064357600080fd5b805161218581612165565b919050565b60006020828403121561219c57600080fd5b81516110c981612165565b6001600160e01b03198116811461064357600080fd5b6000602082840312156121cf57600080fd5b81356110c9816121a7565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715612213576122136121da565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612242576122426121da565b604052919050565b600067ffffffffffffffff821115612264576122646121da565b50601f01601f191660200190565b803561218581612165565b6000602080838503121561229057600080fd5b823567ffffffffffffffff808211156122a857600080fd5b90840190606082870312156122bc57600080fd5b6122c46121f0565b82356122cf816121a7565b815282840135828111156122e257600080fd5b83019150601f820187136122f557600080fd5b81356123086123038261224a565b612219565b818152888683860101111561231c57600080fd5b818685018783013760008683830101528086840152505061233f60408401612272565b60408201529695505050505050565b60006020828403121561236057600080fd5b5035919050565b6000806040838503121561237a57600080fd5b82359150602083013561238c81612165565b809150509250929050565b6000602082840312156123a957600080fd5b81356110c981612165565b6020808252825182820181905260009190848201906040850190845b818110156123f65783516001600160e01b031916835292840192918401916001016123d0565b50909695505050505050565b60005b8381101561241d578181015183820152602001612405565b8381111561242c576000848401525b50505050565b6000815180845261244a816020860160208601612402565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156124e657888303603f19018552815180516001600160e01b0319168452878101516060898601819052906124bf82870182612432565b928901516001600160a01b0316958901959095525094870194925090860190600101612485565b509098975050505050505050565b6000806040838503121561250757600080fd5b50508035926020909101359150565b6000806020838503121561252957600080fd5b823567ffffffffffffffff8082111561254157600080fd5b818501915085601f83011261255557600080fd5b81358181111561256457600080fd5b8660208260051b850101111561257957600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156125e057603f198886030184526125ce858351612432565b945092850192908501906001016125b2565b5092979650505050505050565b600067ffffffffffffffff821115612607576126076121da565b5060051b60200190565b6000602080838503121561262457600080fd5b825167ffffffffffffffff81111561263b57600080fd5b8301601f8101851361264c57600080fd5b805161265a612303826125ed565b81815260059190911b8201830190838101908783111561267957600080fd5b928401925b828410156126a0578351612691816121a7565b8252928401929084019061267e565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156126d4576126d46126ab565b500190565b634e487b7160e01b600052603260045260246000fd5b600082821015612701576127016126ab565b500390565b600060001982141561271a5761271a6126ab565b5060010190565b6000602080838503121561273457600080fd5b825167ffffffffffffffff8082111561274c57600080fd5b818501915085601f83011261276057600080fd5b815161276e612303826125ed565b81815260059190911b8301840190848101908883111561278d57600080fd5b8585015b83811015612855578051858111156127a857600080fd5b86016060818c03601f190112156127bf5760008081fd5b6127c76121f0565b888201516127d4816121a7565b8152604082810151888111156127ea5760008081fd5b8301603f81018e136127fc5760008081fd5b8a81015161280c6123038261224a565b8181528f848385010111156128215760008081fd5b612830828e8301868601612402565b848d01525061284390506060840161217a565b90820152845250918601918601612791565b5098975050505050505050565b600181811c9082168061287657607f821691505b6020821081141561289757634e487b7160e01b600052602260045260246000fd5b50919050565b6000808335601e198436030181126128b457600080fd5b83018035915067ffffffffffffffff8211156128cf57600080fd5b6020019150368190038213156128e457600080fd5b9250929050565b600082516128fd818460208701612402565b9190910192915050565b6020808252602b908201527f526f757465723a20666e2073656c6563746f7220616e64207369676e6174757260408201526a329036b4b9b6b0ba31b41760a91b606082015260800190565b7f5065726d697373696f6e733a206163636f756e7420000000000000000000000081526000835161298a816015850160208801612402565b7001034b99036b4b9b9b4b733903937b6329607d1b60159184019182015283516129bb816026840160208801612402565b01602601949350505050565b6020815260006110c96020830184612432565b60008160001904831182151516156129f4576129f46126ab565b500290565b600081612a0857612a086126ab565b506000190190565b634e487b7160e01b600052603160045260246000fdfe1a3e4131826bb378aa43abb34a33a366bc4a35b55ab18a884fa205b59285ec45d0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0ca264697066735822122053598aa548bade4238687fba586eafd190668a03d9014ada77a09280b6bda94f64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a573800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ebc1977d1ac2fe1f6daaf584e2957f7c436fcdef
-----Decoded View---------------
Arg [0] : _pluginMap (address): 0x17134ECfdA7081439794CE7FB9E928E2283A5738
Arg [1] : _trustedForwarders (address[]): 0xEbc1977d1aC2fe1F6DAaF584E2957F7c436fcdEF
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000017134ecfda7081439794ce7fb9e928e2283a5738
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 000000000000000000000000ebc1977d1ac2fe1f6daaf584e2957f7c436fcdef
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.