Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- ManagedAccountFactory
- Optimization enabled
- true
- Compiler version
- v0.8.23+commit.f704f362
- Optimization runs
- 20
- EVM Version
- london
- Verified at
- 2024-07-10T15:30:02.756488Z
Constructor Arguments
0x000000000000000000000000118b936d79059251df60eec5d65c476b9fdd42640000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000cd68591e4f9fa55c4a9938a5574e22517047a05500000000000000000000000000000000000000000000000000000000000000104163636f756e74457874656e73696f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d4e5132646a543275346d793578704b50674a4d6e5145706f4e6a595a45387567704c6e647667454a4262335800000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000007a0000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008a000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000d604a58db19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000c6164644465706f73697428290000000000000000000000000000000000000000e8a3d485000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d636f6e7472616374555249282900000000000000000000000000000000000000b61d27f6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e6578656375746528616464726573732c75696e743235362c627974657329000047e1da2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002965786563757465426174636828616464726573735b5d2c75696e743235365b5d2c62797465735b5d2900000000000000000000000000000000000000000000008b52d7230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000015676574416c6c4163746976655369676e65727328290000000000000000000000e9523c97000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e676574416c6c41646d696e732829000000000000000000000000000000000000d42f2f35000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000f676574416c6c5369676e65727328290000000000000000000000000000000000399b77da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000176765744d65737361676548617368286279746573333229000000000000000000f15d424e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000206765745065726d697373696f6e73466f725369676e65722861646472657373297dff5a79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001769734163746976655369676e657228616464726573732900000000000000000024d7806c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010697341646d696e286164647265737329000000000000000000000000000000001626ba7e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f697356616c69645369676e617475726528627974657333322c62797465732900bc197c8100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000416f6e455243313135354261746368526563656976656428616464726573732c616464726573732c75696e743235365b5d2c75696e743235365b5d2c62797465732900000000000000000000000000000000000000000000000000000000000000f23a6e6100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000386f6e45524331313535526563656976656428616464726573732c616464726573732c75696e743235362c75696e743235362c6279746573290000000000000000150b7a02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6f6e455243373231526563656976656428616464726573732c616464726573732c75696e743235362c6279746573290000000000000000000000000000000000938e3d7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016736574436f6e747261637455524928737472696e6729000000000000000000005892e23600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000687365745065726d697373696f6e73466f725369676e65722828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c62797465732900000000000000000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019737570706f727473496e74657266616365286279746573342900000000000000a9082d84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006e7665726966795369676e65725065726d697373696f6e526571756573742828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c6279746573290000000000000000000000000000000000004d44560d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002277697468647261774465706f736974546f28616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000000000000
contracts/prebuilts/account/managed/ManagedAccountFactory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
// Utils
import "@thirdweb-dev/dynamic-contracts/src/presets/BaseRouter.sol";
import "../utils/BaseAccountFactory.sol";
// Extensions
import "../../../extension/upgradeable//PermissionsEnumerable.sol";
import "../../../extension/upgradeable//ContractMetadata.sol";
// Smart wallet implementation
import { ManagedAccount, IEntryPoint } from "./ManagedAccount.sol";
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
contract ManagedAccountFactory is BaseAccountFactory, ContractMetadata, PermissionsEnumerable, BaseRouter {
/*///////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor(
address _defaultAdmin,
IEntryPoint _entrypoint,
Extension[] memory _defaultExtensions
)
BaseRouter(_defaultExtensions)
BaseAccountFactory(payable(address(new ManagedAccount(_entrypoint, address(this)))), address(_entrypoint))
{
__BaseRouter_init();
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
bytes32 _extensionRole = keccak256("EXTENSION_ROLE");
_setupRole(_extensionRole, _defaultAdmin);
_setRoleAdmin(_extensionRole, _extensionRole);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Called in `createAccount`. Initializes the account contract created in `createAccount`.
function _initializeAccount(address _account, address _admin, bytes calldata _data) internal override {
ManagedAccount(payable(_account)).initialize(_admin, _data);
}
/// @dev Returns whether all relevant permission and other checks are met before any upgrade.
function _isAuthorizedCallToUpgrade() internal view virtual override returns (bool) {
return hasRole(keccak256("EXTENSION_ROLE"), msg.sender);
}
/// @dev Returns whether contract metadata can be set in the given execution context.
function _canSetContractURI() internal view virtual override returns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/// @notice Returns the sender in the given execution context.
function _msgSender() internal view override(Multicall, Permissions) returns (address) {
return msg.sender;
}
}
contracts/external-deps/openzeppelin/token/ERC721/utils/ERC721Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.0;
import "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/
contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}
contracts/extension/upgradeable/Permissions.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IPermissions.sol";
import "../../lib/Strings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/
library PermissionsStorage {
/// @custom:storage-location erc7201:permissions.storage
/// @dev keccak256(abi.encode(uint256(keccak256("permissions.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant PERMISSIONS_STORAGE_POSITION =
0x0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e500;
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 data() internal pure returns (Data storage data_) {
bytes32 position = PERMISSIONS_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contract Permissions 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) {
return _permissionsStorage()._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) {
if (!_permissionsStorage()._hasRole[role][address(0)]) {
return _permissionsStorage()._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) {
return _permissionsStorage()._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 {
_checkRole(_permissionsStorage()._getRoleAdmin[role], _msgSender());
if (_permissionsStorage()._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 {
_checkRole(_permissionsStorage()._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 {
bytes32 previousAdminRole = _permissionsStorage()._getRoleAdmin[role];
_permissionsStorage()._getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal virtual {
_permissionsStorage()._hasRole[role][account] = true;
emit RoleGranted(role, account, _msgSender());
}
/// @dev Revokes `role` from `account`
function _revokeRole(bytes32 role, address account) internal virtual {
_checkRole(role, account);
delete _permissionsStorage()._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 {
if (!_permissionsStorage()._hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.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 ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.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;
}
/// @dev Returns the Permissions storage.
function _permissionsStorage() internal pure returns (PermissionsStorage.Data storage data) {
data = PermissionsStorage.data();
}
}
lib/dynamic-contracts/src/interface/IExtensionManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IExtension.sol";
/// @title IExtensionManager
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage and API for managing a router's extensions.
interface IExtensionManager is IExtension {
/*///////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @dev Emitted when a extension is added.
event ExtensionAdded(string indexed name, address indexed implementation, Extension extension);
/// @dev Emitted when a extension is replaced.
event ExtensionReplaced(string indexed name, address indexed implementation, Extension extension);
/// @dev Emitted when a extension is removed.
event ExtensionRemoved(string indexed name, Extension extension);
/// @dev Emitted when a function is enabled i.e. made callable.
event FunctionEnabled(string indexed name, bytes4 indexed functionSelector, ExtensionFunction extFunction, ExtensionMetadata extMetadata);
/// @dev Emitted when a function is disabled i.e. made un-callable.
event FunctionDisabled(string indexed name, bytes4 indexed functionSelector, ExtensionMetadata extMetadata);
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Add a new extension to the router.
* @param extension The extension to add.
*/
function addExtension(Extension memory extension) external;
/**
* @notice Fully replace an existing extension of the router.
* @dev The extension with name `extension.name` is the extension being replaced.
* @param extension The extension to replace or overwrite.
*/
function replaceExtension(Extension memory extension) external;
/**
* @notice Remove an existing extension from the router.
* @param extensionName The name of the extension to remove.
*/
function removeExtension(string memory extensionName) external;
/**
* @notice Enables a single function in an existing extension.
* @dev Makes the given function callable on the router.
*
* @param extensionName The name of the extension to which `extFunction` belongs.
* @param extFunction The function to enable.
*/
function enableFunctionInExtension(string memory extensionName, ExtensionFunction memory extFunction) external;
/**
* @notice Disables a single function in an Extension.
*
* @param extensionName The name of the extension to which the function of `functionSelector` belongs.
* @param functionSelector The function to disable.
*/
function disableFunctionInExtension(string memory extensionName, bytes4 functionSelector) external;
}
contracts/prebuilts/account/interface/IStakeManager.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.12;
/**
* manage deposits and stakes.
* deposit is just a balance used to pay for UserOperations (either by a paymaster or an account)
* stake is value locked for at least "unstakeDelay" by the staked entity.
*/
interface IStakeManager {
event Deposited(address indexed account, uint256 totalDeposit);
event Withdrawn(address indexed account, address withdrawAddress, uint256 amount);
/// Emitted when stake or unstake delay are modified
event StakeLocked(address indexed account, uint256 totalStaked, uint256 unstakeDelaySec);
/// Emitted once a stake is scheduled for withdrawal
event StakeUnlocked(address indexed account, uint256 withdrawTime);
event StakeWithdrawn(address indexed account, address withdrawAddress, uint256 amount);
/**
* @param deposit the entity's deposit
* @param staked true if this entity is staked.
* @param stake actual amount of ether staked for this entity.
* @param unstakeDelaySec minimum delay to withdraw the stake.
* @param withdrawTime - first block timestamp where 'withdrawStake' will be callable, or zero if already locked
* @dev sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps)
* and the rest fit into a 2nd cell.
* 112 bit allows for 10^15 eth
* 48 bit for full timestamp
* 32 bit allows 150 years for unstake delay
*/
struct DepositInfo {
uint112 deposit;
bool staked;
uint112 stake;
uint32 unstakeDelaySec;
uint48 withdrawTime;
}
//API struct used by getStakeInfo and simulateValidation
struct StakeInfo {
uint256 stake;
uint256 unstakeDelaySec;
}
/// @return info - full deposit information of given account
function getDepositInfo(address account) external view returns (DepositInfo memory info);
/// @return the deposit (for gas payment) of the account
function balanceOf(address account) external view returns (uint256);
/**
* add to the deposit of the given account
*/
function depositTo(address account) external payable;
/**
* add to the account's stake - amount and delay
* any pending unstake is first cancelled.
* @param _unstakeDelaySec the new lock duration before the deposit can be withdrawn.
*/
function addStake(uint32 _unstakeDelaySec) external payable;
/**
* attempt to unlock the stake.
* the value can be withdrawn (using withdrawStake) after the unstake delay.
*/
function unlockStake() external;
/**
* withdraw from the (unlocked) stake.
* must first call unlockStake and wait for the unstakeDelay to pass
* @param withdrawAddress the address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external;
/**
* withdraw from the deposit.
* @param withdrawAddress the address to send withdrawn value.
* @param withdrawAmount the amount to withdraw.
*/
function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external;
}
contracts/extension/upgradeable/PermissionsEnumerable.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IPermissionsEnumerable.sol";
import "./Permissions.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.
*/
library PermissionsEnumerableStorage {
/// @custom:storage-location erc7201:extension.manager.storage
bytes32 public constant PERMISSIONS_ENUMERABLE_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("permissions.enumerable.storage")) - 1)) & ~bytes32(uint256(0xff));
/**
* @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 data() internal pure returns (Data storage data_) {
bytes32 position = PERMISSIONS_ENUMERABLE_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contract PermissionsEnumerable is IPermissionsEnumerable, Permissions {
/**
* @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) {
uint256 currentIndex = _permissionsEnumerableStorage().roleMembers[role].index;
uint256 check;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (_permissionsEnumerableStorage().roleMembers[role].members[i] != address(0)) {
if (check == index) {
member = _permissionsEnumerableStorage().roleMembers[role].members[i];
return member;
}
check += 1;
} else if (
hasRole(role, address(0)) && i == _permissionsEnumerableStorage().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) {
uint256 currentIndex = _permissionsEnumerableStorage().roleMembers[role].index;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (_permissionsEnumerableStorage().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 virtual 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 virtual override {
super._setupRole(role, account);
_addMember(role, account);
}
/// @dev adds `account` to {roleMembers}, for `role`
function _addMember(bytes32 role, address account) internal {
uint256 idx = _permissionsEnumerableStorage().roleMembers[role].index;
_permissionsEnumerableStorage().roleMembers[role].index += 1;
_permissionsEnumerableStorage().roleMembers[role].members[idx] = account;
_permissionsEnumerableStorage().roleMembers[role].indexOf[account] = idx;
}
/// @dev removes `account` from {roleMembers}, for `role`
function _removeMember(bytes32 role, address account) internal {
uint256 idx = _permissionsEnumerableStorage().roleMembers[role].indexOf[account];
delete _permissionsEnumerableStorage().roleMembers[role].members[idx];
delete _permissionsEnumerableStorage().roleMembers[role].indexOf[account];
}
/// @dev Returns the PermissionsEnumerable storage.
function _permissionsEnumerableStorage() internal pure returns (PermissionsEnumerableStorage.Data storage data) {
data = PermissionsEnumerableStorage.data();
}
}
lib/dynamic-contracts/src/lib/ExtensionManagerStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./StringSet.sol";
import "../interface/IExtension.sol";
/// @title IExtensionManagerStorage
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage for managing a router's extensions.
library ExtensionManagerStorage {
/// @custom:storage-location erc7201:extension.manager.storage
bytes32 public constant EXTENSION_MANAGER_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("extension.manager.storage")) - 1));
struct Data {
/// @dev Set of names of all extensions of the router.
StringSet.Set extensionNames;
/// @dev Mapping from extension name => `Extension` i.e. extension metadata and functions.
mapping(string => IExtension.Extension) extensions;
/// @dev Mapping from function selector => metadata of the extension the function belongs to.
mapping(bytes4 => IExtension.ExtensionMetadata) extensionMetadata;
}
/// @dev Returns access to the extension manager's storage.
function data() internal pure returns (Data storage data_) {
bytes32 position = EXTENSION_MANAGER_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contracts/prebuilts/account/interface/IAccountFactory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import "./IAccountFactoryCore.sol";
interface IAccountFactory is IAccountFactoryCore {
/*///////////////////////////////////////////////////////////////
Callback Functions
//////////////////////////////////////////////////////////////*/
/// @notice Callback function for an Account to register its signers.
function onSignerAdded(address signer, bytes32 salt) external;
/// @notice Callback function for an Account to un-register its signers.
function onSignerRemoved(address signer, bytes32 salt) external;
}
contracts/prebuilts/account/utils/AccountExtension.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
/* solhint-disable reason-string */
// Extensions
import "../../../extension/upgradeable/AccountPermissions.sol";
import "../../../extension/upgradeable/ContractMetadata.sol";
import "../../../external-deps/openzeppelin/token/ERC721/utils/ERC721Holder.sol";
import "../../../external-deps/openzeppelin/token/ERC1155/utils/ERC1155Holder.sol";
// Utils
import "../../../eip/ERC1271.sol";
import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol";
import "../../../external-deps/openzeppelin/utils/structs/EnumerableSet.sol";
import "./BaseAccountFactory.sol";
import "./AccountCore.sol";
import "./AccountCoreStorage.sol";
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC721Holder, ERC1155Holder {
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.AddressSet;
bytes32 private constant MSG_TYPEHASH = keccak256("AccountMessage(bytes message)");
/*///////////////////////////////////////////////////////////////
Constructor, Initializer, Modifiers
//////////////////////////////////////////////////////////////*/
/// @notice Checks whether the caller is the EntryPoint contract or the admin.
modifier onlyAdminOrEntrypoint() virtual {
require(
msg.sender == address(AccountCore(payable(address(this))).entryPoint()) || isAdmin(msg.sender),
"Account: not admin or EntryPoint."
);
_;
}
// solhint-disable-next-line no-empty-blocks
receive() external payable virtual {}
constructor() EIP712("Account", "1") {}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @notice See {IERC165-supportsInterface}.
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155Receiver) returns (bool) {
return
interfaceId == type(IERC1155Receiver).interfaceId ||
interfaceId == type(IERC721Receiver).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice See EIP-1271
*
* @param _hash The original message hash of the data to sign (before mixing this contract's domain separator)
* @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`)
*/
function isValidSignature(
bytes32 _hash,
bytes memory _signature
) public view virtual override returns (bytes4 magicValue) {
bytes32 targetDigest = getMessageHash(_hash);
address signer = targetDigest.recover(_signature);
if (isAdmin(signer)) {
return MAGICVALUE;
}
address caller = msg.sender;
EnumerableSet.AddressSet storage approvedTargets = _accountPermissionsStorage().approvedTargets[signer];
require(
approvedTargets.contains(caller) || (approvedTargets.length() == 1 && approvedTargets.at(0) == address(0)),
"Account: caller not approved target."
);
if (isActiveSigner(signer)) {
magicValue = MAGICVALUE;
}
}
/**
* @notice Returns the hash of message that should be signed for EIP1271 verification.
* @param _hash The message hash to sign for the EIP-1271 origin verifying contract.
* @return messageHash The digest to sign for EIP-1271 verification.
*/
function getMessageHash(bytes32 _hash) public view returns (bytes32) {
bytes32 messageHash = keccak256(abi.encode(_hash));
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash));
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Executes a transaction (called directly from an admin, or by entryPoint)
function execute(address _target, uint256 _value, bytes calldata _calldata) external virtual onlyAdminOrEntrypoint {
_registerOnFactory();
_call(_target, _value, _calldata);
}
/// @notice Executes a sequence transaction (called directly from an admin, or by entryPoint)
function executeBatch(
address[] calldata _target,
uint256[] calldata _value,
bytes[] calldata _calldata
) external virtual onlyAdminOrEntrypoint {
_registerOnFactory();
require(_target.length == _calldata.length && _target.length == _value.length, "Account: wrong array lengths.");
for (uint256 i = 0; i < _target.length; i++) {
_call(_target[i], _value[i], _calldata[i]);
}
}
/// @notice Deposit funds for this account in Entrypoint.
function addDeposit() public payable {
AccountCore(payable(address(this))).entryPoint().depositTo{ value: msg.value }(address(this));
}
/// @notice Withdraw funds for this account from Entrypoint.
function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public {
_onlyAdmin();
AccountCore(payable(address(this))).entryPoint().withdrawTo(withdrawAddress, amount);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Registers the account on the factory if it hasn't been registered yet.
function _registerOnFactory() internal virtual {
address factory = AccountCore(payable(address(this))).factory();
BaseAccountFactory factoryContract = BaseAccountFactory(factory);
if (!factoryContract.isRegistered(address(this))) {
factoryContract.onRegister(AccountCoreStorage.data().creationSalt);
}
}
/// @dev Calls a target contract and reverts if it fails.
function _call(address _target, uint256 value, bytes memory _calldata) internal returns (bytes memory result) {
bool success;
(success, result) = _target.call{ value: value }(_calldata);
if (!success) {
assembly {
revert(add(result, 32), mload(result))
}
}
}
/// @dev Returns whether contract metadata can be set in the given execution context.
function _canSetContractURI() internal view virtual override returns (bool) {
return isAdmin(msg.sender) || msg.sender == address(this);
}
function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual override {}
}
contracts/extension/interface/IPermissions.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @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;
}
contracts/extension/interface/IPermissionsEnumerable.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
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);
}
lib/dynamic-contracts/src/presets/BaseRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Router, IRouter } from "../core/Router.sol";
import { IRouterState } from "../interface/IRouterState.sol";
import { IRouterStateGetters } from "../interface/IRouterStateGetters.sol";
import { BaseRouterStorage } from "../lib/BaseRouterStorage.sol";
import { ExtensionManager } from "./ExtensionManager.sol";
import { StringSet } from "../lib/StringSet.sol";
import "lib/sstore2/contracts/SSTORE2.sol";
/// @title BaseRouter
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice A router with an API to manage its extensions.
abstract contract BaseRouter is Router, ExtensionManager {
using StringSet for StringSet.Set;
/// @notice The address where the router's default extension set is stored.
address public immutable defaultExtensions;
/// @notice Initialize the Router with a set of default extensions.
constructor(Extension[] memory _extensions) {
address pointer;
if(_extensions.length > 0) {
_validateExtensions(_extensions);
pointer = SSTORE2.write(abi.encode(_extensions));
}
defaultExtensions = pointer;
}
/// @notice Initialize the Router with a set of default extensions.
function __BaseRouter_init() internal {
if(defaultExtensions == address(0)) {
return;
}
bytes memory data = SSTORE2.read(defaultExtensions);
Extension[] memory defaults = abi.decode(data, (Extension[]));
// Unchecked since we already validated extensions in constructor.
__BaseRouter_init_unchecked(defaults);
}
/// @notice Initializes the Router with a set of extensions.
function __BaseRouter_init_checked(Extension[] memory _extensions) internal {
_validateExtensions(_extensions);
__BaseRouter_init_unchecked(_extensions);
}
/// @notice Initializes the Router with a set of extensions.
function __BaseRouter_init_unchecked(Extension[] memory _extensions) internal {
for(uint256 i = 0; i < _extensions.length; i += 1) {
Extension memory extension = _extensions[i];
// Store: new extension name.
_extensionManagerStorage().extensionNames.add(extension.metadata.name);
// 1. Store: metadata for extension.
_setMetadataForExtension(extension.metadata.name, extension.metadata);
uint256 len = extension.functions.length;
for (uint256 j = 0; j < len; j += 1) {
// 2. Store: name -> extension.functions map
_extensionManagerStorage().extensions[extension.metadata.name].functions.push(extension.functions[j]);
// 3. Store: metadata for function.
_setMetadataForFunction(extension.functions[j].functionSelector, extension.metadata);
}
emit ExtensionAdded(extension.metadata.name, extension.metadata.implementation, extension);
}
}
/// @notice Returns the implementation contract address for a given function signature.
function getImplementationForFunction(bytes4 _functionSelector) public view virtual override returns (address) {
return getMetadataForFunction(_functionSelector).implementation;
}
/// @dev Validates default extensions.
function _validateExtensions(Extension[] memory _extensions) internal {
uint256 len = _extensions.length;
bool isValid = true;
for (uint256 i = 0; i < len; i += 1) {
isValid = _isValidExtension(_extensions[i]);
if(!isValid) {
break;
}
}
require(isValid, "BaseRouter: invalid extension.");
}
function _isValidExtension(Extension memory _extension) internal returns (bool isValid) {
isValid = bytes(_extension.metadata.name).length > 0 // non-empty name
&& !BaseRouterStorage.data().extensionMap[_extension.metadata.name] // unused name
&& _extension.metadata.implementation != address(0); // non-empty implementation
BaseRouterStorage.data().extensionMap[_extension.metadata.name] = true;
if(!isValid) {
return false;
}
uint256 len = _extension.functions.length;
for(uint256 i = 0; i < len; i += 1) {
if(!isValid) {
break;
}
ExtensionFunction memory _extFunction = _extension.functions[i];
/**
* Note: `bytes4(0)` is the function selector for the `receive` function.
* So, we maintain a special fn selector-signature mismatch check for the `receive` function.
**/
bool mismatch = false;
if(_extFunction.functionSelector == bytes4(0)) {
mismatch = keccak256(abi.encode(_extFunction.functionSignature)) != keccak256(abi.encode("receive()"));
} else {
mismatch = _extFunction.functionSelector !=
bytes4(keccak256(abi.encodePacked(_extFunction.functionSignature)));
}
// No fn signature-selector mismatch and no duplicate function.
isValid = !mismatch && !BaseRouterStorage.data().functionMap[_extFunction.functionSelector];
BaseRouterStorage.data().functionMap[_extFunction.functionSelector] = true;
}
}
}
lib/dynamic-contracts/src/interface/IExtension.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title IExtension
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Provides an `Extension` abstraction for a router's implementation contracts.
interface IExtension {
/*///////////////////////////////////////////////////////////////
Structs
//////////////////////////////////////////////////////////////*/
/**
* @notice An interface to describe an extension's metadata.
*
* @param name The unique name of the extension.
* @param metadataURI The URI where the metadata for the extension lives.
* @param implementation The implementation smart contract address of the extension.
*/
struct ExtensionMetadata {
string name;
string metadataURI;
address implementation;
}
/**
* @notice An interface to describe an extension's function.
*
* @param functionSelector The 4 byte selector of the function.
* @param functionSignature Function signature as a string. E.g. "transfer(address,address,uint256)"
*/
struct ExtensionFunction {
bytes4 functionSelector;
string functionSignature;
}
/**
* @notice An interface to describe an extension.
*
* @param metadata The extension's metadata; it's name, metadata URI and implementation contract address.
* @param functions The functions that belong to the extension.
*/
struct Extension {
ExtensionMetadata metadata;
ExtensionFunction[] functions;
}
}
contracts/extension/upgradeable/AccountPermissions.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IAccountPermissions.sol";
import "../../external-deps/openzeppelin/utils/cryptography/EIP712.sol";
import "../../external-deps/openzeppelin/utils/structs/EnumerableSet.sol";
library AccountPermissionsStorage {
/// @custom:storage-location erc7201:account.permissions.storage
/// @dev keccak256(abi.encode(uint256(keccak256("account.permissions.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant ACCOUNT_PERMISSIONS_STORAGE_POSITION =
0x3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def00;
struct Data {
/// @dev The set of all admins of the wallet.
EnumerableSet.AddressSet allAdmins;
/// @dev The set of all signers with permission to use the account.
EnumerableSet.AddressSet allSigners;
/// @dev Map from address => whether the address is an admin.
mapping(address => bool) isAdmin;
/// @dev Map from signer address => active restrictions for that signer.
mapping(address => IAccountPermissions.SignerPermissionsStatic) signerPermissions;
/// @dev Map from signer address => approved target the signer can call using the account contract.
mapping(address => EnumerableSet.AddressSet) approvedTargets;
/// @dev Mapping from a signed request UID => whether the request is processed.
mapping(bytes32 => bool) executed;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = ACCOUNT_PERMISSIONS_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
abstract contract AccountPermissions is IAccountPermissions, EIP712 {
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.AddressSet;
bytes32 private constant TYPEHASH =
keccak256(
"SignerPermissionRequest(address signer,uint8 isAdmin,address[] approvedTargets,uint256 nativeTokenLimitPerTransaction,uint128 permissionStartTimestamp,uint128 permissionEndTimestamp,uint128 reqValidityStartTimestamp,uint128 reqValidityEndTimestamp,bytes32 uid)"
);
function _onlyAdmin() internal virtual {
require(isAdmin(msg.sender), "!admin");
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Sets the permissions for a given signer.
function setPermissionsForSigner(SignerPermissionRequest calldata _req, bytes calldata _signature) external {
address targetSigner = _req.signer;
require(
_req.reqValidityStartTimestamp <= block.timestamp && block.timestamp < _req.reqValidityEndTimestamp,
"!period"
);
(bool success, address signer) = verifySignerPermissionRequest(_req, _signature);
require(success, "!sig");
_accountPermissionsStorage().executed[_req.uid] = true;
//isAdmin > 0, set admin or remove admin
if (_req.isAdmin > 0) {
//isAdmin = 1, set admin
//isAdmin > 1, remove admin
bool _isAdmin = _req.isAdmin == 1;
_setAdmin(targetSigner, _isAdmin);
return;
}
require(!isAdmin(targetSigner), "admin");
_accountPermissionsStorage().allSigners.add(targetSigner);
_accountPermissionsStorage().signerPermissions[targetSigner] = SignerPermissionsStatic(
_req.nativeTokenLimitPerTransaction,
_req.permissionStartTimestamp,
_req.permissionEndTimestamp
);
address[] memory currentTargets = _accountPermissionsStorage().approvedTargets[targetSigner].values();
uint256 len = currentTargets.length;
for (uint256 i = 0; i < len; i += 1) {
_accountPermissionsStorage().approvedTargets[targetSigner].remove(currentTargets[i]);
}
len = _req.approvedTargets.length;
for (uint256 i = 0; i < len; i += 1) {
_accountPermissionsStorage().approvedTargets[targetSigner].add(_req.approvedTargets[i]);
}
_afterSignerPermissionsUpdate(_req);
emit SignerPermissionsUpdated(signer, targetSigner, _req);
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @notice Returns whether the given account is an admin.
function isAdmin(address _account) public view virtual returns (bool) {
return _accountPermissionsStorage().isAdmin[_account];
}
/// @notice Returns whether the given account is an active signer on the account.
function isActiveSigner(address signer) public view returns (bool) {
SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer];
return
permissions.startTimestamp <= block.timestamp &&
block.timestamp < permissions.endTimestamp &&
_accountPermissionsStorage().approvedTargets[signer].length() > 0;
}
/// @notice Returns the restrictions under which a signer can use the smart wallet.
function getPermissionsForSigner(address signer) external view returns (SignerPermissions memory) {
SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer];
return
SignerPermissions(
signer,
_accountPermissionsStorage().approvedTargets[signer].values(),
permissions.nativeTokenLimitPerTransaction,
permissions.startTimestamp,
permissions.endTimestamp
);
}
/// @dev Verifies that a request is signed by an authorized account.
function verifySignerPermissionRequest(
SignerPermissionRequest calldata req,
bytes calldata signature
) public view virtual returns (bool success, address signer) {
signer = _recoverAddress(_encodeRequest(req), signature);
success = !_accountPermissionsStorage().executed[req.uid] && isAdmin(signer);
}
/// @notice Returns all active and inactive signers of the account.
function getAllSigners() external view returns (SignerPermissions[] memory signers) {
address[] memory allSigners = _accountPermissionsStorage().allSigners.values();
uint256 len = allSigners.length;
signers = new SignerPermissions[](len);
for (uint256 i = 0; i < len; i += 1) {
address signer = allSigners[i];
SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer];
signers[i] = SignerPermissions(
signer,
_accountPermissionsStorage().approvedTargets[signer].values(),
permissions.nativeTokenLimitPerTransaction,
permissions.startTimestamp,
permissions.endTimestamp
);
}
}
/// @notice Returns all signers with active permissions to use the account.
function getAllActiveSigners() external view returns (SignerPermissions[] memory signers) {
address[] memory allSigners = _accountPermissionsStorage().allSigners.values();
uint256 len = allSigners.length;
uint256 numOfActiveSigners = 0;
for (uint256 i = 0; i < len; i += 1) {
if (isActiveSigner(allSigners[i])) {
numOfActiveSigners++;
} else {
allSigners[i] = address(0);
}
}
signers = new SignerPermissions[](numOfActiveSigners);
uint256 index = 0;
for (uint256 i = 0; i < len; i += 1) {
if (allSigners[i] != address(0)) {
address signer = allSigners[i];
SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer];
signers[index++] = SignerPermissions(
signer,
_accountPermissionsStorage().approvedTargets[signer].values(),
permissions.nativeTokenLimitPerTransaction,
permissions.startTimestamp,
permissions.endTimestamp
);
}
}
}
/// @notice Returns all admins of the account.
function getAllAdmins() external view returns (address[] memory) {
return _accountPermissionsStorage().allAdmins.values();
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @notice Runs after every `changeRole` run.
function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual;
/// @notice Makes the given account an admin.
function _setAdmin(address _account, bool _isAdmin) internal virtual {
_accountPermissionsStorage().isAdmin[_account] = _isAdmin;
if (_isAdmin) {
_accountPermissionsStorage().allAdmins.add(_account);
} else {
_accountPermissionsStorage().allAdmins.remove(_account);
}
emit AdminUpdated(_account, _isAdmin);
}
/// @dev Returns the address of the signer of the request.
function _recoverAddress(bytes memory _encoded, bytes calldata _signature) internal view virtual returns (address) {
return _hashTypedDataV4(keccak256(_encoded)).recover(_signature);
}
/// @dev Encodes a request for recovery of the signer in `recoverAddress`.
function _encodeRequest(SignerPermissionRequest calldata _req) internal pure virtual returns (bytes memory) {
return
abi.encode(
TYPEHASH,
_req.signer,
_req.isAdmin,
keccak256(abi.encodePacked(_req.approvedTargets)),
_req.nativeTokenLimitPerTransaction,
_req.permissionStartTimestamp,
_req.permissionEndTimestamp,
_req.reqValidityStartTimestamp,
_req.reqValidityEndTimestamp,
_req.uid
);
}
/// @dev Returns the AccountPermissions storage.
function _accountPermissionsStorage() internal pure returns (AccountPermissionsStorage.Data storage data) {
data = AccountPermissionsStorage.data();
}
}
contracts/prebuilts/account/interface/IAccountFactoryCore.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
interface IAccountFactoryCore {
/*///////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when a new Account is created.
event AccountCreated(address indexed account, address indexed accountAdmin);
/// @notice Emitted when a new signer is added to an Account.
event SignerAdded(address indexed account, address indexed signer);
/// @notice Emitted when a new signer is added to an Account.
event SignerRemoved(address indexed account, address indexed signer);
/*///////////////////////////////////////////////////////////////
Extension Functions
//////////////////////////////////////////////////////////////*/
/// @notice Deploys a new Account for admin.
function createAccount(address admin, bytes calldata _data) external returns (address account);
/*///////////////////////////////////////////////////////////////
View Functions
//////////////////////////////////////////////////////////////*/
/// @notice Returns the address of the Account implementation.
function accountImplementation() external view returns (address);
/// @notice Returns all accounts created on the factory.
function getAllAccounts() external view returns (address[] memory);
/// @notice Returns the address of an Account that would be deployed with the given admin signer.
function getAddress(address adminSigner, bytes calldata data) external view returns (address);
/// @notice Returns all accounts on which a signer has (active or inactive) permissions.
function getAccountsOfSigner(address signer) external view returns (address[] memory accounts);
}
lib/dynamic-contracts/src/interface/IRouterStateGetters.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IExtension.sol";
/// @title IRouterStateGetters.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Helper view functions to inspect a router's state.
interface IRouterStateGetters is IExtension {
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the extension metadata for a given function.
* @param functionSelector The function selector to get the extension metadata for.
* @return metadata The extension metadata for a given function.
*/
function getMetadataForFunction(bytes4 functionSelector) external view returns (ExtensionMetadata memory metadata);
/**
* @notice Returns the extension metadata and functions for a given extension.
* @param extensionName The name of the extension to get the metadata and functions for.
* @return extension The extension metadata and functions for a given extension.
*/
function getExtension(string memory extensionName) external view returns (Extension memory);
}
contracts/extension/upgradeable/ContractMetadata.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IContractMetadata.sol";
/**
* @author thirdweb.com
*
* @title Contract Metadata
* @notice Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/
library ContractMetadataStorage {
/// @custom:storage-location erc7201:contract.metadata.storage
/// @dev keccak256(abi.encode(uint256(keccak256("contract.metadata.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant CONTRACT_METADATA_STORAGE_POSITION =
0x4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da900;
struct Data {
/// @notice Returns the contract metadata URI.
string contractURI;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = CONTRACT_METADATA_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
abstract contract ContractMetadata is IContractMetadata {
/**
* @notice Lets a contract admin set the URI for contract-level metadata.
* @dev Caller should be authorized to setup contractURI, e.g. contract admin.
* See {_canSetContractURI}.
* Emits {ContractURIUpdated Event}.
*
* @param _uri keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function setContractURI(string memory _uri) external override {
if (!_canSetContractURI()) {
revert("Not authorized");
}
_setupContractURI(_uri);
}
/// @dev Lets a contract admin set the URI for contract-level metadata.
function _setupContractURI(string memory _uri) internal {
string memory prevURI = _contractMetadataStorage().contractURI;
_contractMetadataStorage().contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
/// @notice Returns the contract metadata URI.
function contractURI() public view virtual override returns (string memory) {
return _contractMetadataStorage().contractURI;
}
/// @dev Returns the AccountPermissions storage.
function _contractMetadataStorage() internal pure returns (ContractMetadataStorage.Data storage data) {
data = ContractMetadataStorage.data();
}
/// @dev Returns whether contract metadata can be set in the given execution context.
function _canSetContractURI() internal view virtual returns (bool);
}
contracts/prebuilts/account/utils/BaseAccount.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-empty-blocks */
import "../interface/IAccount.sol";
import "../interface/IEntrypoint.sol";
import "./Helpers.sol";
/**
* Basic account implementation.
* this contract provides the basic logic for implementing the IAccount interface - validateUserOp
* specific account implementation should inherit it and provide the account-specific logic
*/
abstract contract BaseAccount is IAccount {
using UserOperationLib for UserOperation;
//return value in case of signature failure, with no time-range.
// equivalent to _packValidationData(true,0,0);
uint256 internal constant SIG_VALIDATION_FAILED = 1;
/**
* Return the account nonce.
* This method returns the next sequential nonce.
* For a nonce of a specific key, use `entrypoint.getNonce(account, key)`
*/
function getNonce() public view virtual returns (uint256) {
return entryPoint().getNonce(address(this), 0);
}
/**
* return the entryPoint used by this account.
* subclass should return the current entryPoint used by this account.
*/
function entryPoint() public view virtual returns (IEntryPoint);
/**
* Validate user's signature and nonce.
* subclass doesn't need to override this method. Instead, it should override the specific internal validation methods.
*/
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external virtual override returns (uint256 validationData) {
_requireFromEntryPoint();
validationData = _validateSignature(userOp, userOpHash);
_validateNonce(userOp.nonce);
_payPrefund(missingAccountFunds);
}
/**
* ensure the request comes from the known entrypoint.
*/
function _requireFromEntryPoint() internal view virtual {
require(msg.sender == address(entryPoint()), "account: not from EntryPoint");
}
/**
* validate the signature is valid for this message.
* @param userOp validate the userOp.signature field
* @param userOpHash convenient field: the hash of the request, to check the signature against
* (also hashes the entrypoint and chain id)
* @return validationData signature and time-range of this operation
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* If the account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function _validateSignature(
UserOperation calldata userOp,
bytes32 userOpHash
) internal virtual returns (uint256 validationData);
/**
* Validate the nonce of the UserOperation.
* This method may validate the nonce requirement of this account.
* e.g.
* To limit the nonce to use sequenced UserOps only (no "out of order" UserOps):
* `require(nonce < type(uint64).max)`
* For a hypothetical account that *requires* the nonce to be out-of-order:
* `require(nonce & type(uint64).max == 0)`
*
* The actual nonce uniqueness is managed by the EntryPoint, and thus no other
* action is needed by the account itself.
*
* @param nonce to validate
*
* solhint-disable-next-line no-empty-blocks
*/
function _validateNonce(uint256 nonce) internal view virtual {}
/**
* sends to the entrypoint (msg.sender) the missing funds for this transaction.
* subclass MAY override this method for better funds management
* (e.g. send to the entryPoint more than the minimum required, so that in future transactions
* it will not be required to send again)
* @param missingAccountFunds the minimum value this method should send the entrypoint.
* this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster.
*/
function _payPrefund(uint256 missingAccountFunds) internal virtual {
if (missingAccountFunds != 0) {
(bool success, ) = payable(msg.sender).call{ value: missingAccountFunds, gas: type(uint256).max }("");
(success);
//ignore failure (its EntryPoint's job to verify, not account.)
}
}
}
contracts/prebuilts/account/interface/IAggregator.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import "../utils/UserOperation.sol";
/**
* Aggregated Signatures validator.
*/
interface IAggregator {
/**
* validate aggregated signature.
* revert if the aggregated signature does not match the given list of operations.
*/
function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view;
/**
* validate signature of a single userOp
* This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation
* First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps.
* @param userOp the userOperation received from the user.
* @return sigForUserOp the value to put into the signature field of the userOp when calling handleOps.
* (usually empty, unless account and aggregator support some kind of "multisig"
*/
function validateUserOpSignature(UserOperation calldata userOp) external view returns (bytes memory sigForUserOp);
/**
* aggregate multiple signatures into a single value.
* This method is called off-chain to calculate the signature to pass with handleOps()
* bundler MAY use optimized custom code perform this aggregation
* @param userOps array of UserOperations to collect the signatures from.
* @return aggregatedSignature the aggregated signature
*/
function aggregateSignatures(
UserOperation[] calldata userOps
) external view returns (bytes memory aggregatedSignature);
}
contracts/extension/interface/IAccountPermissions.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
interface IAccountPermissions {
/*///////////////////////////////////////////////////////////////
Types
//////////////////////////////////////////////////////////////*/
/**
* @notice The payload that must be signed by an authorized wallet to set permissions for a signer to use the smart wallet.
*
* @param signer The addres of the signer to give permissions.
* @param approvedTargets The list of approved targets that a role holder can call using the smart wallet.
* @param nativeTokenLimitPerTransaction The maximum value that can be transferred by a role holder in a single transaction.
* @param permissionStartTimestamp The UNIX timestamp at and after which a signer has permission to use the smart wallet.
* @param permissionEndTimestamp The UNIX timestamp at and after which a signer no longer has permission to use the smart wallet.
* @param reqValidityStartTimestamp The UNIX timestamp at and after which a signature is valid.
* @param reqValidityEndTimestamp The UNIX timestamp at and after which a signature is invalid/expired.
* @param uid A unique non-repeatable ID for the payload.
* @param isAdmin Whether the signer should be an admin.
*/
struct SignerPermissionRequest {
address signer;
uint8 isAdmin;
address[] approvedTargets;
uint256 nativeTokenLimitPerTransaction;
uint128 permissionStartTimestamp;
uint128 permissionEndTimestamp;
uint128 reqValidityStartTimestamp;
uint128 reqValidityEndTimestamp;
bytes32 uid;
}
/**
* @notice The permissions that a signer has to use the smart wallet.
*
* @param signer The address of the signer.
* @param approvedTargets The list of approved targets that a role holder can call using the smart wallet.
* @param nativeTokenLimitPerTransaction The maximum value that can be transferred by a role holder in a single transaction.
* @param startTimestamp The UNIX timestamp at and after which a signer has permission to use the smart wallet.
* @param endTimestamp The UNIX timestamp at and after which a signer no longer has permission to use the smart wallet.
*/
struct SignerPermissions {
address signer;
address[] approvedTargets;
uint256 nativeTokenLimitPerTransaction;
uint128 startTimestamp;
uint128 endTimestamp;
}
/**
* @notice Internal struct for storing permissions for a signer (without approved targets).
*
* @param nativeTokenLimitPerTransaction The maximum value that can be transferred by a role holder in a single transaction.
* @param startTimestamp The UNIX timestamp at and after which a signer has permission to use the smart wallet.
* @param endTimestamp The UNIX timestamp at and after which a signer no longer has permission to use the smart wallet.
*/
struct SignerPermissionsStatic {
uint256 nativeTokenLimitPerTransaction;
uint128 startTimestamp;
uint128 endTimestamp;
}
/*///////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when permissions for a signer are updated.
event SignerPermissionsUpdated(
address indexed authorizingSigner,
address indexed targetSigner,
SignerPermissionRequest permissions
);
/// @notice Emitted when an admin is set or removed.
event AdminUpdated(address indexed signer, bool isAdmin);
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @notice Returns whether the given account is an admin.
function isAdmin(address signer) external view returns (bool);
/// @notice Returns whether the given account is an active signer on the account.
function isActiveSigner(address signer) external view returns (bool);
/// @notice Returns the restrictions under which a signer can use the smart wallet.
function getPermissionsForSigner(address signer) external view returns (SignerPermissions memory permissions);
/// @notice Returns all active and inactive signers of the account.
function getAllSigners() external view returns (SignerPermissions[] memory signers);
/// @notice Returns all signers with active permissions to use the account.
function getAllActiveSigners() external view returns (SignerPermissions[] memory signers);
/// @notice Returns all admins of the account.
function getAllAdmins() external view returns (address[] memory admins);
/// @dev Verifies that a request is signed by an authorized account.
function verifySignerPermissionRequest(
SignerPermissionRequest calldata req,
bytes calldata signature
) external view returns (bool success, address signer);
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Sets the permissions for a given signer.
function setPermissionsForSigner(SignerPermissionRequest calldata req, bytes calldata signature) external;
}
contracts/prebuilts/account/interface/IAccount.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import "../utils/UserOperation.sol";
interface IAccount {
/**
* Validate user's signature and nonce
* the entryPoint will make the call to the recipient only if this validation call returns successfully.
* signature failure should be reported by returning SIG_VALIDATION_FAILED (1).
* This allows making a "simulation call" without a valid signature
* Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.
*
* @dev Must validate caller is the entryPoint.
* Must validate the signature and nonce
* @param userOp the operation that is about to be executed.
* @param userOpHash hash of the user's request data. can be used as the basis for signature.
* @param missingAccountFunds missing funds on the account's deposit in the entrypoint.
* This is the minimum amount to transfer to the sender(entryPoint) to be able to make the call.
* The excess is left as a deposit in the entrypoint, for future calls.
* can be withdrawn anytime using "entryPoint.withdrawTo()"
* In case there is a paymaster in the request (or the current deposit is high enough), this value will be zero.
* @return validationData packaged ValidationData structure. use `_packValidationData` and `_unpackValidationData` to encode and decode
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* If an account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
}
contracts/extension/upgradeable/Initializable.sol
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "../../lib/Address.sol";
library InitStorage {
/// @custom:storage-location erc7201:init.storage
/// @dev keccak256(abi.encode(uint256(keccak256("init.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 constant INIT_STORAGE_POSITION = 0x322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee0300;
/// @dev Layout of the entrypoint contract's storage.
struct Data {
uint8 initialized;
bool initializing;
}
/// @dev Returns the entrypoint contract's data at the relevant storage location.
function data() internal pure returns (Data storage data_) {
bytes32 position = INIT_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
abstract contract Initializable {
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
uint8 _initialized = _initStorage().initialized;
bool _initializing = _initStorage().initializing;
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initStorage().initialized = 1;
if (isTopLevelCall) {
_initStorage().initializing = true;
}
_;
if (isTopLevelCall) {
_initStorage().initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
uint8 _initialized = _initStorage().initialized;
bool _initializing = _initStorage().initializing;
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initStorage().initialized = version;
_initStorage().initializing = true;
_;
_initStorage().initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initStorage().initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
uint8 _initialized = _initStorage().initialized;
bool _initializing = _initStorage().initializing;
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initStorage().initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/// @dev Returns the InitStorage storage.
function _initStorage() internal pure returns (InitStorage.Data storage data) {
data = InitStorage.data();
}
}
contracts/eip/interface/IERC165.sol
// 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);
}
lib/dynamic-contracts/lib/sstore2/contracts/SSTORE2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./utils/Bytecode.sol";
/**
@title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost.
@author Agustin Aguilar <[email protected]>
Readme: https://github.com/0xsequence/sstore2#readme
*/
library SSTORE2 {
error WriteError();
/**
@notice Stores `_data` and returns `pointer` as key for later retrieval
@dev The pointer is a contract address with `_data` as code
@param _data to be written
@return pointer Pointer to the written `_data`
*/
function write(bytes memory _data) internal returns (address pointer) {
// Append 00 to _data so contract can't be called
// Build init code
bytes memory code = Bytecode.creationCodeFor(
abi.encodePacked(
hex'00',
_data
)
);
// Deploy contract using create
assembly { pointer := create(0, add(code, 32), mload(code)) }
// Address MUST be non-zero
if (pointer == address(0)) revert WriteError();
}
/**
@notice Reads the contents of the `_pointer` code as data, skips the first byte
@dev The function is intended for reading pointers generated by `write`
@param _pointer to be read
@return data read from `_pointer` contract
*/
function read(address _pointer) internal view returns (bytes memory) {
return Bytecode.codeAt(_pointer, 1, type(uint256).max);
}
/**
@notice Reads the contents of the `_pointer` code as data, skips the first byte
@dev The function is intended for reading pointers generated by `write`
@param _pointer to be read
@param _start number of bytes to skip
@return data read from `_pointer` contract
*/
function read(address _pointer, uint256 _start) internal view returns (bytes memory) {
return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max);
}
/**
@notice Reads the contents of the `_pointer` code as data, skips the first byte
@dev The function is intended for reading pointers generated by `write`
@param _pointer to be read
@param _start number of bytes to skip
@param _end index before which to end extraction
@return data read from `_pointer` contract
*/
function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) {
return Bytecode.codeAt(_pointer, _start + 1, _end + 1);
}
}
contracts/prebuilts/account/utils/AccountCoreStorage.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
library AccountCoreStorage {
/// @custom:storage-location erc7201:account.core.storage
/// @dev keccak256(abi.encode(uint256(keccak256("account.core.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant ACCOUNT_CORE_STORAGE_POSITION =
0x036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b548300;
struct Data {
address entrypointOverride;
bytes32 creationSalt;
}
function data() internal pure returns (Data storage acountCoreData) {
bytes32 position = ACCOUNT_CORE_STORAGE_POSITION;
assembly {
acountCoreData.slot := position
}
}
}
contracts/external-deps/openzeppelin/utils/structs/EnumerableSet.sol
// 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;
}
}
contracts/lib/Strings.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory str) {
str = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(str, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for {
let i := 0
} 1 {
} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) {
break
}
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
str := mload(0x40)
// Allocate the memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
str := add(str, 2)
mstore(str, 40)
let o := add(str, 0x20)
mstore(add(o, 40), 0)
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {
let i := 0
} 1 {
} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) {
break
}
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(raw)
str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(str, add(length, length)) // Store the length of the output.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(str, 0x20)
let end := add(raw, length)
for {
} iszero(eq(raw, end)) {
} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
}
lib/dynamic-contracts/src/lib/BaseRouterStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title BaseRouterStorage
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage for base router
library BaseRouterStorage {
/// @custom:storage-location erc7201:base.router.storage
bytes32 public constant BASE_ROUTER_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("base.router.storage")) - 1));
struct Data {
/// @dev Mapping used only for checking default extension validity in constructor.
mapping(bytes4 => bool) functionMap;
/// @dev Mapping used only for checking default extension validity in constructor.
mapping(string => bool) extensionMap;
}
/// @dev Returns access to base router storage.
function data() internal pure returns (Data storage data_) {
bytes32 position = BASE_ROUTER_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contracts/lib/BytesLib.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/// Credits: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol
library BytesLib {
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
}
lib/dynamic-contracts/lib/sstore2/contracts/utils/Bytecode.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library Bytecode {
error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end);
/**
@notice Generate a creation code that results on a contract with `_code` as bytecode
@param _code The returning value of the resulting `creationCode`
@return creationCode (constructor) for new contract
*/
function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) {
/*
0x00 0x63 0x63XXXXXX PUSH4 _code.length size
0x01 0x80 0x80 DUP1 size size
0x02 0x60 0x600e PUSH1 14 14 size size
0x03 0x60 0x6000 PUSH1 00 0 14 size size
0x04 0x39 0x39 CODECOPY size
0x05 0x60 0x6000 PUSH1 00 0 size
0x06 0xf3 0xf3 RETURN
<CODE>
*/
return abi.encodePacked(
hex"63",
uint32(_code.length),
hex"80_60_0E_60_00_39_60_00_F3",
_code
);
}
/**
@notice Returns the size of the code on a given address
@param _addr Address that may or may not contain code
@return size of the code on the given `_addr`
*/
function codeSize(address _addr) internal view returns (uint256 size) {
assembly { size := extcodesize(_addr) }
}
/**
@notice Returns the code of a given address
@dev It will fail if `_end < _start`
@param _addr Address that may or may not contain code
@param _start number of bytes of code to skip on read
@param _end index before which to end extraction
@return oCode read from `_addr` deployed bytecode
Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd
*/
function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) {
uint256 csize = codeSize(_addr);
if (csize == 0) return bytes("");
if (_start > csize) return bytes("");
if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end);
unchecked {
uint256 reqSize = _end - _start;
uint256 maxSize = csize - _start;
uint256 size = maxSize < reqSize ? maxSize : reqSize;
assembly {
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
oCode := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(oCode, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(oCode, 0x20), _start, size)
}
}
}
}
contracts/prebuilts/account/utils/AccountCore.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
/* solhint-disable reason-string */
// Base
import "./../utils/BaseAccount.sol";
// Fixed Extensions
import "../../../extension/Multicall.sol";
import "../../../extension/upgradeable/Initializable.sol";
import "../../../extension/upgradeable/AccountPermissions.sol";
// Utils
import "./Helpers.sol";
import "./AccountCoreStorage.sol";
import "./BaseAccountFactory.sol";
import { AccountExtension } from "./AccountExtension.sol";
import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol";
import "../interface/IAccountCore.sol";
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
contract AccountCore is IAccountCore, Initializable, Multicall, BaseAccount, AccountPermissions {
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.AddressSet;
/*///////////////////////////////////////////////////////////////
State
//////////////////////////////////////////////////////////////*/
/// @notice EIP 4337 factory for this contract.
address public immutable factory;
/// @notice EIP 4337 Entrypoint contract.
IEntryPoint private immutable entrypointContract;
/*///////////////////////////////////////////////////////////////
Constructor, Initializer, Modifiers
//////////////////////////////////////////////////////////////*/
constructor(IEntryPoint _entrypoint, address _factory) EIP712("Account", "1") {
_disableInitializers();
factory = _factory;
entrypointContract = _entrypoint;
}
/// @notice Initializes the smart contract wallet.
function initialize(address _defaultAdmin, bytes calldata _data) public virtual initializer {
// This is passed as data in the `_registerOnFactory()` call in `AccountExtension` / `Account`.
AccountCoreStorage.data().creationSalt = _generateSalt(_defaultAdmin, _data);
_setAdmin(_defaultAdmin, true);
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @notice Returns the EIP 4337 entrypoint contract.
function entryPoint() public view virtual override returns (IEntryPoint) {
address entrypointOverride = AccountCoreStorage.data().entrypointOverride;
if (address(entrypointOverride) != address(0)) {
return IEntryPoint(entrypointOverride);
}
return entrypointContract;
}
/**
@notice Returns whether a signer is authorized to perform transactions using the account.
Validity of the signature is based upon signer permission start/end timestamps, txn target, and txn value.
Account admins will always return true, and signers with address(0) as the only approved target will skip target checks.
@param _signer The signer to check.
@param _userOp The user operation to check.
@return Whether the signer is authorized to perform the transaction.
*/
/* solhint-disable*/
function isValidSigner(address _signer, UserOperation calldata _userOp) public view virtual returns (bool) {
// First, check if the signer is an admin.
if (_accountPermissionsStorage().isAdmin[_signer]) {
return true;
}
SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[_signer];
EnumerableSet.AddressSet storage approvedTargets = _accountPermissionsStorage().approvedTargets[_signer];
// If not an admin, check if the signer is active.
if (
permissions.startTimestamp > block.timestamp ||
block.timestamp >= permissions.endTimestamp ||
approvedTargets.length() == 0
) {
// Account: no active permissions.
return false;
}
// Extract the function signature from the userOp calldata and check whether the signer is attempting to call `execute` or `executeBatch`.
bytes4 sig = getFunctionSignature(_userOp.callData);
// if address(0) is the only approved target, set isWildCard to true (wildcard approved).
bool isWildCard = approvedTargets.length() == 1 && approvedTargets.at(0) == address(0);
// checking target and value for `execute`
if (sig == AccountExtension.execute.selector) {
// Extract the `target` and `value` arguments from the calldata for `execute`.
(address target, uint256 value) = decodeExecuteCalldata(_userOp.callData);
// if wildcard target is not approved, check that the target is in the approvedTargets set.
if (!isWildCard) {
// Check if the target is approved.
if (!approvedTargets.contains(target)) {
// Account: target not approved.
return false;
}
}
// Check if the value is within the allowed range.
if (permissions.nativeTokenLimitPerTransaction < value) {
// Account: value too high OR Account: target not approved.
return false;
}
}
// checking target and value for `executeBatch`
else if (sig == AccountExtension.executeBatch.selector) {
// Extract the `target` and `value` array arguments from the calldata for `executeBatch`.
(address[] memory targets, uint256[] memory values, ) = decodeExecuteBatchCalldata(_userOp.callData);
// if wildcard target is not approved, check that the targets are in the approvedTargets set.
if (!isWildCard) {
for (uint256 i = 0; i < targets.length; i++) {
if (!approvedTargets.contains(targets[i])) {
// If any target is not approved, break the loop.
return false;
}
}
}
// For each target+value pair, check if the value is within the allowed range.
for (uint256 i = 0; i < targets.length; i++) {
if (permissions.nativeTokenLimitPerTransaction < values[i]) {
// Account: value too high OR Account: target not approved.
return false;
}
}
} else {
// Account: calling invalid fn.
return false;
}
return true;
}
/* solhint-enable */
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Overrides the Entrypoint contract being used.
function setEntrypointOverride(IEntryPoint _entrypointOverride) public virtual {
_onlyAdmin();
AccountCoreStorage.data().entrypointOverride = address(_entrypointOverride);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Returns the salt used when deploying an Account.
function _generateSalt(address _admin, bytes memory _data) internal view virtual returns (bytes32) {
return keccak256(abi.encode(_admin, _data));
}
function getFunctionSignature(bytes calldata data) internal pure returns (bytes4 functionSelector) {
require(data.length >= 4, "!Data");
return bytes4(data[:4]);
}
function decodeExecuteCalldata(bytes calldata data) internal pure returns (address _target, uint256 _value) {
require(data.length >= 4 + 32 + 32, "!Data");
// Decode the address, which is bytes 4 to 35
_target = abi.decode(data[4:36], (address));
// Decode the value, which is bytes 36 to 68
_value = abi.decode(data[36:68], (uint256));
}
function decodeExecuteBatchCalldata(
bytes calldata data
) internal pure returns (address[] memory _targets, uint256[] memory _values, bytes[] memory _callData) {
require(data.length >= 4 + 32 + 32 + 32, "!Data");
(_targets, _values, _callData) = abi.decode(data[4:], (address[], uint256[], bytes[]));
}
/// @notice Validates the signature of a user operation.
function _validateSignature(
UserOperation calldata userOp,
bytes32 userOpHash
) internal virtual override returns (uint256 validationData) {
bytes32 hash = userOpHash.toEthSignedMessageHash();
address signer = hash.recover(userOp.signature);
if (!isValidSigner(signer, userOp)) return SIG_VALIDATION_FAILED;
SignerPermissionsStatic memory permissions = _accountPermissionsStorage().signerPermissions[signer];
uint48 validAfter = uint48(permissions.startTimestamp);
uint48 validUntil = uint48(permissions.endTimestamp);
return _packValidationData(ValidationData(address(0), validAfter, validUntil));
}
/// @notice Makes the given account an admin.
function _setAdmin(address _account, bool _isAdmin) internal virtual override {
super._setAdmin(_account, _isAdmin);
if (factory.code.length > 0) {
if (_isAdmin) {
BaseAccountFactory(factory).onSignerAdded(_account, AccountCoreStorage.data().creationSalt);
} else {
BaseAccountFactory(factory).onSignerRemoved(_account, AccountCoreStorage.data().creationSalt);
}
}
}
/// @notice Runs after every `changeRole` run.
function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual override {
if (factory.code.length > 0) {
BaseAccountFactory(factory).onSignerAdded(_req.signer, AccountCoreStorage.data().creationSalt);
}
}
}
contracts/prebuilts/account/utils/BaseAccountFactory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
// Utils
import "../../../extension/Multicall.sol";
import "../../../external-deps/openzeppelin/proxy/Clones.sol";
import "../../../external-deps/openzeppelin/utils/structs/EnumerableSet.sol";
import "../utils/BaseAccount.sol";
import "../../../extension/interface/IAccountPermissions.sol";
import "../../../lib/BytesLib.sol";
// Interface
import "../interface/IEntrypoint.sol";
import "../interface/IAccountFactory.sol";
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
abstract contract BaseAccountFactory is IAccountFactory, Multicall {
using EnumerableSet for EnumerableSet.AddressSet;
/*///////////////////////////////////////////////////////////////
State
//////////////////////////////////////////////////////////////*/
address public immutable accountImplementation;
address public immutable entrypoint;
EnumerableSet.AddressSet private allAccounts;
mapping(address => EnumerableSet.AddressSet) internal accountsOfSigner;
/*///////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor(address _accountImpl, address _entrypoint) {
accountImplementation = _accountImpl;
entrypoint = _entrypoint;
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Deploys a new Account for admin.
function createAccount(address _admin, bytes calldata _data) external virtual override returns (address) {
address impl = accountImplementation;
bytes32 salt = _generateSalt(_admin, _data);
address account = Clones.predictDeterministicAddress(impl, salt);
if (account.code.length > 0) {
return account;
}
account = Clones.cloneDeterministic(impl, salt);
if (msg.sender != entrypoint) {
require(allAccounts.add(account), "AccountFactory: account already registered");
}
_initializeAccount(account, _admin, _data);
emit AccountCreated(account, _admin);
return account;
}
/// @notice Callback function for an Account to register itself on the factory.
function onRegister(bytes32 _salt) external {
address account = msg.sender;
require(_isAccountOfFactory(account, _salt), "AccountFactory: not an account.");
require(allAccounts.add(account), "AccountFactory: account already registered");
}
function onSignerAdded(address _signer, bytes32 _salt) external {
address account = msg.sender;
require(_isAccountOfFactory(account, _salt), "AccountFactory: not an account.");
bool isNewSigner = accountsOfSigner[_signer].add(account);
if (isNewSigner) {
emit SignerAdded(account, _signer);
}
}
/// @notice Callback function for an Account to un-register its signers.
function onSignerRemoved(address _signer, bytes32 _salt) external {
address account = msg.sender;
require(_isAccountOfFactory(account, _salt), "AccountFactory: not an account.");
bool isAccount = accountsOfSigner[_signer].remove(account);
if (isAccount) {
emit SignerRemoved(account, _signer);
}
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @notice Returns whether an account is registered on this factory.
function isRegistered(address _account) external view returns (bool) {
return allAccounts.contains(_account);
}
/// @notice Returns the total number of accounts.
function totalAccounts() external view returns (uint256) {
return allAccounts.length();
}
/// @notice Returns all accounts between the given indices.
function getAccounts(uint256 _start, uint256 _end) external view returns (address[] memory accounts) {
require(_start < _end && _end <= allAccounts.length(), "BaseAccountFactory: invalid indices");
uint256 len = _end - _start;
accounts = new address[](_end - _start);
for (uint256 i = 0; i < len; i += 1) {
accounts[i] = allAccounts.at(i + _start);
}
}
/// @notice Returns all accounts created on the factory.
function getAllAccounts() external view returns (address[] memory) {
return allAccounts.values();
}
/// @notice Returns the address of an Account that would be deployed with the given admin signer.
function getAddress(address _adminSigner, bytes calldata _data) public view returns (address) {
bytes32 salt = _generateSalt(_adminSigner, _data);
return Clones.predictDeterministicAddress(accountImplementation, salt);
}
/// @notice Returns all accounts that the given address is a signer of.
function getAccountsOfSigner(address signer) external view returns (address[] memory accounts) {
return accountsOfSigner[signer].values();
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Returns whether the caller is an account deployed by this factory.
function _isAccountOfFactory(address _account, bytes32 _salt) internal view virtual returns (bool) {
address predicted = Clones.predictDeterministicAddress(accountImplementation, _salt);
return _account == predicted;
}
function _getImplementation(address cloneAddress) internal view returns (address) {
bytes memory code = cloneAddress.code;
return BytesLib.toAddress(code, 10);
}
/// @dev Returns the salt used when deploying an Account.
function _generateSalt(address _admin, bytes memory _data) internal view virtual returns (bytes32) {
return keccak256(abi.encode(_admin, _data));
}
/// @dev Called in `createAccount`. Initializes the account contract created in `createAccount`.
function _initializeAccount(address _account, address _admin, bytes calldata _data) internal virtual;
}
lib/dynamic-contracts/src/interface/IRouterState.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IExtension.sol";
/// @title ERC-7504 Dynamic Contracts: IRouterState.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defines an API to expose a router's extensions.
interface IRouterState is IExtension {
/*///////////////////////////////////////////////////////////////
View Functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns all extensions of the Router.
* @return allExtensions An array of all extensions.
*/
function getAllExtensions() external view returns (Extension[] memory allExtensions);
}
contracts/prebuilts/account/utils/UserOperation.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */
import { calldataKeccak } from "./Helpers.sol";
/**
* User Operation struct
* @param sender the sender account of this request.
* @param nonce unique value the sender uses to verify it is not a replay.
* @param initCode if set, the account contract will be created by this constructor/
* @param callData the method call to execute on this account.
* @param callGasLimit the gas limit passed to the callData method call.
* @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
* @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
* @param maxFeePerGas same as EIP-1559 gas parameter.
* @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
* @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender.
* @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID.
*/
struct UserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData;
bytes signature;
}
/**
* Utility functions helpful when working with UserOperation structs.
*/
library UserOperationLib {
function getSender(UserOperation calldata userOp) internal pure returns (address) {
address data;
//read sender from userOp, which is first userOp member (saves 800 gas...)
assembly {
data := calldataload(userOp)
}
return address(uint160(data));
}
//relayer/block builder might submit the TX with higher priorityFee, but the user should not
// pay above what he signed for.
function gasPrice(UserOperation calldata userOp) internal view returns (uint256) {
unchecked {
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
if (maxFeePerGas == maxPriorityFeePerGas) {
//legacy mode (for networks that don't support basefee opcode)
return maxFeePerGas;
}
return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
}
}
function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) {
address sender = getSender(userOp);
uint256 nonce = userOp.nonce;
bytes32 hashInitCode = calldataKeccak(userOp.initCode);
bytes32 hashCallData = calldataKeccak(userOp.callData);
uint256 callGasLimit = userOp.callGasLimit;
uint256 verificationGasLimit = userOp.verificationGasLimit;
uint256 preVerificationGas = userOp.preVerificationGas;
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);
return
abi.encode(
sender,
nonce,
hashInitCode,
hashCallData,
callGasLimit,
verificationGasLimit,
preVerificationGas,
maxFeePerGas,
maxPriorityFeePerGas,
hashPaymasterAndData
);
}
function hash(UserOperation calldata userOp) internal pure returns (bytes32) {
return keccak256(pack(userOp));
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
contracts/external-deps/openzeppelin/utils/cryptography/EIP712.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*/
abstract contract EIP712 {
/* solhint-disable var-name-mixedcase */
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS = address(this);
_TYPE_HASH = typeHash;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
contracts/external-deps/openzeppelin/token/ERC1155/IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../../../eip/interface/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
contracts/extension/interface/IContractMetadata.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
*
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/
interface IContractMetadata {
/// @dev Returns the metadata URI of the contract.
function contractURI() external view returns (string memory);
/**
* @dev Sets contract URI for the storefront-level metadata of the contract.
* Only module admin can call this function.
*/
function setContractURI(string calldata _uri) external;
/// @dev Emitted when the contract URI is updated.
event ContractURIUpdated(string prevURI, string newURI);
}
contracts/extension/interface/IMulticall.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @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);
}
contracts/external-deps/openzeppelin/token/ERC1155/utils/ERC1155Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.0;
import "./ERC1155Receiver.sol";
/**
* Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*
* @dev _Available since v3.1._
*/
contract ERC1155Holder is ERC1155Receiver {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}
contracts/eip/ERC165.sol
// 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;
}
}
lib/dynamic-contracts/src/interface/IRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ERC-7504 Dynamic Contracts: IRouter.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Routes an incoming call to an appropriate implementation address.
/// @dev Fallback function delegateCalls `getImplementationForFunction(msg.sig)` for a given incoming call.
/// NOTE: The ERC-165 identifier for this interface is 0xce0b6013.
interface IRouter {
/**
* @notice delegateCalls the appropriate implementation address for the given incoming function call.
* @dev The implementation address to delegateCall MUST be retrieved from calling `getImplementationForFunction` with the
* incoming call's function selector.
*/
fallback() external payable;
/*///////////////////////////////////////////////////////////////
View Functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the implementation address to delegateCall for the given function selector.
* @param _functionSelector The function selector to get the implementation address for.
* @return implementation The implementation address to delegateCall for the given function selector.
*/
function getImplementationForFunction(bytes4 _functionSelector) external view returns (address implementation);
}
contracts/external-deps/openzeppelin/utils/cryptography/ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../../../../lib/Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}
contracts/external-deps/openzeppelin/token/ERC721/IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
contracts/external-deps/openzeppelin/token/ERC1155/utils/ERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../IERC1155Receiver.sol";
import "../../../../../eip/ERC165.sol";
/**
* @dev _Available since v3.1._
*/
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
}
lib/dynamic-contracts/src/presets/ExtensionManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interface/IExtensionManager.sol";
import "../interface/IRouterState.sol";
import "../interface/IRouterStateGetters.sol";
import "../lib/ExtensionManagerStorage.sol";
/// @title ExtensionManager
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage and API for managing a router's extensions.
abstract contract ExtensionManager is IExtensionManager, IRouterState, IRouterStateGetters {
using StringSet for StringSet.Set;
/*///////////////////////////////////////////////////////////////
Modifier
//////////////////////////////////////////////////////////////*/
/// @notice Checks that a call to any external function is authorized.
modifier onlyAuthorizedCall() {
require(_isAuthorizedCallToUpgrade(), "ExtensionManager: unauthorized.");
_;
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns all extensions of the Router.
* @return allExtensions An array of all extensions.
*/
function getAllExtensions() external view virtual override returns (Extension[] memory allExtensions) {
string[] memory names = _extensionManagerStorage().extensionNames.values();
uint256 len = names.length;
allExtensions = new Extension[](len);
for (uint256 i = 0; i < len; i += 1) {
allExtensions[i] = _getExtension(names[i]);
}
}
/**
* @notice Returns the extension metadata for a given function.
* @param functionSelector The function selector to get the extension metadata for.
* @return metadata The extension metadata for a given function.
*/
function getMetadataForFunction(bytes4 functionSelector) public view virtual returns (ExtensionMetadata memory) {
return _extensionManagerStorage().extensionMetadata[functionSelector];
}
/**
* @notice Returns the extension metadata and functions for a given extension.
* @param extensionName The name of the extension to get the metadata and functions for.
* @return extension The extension metadata and functions for a given extension.
*/
function getExtension(string memory extensionName) public view virtual returns (Extension memory) {
return _getExtension(extensionName);
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Add a new extension to the router.
* @param _extension The extension to add.
*/
function addExtension(Extension memory _extension) public virtual onlyAuthorizedCall {
_addExtension(_extension);
}
/**
* @notice Fully replace an existing extension of the router.
* @dev The extension with name `extension.name` is the extension being replaced.
* @param _extension The extension to replace or overwrite.
*/
function replaceExtension(Extension memory _extension) public virtual onlyAuthorizedCall {
_replaceExtension(_extension);
}
/**
* @notice Remove an existing extension from the router.
* @param _extensionName The name of the extension to remove.
*/
function removeExtension(string memory _extensionName) public virtual onlyAuthorizedCall {
_removeExtension(_extensionName);
}
/**
* @notice Enables a single function in an existing extension.
* @dev Makes the given function callable on the router.
*
* @param _extensionName The name of the extension to which `extFunction` belongs.
* @param _function The function to enable.
*/
function enableFunctionInExtension(string memory _extensionName, ExtensionFunction memory _function) public virtual onlyAuthorizedCall {
_enableFunctionInExtension(_extensionName, _function);
}
/**
* @notice Disables a single function in an Extension.
*
* @param _extensionName The name of the extension to which the function of `functionSelector` belongs.
* @param _functionSelector The function to disable.
*/
function disableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) public virtual onlyAuthorizedCall {
_disableFunctionInExtension(_extensionName, _functionSelector);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Add a new extension to the router.
function _addExtension(Extension memory _extension) internal virtual {
// Check: extension namespace must not already exist.
// Check: provided extension namespace must not be empty.
// Check: provided extension implementation must be non-zero.
// Store: new extension name.
require(_canAddExtension(_extension), "ExtensionManager: cannot add extension.");
// 1. Store: metadata for extension.
_setMetadataForExtension(_extension.metadata.name, _extension.metadata);
uint256 len = _extension.functions.length;
for (uint256 i = 0; i < len; i += 1) {
// 2. Store: function for extension.
_addToFunctionMap(_extension.metadata.name, _extension.functions[i]);
// 3. Store: metadata for function.
_setMetadataForFunction(_extension.functions[i].functionSelector, _extension.metadata);
}
emit ExtensionAdded(_extension.metadata.name, _extension.metadata.implementation, _extension);
}
/// @dev Fully replace an existing extension of the router.
function _replaceExtension(Extension memory _extension) internal virtual {
// Check: extension namespace must already exist.
// Check: provided extension implementation must be non-zero.
require(_canReplaceExtension(_extension), "ExtensionManager: cannot replace extension.");
// 1. Store: metadata for extension.
_setMetadataForExtension(_extension.metadata.name, _extension.metadata);
// 2. Delete: existing extension.functions and metadata for each function.
_removeAllFunctionsFromExtension(_extension.metadata.name);
uint256 len = _extension.functions.length;
for (uint256 i = 0; i < len; i += 1) {
// 2. Store: function for extension.
_addToFunctionMap(_extension.metadata.name, _extension.functions[i]);
// 3. Store: metadata for function.
_setMetadataForFunction(_extension.functions[i].functionSelector, _extension.metadata);
}
emit ExtensionReplaced(_extension.metadata.name, _extension.metadata.implementation, _extension);
}
/// @dev Remove an existing extension from the router.
function _removeExtension(string memory _extensionName) internal virtual {
// Check: extension namespace must already exist.
// Delete: extension namespace.
require(_canRemoveExtension(_extensionName), "ExtensionManager: cannot remove extension.");
Extension memory extension = _extensionManagerStorage().extensions[_extensionName];
// 1. Delete: metadata for extension.
_deleteMetadataForExtension(_extensionName);
// 2. Delete: existing extension.functions and metadata for each function.
_removeAllFunctionsFromExtension(_extensionName);
emit ExtensionRemoved(_extensionName, extension);
}
/// @dev Makes the given function callable on the router.
function _enableFunctionInExtension(string memory _extensionName, ExtensionFunction memory _function) internal virtual {
// Check: extension namespace must already exist.
require(_canEnableFunctionInExtension(_extensionName, _function), "ExtensionManager: cannot Store: function for extension.");
// 1. Store: function for extension.
_addToFunctionMap(_extensionName, _function);
ExtensionMetadata memory metadata = _extensionManagerStorage().extensions[_extensionName].metadata;
// 2. Store: metadata for function.
_setMetadataForFunction(_function.functionSelector, metadata);
emit FunctionEnabled(_extensionName, _function.functionSelector, _function, metadata);
}
/// @dev Disables a single function in an Extension.
function _disableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) public virtual onlyAuthorizedCall {
// Check: extension namespace must already exist.
// Check: function must be mapped to provided extension.
require(_canDisableFunctionInExtension(_extensionName, _functionSelector), "ExtensionManager: cannot remove function from extension.");
ExtensionMetadata memory extMetadata = _extensionManagerStorage().extensionMetadata[_functionSelector];
// 1. Delete: function from extension.
_deleteFromFunctionMap(_extensionName, _functionSelector);
// 2. Delete: metadata for function.
_deleteMetadataForFunction(_functionSelector);
emit FunctionDisabled(_extensionName, _functionSelector, extMetadata);
}
/// @dev Returns the Extension for a given name.
function _getExtension(string memory _extensionName) internal view returns (Extension memory) {
return _extensionManagerStorage().extensions[_extensionName];
}
/// @dev Sets the ExtensionMetadata for a given extension.
function _setMetadataForExtension(string memory _extensionName, ExtensionMetadata memory _metadata) internal {
_extensionManagerStorage().extensions[_extensionName].metadata = _metadata;
}
/// @dev Deletes the ExtensionMetadata for a given extension.
function _deleteMetadataForExtension(string memory _extensionName) internal {
delete _extensionManagerStorage().extensions[_extensionName].metadata;
}
/// @dev Sets the ExtensionMetadata for a given function.
function _setMetadataForFunction(bytes4 _functionSelector, ExtensionMetadata memory _metadata) internal {
_extensionManagerStorage().extensionMetadata[_functionSelector] = _metadata;
}
/// @dev Deletes the ExtensionMetadata for a given function.
function _deleteMetadataForFunction(bytes4 _functionSelector) internal {
delete _extensionManagerStorage().extensionMetadata[_functionSelector];
}
/// @dev Adds a function to the function map of an extension.
function _addToFunctionMap(string memory _extensionName, ExtensionFunction memory _extFunction) internal virtual {
/**
* Note: `bytes4(0)` is the function selector for the `receive` function.
* So, we maintain a special fn selector-signature mismatch check for the `receive` function.
**/
bool mismatch = false;
if(_extFunction.functionSelector == bytes4(0)) {
mismatch = keccak256(abi.encode(_extFunction.functionSignature)) != keccak256(abi.encode("receive()"));
} else {
mismatch = _extFunction.functionSelector !=
bytes4(keccak256(abi.encodePacked(_extFunction.functionSignature)));
}
// Check: function selector and signature must match.
require(
!mismatch,
"ExtensionManager: fn selector and signature mismatch."
);
// Check: function must not already be mapped to an implementation.
require(
_extensionManagerStorage().extensionMetadata[_extFunction.functionSelector].implementation == address(0),
"ExtensionManager: function impl already exists."
);
// Store: name -> extension.functions map
_extensionManagerStorage().extensions[_extensionName].functions.push(_extFunction);
}
/// @dev Deletes a function from an extension's function map.
function _deleteFromFunctionMap(string memory _extensionName, bytes4 _functionSelector) internal {
ExtensionFunction[] memory extensionFunctions = _extensionManagerStorage().extensions[_extensionName].functions;
uint256 len = extensionFunctions.length;
for (uint256 i = 0; i < len; i += 1) {
if(extensionFunctions[i].functionSelector == _functionSelector) {
// Delete: particular function from name -> extension.functions map
_extensionManagerStorage().extensions[_extensionName].functions[i] = _extensionManagerStorage().extensions[_extensionName].functions[len - 1];
_extensionManagerStorage().extensions[_extensionName].functions.pop();
break;
}
}
}
/// @dev Removes all functions from an Extension.
function _removeAllFunctionsFromExtension(string memory _extensionName) internal {
ExtensionFunction[] memory functions = _extensionManagerStorage().extensions[_extensionName].functions;
// Delete: existing name -> extension.functions map
delete _extensionManagerStorage().extensions[_extensionName].functions;
for(uint256 i = 0; i < functions.length; i += 1) {
// Delete: metadata for function.
_deleteMetadataForFunction(functions[i].functionSelector);
}
}
/// @dev Returns whether a new extension can be added in the given execution context.
function _canAddExtension(Extension memory _extension) internal virtual returns (bool) {
// Check: provided extension namespace must not be empty.
require(bytes(_extension.metadata.name).length > 0, "ExtensionManager: empty name.");
// Check: extension namespace must not already exist.
// Store: new extension name.
require(_extensionManagerStorage().extensionNames.add(_extension.metadata.name), "ExtensionManager: extension already exists.");
// Check: extension implementation must be non-zero.
require(_extension.metadata.implementation != address(0), "ExtensionManager: adding extension without implementation.");
return true;
}
/// @dev Returns whether an extension can be replaced in the given execution context.
function _canReplaceExtension(Extension memory _extension) internal virtual returns (bool) {
// Check: extension namespace must already exist.
require(_extensionManagerStorage().extensionNames.contains(_extension.metadata.name), "ExtensionManager: extension does not exist.");
// Check: extension implementation must be non-zero.
require(_extension.metadata.implementation != address(0), "ExtensionManager: adding extension without implementation.");
return true;
}
/// @dev Returns whether an extension can be removed in the given execution context.
function _canRemoveExtension(string memory _extensionName) internal virtual returns (bool) {
// Check: extension namespace must already exist.
// Delete: extension namespace.
require(_extensionManagerStorage().extensionNames.remove(_extensionName), "ExtensionManager: extension does not exist.");
return true;
}
/// @dev Returns whether a function can be enabled in an extension in the given execution context.
function _canEnableFunctionInExtension(string memory _extensionName, ExtensionFunction memory) internal view virtual returns (bool) {
// Check: extension namespace must already exist.
require(_extensionManagerStorage().extensionNames.contains(_extensionName), "ExtensionManager: extension does not exist.");
return true;
}
/// @dev Returns whether a function can be disabled in an extension in the given execution context.
function _canDisableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) internal view virtual returns (bool) {
// Check: extension namespace must already exist.
require(_extensionManagerStorage().extensionNames.contains(_extensionName), "ExtensionManager: extension does not exist.");
// Check: function must be mapped to provided extension.
require(keccak256(abi.encode(_extensionManagerStorage().extensionMetadata[_functionSelector].name)) == keccak256(abi.encode(_extensionName)), "ExtensionManager: incorrect extension.");
return true;
}
/// @dev Returns the ExtensionManager storage.
function _extensionManagerStorage() internal pure returns (ExtensionManagerStorage.Data storage data) {
data = ExtensionManagerStorage.data();
}
/// @dev To override; returns whether all relevant permission and other checks are met before any upgrade.
function _isAuthorizedCallToUpgrade() internal view virtual returns (bool);
}
contracts/prebuilts/account/interface/INonceManager.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
interface INonceManager {
/**
* Return the next nonce for this sender.
* Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop)
* But UserOp with different keys can come with arbitrary order.
*
* @param sender the account address
* @param key the high 192 bit of the nonce
* @return nonce a full nonce to pass for next UserOp with this sender.
*/
function getNonce(address sender, uint192 key) external view returns (uint256 nonce);
/**
* Manually increment the nonce of the sender.
* This method is exposed just for completeness..
* Account does NOT need to call it, neither during validation, nor elsewhere,
* as the EntryPoint will update the nonce regardless.
* Possible use-case is call it with various keys to "initialize" their nonces to one, so that future
* UserOperations will not pay extra for the first transaction with a given key.
*/
function incrementNonce(uint192 key) external;
}
contracts/prebuilts/account/interface/IAccountCore.sol
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.12;
import "./IAccount.sol";
import "../../../extension/interface/IAccountPermissions.sol";
import "../../../extension/interface/IMulticall.sol";
interface IAccountCore is IAccount, IAccountPermissions, IMulticall {
/// @dev Returns the address of the factory from which the account was created.
function factory() external view returns (address);
}
contracts/external-deps/openzeppelin/proxy/Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
contracts/extension/Multicall.sol
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../lib/Address.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 returns (bytes[] memory results) {
results = new bytes[](data.length);
address sender = _msgSender();
bool isForwarder = msg.sender != sender;
for (uint256 i = 0; i < data.length; i++) {
if (isForwarder) {
results[i] = Address.functionDelegateCall(address(this), abi.encodePacked(data[i], sender));
} else {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
}
return results;
}
/// @notice Returns the sender in the given execution context.
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
}
lib/dynamic-contracts/src/core/Router.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interface/IRouter.sol";
/// @title ERC-7504 Dynamic Contracts: Router.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Routes an incoming call to an appropriate implementation address.
abstract contract Router is IRouter {
/**
* @notice delegateCalls the appropriate implementation address for the given incoming function call.
* @dev The implementation address to delegateCall MUST be retrieved from calling `getImplementationForFunction` with the
* incoming call's function selector.
*/
fallback() external payable virtual {
if(msg.data.length == 0) return;
address implementation = getImplementationForFunction(msg.sig);
require(implementation != address(0), "Router: function does not exist.");
_delegate(implementation);
}
/// @dev delegateCalls an `implementation` smart contract.
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())
}
}
}
/**
* @notice Returns the implementation address to delegateCall for the given function selector.
* @param _functionSelector The function selector to get the implementation address for.
* @return implementation The implementation address to delegateCall for the given function selector.
*/
function getImplementationForFunction(bytes4 _functionSelector) public view virtual returns (address implementation);
}
contracts/prebuilts/account/interface/IEntrypoint.sol
/**
** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
** Only one instance required on each chain.
**/
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
/* solhint-disable reason-string */
import "../utils/UserOperation.sol";
import "./IStakeManager.sol";
import "./IAggregator.sol";
import "./INonceManager.sol";
interface IEntryPoint is IStakeManager, INonceManager {
/***
* An event emitted after each successful request
* @param userOpHash - unique identifier for the request (hash its entire content, except signature).
* @param sender - the account that generates this request.
* @param paymaster - if non-null, the paymaster that pays for this request.
* @param nonce - the nonce value from the request.
* @param success - true if the sender transaction succeeded, false if reverted.
* @param actualGasCost - actual amount paid (by account or paymaster) for this UserOperation.
* @param actualGasUsed - total gas used by this UserOperation (including preVerification, creation, validation and execution).
*/
event UserOperationEvent(
bytes32 indexed userOpHash,
address indexed sender,
address indexed paymaster,
uint256 nonce,
bool success,
uint256 actualGasCost,
uint256 actualGasUsed
);
/**
* account "sender" was deployed.
* @param userOpHash the userOp that deployed this account. UserOperationEvent will follow.
* @param sender the account that is deployed
* @param factory the factory used to deploy this account (in the initCode)
* @param paymaster the paymaster used by this UserOp
*/
event AccountDeployed(bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster);
/**
* An event emitted if the UserOperation "callData" reverted with non-zero length
* @param userOpHash the request unique identifier.
* @param sender the sender of this request
* @param nonce the nonce used in the request
* @param revertReason - the return bytes from the (reverted) call to "callData".
*/
event UserOperationRevertReason(
bytes32 indexed userOpHash,
address indexed sender,
uint256 nonce,
bytes revertReason
);
/**
* an event emitted by handleOps(), before starting the execution loop.
* any event emitted before this event, is part of the validation.
*/
event BeforeExecution();
/**
* signature aggregator used by the following UserOperationEvents within this bundle.
*/
event SignatureAggregatorChanged(address indexed aggregator);
/**
* a custom revert error of handleOps, to identify the offending op.
* NOTE: if simulateValidation passes successfully, there should be no reason for handleOps to fail on it.
* @param opIndex - index into the array of ops to the failed one (in simulateValidation, this is always zero)
* @param reason - revert reason
* The string starts with a unique code "AAmn", where "m" is "1" for factory, "2" for account and "3" for paymaster issues,
* so a failure can be attributed to the correct entity.
* Should be caught in off-chain handleOps simulation and not happen on-chain.
* Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts.
*/
error FailedOp(uint256 opIndex, string reason);
/**
* error case when a signature aggregator fails to verify the aggregated signature it had created.
*/
error SignatureValidationFailed(address aggregator);
/**
* Successful result from simulateValidation.
* @param returnInfo gas and time-range returned values
* @param senderInfo stake information about the sender
* @param factoryInfo stake information about the factory (if any)
* @param paymasterInfo stake information about the paymaster (if any)
*/
error ValidationResult(ReturnInfo returnInfo, StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo);
/**
* Successful result from simulateValidation, if the account returns a signature aggregator
* @param returnInfo gas and time-range returned values
* @param senderInfo stake information about the sender
* @param factoryInfo stake information about the factory (if any)
* @param paymasterInfo stake information about the paymaster (if any)
* @param aggregatorInfo signature aggregation info (if the account requires signature aggregator)
* bundler MUST use it to verify the signature, or reject the UserOperation
*/
error ValidationResultWithAggregation(
ReturnInfo returnInfo,
StakeInfo senderInfo,
StakeInfo factoryInfo,
StakeInfo paymasterInfo,
AggregatorStakeInfo aggregatorInfo
);
/**
* return value of getSenderAddress
*/
error SenderAddressResult(address sender);
/**
* return value of simulateHandleOp
*/
error ExecutionResult(
uint256 preOpGas,
uint256 paid,
uint48 validAfter,
uint48 validUntil,
bool targetSuccess,
bytes targetResult
);
//UserOps handled, per aggregator
struct UserOpsPerAggregator {
UserOperation[] userOps;
// aggregator address
IAggregator aggregator;
// aggregated signature
bytes signature;
}
/**
* Execute a batch of UserOperation.
* no signature aggregator is used.
* if any account requires an aggregator (that is, it returned an aggregator when
* performing simulateValidation), then handleAggregatedOps() must be used instead.
* @param ops the operations to execute
* @param beneficiary the address to receive the fees
*/
function handleOps(UserOperation[] calldata ops, address payable beneficiary) external;
/**
* Execute a batch of UserOperation with Aggregators
* @param opsPerAggregator the operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts)
* @param beneficiary the address to receive the fees
*/
function handleAggregatedOps(
UserOpsPerAggregator[] calldata opsPerAggregator,
address payable beneficiary
) external;
/**
* generate a request Id - unique identifier for this request.
* the request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid.
*/
function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32);
/**
* Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp.
* @dev this method always revert. Successful result is ValidationResult error. other errors are failures.
* @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data.
* @param userOp the user operation to validate.
*/
function simulateValidation(UserOperation calldata userOp) external;
/**
* gas and return values during simulation
* @param preOpGas the gas used for validation (including preValidationGas)
* @param prefund the required prefund for this operation
* @param sigFailed validateUserOp's (or paymaster's) signature check failed
* @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range)
* @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range)
* @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp)
*/
struct ReturnInfo {
uint256 preOpGas;
uint256 prefund;
bool sigFailed;
uint48 validAfter;
uint48 validUntil;
bytes paymasterContext;
}
/**
* returned aggregated signature info.
* the aggregator returned by the account, and its current stake.
*/
struct AggregatorStakeInfo {
address aggregator;
StakeInfo stakeInfo;
}
/**
* Get counterfactual sender address.
* Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation.
* this method always revert, and returns the address in SenderAddressResult error
* @param initCode the constructor code to be passed into the UserOperation.
*/
function getSenderAddress(bytes memory initCode) external;
/**
* simulate full execution of a UserOperation (including both validation and target execution)
* this method will always revert with "ExecutionResult".
* it performs full validation of the UserOperation, but ignores signature error.
* an optional target address is called after the userop succeeds, and its value is returned
* (before the entire call is reverted)
* Note that in order to collect the success/failure of the target call, it must be executed
* with trace enabled to track the emitted events.
* @param op the UserOperation to simulate
* @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult
* are set to the return from that call.
* @param targetCallData callData to pass to target address
*/
function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external;
}
contracts/prebuilts/account/utils/Helpers.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */
/* solhint-disable func-visibility */
/**
* returned data from validateUserOp.
* validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData`
* @param aggregator - address(0) - the account validated the signature by itself.
* address(1) - the account failed to validate the signature.
* otherwise - this is an address of a signature aggregator that must be used to validate the signature.
* @param validAfter - this UserOp is valid only after this timestamp.
* @param validaUntil - this UserOp is valid only up to this timestamp.
*/
struct ValidationData {
address aggregator;
uint48 validAfter;
uint48 validUntil;
}
//extract sigFailed, validAfter, validUntil.
// also convert zero validUntil to type(uint48).max
function _parseValidationData(uint256 validationData) pure returns (ValidationData memory data) {
address aggregator = address(uint160(validationData));
uint48 validUntil = uint48(validationData >> 160);
if (validUntil == 0) {
validUntil = type(uint48).max;
}
uint48 validAfter = uint48(validationData >> (48 + 160));
return ValidationData(aggregator, validAfter, validUntil);
}
// intersect account and paymaster ranges.
function _intersectTimeRange(
uint256 validationData,
uint256 paymasterValidationData
) pure returns (ValidationData memory) {
ValidationData memory accountValidationData = _parseValidationData(validationData);
ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData);
address aggregator = accountValidationData.aggregator;
if (aggregator == address(0)) {
aggregator = pmValidationData.aggregator;
}
uint48 validAfter = accountValidationData.validAfter;
uint48 validUntil = accountValidationData.validUntil;
uint48 pmValidAfter = pmValidationData.validAfter;
uint48 pmValidUntil = pmValidationData.validUntil;
if (validAfter < pmValidAfter) validAfter = pmValidAfter;
if (validUntil > pmValidUntil) validUntil = pmValidUntil;
return ValidationData(aggregator, validAfter, validUntil);
}
/**
* helper to pack the return value for validateUserOp
* @param data - the ValidationData to pack
*/
function _packValidationData(ValidationData memory data) pure returns (uint256) {
return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48));
}
/**
* helper to pack the return value for validateUserOp, when not using an aggregator
* @param sigFailed - true for signature failure, false for success
* @param validUntil last timestamp this UserOperation is valid (or zero for infinite)
* @param validAfter first timestamp this UserOperation is valid
*/
function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) {
return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48));
}
/**
* keccak function over calldata.
* @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
*/
function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
assembly {
let mem := mload(0x40)
let len := data.length
calldatacopy(mem, data.offset, len)
ret := keccak256(mem, len)
}
}
contracts/lib/Address.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.1;
/// @author thirdweb, OpenZeppelin Contracts (v4.9.0)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
lib/dynamic-contracts/src/lib/StringSet.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library StringSet {
struct Set {
// Storage of set values
string[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(string => 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, string memory 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, string memory 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) {
string memory 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, string memory 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 (string memory) {
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 (string[] memory) {
return set._values;
}
/**
* @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, string memory value) internal returns (bool) {
return _add(set, 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(Set storage set, string memory value) internal returns (bool) {
return _remove(set, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Set storage set, string memory value) internal view returns (bool) {
return _contains(set, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Set storage set) internal view returns (uint256) {
return _length(set);
}
/**
* @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) internal view returns (string memory) {
return _at(set, 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) internal view returns (string[] memory) {
return _values(set);
}
}
contracts/prebuilts/account/managed/ManagedAccount.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
/* solhint-disable reason-string */
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
import "../utils/AccountCore.sol";
import "@thirdweb-dev/dynamic-contracts/src/core/Router.sol";
import "@thirdweb-dev/dynamic-contracts/src/interface/IRouterState.sol";
contract ManagedAccount is AccountCore, Router, IRouterState {
constructor(IEntryPoint _entrypoint, address _factory) AccountCore(_entrypoint, _factory) {}
/// @notice Returns the implementation contract address for a given function signature.
function getImplementationForFunction(bytes4 _functionSelector) public view virtual override returns (address) {
return Router(payable(factory)).getImplementationForFunction(_functionSelector);
}
/// @notice Returns all extensions of the Router.
function getAllExtensions() external view returns (Extension[] memory) {
return IRouterState(payable(factory)).getAllExtensions();
}
}
contracts/eip/ERC1271.sol
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
abstract contract ERC1271 {
// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 internal constant MAGICVALUE = 0x1626ba7e;
/**
* @dev Should return whether the signature provided is valid for the provided hash
* @param _hash Hash of the data to be signed
* @param _signature Signature byte array associated with _hash
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes32 _hash, bytes memory _signature) public view virtual returns (bytes4 magicValue);
}
Compiler Settings
{"remappings":[":@chainlink/=lib/chainlink/",":@ds-test/=lib/ds-test/src/",":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",":@std/=lib/forge-std/src/",":@thirdweb-dev/dynamic-contracts/=lib/dynamic-contracts/",":ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/",":ERC721A/=lib/ERC721A/contracts/",":chainlink/=lib/chainlink/contracts/",":contracts/=contracts/",":ds-test/=lib/ds-test/src/",":dynamic-contracts/=lib/dynamic-contracts/src/",":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",":erc721a-upgradeable/=lib/ERC721A-Upgradeable/",":erc721a/=lib/ERC721A/",":forge-std/=lib/forge-std/src/",":lib/sstore2/=lib/dynamic-contracts/lib/sstore2/",":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",":openzeppelin-contracts/=lib/openzeppelin-contracts/",":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",":sstore2/=lib/dynamic-contracts/lib/sstore2/contracts/"],"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":20,"enabled":true},"libraries":{},"evmVersion":"london"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_defaultAdmin","internalType":"address"},{"type":"address","name":"_entrypoint","internalType":"contract IEntryPoint"},{"type":"tuple[]","name":"_defaultExtensions","internalType":"struct IExtension.Extension[]","components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}]},{"type":"error","name":"InvalidCodeAtRange","inputs":[{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_start","internalType":"uint256"},{"type":"uint256","name":"_end","internalType":"uint256"}]},{"type":"error","name":"WriteError","inputs":[]},{"type":"event","name":"AccountCreated","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"accountAdmin","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ContractURIUpdated","inputs":[{"type":"string","name":"prevURI","internalType":"string","indexed":false},{"type":"string","name":"newURI","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"ExtensionAdded","inputs":[{"type":"string","name":"name","internalType":"string","indexed":true},{"type":"address","name":"implementation","internalType":"address","indexed":true},{"type":"tuple","name":"extension","internalType":"struct IExtension.Extension","indexed":false,"components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}],"anonymous":false},{"type":"event","name":"ExtensionRemoved","inputs":[{"type":"string","name":"name","internalType":"string","indexed":true},{"type":"tuple","name":"extension","internalType":"struct IExtension.Extension","indexed":false,"components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}],"anonymous":false},{"type":"event","name":"ExtensionReplaced","inputs":[{"type":"string","name":"name","internalType":"string","indexed":true},{"type":"address","name":"implementation","internalType":"address","indexed":true},{"type":"tuple","name":"extension","internalType":"struct IExtension.Extension","indexed":false,"components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}],"anonymous":false},{"type":"event","name":"FunctionDisabled","inputs":[{"type":"string","name":"name","internalType":"string","indexed":true},{"type":"bytes4","name":"functionSelector","internalType":"bytes4","indexed":true},{"type":"tuple","name":"extMetadata","internalType":"struct IExtension.ExtensionMetadata","indexed":false,"components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]}],"anonymous":false},{"type":"event","name":"FunctionEnabled","inputs":[{"type":"string","name":"name","internalType":"string","indexed":true},{"type":"bytes4","name":"functionSelector","internalType":"bytes4","indexed":true},{"type":"tuple","name":"extFunction","internalType":"struct IExtension.ExtensionFunction","indexed":false,"components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]},{"type":"tuple","name":"extMetadata","internalType":"struct IExtension.ExtensionMetadata","indexed":false,"components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SignerAdded","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"signer","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SignerRemoved","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"signer","internalType":"address","indexed":true}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"_disableFunctionInExtension","inputs":[{"type":"string","name":"_extensionName","internalType":"string"},{"type":"bytes4","name":"_functionSelector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"accountImplementation","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addExtension","inputs":[{"type":"tuple","name":"_extension","internalType":"struct IExtension.Extension","components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"contractURI","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"createAccount","inputs":[{"type":"address","name":"_admin","internalType":"address"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"defaultExtensions","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableFunctionInExtension","inputs":[{"type":"string","name":"_extensionName","internalType":"string"},{"type":"bytes4","name":"_functionSelector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"enableFunctionInExtension","inputs":[{"type":"string","name":"_extensionName","internalType":"string"},{"type":"tuple","name":"_function","internalType":"struct IExtension.ExtensionFunction","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"entrypoint","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"accounts","internalType":"address[]"}],"name":"getAccounts","inputs":[{"type":"uint256","name":"_start","internalType":"uint256"},{"type":"uint256","name":"_end","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"accounts","internalType":"address[]"}],"name":"getAccountsOfSigner","inputs":[{"type":"address","name":"signer","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getAddress","inputs":[{"type":"address","name":"_adminSigner","internalType":"address"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getAllAccounts","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"allExtensions","internalType":"struct IExtension.Extension[]","components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}],"name":"getAllExtensions","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IExtension.Extension","components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}],"name":"getExtension","inputs":[{"type":"string","name":"extensionName","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getImplementationForFunction","inputs":[{"type":"bytes4","name":"_functionSelector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]}],"name":"getMetadataForFunction","inputs":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"member","internalType":"address"}],"name":"getRoleMember","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"count","internalType":"uint256"}],"name":"getRoleMemberCount","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRoleWithSwitch","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isRegistered","inputs":[{"type":"address","name":"_account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes[]","name":"results","internalType":"bytes[]"}],"name":"multicall","inputs":[{"type":"bytes[]","name":"data","internalType":"bytes[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"onRegister","inputs":[{"type":"bytes32","name":"_salt","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"onSignerAdded","inputs":[{"type":"address","name":"_signer","internalType":"address"},{"type":"bytes32","name":"_salt","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"onSignerRemoved","inputs":[{"type":"address","name":"_signer","internalType":"address"},{"type":"bytes32","name":"_salt","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeExtension","inputs":[{"type":"string","name":"_extensionName","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"replaceExtension","inputs":[{"type":"tuple","name":"_extension","internalType":"struct IExtension.Extension","components":[{"type":"tuple","name":"metadata","internalType":"struct IExtension.ExtensionMetadata","components":[{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"metadataURI","internalType":"string"},{"type":"address","name":"implementation","internalType":"address"}]},{"type":"tuple[]","name":"functions","internalType":"struct IExtension.ExtensionFunction[]","components":[{"type":"bytes4","name":"functionSelector","internalType":"bytes4"},{"type":"string","name":"functionSignature","internalType":"string"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractURI","inputs":[{"type":"string","name":"_uri","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalAccounts","inputs":[]}]
Contract Creation Code
0x60e06040523480156200001157600080fd5b506040516200990938038062009909833981016040819052620000349162000ffc565b808230604051620000459062000c23565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801562000079573d6000803e3d6000fd5b506001600160a01b03908116608052831660a052805160009015620000d357620000a3826200013a565b620000d082604051602001620000ba91906200116e565b60408051601f19818403018152919052620001ee565b90505b6001600160a01b031660c05250620000ea62000259565b620000f7600084620002ac565b7f55add213c41f3851b4506717b8af695a4256979dff496dcaae7789f6121331aa620001248185620002ac565b620001308180620002c4565b505050506200147f565b8051600160005b82811015620001955762000177848281518110620001635762000163620011d6565b60200260200101516200032b60201b60201c565b9150811562000195576200018d60018262001202565b905062000141565b5080620001e95760405162461bcd60e51b815260206004820152601e60248201527f42617365526f757465723a20696e76616c696420657874656e73696f6e2e000060448201526064015b60405180910390fd5b505050565b6000806200021e8360405160200162000208919062001218565b60408051601f198184030181529190526200058d565b90508051602082016000f091506001600160a01b038216620002535760405163046a55db60e11b815260040160405180910390fd5b50919050565b60c0516001600160a01b03166200026c57565b60006200028160c051620005bb60201b60201c565b90506000818060200190518101906200029b919062001240565b9050620002a881620005d3565b5050565b620002b88282620007ad565b620002a8828262000827565b60008281527f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e5016020526040808220805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b805151516000901580159062000376575062000346620008f5565b60010182600001516000015160405162000361919062001278565b9081526040519081900360200190205460ff16155b80156200039057508151604001516001600160a01b031615155b905060016200039e620008f5565b600101836000015160000151604051620003b9919062001278565b908152604051908190036020019020805491151560ff1990921691909117905580620003e757506000919050565b60208201515160005b818110156200058657821562000586576000846020015182815181106200041b576200041b620011d6565b602090810291909101015180519091506000906001600160e01b031916620004b8576040516020016200046b9060208082526009908201526872656365697665282960b81b604082015260600190565b60405160208183030381529060405280519060200120826020015160405160200162000498919062001296565b604051602081830303815290604052805190602001201415905062000501565b602080830151604051620004cd920162001278565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916141590505b8015801562000536575062000515620008f5565b82516001600160e01b0319166000908152602091909152604090205460ff16155b9450600162000544620008f5565b92516001600160e01b03191660009081526020939093526040909220805460ff191692151592909217909155506200057e60018262001202565b9050620003f0565b5050919050565b6060815182604051602001620005a5929190620012ab565b6040516020818303038152906040529050919050565b6060620005cd82600160001962000956565b92915050565b60005b8151811015620002a8576000828281518110620005f757620005f7620011d6565b60200260200101519050620006258160000151600001516200061e62000a1460201b60201c565b9062000a20565b5080518051620006359162000a2e565b60208101515160005b818110156200072f576200065162000a14565b6002018360000151600001516040516200066c919062001278565b908152602001604051809103902060030183602001518281518110620006965762000696620011d6565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c919091178155918101519092820190620006e6908262001388565b5050506200071a83602001518281518110620007065762000706620011d6565b602090810291909101015151845162000ab0565b6200072760018262001202565b90506200063e565b508151604080820151915190516001600160a01b039092169162000754919062001278565b60405180910390207fbb37a605de78ba6bc667aeaf438d0aae8247e6f48a8fad23730e4fbbb480abf3846040516200078d919062001454565b60405180910390a350620007a5905060018262001202565b9050620005d6565b60008281527f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e500602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006200083362000ae8565b60008481526020919091526040902054905060016200085162000ae8565b60008581526020919091526040812080549091906200087290849062001202565b909155508290506200088362000ae8565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580620008c562000ae8565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b905090565b6000806200092560017f11c19c8d567686e9e4073585fe511ac02fcfc0ce76ceba4592185bf5bec3cd1f62001469565b6040516020016200093891815260200190565b60408051601f19818403018152919052805160209091012092915050565b6060833b60008190036200097b57505060408051602081019091526000815262000a0d565b808411156200099b57505060408051602081019091526000815262000a0d565b83831015620009cf5760405163162544fd60e11b8152600481018290526024810185905260448101849052606401620001e0565b8383038482036000828210620009e65782620009e8565b815b60408051603f8301601f19168101909152818152955090508087602087018a3c505050505b9392505050565b6000620008f062000af4565b600062000a0d838362000b24565b8062000a3962000a14565b6002018360405162000a4c919062001278565b9081526040519081900360200190208151819062000a6b908262001388565b506020820151600182019062000a82908262001388565b5060409190910151600290910180546001600160a01b0319166001600160a01b039092169190911790555050565b8062000abb62000a14565b6001600160e01b031984166000908152600391909101602052604090208151819062000a6b908262001388565b6000620008f062000b8f565b6000806200092560017f775b9fab5634a62bb2a682c067408edbed43efd726183d2e2af744334d47acb762001469565b600062000b32838362000bf4565b62000b865782546001810184556000848152602090200162000b55838262001388565b508254604051600185019062000b6d90859062001278565b90815260405190819003602001902055506001620005cd565b506000620005cd565b60008060ff1962000bc260017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c62001469565b60405160200162000bd591815260200190565b60408051601f1981840301815291905280516020909101201692915050565b6000826001018260405162000c0a919062001278565b9081526040519081900360200190205415159392505050565b613891806200607883390190565b6001600160a01b038116811462000c4757600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171562000c855762000c8562000c4a565b60405290565b604051606081016001600160401b038111828210171562000c855762000c8562000c4a565b604051601f8201601f191681016001600160401b038111828210171562000cdb5762000cdb62000c4a565b604052919050565b60006001600160401b0382111562000cff5762000cff62000c4a565b5060051b60200190565b60005b8381101562000d2657818101518382015260200162000d0c565b50506000910152565b600082601f83011262000d4157600080fd5b81516001600160401b0381111562000d5d5762000d5d62000c4a565b62000d72601f8201601f191660200162000cb0565b81815284602083860101111562000d8857600080fd5b62000d9b82602083016020870162000d09565b949350505050565b600082601f83011262000db557600080fd5b8151602062000dce62000dc88362000ce3565b62000cb0565b82815260059290921b8401810191818101908684111562000dee57600080fd5b8286015b8481101562000e905780516001600160401b038082111562000e145760008081fd5b908801906040828b03601f190181131562000e2f5760008081fd5b62000e3962000c60565b838801516001600160e01b03198116811462000e555760008081fd5b815290830151908282111562000e6b5760008081fd5b62000e7b8c898487010162000d2f565b81890152865250505091830191830162000df2565b509695505050505050565b600082601f83011262000ead57600080fd5b8151602062000ec062000dc88362000ce3565b82815260059290921b8401810191818101908684111562000ee057600080fd5b8286015b8481101562000e905780516001600160401b038082111562000f0557600080fd5b90880190601f196040838c038201121562000f1f57600080fd5b62000f2962000c60565b878401518381111562000f3b57600080fd5b84016060818e038401121562000f5057600080fd5b62000f5a62000c8b565b9250888101518481111562000f6e57600080fd5b62000f7e8e8b8385010162000d2f565b84525060408101518481111562000f9457600080fd5b62000fa48e8b8385010162000d2f565b848b0152506060015162000fb88162000c31565b80604084015250818152604084015191508282111562000fd757600080fd5b62000fe78c898487010162000da3565b81890152865250505091830191830162000ee4565b6000806000606084860312156200101257600080fd5b83516200101f8162000c31565b6020850151909350620010328162000c31565b60408501519092506001600160401b038111156200104f57600080fd5b6200105d8682870162000e9b565b9150509250925092565b600081518084526200108181602086016020860162000d09565b601f01601f19169290920160200192915050565b60006040825160408552805160606040870152620010b760a087018262001067565b9050602080830151603f19888403016060890152620010d7838262001067565b604094909401516001600160a01b03166080890152508581015187840382890152805180855290820193925081830190600581901b8401830160005b828110156200116057858203601f19018452865180516001600160e01b03191683528501518583018990526200114c8984018262001067565b978601979486019492505060010162001113565b509998505050505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015620011c957603f19888603018452620011b685835162001095565b9450928501929085019060010162001197565b5092979650505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115620005cd57620005cd620011ec565b60008152600082516200123381600185016020870162000d09565b9190910160010192915050565b6000602082840312156200125357600080fd5b81516001600160401b038111156200126a57600080fd5b62000d9b8482850162000e9b565b600082516200128c81846020870162000d09565b9190910192915050565b60208152600062000a0d602083018462001067565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201528151600090620012f081600e85016020870162000d09565b91909101600e019392505050565b600181811c908216806200131357607f821691505b6020821081036200025357634e487b7160e01b600052602260045260246000fd5b601f821115620001e9576000816000526020600020601f850160051c810160208610156200135f5750805b601f850160051c820191505b8181101562001380578281556001016200136b565b505050505050565b81516001600160401b03811115620013a457620013a462000c4a565b620013bc81620013b58454620012fe565b8462001334565b602080601f831160018114620013f45760008415620013db5750858301515b600019600386901b1c1916600185901b17855562001380565b600085815260208120601f198616915b82811015620014255788860151825594840194600190910190840162001404565b5085821015620014445787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208152600062000a0d602083018462001095565b81810381811115620005cd57620005cd620011ec565b60805160a05160c051614bad620014cb600039600061038401526000818161056101526114c70152600081816102aa01528181610d9d0152818161142301526117a10152614bad6000f3fe6080604052600436106101a45760003560e01c80639387a380116100e85780639387a380146104ad578063938e3d7b146104cd578063a0dbaefd146104ed578063a217fddf1461051a578063a32fa5b31461052f578063a65d69d41461054f578063ac9650d814610583578063c0562f6d146105b0578063c22707ee146105d0578063c3c5a547146105fd578063ca15c8731461061d578063ce0b60131461063d578063d547741f1461065d578063d8fd8f441461067d578063e05688fe1461069d578063e68a7c3b146106bd578063e8a3d485146106dd578063ee7d2adf146106ff576101a4565b806308e93d0a1461022d5780630b61e12b146102585780630e6254fd1461027857806311464fbe14610298578063248a9ca3146102e45780632f2ff15d1461031257806336568abe14610332578063429eed8014610352578063463c4864146103725780634a00cc48146103a6578063512cf914146103c857806358451f97146103e857806383a03f8c146103fd5780638856a1131461041d5780638878ed331461043d5780639010d07c1461045d57806391d148541461047d575b366000036101ae57005b60006101c56000356001600160e01b03191661071f565b90506001600160a01b0381166102225760405162461bcd60e51b815260206004820181905260248201527f526f757465723a2066756e6374696f6e20646f6573206e6f742065786973742e60448201526064015b60405180910390fd5b61022b81610734565b005b34801561023957600080fd5b5061024261075d565b60405161024f9190613d38565b60405180910390f35b34801561026457600080fd5b5061022b610273366004613da1565b61076e565b34801561028457600080fd5b50610242610293366004613dcb565b610806565b3480156102a457600080fd5b506102cc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024f565b3480156102f057600080fd5b506103046102ff366004613de6565b610830565b60405190815260200161024f565b34801561031e57600080fd5b5061022b61032d366004613dff565b61084e565b34801561033e57600080fd5b5061022b61034d366004613dff565b6108f8565b34801561035e57600080fd5b5061022b61036d366004613f42565b610957565b34801561037e57600080fd5b506102cc7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103b257600080fd5b506103bb610bce565b60405161024f91906140c5565b3480156103d457600080fd5b5061022b6103e3366004613f42565b610c9d565b3480156103f457600080fd5b50610304610ccb565b34801561040957600080fd5b5061022b610418366004613de6565b610cd7565b34801561042957600080fd5b5061022b610438366004614181565b610d25565b34801561044957600080fd5b506102cc6104583660046141e4565b610d53565b34801561046957600080fd5b506102cc610478366004614266565b610dcd565b34801561048957600080fd5b5061049d610498366004613dff565b610edb565b604051901515815260200161024f565b3480156104b957600080fd5b5061022b6104c8366004613da1565b610f0f565b3480156104d957600080fd5b5061022b6104e8366004614288565b610fa6565b3480156104f957600080fd5b5061050d6105083660046142bc565b610ff7565b60405161024f91906142d7565b34801561052657600080fd5b50610304600081565b34801561053b57600080fd5b5061049d61054a366004613dff565b61116d565b34801561055b57600080fd5b506102cc7f000000000000000000000000000000000000000000000000000000000000000081565b34801561058f57600080fd5b506105a361059e3660046142ea565b6111d0565b60405161024f919061435e565b3480156105bc57600080fd5b5061022b6105cb366004614453565b61132c565b3480156105dc57600080fd5b506105f06105eb366004614288565b611359565b60405161024f9190614544565b34801561060957600080fd5b5061049d610618366004613dcb565b61136a565b34801561062957600080fd5b50610304610638366004613de6565b611376565b34801561064957600080fd5b506102cc6106583660046142bc565b61071f565b34801561066957600080fd5b5061022b610678366004613dff565b611413565b34801561068957600080fd5b506102cc6106983660046141e4565b61141e565b3480156106a957600080fd5b5061022b6106b8366004614453565b611569565b3480156106c957600080fd5b506102426106d8366004614266565b611596565b3480156106e957600080fd5b506106f26116c7565b60405161024f9190614557565b34801561070b57600080fd5b5061022b61071a366004614288565b61175f565b600061072a82610ff7565b6040015192915050565b3660008037600080366000845af43d6000803e808015610753573d6000f35b3d6000fd5b505050565b6060610769600061178c565b905090565b336107798183611799565b6107955760405162461bcd60e51b81526004016102199061456a565b6001600160a01b03831660009081526002602052604081206107b790836117dd565b9050801561080057836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061082a9061178c565b92915050565b600061083a6117f2565b600092835260010160205250604090205490565b6108726108596117f2565b6000848152600191909101602052604090205433611816565b61087a6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156108ea5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610219565b6108f4828261189b565b5050565b336001600160a01b0382161461094d5760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610219565b6108f482826118af565b61095f6118c3565b61097b5760405162461bcd60e51b8152600401610219906145a1565b61098582826118ef565b6109f25760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f766520604482015277333ab731ba34b7b710333937b69032bc3a32b739b4b7b71760411b6064820152608401610219565b60006109fc6119ee565b6001600160e01b031983166000908152600391909101602052604090819020815160608101909252805482908290610a33906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5f906145d8565b8015610aac5780601f10610a8157610100808354040283529160200191610aac565b820191906000526020600020905b815481529060010190602001808311610a8f57829003601f168201915b50505050508152602001600182018054610ac5906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610af1906145d8565b8015610b3e5780601f10610b1357610100808354040283529160200191610b3e565b820191906000526020600020905b815481529060010190602001808311610b2157829003601f168201915b5050509183525050600291909101546001600160a01b03166020909101529050610b6883836119f8565b610b7182611cc5565b816001600160e01b03191683604051610b8a919061460c565b60405180910390207fbb931a9651175c9c82f86afbf6ad37a9141aa8d1d42bf798739be245a12e4e8883604051610bc191906142d7565b60405180910390a3505050565b60606000610be2610bdd6119ee565b611d18565b8051909150806001600160401b03811115610bff57610bff613e2b565b604051908082528060200260200182016040528015610c3857816020015b610c25613c4f565b815260200190600190039081610c1d5790505b50925060005b81811015610c9757610c68838281518110610c5b57610c5b614628565b6020026020010151611d23565b848281518110610c7a57610c7a614628565b6020908102919091010152610c90600182614654565b9050610c3e565b50505090565b610ca56118c3565b610cc15760405162461bcd60e51b8152600401610219906145a1565b6108f48282610957565b60006107696000611fac565b33610ce28183611799565b610cfe5760405162461bcd60e51b81526004016102199061456a565b610d096000826117dd565b6108f45760405162461bcd60e51b815260040161021990614667565b610d2d6118c3565b610d495760405162461bcd60e51b8152600401610219906145a1565b6108f48282611fb6565b600080610d968585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b9050610dc27f000000000000000000000000000000000000000000000000000000000000000082612238565b9150505b9392505050565b600080610dd8612298565b600085815260209190915260408120549150805b82811015610ed2576000610dfe612298565b60008881526020918252604080822085835260010190925220546001600160a01b031614610e7657848203610e6457610e35612298565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061082a915050565b610e6f600183614654565b9150610ec0565b610e81866000610edb565b8015610ead5750610e90612298565b600087815260209182526040808220828052600201909252205481145b15610ec057610ebd600183614654565b91505b610ecb600182614654565b9050610dec565b50505092915050565b6000610ee56117f2565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b33610f1a8183611799565b610f365760405162461bcd60e51b81526004016102199061456a565b6001600160a01b0383166000908152600260205260408120610f5890836122a2565b9050801561080057836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610fae6122b7565b610feb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610219565b610ff4816122c3565b50565b610fff613c6f565b6110076119ee565b6001600160e01b03198316600090815260039190910160205260409081902081516060810190925280548290829061103e906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461106a906145d8565b80156110b75780601f1061108c576101008083540402835291602001916110b7565b820191906000526020600020905b81548152906001019060200180831161109a57829003601f168201915b505050505081526020016001820180546110d0906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546110fc906145d8565b80156111495780601f1061111e57610100808354040283529160200191611149565b820191906000526020600020905b81548152906001019060200180831161112c57829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015292915050565b60006111776117f2565b600084815260209182526040808220828052909252205460ff166111c75761119d6117f2565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061082a565b50600192915050565b6060816001600160401b038111156111ea576111ea613e2b565b60405190808252806020026020018201604052801561121d57816020015b60608152602001906001900390816112085790505b509050336000805b84811015610ed25781156112a4576112823087878481811061124957611249614628565b905060200281019061125b91906146b1565b8660405160200161126e939291906146fe565b6040516020818303038152906040526123aa565b84828151811061129457611294614628565b6020026020010181905250611324565b611306308787848181106112ba576112ba614628565b90506020028101906112cc91906146b1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123aa92505050565b84828151811061131857611318614628565b60200260200101819052505b600101611225565b6113346118c3565b6113505760405162461bcd60e51b8152600401610219906145a1565b610ff4816123cf565b611361613c4f565b61082a82611d23565b600061082a8183612538565b600080611381612298565b6000848152602091909152604081205491505b818110156113ee5760006113a6612298565b60008681526020918252604080822085835260010190925220546001600160a01b0316146113dc576113d9600184614654565b92505b6113e7600182614654565b9050611394565b506113fa836000610edb565b1561140d5761140a600183614654565b91505b50919050565b61094d6108596117f2565b6000807f0000000000000000000000000000000000000000000000000000000000000000905060006114868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b905060006114948383612238565b90506001600160a01b0381163b156114b0579250610dc6915050565b6114ba838361255a565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611513576114f76000826117dd565b6115135760405162461bcd60e51b815260040161021990614667565b61151f818888886125f1565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b6115716118c3565b61158d5760405162461bcd60e51b8152600401610219906145a1565b610ff481612659565b606081831080156115b057506115ac6000611fac565b8211155b6116085760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610219565b6000611614848461471f565b9050611620848461471f565b6001600160401b0381111561163757611637613e2b565b604051908082528060200260200182016040528015611660578160200160208202803683370190505b50915060005b818110156116bf5761168361167b8683614654565b600090612783565b83828151811061169557611695614628565b6001600160a01b03909216602092830291909101909101526116b8600182614654565b9050611666565b505092915050565b60606116d161278f565b80546116dc906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611708906145d8565b80156117555780601f1061172a57610100808354040283529160200191611755565b820191906000526020600020905b81548152906001019060200180831161173857829003601f168201915b5050505050905090565b6117676118c3565b6117835760405162461bcd60e51b8152600401610219906145a1565b610ff4816127b3565b60606000610dc683612afd565b6000806117c67f000000000000000000000000000000000000000000000000000000000000000084612238565b6001600160a01b0385811691161491505092915050565b6000610dc6836001600160a01b038416612b59565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b61181e6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166108f457611859816001600160a01b03166014612ba8565b611864836020612ba8565b604051602001611875929190614732565b60408051601f198184030181529082905262461bcd60e51b825261021991600401614557565b6118a58282612d43565b6108f48282612dac565b6118b98282612e6b565b6108f48282612ed4565b60006107697f55add213c41f3851b4506717b8af695a4256979dff496dcaae7789f6121331aa33610edb565b6000611903836118fd6119ee565b90612f63565b61191f5760405162461bcd60e51b81526004016102199061479f565b826040516020016119309190614557565b6040516020818303038152906040528051906020012061194e6119ee565b6001600160e01b0319841660009081526003919091016020908152604091829020915161197c9291016147ea565b60405160208183030381529060405280519060200120146111c75760405162461bcd60e51b815260206004820152602660248201527f457874656e73696f6e4d616e616765723a20696e636f727265637420657874656044820152653739b4b7b71760d11b6064820152608401610219565b6000610769612f6f565b6000611a026119ee565b60020183604051611a13919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b82821015611b215760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611a90906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611abc906145d8565b8015611b095780601f10611ade57610100808354040283529160200191611b09565b820191906000526020600020905b815481529060010190602001808311611aec57829003601f168201915b50505050508152505081526020019060010190611a44565b5050825192935060009150505b81811015611cbe57836001600160e01b031916838281518110611b5357611b53614628565b6020026020010151600001516001600160e01b03191603611cac57611b766119ee565b60020185604051611b87919061460c565b908152604051908190036020019020600301611ba460018461471f565b81548110611bb457611bb4614628565b9060005260206000209060020201611bca6119ee565b60020186604051611bdb919061460c565b90815260200160405180910390206003018281548110611bfd57611bfd614628565b600091825260209091208254600290920201805463ffffffff191663ffffffff909216919091178155600180820190611c38908401826148d7565b50905050611c446119ee565b60020185604051611c55919061460c565b9081526020016040518091039020600301805480611c7557611c756149ad565b600082815260208120600260001990930192830201805463ffffffff1916815590611ca36001830182613c99565b50509055611cbe565b611cb7600182614654565b9050611b2e565b5050505050565b611ccd6119ee565b6001600160e01b0319821660009081526003919091016020526040812090611cf58282613c99565b611d03600183016000613c99565b5060020180546001600160a01b031916905550565b606061082a82612fcd565b611d2b613c4f565b611d336119ee565b60020182604051611d44919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290611d73906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9f906145d8565b8015611dec5780601f10611dc157610100808354040283529160200191611dec565b820191906000526020600020905b815481529060010190602001808311611dcf57829003601f168201915b50505050508152602001600182018054611e05906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611e31906145d8565b8015611e7e5780601f10611e5357610100808354040283529160200191611e7e565b820191906000526020600020905b815481529060010190602001808311611e6157829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015611f9e5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611f0d906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611f39906145d8565b8015611f865780601f10611f5b57610100808354040283529160200191611f86565b820191906000526020600020905b815481529060010190602001808311611f6957829003601f168201915b50505050508152505081526020019060010190611ec1565b505050915250909392505050565b600061082a825490565b611fc082826130aa565b61202c5760405162461bcd60e51b815260206004820152603760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742053746f72653a20604482015276333ab731ba34b7b7103337b91032bc3a32b739b4b7b71760491b6064820152608401610219565b61203682826130d4565b60006120406119ee565b60020183604051612051919061460c565b9081526040805191829003602001822060608301909152805482908290612077906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546120a3906145d8565b80156120f05780601f106120c5576101008083540402835291602001916120f0565b820191906000526020600020905b8154815290600101906020018083116120d357829003601f168201915b50505050508152602001600182018054612109906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612135906145d8565b80156121825780601f1061215757610100808354040283529160200191612182565b820191906000526020600020905b81548152906001019060200180831161216557829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015282519091506121af9082613322565b81600001516001600160e01b031916836040516121cc919061460c565b60405180910390207f681115194e519bda23de4da5218f3bc38f5585eab7c6b7d5fa66caa4602f574d8484604051610bc19291906149c3565b6000828260405160200161221a9291906149e8565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610dc6565b6000610769613399565b6000610dc6836001600160a01b0384166133fb565b60006107698133610edb565b60006122cd61278f565b80546122d8906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612304906145d8565b80156123515780601f1061232657610100808354040283529160200191612351565b820191906000526020600020905b81548152906001019060200180831161233457829003601f168201915b505050505090508161236161278f565b9061236c9082614a0c565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a16818360405161239e929190614abd565b60405180910390a15050565b6060610dc68383604051806060016040528060278152602001614b51602791396134ee565b6123d881613566565b6124385760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74207265706c61636560448201526a1032bc3a32b739b4b7b71760a91b6064820152608401610219565b805180516124459161361a565b80515161245190613651565b60208101515160005b818110156124d2576124918360000151600001518460200151838151811061248457612484614628565b60200260200101516130d4565b6124c0836020015182815181106124aa576124aa614628565b6020026020010151600001518460000151613322565b6124cb600182614654565b905061245a565b508151604080820151915190516001600160a01b03909216916124f5919061460c565b60405180910390207f5f1ef2b136db521971a88818ce904a8e310082338afdc100212a3127066421588460405161252c9190614544565b60405180910390a35050565b6001600160a01b03811660009081526001830160205260408120541515610dc6565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661082a5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610219565b60405163347d5e2560e21b81526001600160a01b0385169063d1f578949061262190869086908690600401614ae2565b600060405180830381600087803b15801561263b57600080fd5b505af115801561264f573d6000803e3d6000fd5b5050505050505050565b612662816137fa565b6126be5760405162461bcd60e51b815260206004820152602760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74206164642065787460448201526632b739b4b7b71760c91b6064820152608401610219565b805180516126cb9161361a565b60208101515160005b81811015612729576126fe8360000151600001518460200151838151811061248457612484614628565b612717836020015182815181106124aa576124aa614628565b612722600182614654565b90506126d4565b508151604080820151915190516001600160a01b039092169161274c919061460c565b60405180910390207fbb37a605de78ba6bc667aeaf438d0aae8247e6f48a8fad23730e4fbbb480abf38460405161252c9190614544565b6000610dc683836138c2565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b6127bc816138ec565b61281b5760405162461bcd60e51b815260206004820152602a60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f76652060448201526932bc3a32b739b4b7b71760b11b6064820152608401610219565b60006128256119ee565b60020182604051612836919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290612865906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612891906145d8565b80156128de5780601f106128b3576101008083540402835291602001916128de565b820191906000526020600020905b8154815290600101906020018083116128c157829003601f168201915b505050505081526020016001820180546128f7906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612923906145d8565b80156129705780601f1061294557610100808354040283529160200191612970565b820191906000526020600020905b81548152906001019060200180831161295357829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015612a905760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916129ff906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612a2b906145d8565b8015612a785780601f10612a4d57610100808354040283529160200191612a78565b820191906000526020600020905b815481529060010190602001808311612a5b57829003601f168201915b505050505081525050815260200190600101906129b3565b50505050815250509050612aa38261391c565b612aac82613651565b81604051612aba919061460c565b60405180910390207f3169a23cec9ad1a25ab59bbe00ecf8973dd840c745775ea8877041ef5ce65bcc82604051612af19190614544565b60405180910390a25050565b606081600001805480602002602001604051908101604052809291908181526020018280548015612b4d57602002820191906000526020600020905b815481526020019060010190808311612b39575b50505050509050919050565b6000818152600183016020526040812054612ba05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561082a565b50600061082a565b60606000612bb7836002614b22565b612bc2906002614654565b6001600160401b03811115612bd957612bd9613e2b565b6040519080825280601f01601f191660200182016040528015612c03576020820181803683370190505b509050600360fc1b81600081518110612c1e57612c1e614628565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612c4d57612c4d614628565b60200101906001600160f81b031916908160001a9053506000612c71846002614b22565b612c7c906001614654565b90505b6001811115612cf4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612cb057612cb0614628565b1a60f81b828281518110612cc657612cc6614628565b60200101906001600160f81b031916908160001a90535060049490941c93612ced81614b39565b9050612c7f565b508315610dc65760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610219565b6001612d4d6117f2565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000612db6612298565b6000848152602091909152604090205490506001612dd2612298565b6000858152602091909152604081208054909190612df1908490614654565b90915550829050612e00612298565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580612e40612298565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b612e758282611816565b612e7d6117f2565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000612ede612298565b6000848152602091825260408082206001600160a01b038616835260020190925220549050612f0b612298565b6000848152602091825260408082208483526001019092522080546001600160a01b0319169055612f3a612298565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b6000610dc68383613950565b600080612f9d60017f775b9fab5634a62bb2a682c067408edbed43efd726183d2e2af744334d47acb761471f565b604051602001612faf91815260200190565b60408051601f19818403018152919052805160209091012092915050565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561309f578382906000526020600020018054613012906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461303e906145d8565b801561308b5780601f106130605761010080835404028352916020019161308b565b820191906000526020600020905b81548152906001019060200180831161306e57829003601f168201915b505050505081526020019060010190612ff3565b505050509050919050565b60006130b8836118fd6119ee565b6111c75760405162461bcd60e51b81526004016102199061479f565b80516000906001600160e01b03191661315e576040516020016131149060208082526009908201526872656365697665282960b81b604082015260600190565b60405160208183030381529060405280519060200120826020015160405160200161313f9190614557565b60405160208183030381529060405280519060200120141590506131a5565b602080830151604051613171920161460c565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916141590505b80156132115760405162461bcd60e51b815260206004820152603560248201527f457874656e73696f6e4d616e616765723a20666e2073656c6563746f7220616e604482015274321039b4b3b730ba3ab9329036b4b9b6b0ba31b41760591b6064820152608401610219565b600061321b6119ee565b83516001600160e01b031916600090815260039190910160205260409020600201546001600160a01b0316146132ab5760405162461bcd60e51b815260206004820152602f60248201527f457874656e73696f6e4d616e616765723a2066756e6374696f6e20696d706c2060448201526e30b63932b0b23c9032bc34b9ba399760891b6064820152608401610219565b6132b36119ee565b600201836040516132c4919061460c565b908152604051602091819003820190206003018054600180820183556000928352918390208551600290920201805463ffffffff191660e09290921c9190911781559184015184929182019061331a9082614a0c565b505050505050565b8061332b6119ee565b6001600160e01b03198416600090815260039190910160205260409020815181906133569082614a0c565b506020820151600182019061336b9082614a0c565b5060409190910151600290910180546001600160a01b0319166001600160a01b039092169190911790555050565b60008060ff196133ca60017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c61471f565b6040516020016133dc91815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156134e457600061341f60018361471f565b85549091506000906134339060019061471f565b905081811461349857600086600001828154811061345357613453614628565b906000526020600020015490508087600001848154811061347657613476614628565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134a9576134a96149ad565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061082a565b600091505061082a565b6060600080856001600160a01b03168560405161350b919061460c565b600060405180830381855af49150503d8060008114613546576040519150601f19603f3d011682016040523d82523d6000602084013e61354b565b606091505b509150915061355c8683838761397d565b9695505050505050565b805151600090613578906118fd6119ee565b6135945760405162461bcd60e51b81526004016102199061479f565b8151604001516001600160a01b03166136125760405162461bcd60e51b815260206004820152603a60248201527f457874656e73696f6e4d616e616765723a20616464696e6720657874656e736960448201527937b7103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760311b6064820152608401610219565b506001919050565b806136236119ee565b60020183604051613634919061460c565b908152604051908190036020019020815181906133569082614a0c565b600061365b6119ee565b6002018260405161366c919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b8282101561377a5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916136e9906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613715906145d8565b80156137625780601f1061373757610100808354040283529160200191613762565b820191906000526020600020905b81548152906001019060200180831161374557829003601f168201915b5050505050815250508152602001906001019061369d565b5050505090506137886119ee565b60020182604051613799919061460c565b908152602001604051809103902060030160006137b69190613cd3565b60005b8151811015610758576137e88282815181106137d7576137d7614628565b602002602001015160000151611cc5565b6137f3600182614654565b90506137b9565b8051515160009061384d5760405162461bcd60e51b815260206004820152601d60248201527f457874656e73696f6e4d616e616765723a20656d707479206e616d652e0000006044820152606401610219565b8151516138629061385c6119ee565b906139fe565b6135945760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20616c726560448201526a30b23c9032bc34b9ba399760a91b6064820152608401610219565b60008260000182815481106138d9576138d9614628565b9060005260206000200154905092915050565b6000613900826138fa6119ee565b90613a0a565b6136125760405162461bcd60e51b81526004016102199061479f565b6139246119ee565b60020181604051613935919061460c565b9081526040519081900360200190206000611cf58282613c99565b60008260010182604051613964919061460c565b9081526040519081900360200190205415159392505050565b606083156139ec5782516000036139e5576001600160a01b0385163b6139e55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610219565b50816139f6565b6139f68383613a16565b949350505050565b6000610dc68383613a40565b6000610dc68383613a9a565b815115613a265781518083602001fd5b8060405162461bcd60e51b81526004016102199190614557565b6000613a4c8383613950565b612ba057825460018101845560008481526020902001613a6c8382614a0c565b5082546040516001850190613a8290859061460c565b9081526040519081900360200190205550600161082a565b6000808360010183604051613aaf919061460c565b9081526020016040518091039020549050806000146134e4576000613ad560018361471f565b8554909150600090613ae99060019061471f565b9050818114613bf0576000866000018281548110613b0957613b09614628565b906000526020600020018054613b1e906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613b4a906145d8565b8015613b975780601f10613b6c57610100808354040283529160200191613b97565b820191906000526020600020905b815481529060010190602001808311613b7a57829003601f168201915b5050505050905080876000018481548110613bb457613bb4614628565b906000526020600020019081613bca9190614a0c565b50838760010182604051613bde919061460c565b90815260405190819003602001902055505b8554869080613c0157613c016149ad565b600190038181906000526020600020016000613c1d9190613c99565b90558560010185604051613c31919061460c565b9081526020016040518091039020600090556001935050505061082a565b6040518060400160405280613c62613c6f565b8152602001606081525090565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b508054613ca5906145d8565b6000825580601f10613cb5575050565b601f016020900490600052602060002090810190610ff49190613cf4565b5080546000825560020290600052602060002090810190610ff49190613d0d565b5b80821115613d095760008155600101613cf5565b5090565b80821115613d0957805463ffffffff191681556000613d2f6001830182613c99565b50600201613d0d565b6020808252825182820181905260009190848201906040850190845b81811015613d795783516001600160a01b031683529284019291840191600101613d54565b50909695505050505050565b80356001600160a01b0381168114613d9c57600080fd5b919050565b60008060408385031215613db457600080fd5b613dbd83613d85565b946020939093013593505050565b600060208284031215613ddd57600080fd5b610dc682613d85565b600060208284031215613df857600080fd5b5035919050565b60008060408385031215613e1257600080fd5b82359150613e2260208401613d85565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715613e6357613e63613e2b565b60405290565b604051606081016001600160401b0381118282101715613e6357613e63613e2b565b604051601f8201601f191681016001600160401b0381118282101715613eb357613eb3613e2b565b604052919050565b600082601f830112613ecc57600080fd5b81356001600160401b03811115613ee557613ee5613e2b565b613ef8601f8201601f1916602001613e8b565b818152846020838601011115613f0d57600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160e01b031981168114613d9c57600080fd5b60008060408385031215613f5557600080fd5b82356001600160401b03811115613f6b57600080fd5b613f7785828601613ebb565b925050613e2260208401613f2a565b60005b83811015613fa1578181015183820152602001613f89565b50506000910152565b60008151808452613fc2816020860160208601613f86565b601f01601f19169290920160200192915050565b6000815160608452613feb6060850182613faa565b9050602083015184820360208601526140048282613faa565b6040948501516001600160a01b03169590940194909452509092915050565b63ffffffff60e01b815116825260006020820151604060208501526139f66040850182613faa565b60008151604084526140606040850182613fd6565b9050602080840151858303828701528281518085528385019150838160051b860101848401935060005b828110156140b857601f198783030184526140a6828651614023565b9486019493860193915060010161408a565b5098975050505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f1988860301845261410a85835161404b565b945092850192908501906001016140ee565b5092979650505050505050565b60006040828403121561413b57600080fd5b614143613e41565b905061414e82613f2a565b815260208201356001600160401b0381111561416957600080fd5b61417584828501613ebb565b60208301525092915050565b6000806040838503121561419457600080fd5b82356001600160401b03808211156141ab57600080fd5b6141b786838701613ebb565b935060208501359150808211156141cd57600080fd5b506141da85828601614129565b9150509250929050565b6000806000604084860312156141f957600080fd5b61420284613d85565b925060208401356001600160401b038082111561421e57600080fd5b818601915086601f83011261423257600080fd5b81358181111561424157600080fd5b87602082850101111561425357600080fd5b6020830194508093505050509250925092565b6000806040838503121561427957600080fd5b50508035926020909101359150565b60006020828403121561429a57600080fd5b81356001600160401b038111156142b057600080fd5b6139f684828501613ebb565b6000602082840312156142ce57600080fd5b610dc682613f2a565b602081526000610dc66020830184613fd6565b600080602083850312156142fd57600080fd5b82356001600160401b038082111561431457600080fd5b818501915085601f83011261432857600080fd5b81358181111561433757600080fd5b8660208260051b850101111561434c57600080fd5b60209290920196919550909350505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f198886030184526143a3858351613faa565b94509285019290850190600101614387565b600082601f8301126143c657600080fd5b813560206001600160401b03808311156143e2576143e2613e2b565b8260051b6143f1838201613e8b565b938452858101830193838101908886111561440b57600080fd5b84880192505b85831015614447578235848111156144295760008081fd5b6144378a87838c0101614129565b8352509184019190840190614411565b98975050505050505050565b60006020828403121561446557600080fd5b81356001600160401b038082111561447c57600080fd5b908301906040828603121561449057600080fd5b614498613e41565b8235828111156144a757600080fd5b8301606081880312156144b957600080fd5b6144c1613e69565b8135848111156144d057600080fd5b6144dc89828501613ebb565b8252506020820135848111156144f157600080fd5b6144fd89828501613ebb565b60208301525061450f60408301613d85565b604082015282525060208301358281111561452957600080fd5b614535878286016143b5565b60208301525095945050505050565b602081526000610dc6602083018461404b565b602081526000610dc66020830184613faa565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252601f908201527f457874656e73696f6e4d616e616765723a20756e617574686f72697a65642e00604082015260600190565b600181811c908216806145ec57607f821691505b60208210810361140d57634e487b7160e01b600052602260045260246000fd5b6000825161461e818460208701613f86565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561082a5761082a61463e565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b6000808335601e198436030181126146c857600080fd5b8301803591506001600160401b038211156146e257600080fd5b6020019150368190038213156146f757600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561082a5761082a61463e565b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351614762816015850160208801613f86565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351614793816026840160208801613f86565b01602601949350505050565b6020808252602b908201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20646f657360408201526a103737ba1032bc34b9ba1760a91b606082015260800190565b60006020808352600084546147fe816145d8565b8060208701526040600180841660008114614820576001811461483c5761486c565b60ff19851660408a0152604084151560051b8a0101955061486c565b89600052602060002060005b858110156148635781548b8201860152908301908801614848565b8a016040019650505b509398975050505050505050565b601f821115610758576000816000526020600020601f850160051c810160208610156148a35750805b601f850160051c820191505b8181101561331a578281556001016148af565b600019600383901b1c191660019190911b1790565b8181036148e2575050565b6148ec82546145d8565b6001600160401b0381111561490357614903613e2b565b6149178161491184546145d8565b8461487a565b6000601f82116001811461494557600083156149335750848201545b61493d84826148c2565b855550611cbe565b600085815260209020601f19841690600086815260209020845b8381101561497f578286015482556001958601959091019060200161495f565b508583101561499d5781850154600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603160045260246000fd5b6040815260006149d66040830185614023565b8281036020840152610dc28185613fd6565b6001600160a01b03831681526040602082018190526000906139f690830184613faa565b81516001600160401b03811115614a2557614a25613e2b565b614a338161491184546145d8565b602080601f831160018114614a625760008415614a505750858301515b614a5a85826148c2565b86555061331a565b600085815260208120601f198616915b82811015614a9157888601518255948401946001909101908401614a72565b508582101561499d57939096015160001960f8600387901b161c19169092555050600190811b01905550565b604081526000614ad06040830185613faa565b8281036020840152610dc28185613faa565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761082a5761082a61463e565b600081614b4857614b4861463e565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ea0bf6593fb849f1c8bca9503fc128d4ca8a5664256139b4a63c87879333ff4a64736f6c634300081700336101806040523480156200001257600080fd5b506040516200389138038062003891833981016040819052620000359162000250565b60408051808201825260078152661058d8dbdd5b9d60ca1b60208083019182528351808501855260018152603160f81b908201529151902060e08190527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101008190524660a081815285517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818701819052818801959095526060810193909352608080840192909252308382018190528651808503909201825260c093840190965280519401939093209092529190526101205281816200011762000134565b6001600160a01b03908116610140521661016052506200028f9050565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee03005460ff808216916101009004168015620001c55760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60ff828116101562000233577f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee0300805460ff191660ff90811790915560408051918252517f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989181900360200190a15b5050565b6001600160a01b03811681146200024d57600080fd5b50565b600080604083850312156200026457600080fd5b8251620002718162000237565b6020840151909250620002848162000237565b809150509250929050565b60805160a05160c05160e0516101005161012051610140516101605161356b62000326600039600061111a01526000818161033401528181610431015281816107eb015281816119660152818161199401528181611a1b01528181611a960152611ac60152600061232e0152600061237d01526000612358015260006122b1015260006122db01526000612305015261356b6000f3fe6080604052600436106100d95760003560e01c80631dd756c51461016257806324d7806c146101975780633a871cdd146101b75780634a00cc48146101e55780635892e236146102075780637dff5a79146102275780638b52d72314610247578063a9082d8414610269578063ac9650d8146102a8578063b0d691fe146102d5578063b76464d514610302578063c45a015514610322578063ce0b601314610356578063d087d28814610376578063d1f578941461038b578063d42f2f35146103ab578063e9523c97146103c0578063f15d424e146103e2575b366000036100e357005b60006100fa6000356001600160e01b03191661040f565b90506001600160a01b0381166101575760405162461bcd60e51b815260206004820181905260248201527f526f757465723a2066756e6374696f6e20646f6573206e6f742065786973742e60448201526064015b60405180910390fd5b610160816104aa565b005b34801561016e57600080fd5b5061018261017d3660046125ae565b6104ce565b60405190151581526020015b60405180910390f35b3480156101a357600080fd5b506101826101b23660046125fd565b610792565b3480156101c357600080fd5b506101d76101d236600461261a565b6107c1565b60405190815260200161018e565b3480156101f157600080fd5b506101fa6107e7565b60405161018e91906126b7565b34801561021357600080fd5b50610160610222366004612811565b610874565b34801561023357600080fd5b506101826102423660046125fd565b610c3a565b34801561025357600080fd5b5061025c610cf3565b60405161018e9190612933565b34801561027557600080fd5b50610289610284366004612811565b610f3a565b6040805192151583526001600160a01b0390911660208301520161018e565b3480156102b457600080fd5b506102c86102c3366004612997565b610f91565b60405161018e9190612a0b565b3480156102e157600080fd5b506102ea6110f6565b6040516001600160a01b03909116815260200161018e565b34801561030e57600080fd5b5061016061031d3660046125fd565b61113f565b34801561032e57600080fd5b506102ea7f000000000000000000000000000000000000000000000000000000000000000081565b34801561036257600080fd5b506102ea610371366004612a78565b61040f565b34801561038257600080fd5b506101d7611171565b34801561039757600080fd5b506101606103a6366004612a95565b6111ec565b3480156103b757600080fd5b5061025c6113a5565b3480156103cc57600080fd5b506103d5611516565b60405161018e9190612adc565b3480156103ee57600080fd5b506104026103fd3660046125fd565b611528565b60405161018e9190612aef565b60405163ce0b601360e01b81526001600160e01b0319821660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ce0b601390602401602060405180830381865afa158015610480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a49190612b02565b92915050565b3660008037600080366000845af43d6000803e8080156104c9573d6000f35b3d6000fd5b60006104d8611600565b6001600160a01b0384166000908152600491909101602052604090205460ff1615610505575060016104a4565b600061050f611600565b6001600160a01b0385166000908152600591909101602090815260408083208151606081018352815481526001909101546001600160801b0380821694830194909452600160801b900490921690820152915061056a611600565b6006016000866001600160a01b03166001600160a01b0316815260200190815260200160002090504282602001516001600160801b031611806105ba575081604001516001600160801b03164210155b806105cb57506105c981611624565b155b156105db576000925050506104a4565b60006105f26105ed6060870187612b1f565b61162e565b905060006105ff83611624565b6001148015610620575060006106158482611668565b6001600160a01b0316145b90506324f16c0560e11b6001600160e01b03198316016106975760008061065261064d60608a018a612b1f565b611674565b91509150826106785761066585836116d9565b61067857600096505050505050506104a4565b855181111561069057600096505050505050506104a4565b5050610785565b635c0f12eb60e11b6001600160e01b0319831601610778576000806106c76106c260608a018a612b1f565b6116fb565b5091509150826107275760005b8251811015610725576107098382815181106106f2576106f2612b65565b6020026020010151876116d990919063ffffffff16565b61071d5760009750505050505050506104a4565b6001016106d4565b505b60005b82518110156107705781818151811061074557610745612b65565b6020026020010151876000015110156107685760009750505050505050506104a4565b60010161072a565b505050610785565b60009450505050506104a4565b5060019695505050505050565b600061079c611600565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b60006107cb611748565b6107d584846117b1565b90506107e0826118f9565b9392505050565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634a00cc486040518163ffffffff1660e01b8152600401600060405180830381865afa158015610847573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261086f9190810190612d74565b905090565b600061088360208501856125fd565b90504261089660e0860160c08701612f10565b6001600160801b0316111580156108c557506108b9610100850160e08601612f10565b6001600160801b031642105b6108fb5760405162461bcd60e51b8152602060048201526007602482015266085c195c9a5bd960ca1b604482015260640161014e565b600080610909868686610f3a565b91509150816109435760405162461bcd60e51b815260040161014e906020808252600490820152632173696760e01b604082015260600190565b600161094d611600565b610100880135600090815260079190910160209081526040808320805460ff191694151594909417909355909161098991908901908901612f3c565b60ff1611156109bf5760006109a46040880160208901612f3c565b60ff1660011490506109b68482611952565b50505050505050565b6109c883610792565b156109fd5760405162461bcd60e51b815260206004820152600560248201526430b236b4b760d91b604482015260640161014e565b610a1283610a09611600565b60020190611a55565b50604051806060016040528087606001358152602001876080016020810190610a3b9190612f10565b6001600160801b03168152602001610a5960c0890160a08a01612f10565b6001600160801b03169052610a6c611600565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610ae2610ac1611600565b6001600160a01b038616600090815260069190910160205260409020611a6a565b805190915060005b81811015610b4c57610b39838281518110610b0757610b07612b65565b6020026020010151610b17611600565b6001600160a01b03891660009081526006919091016020526040902090611a77565b50610b45600182612f6d565b9050610aea565b50610b5a6040890189612f80565b9050905060005b81811015610bdb57610bc8610b7960408b018b612f80565b83818110610b8957610b89612b65565b9050602002016020810190610b9e91906125fd565b610ba6611600565b6001600160a01b03891660009081526006919091016020526040902090611a55565b50610bd4600182612f6d565b9050610b61565b50610be588611a8c565b846001600160a01b0316836001600160a01b03167ff21d10c26e35863a8df291aca54181ee8c4a3bc8e00246c3f7a5a14b69d826a78a604051610c28919061304f565b60405180910390a35050505050505050565b600080610c45611600565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b90910416928101929092529091504210801590610cb6575080604001516001600160801b031642105b80156107e057506000610ceb610cca611600565b6001600160a01b038616600090815260069190910160205260409020611624565b119392505050565b60606000610d0a610d02611600565b600201611a6a565b80519091506000805b82811015610d9b57610d3d848281518110610d3057610d30612b65565b6020026020010151610c3a565b15610d545781610d4c8161313a565b925050610d89565b6000848281518110610d6857610d68612b65565b60200260200101906001600160a01b031690816001600160a01b0316815250505b610d94600182612f6d565b9050610d13565b50806001600160401b03811115610db457610db4612b7b565b604051908082528060200260200182016040528015610ded57816020015b610dda612526565b815260200190600190039081610dd25790505b5093506000805b83811015610f325760006001600160a01b0316858281518110610e1957610e19612b65565b60200260200101516001600160a01b031614610f20576000858281518110610e4357610e43612b65565b602002602001015190506000610e57611600565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101610ec1610ac1611600565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250888580610f009061313a565b965081518110610f1257610f12612b65565b602002602001018190525050505b610f2b600182612f6d565b9050610df4565b505050505090565b600080610f50610f4986611b4f565b8585611c93565b9050610f5a611600565b6101008601356000908152600791909101602052604090205460ff16158015610f875750610f8781610792565b9150935093915050565b6060816001600160401b03811115610fab57610fab612b7b565b604051908082528060200260200182016040528015610fde57816020015b6060815260200190600190039081610fc95790505b509050336000805b848110156110ed578115611065576110433087878481811061100a5761100a612b65565b905060200281019061101c9190612b1f565b8660405160200161102f93929190613153565b604051602081830303815290604052611ced565b84828151811061105557611055612b65565b60200260200101819052506110e5565b6110c73087878481811061107b5761107b612b65565b905060200281019061108d9190612b1f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ced92505050565b8482815181106110d9576110d9612b65565b60200260200101819052505b600101610fe6565b50505092915050565b600080611101611d12565b546001600160a01b03169050801561111857919050565b7f000000000000000000000000000000000000000000000000000000000000000091505090565b611147611d36565b80611150611d12565b80546001600160a01b0319166001600160a01b039290921691909117905550565b600061117b6110f6565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401602060405180830381865afa1580156111c8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f9190613174565b60006111f6611d74565b5460ff1690506000611206611d74565b54610100900460ff1690508015808015611223575060018360ff16105b80611242575061123230611d98565b15801561124257508260ff166001145b6112a55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161014e565b60016112af611d74565b805460ff191660ff9290921691909117905580156112e85760016112d1611d74565b80549115156101000261ff00199092169190911790555b6113288686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611da792505050565b611330611d12565b60010181905550611342866001611952565b801561139d576000611352611d74565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b606060006113b4610d02611600565b8051909150806001600160401b038111156113d1576113d1612b7b565b60405190808252806020026020018201604052801561140a57816020015b6113f7612526565b8152602001906001900390816113ef5790505b50925060005b8181101561151057600083828151811061142c5761142c612b65565b602002602001015190506000611440611600565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016114aa610ac1611600565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b03168152508684815181106114ef576114ef612b65565b602002602001018190525050506001816115099190612f6d565b9050611410565b50505090565b606061086f611523611600565b611a6a565b611530612526565b600061153a611600565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a0810190945291835290925081016115c56115a4611600565b6001600160a01b038716600090815260069190910160205260409020611a6a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b7f3181e78fc1b109bc611fd2406150bf06e33faa75f71cba12c3e1fd670f2def0090565b60006104a4825490565b600060048210156116515760405162461bcd60e51b815260040161014e9061318d565b61165f6004600084866131ac565b6107e0916131d6565b60006107e08383611dda565b60008060448310156116985760405162461bcd60e51b815260040161014e9061318d565b6116a66024600485876131ac565b8101906116b391906125fd565b91506116c36044602485876131ac565b8101906116d09190613206565b90509250929050565b6001600160a01b038116600090815260018301602052604081205415156107e0565b6060808060648410156117205760405162461bcd60e51b815260040161014e9061318d565b61172d84600481886131ac565b81019061173a919061333c565b919790965090945092505050565b6117506110f6565b6001600160a01b0316336001600160a01b0316146117af5760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b604482015260640161014e565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c8120600061182f6117f2610140870187612b1f565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611e049050565b905061183b81866104ce565b61184a576001925050506104a4565b6000611854611600565b6001600160a01b03929092166000908152600590920160209081526040808420815160608082018452825482526001909201546001600160801b0380821683870152600160801b8204908116928501929092528351928301845295825265ffffffffffff8087169483019490945292831691015260d09290921b6001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795945050505050565b50565b80156118f657604051600090339060001990849084818181858888f193505050503d8060008114611946576040519150601f19603f3d011682016040523d82523d6000602084013e61194b565b606091505b5050505050565b61195c8282611e28565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b15611a51578015611a19577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630b61e12b836119ca611d12565b600101546040518363ffffffff1660e01b81526004016119eb929190613421565b600060405180830381600087803b158015611a0557600080fd5b505af115801561139d573d6000803e3d6000fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639387a380836119ca611d12565b5050565b60006107e0836001600160a01b038416611ed7565b606060006107e083611f26565b60006107e0836001600160a01b038416611f82565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156118f6576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630b61e12b611af860208401846125fd565b611b00611d12565b600101546040518363ffffffff1660e01b8152600401611b21929190613421565b600060405180830381600087803b158015611b3b57600080fd5b505af115801561194b573d6000803e3d6000fd5b60607f3fd4a1a1a267c84185e3b7eecd57c68783c0581d538b9d6e5f23e4670497c1e9611b7f60208401846125fd565b611b8f6040850160208601612f3c565b611b9c6040860186612f80565b604051602001611bad92919061343a565b60408051601f1981840301815291905280516020909101206060860135611bda60a0880160808901612f10565b611bea60c0890160a08a01612f10565b611bfa60e08a0160c08b01612f10565b611c0b6101008b0160e08c01612f10565b60408051602081019a909a526001600160a01b039098169789019790975260ff9095166060880152608087019390935260a08601919091526001600160801b0390811660c086015290811660e0850152908116610100848101919091529116610120830152830135610140820152610160016040516020818303038152906040529050919050565b6000611ce583838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505087516020890120611cdf92509050612075565b90611e04565b949350505050565b60606107e0838360405180606001604052806027815260200161350f602791396120a2565b7f036f52c1827dab135f7fd44ca0bddde297e2f659c710e0ec53e975f22b54830090565b611d3f33610792565b6117af5760405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b604482015260640161014e565b7f322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee030090565b6001600160a01b03163b151590565b60008282604051602001611dbc92919061347c565b60405160208183030381529060405280519060200120905092915050565b6000826000018281548110611df157611df1612b65565b9060005260206000200154905092915050565b6000806000611e13858561211a565b91509150611e208161215f565b509392505050565b80611e31611600565b6001600160a01b038416600090815260049190910160205260409020805460ff19169115159190911790558015611e7a57611e7482611e6e611600565b90611a55565b50611e8e565b611e8c82611e86611600565b90611a77565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a1113382604051611ecb911515815260200190565b60405180910390a25050565b6000818152600183016020526040812054611f1e575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104a4565b5060006104a4565b606081600001805480602002602001604051908101604052809291908181526020018280548015611f7657602002820191906000526020600020905b815481526020019060010190808311611f62575b50505050509050919050565b6000818152600183016020526040812054801561206b576000611fa66001836134a0565b8554909150600090611fba906001906134a0565b905081811461201f576000866000018281548110611fda57611fda612b65565b9060005260206000200154905080876000018481548110611ffd57611ffd612b65565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612030576120306134b3565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104a4565b60009150506104a4565b60006104a46120826122a4565b8360405161190160f01b8152600281019290925260228201526042902090565b6060600080856001600160a01b0316856040516120bf91906134c9565b600060405180830381855af49150503d80600081146120fa576040519150601f19603f3d011682016040523d82523d6000602084013e6120ff565b606091505b5091509150612110868383876123cb565b9695505050505050565b60008082516041036121505760208301516040840151606085015160001a61214487828585612442565b94509450505050612158565b506000905060025b9250929050565b6000816004811115612173576121736134e5565b0361217b5750565b600181600481111561218f5761218f6134e5565b036121d75760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015260640161014e565b60028160048111156121eb576121eb6134e5565b036122385760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161014e565b600381600481111561224c5761224c6134e5565b036118f65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161014e565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480156122fd57507f000000000000000000000000000000000000000000000000000000000000000046145b1561232757507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60608315612438578251600003612431576123e585611d98565b6124315760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014e565b5081611ce5565b611ce583836124fc565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561246f57506000905060036124f3565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156124c3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166124ec576000600192509250506124f3565b9150600090505b94509492505050565b81511561250c5781518083602001fd5b8060405162461bcd60e51b815260040161014e91906134fb565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b6001600160a01b03811681146118f657600080fd5b803561259081612570565b919050565b600061016082840312156125a857600080fd5b50919050565b600080604083850312156125c157600080fd5b82356125cc81612570565b915060208301356001600160401b038111156125e757600080fd5b6125f385828601612595565b9150509250929050565b60006020828403121561260f57600080fd5b81356107e081612570565b60008060006060848603121561262f57600080fd5b83356001600160401b0381111561264557600080fd5b61265186828701612595565b9660208601359650604090950135949350505050565b60005b8381101561268257818101518382015260200161266a565b50506000910152565b600081518084526126a3816020860160208601612667565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b8701018488016000805b848110156127c157603f19808b86030187528351805189875280516060808c8a015261270e60a08a018361268b565b91508c830151858a840301828b0152612727838261268b565b938d01516001600160a01b031660808b0152505050908a01518682038b88015280518083529192508a01908a830190600581901b84018c01865b828110156127aa57858203601f19018452845180516001600160e01b03191683528e01518e83018e90526127978e84018261268b565b958f0195948f0194925050600101612761565b50998c0199975050509389019350506001016126df565b50919998505050505050505050565b60008083601f8401126127e257600080fd5b5081356001600160401b038111156127f957600080fd5b60208301915083602082850101111561215857600080fd5b60008060006040848603121561282657600080fd5b83356001600160401b038082111561283d57600080fd5b90850190610120828803121561285257600080fd5b9093506020850135908082111561286857600080fd5b50612875868287016127d0565b9497909650939450505050565b60008151808452602080850194506020840160005b838110156128bc5781516001600160a01b031687529582019590820190600101612897565b509495945050505050565b6001600160801b03169052565b60018060a01b0381511682526000602082015160a060208501526128fb60a0850182612882565b604084810151908601526060808501516001600160801b03908116918701919091526080948501511693909401929092525090919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561298a57603f198886030184526129788583516128d4565b9450928501929085019060010161295c565b5092979650505050505050565b600080602083850312156129aa57600080fd5b82356001600160401b03808211156129c157600080fd5b818501915085601f8301126129d557600080fd5b8135818111156129e457600080fd5b8660208260051b85010111156129f957600080fd5b60209290920196919550909350505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561298a57603f19888603018452612a5085835161268b565b94509285019290850190600101612a34565b6001600160e01b0319811681146118f657600080fd5b600060208284031215612a8a57600080fd5b81356107e081612a62565b600080600060408486031215612aaa57600080fd5b8335612ab581612570565b925060208401356001600160401b03811115612ad057600080fd5b612875868287016127d0565b6020815260006107e06020830184612882565b6020815260006107e060208301846128d4565b600060208284031215612b1457600080fd5b81516107e081612570565b6000808335601e19843603018112612b3657600080fd5b8301803591506001600160401b03821115612b5057600080fd5b60200191503681900382131561215857600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612bb357612bb3612b7b565b60405290565b604051606081016001600160401b0381118282101715612bb357612bb3612b7b565b604051601f8201601f191681016001600160401b0381118282101715612c0357612c03612b7b565b604052919050565b60006001600160401b03821115612c2457612c24612b7b565b5060051b60200190565b60006001600160401b03821115612c4757612c47612b7b565b50601f01601f191660200190565b600082601f830112612c6657600080fd5b8151612c79612c7482612c2e565b612bdb565b818152846020838601011115612c8e57600080fd5b611ce5826020830160208701612667565b600082601f830112612cb057600080fd5b81516020612cc0612c7483612c0b565b82815260059290921b84018101918181019086841115612cdf57600080fd5b8286015b84811015612d695780516001600160401b0380821115612d035760008081fd5b908801906040828b03601f1901811315612d1d5760008081fd5b612d25612b91565b87840151612d3281612a62565b8152908301519082821115612d475760008081fd5b612d558c8984870101612c55565b818901528652505050918301918301612ce3565b509695505050505050565b600060208284031215612d8657600080fd5b81516001600160401b0380821115612d9d57600080fd5b818401915084601f830112612db157600080fd5b8151612dbf612c7482612c0b565b8082825260208201915060208360051b860101925087831115612de157600080fd5b602085015b83811015612eed57805185811115612dfd57600080fd5b8601601f196040828c0382011215612e1457600080fd5b612e1c612b91565b602083015188811115612e2e57600080fd5b83016060818e0384011215612e4257600080fd5b612e4a612bb9565b9250602081015189811115612e5e57600080fd5b612e6d8e602083850101612c55565b845250604081015189811115612e8257600080fd5b612e918e602083850101612c55565b60208501525060600151612ea481612570565b806040840152508181526040830151915087821115612ec257600080fd5b612ed18c602084860101612c9f565b6020820152808652505050602083019250602081019050612de6565b50979650505050505050565b80356001600160801b038116811461259057600080fd5b600060208284031215612f2257600080fd5b6107e082612ef9565b803560ff8116811461259057600080fd5b600060208284031215612f4e57600080fd5b6107e082612f2b565b634e487b7160e01b600052601160045260246000fd5b808201808211156104a4576104a4612f57565b6000808335601e19843603018112612f9757600080fd5b8301803591506001600160401b03821115612fb157600080fd5b6020019150600581901b360382131561215857600080fd5b6000808335601e19843603018112612fe057600080fd5b83016020810192503590506001600160401b03811115612fff57600080fd5b8060051b360382131561215857600080fd5b8183526000602080850194508260005b858110156128bc57813561303481612570565b6001600160a01b031687529582019590820190600101613021565b602081526130706020820161306384612585565b6001600160a01b03169052565b600061307e60208401612f2b565b60ff81166040840152506130956040840184612fc9565b6101208060608601526130ad61014086018385613011565b9250606086013560808601526130c560808701612ef9565b91506130d460a08601836128c7565b6130e060a08701612ef9565b91506130ef60c08601836128c7565b6130fb60c08701612ef9565b915061310a60e08601836128c7565b61311660e08701612ef9565b9150610100613127818701846128c7565b9590950135939094019290925250919050565b60006001820161314c5761314c612f57565b5060010190565b8284823760609190911b6001600160601b0319169101908152601401919050565b60006020828403121561318657600080fd5b5051919050565b602080825260059082015264214461746160d81b604082015260600190565b600080858511156131bc57600080fd5b838611156131c957600080fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156131fe5780818660040360031b1b83161692505b505092915050565b60006020828403121561321857600080fd5b5035919050565b600082601f83011261323057600080fd5b81356020613240612c7483612c0b565b8083825260208201915060208460051b87010193508684111561326257600080fd5b602086015b84811015612d695780358352918301918301613267565b600082601f83011261328f57600080fd5b8135602061329f612c7483612c0b565b82815260059290921b840181019181810190868411156132be57600080fd5b8286015b84811015612d695780356001600160401b038111156132e15760008081fd5b8701603f810189136132f35760008081fd5b848101356040613305612c7483612c2e565b8281528b8284860101111561331a5760008081fd5b82828501898301376000928101880192909252508452509183019183016132c2565b60008060006060848603121561335157600080fd5b83356001600160401b038082111561336857600080fd5b818601915086601f83011261337c57600080fd5b8135602061338c612c7483612c0b565b82815260059290921b8401810191818101908a8411156133ab57600080fd5b948201945b838610156133d25785356133c381612570565b825294820194908201906133b0565b975050870135925050808211156133e857600080fd5b6133f48783880161321f565b9350604086013591508082111561340a57600080fd5b506134178682870161327e565b9150509250925092565b6001600160a01b03929092168252602082015260400190565b60008184825b8581101561347157813561345381612570565b6001600160a01b031683526020928301929190910190600101613440565b509095945050505050565b6001600160a01b0383168152604060208201819052600090611ce59083018461268b565b818103818111156104a4576104a4612f57565b634e487b7160e01b600052603160045260246000fd5b600082516134db818460208701612667565b9190910192915050565b634e487b7160e01b600052602160045260246000fd5b6020815260006107e0602083018461268b56fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122055c7ac679e117964ab4e3ff4448918e749659848bbe88b20fd0a9bd2116d360564736f6c63430008170033000000000000000000000000118b936d79059251df60eec5d65c476b9fdd42640000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000cd68591e4f9fa55c4a9938a5574e22517047a05500000000000000000000000000000000000000000000000000000000000000104163636f756e74457874656e73696f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d4e5132646a543275346d793578704b50674a4d6e5145706f4e6a595a45387567704c6e647667454a4262335800000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000007a0000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008a000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000d604a58db19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000c6164644465706f73697428290000000000000000000000000000000000000000e8a3d485000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d636f6e7472616374555249282900000000000000000000000000000000000000b61d27f6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e6578656375746528616464726573732c75696e743235362c627974657329000047e1da2a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002965786563757465426174636828616464726573735b5d2c75696e743235365b5d2c62797465735b5d2900000000000000000000000000000000000000000000008b52d7230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000015676574416c6c4163746976655369676e65727328290000000000000000000000e9523c97000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e676574416c6c41646d696e732829000000000000000000000000000000000000d42f2f35000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000f676574416c6c5369676e65727328290000000000000000000000000000000000399b77da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000176765744d65737361676548617368286279746573333229000000000000000000f15d424e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000206765745065726d697373696f6e73466f725369676e65722861646472657373297dff5a79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001769734163746976655369676e657228616464726573732900000000000000000024d7806c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010697341646d696e286164647265737329000000000000000000000000000000001626ba7e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f697356616c69645369676e617475726528627974657333322c62797465732900bc197c8100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000416f6e455243313135354261746368526563656976656428616464726573732c616464726573732c75696e743235365b5d2c75696e743235365b5d2c62797465732900000000000000000000000000000000000000000000000000000000000000f23a6e6100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000386f6e45524331313535526563656976656428616464726573732c616464726573732c75696e743235362c75696e743235362c6279746573290000000000000000150b7a02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6f6e455243373231526563656976656428616464726573732c616464726573732c75696e743235362c6279746573290000000000000000000000000000000000938e3d7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016736574436f6e747261637455524928737472696e6729000000000000000000005892e23600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000687365745065726d697373696f6e73466f725369676e65722828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c62797465732900000000000000000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019737570706f727473496e74657266616365286279746573342900000000000000a9082d84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006e7665726966795369676e65725065726d697373696f6e526571756573742828616464726573732c75696e74382c616464726573735b5d2c75696e743235362c75696e743132382c75696e743132382c75696e743132382c75696e743132382c62797465733332292c6279746573290000000000000000000000000000000000004d44560d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002277697468647261774465706f736974546f28616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x6080604052600436106101a45760003560e01c80639387a380116100e85780639387a380146104ad578063938e3d7b146104cd578063a0dbaefd146104ed578063a217fddf1461051a578063a32fa5b31461052f578063a65d69d41461054f578063ac9650d814610583578063c0562f6d146105b0578063c22707ee146105d0578063c3c5a547146105fd578063ca15c8731461061d578063ce0b60131461063d578063d547741f1461065d578063d8fd8f441461067d578063e05688fe1461069d578063e68a7c3b146106bd578063e8a3d485146106dd578063ee7d2adf146106ff576101a4565b806308e93d0a1461022d5780630b61e12b146102585780630e6254fd1461027857806311464fbe14610298578063248a9ca3146102e45780632f2ff15d1461031257806336568abe14610332578063429eed8014610352578063463c4864146103725780634a00cc48146103a6578063512cf914146103c857806358451f97146103e857806383a03f8c146103fd5780638856a1131461041d5780638878ed331461043d5780639010d07c1461045d57806391d148541461047d575b366000036101ae57005b60006101c56000356001600160e01b03191661071f565b90506001600160a01b0381166102225760405162461bcd60e51b815260206004820181905260248201527f526f757465723a2066756e6374696f6e20646f6573206e6f742065786973742e60448201526064015b60405180910390fd5b61022b81610734565b005b34801561023957600080fd5b5061024261075d565b60405161024f9190613d38565b60405180910390f35b34801561026457600080fd5b5061022b610273366004613da1565b61076e565b34801561028457600080fd5b50610242610293366004613dcb565b610806565b3480156102a457600080fd5b506102cc7f0000000000000000000000001c292876b607cd5af869091f0fd8c601ca02280181565b6040516001600160a01b03909116815260200161024f565b3480156102f057600080fd5b506103046102ff366004613de6565b610830565b60405190815260200161024f565b34801561031e57600080fd5b5061022b61032d366004613dff565b61084e565b34801561033e57600080fd5b5061022b61034d366004613dff565b6108f8565b34801561035e57600080fd5b5061022b61036d366004613f42565b610957565b34801561037e57600080fd5b506102cc7f000000000000000000000000cd6c54b9e4a792177b7c0f497e1927d90f880b9e81565b3480156103b257600080fd5b506103bb610bce565b60405161024f91906140c5565b3480156103d457600080fd5b5061022b6103e3366004613f42565b610c9d565b3480156103f457600080fd5b50610304610ccb565b34801561040957600080fd5b5061022b610418366004613de6565b610cd7565b34801561042957600080fd5b5061022b610438366004614181565b610d25565b34801561044957600080fd5b506102cc6104583660046141e4565b610d53565b34801561046957600080fd5b506102cc610478366004614266565b610dcd565b34801561048957600080fd5b5061049d610498366004613dff565b610edb565b604051901515815260200161024f565b3480156104b957600080fd5b5061022b6104c8366004613da1565b610f0f565b3480156104d957600080fd5b5061022b6104e8366004614288565b610fa6565b3480156104f957600080fd5b5061050d6105083660046142bc565b610ff7565b60405161024f91906142d7565b34801561052657600080fd5b50610304600081565b34801561053b57600080fd5b5061049d61054a366004613dff565b61116d565b34801561055b57600080fd5b506102cc7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b34801561058f57600080fd5b506105a361059e3660046142ea565b6111d0565b60405161024f919061435e565b3480156105bc57600080fd5b5061022b6105cb366004614453565b61132c565b3480156105dc57600080fd5b506105f06105eb366004614288565b611359565b60405161024f9190614544565b34801561060957600080fd5b5061049d610618366004613dcb565b61136a565b34801561062957600080fd5b50610304610638366004613de6565b611376565b34801561064957600080fd5b506102cc6106583660046142bc565b61071f565b34801561066957600080fd5b5061022b610678366004613dff565b611413565b34801561068957600080fd5b506102cc6106983660046141e4565b61141e565b3480156106a957600080fd5b5061022b6106b8366004614453565b611569565b3480156106c957600080fd5b506102426106d8366004614266565b611596565b3480156106e957600080fd5b506106f26116c7565b60405161024f9190614557565b34801561070b57600080fd5b5061022b61071a366004614288565b61175f565b600061072a82610ff7565b6040015192915050565b3660008037600080366000845af43d6000803e808015610753573d6000f35b3d6000fd5b505050565b6060610769600061178c565b905090565b336107798183611799565b6107955760405162461bcd60e51b81526004016102199061456a565b6001600160a01b03831660009081526002602052604081206107b790836117dd565b9050801561080057836001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35b50505050565b6001600160a01b038116600090815260026020526040902060609061082a9061178c565b92915050565b600061083a6117f2565b600092835260010160205250604090205490565b6108726108596117f2565b6000848152600191909101602052604090205433611816565b61087a6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156108ea5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610219565b6108f4828261189b565b5050565b336001600160a01b0382161461094d5760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610219565b6108f482826118af565b61095f6118c3565b61097b5760405162461bcd60e51b8152600401610219906145a1565b61098582826118ef565b6109f25760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f766520604482015277333ab731ba34b7b710333937b69032bc3a32b739b4b7b71760411b6064820152608401610219565b60006109fc6119ee565b6001600160e01b031983166000908152600391909101602052604090819020815160608101909252805482908290610a33906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5f906145d8565b8015610aac5780601f10610a8157610100808354040283529160200191610aac565b820191906000526020600020905b815481529060010190602001808311610a8f57829003601f168201915b50505050508152602001600182018054610ac5906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054610af1906145d8565b8015610b3e5780601f10610b1357610100808354040283529160200191610b3e565b820191906000526020600020905b815481529060010190602001808311610b2157829003601f168201915b5050509183525050600291909101546001600160a01b03166020909101529050610b6883836119f8565b610b7182611cc5565b816001600160e01b03191683604051610b8a919061460c565b60405180910390207fbb931a9651175c9c82f86afbf6ad37a9141aa8d1d42bf798739be245a12e4e8883604051610bc191906142d7565b60405180910390a3505050565b60606000610be2610bdd6119ee565b611d18565b8051909150806001600160401b03811115610bff57610bff613e2b565b604051908082528060200260200182016040528015610c3857816020015b610c25613c4f565b815260200190600190039081610c1d5790505b50925060005b81811015610c9757610c68838281518110610c5b57610c5b614628565b6020026020010151611d23565b848281518110610c7a57610c7a614628565b6020908102919091010152610c90600182614654565b9050610c3e565b50505090565b610ca56118c3565b610cc15760405162461bcd60e51b8152600401610219906145a1565b6108f48282610957565b60006107696000611fac565b33610ce28183611799565b610cfe5760405162461bcd60e51b81526004016102199061456a565b610d096000826117dd565b6108f45760405162461bcd60e51b815260040161021990614667565b610d2d6118c3565b610d495760405162461bcd60e51b8152600401610219906145a1565b6108f48282611fb6565b600080610d968585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b9050610dc27f0000000000000000000000001c292876b607cd5af869091f0fd8c601ca02280182612238565b9150505b9392505050565b600080610dd8612298565b600085815260209190915260408120549150805b82811015610ed2576000610dfe612298565b60008881526020918252604080822085835260010190925220546001600160a01b031614610e7657848203610e6457610e35612298565b600087815260209182526040808220938252600190930190915220546001600160a01b0316925061082a915050565b610e6f600183614654565b9150610ec0565b610e81866000610edb565b8015610ead5750610e90612298565b600087815260209182526040808220828052600201909252205481145b15610ec057610ebd600183614654565b91505b610ecb600182614654565b9050610dec565b50505092915050565b6000610ee56117f2565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b33610f1a8183611799565b610f365760405162461bcd60e51b81526004016102199061456a565b6001600160a01b0383166000908152600260205260408120610f5890836122a2565b9050801561080057836001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a350505050565b610fae6122b7565b610feb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610219565b610ff4816122c3565b50565b610fff613c6f565b6110076119ee565b6001600160e01b03198316600090815260039190910160205260409081902081516060810190925280548290829061103e906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461106a906145d8565b80156110b75780601f1061108c576101008083540402835291602001916110b7565b820191906000526020600020905b81548152906001019060200180831161109a57829003601f168201915b505050505081526020016001820180546110d0906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546110fc906145d8565b80156111495780601f1061111e57610100808354040283529160200191611149565b820191906000526020600020905b81548152906001019060200180831161112c57829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015292915050565b60006111776117f2565b600084815260209182526040808220828052909252205460ff166111c75761119d6117f2565b6000848152602091825260408082206001600160a01b0386168352909252205460ff16905061082a565b50600192915050565b6060816001600160401b038111156111ea576111ea613e2b565b60405190808252806020026020018201604052801561121d57816020015b60608152602001906001900390816112085790505b509050336000805b84811015610ed25781156112a4576112823087878481811061124957611249614628565b905060200281019061125b91906146b1565b8660405160200161126e939291906146fe565b6040516020818303038152906040526123aa565b84828151811061129457611294614628565b6020026020010181905250611324565b611306308787848181106112ba576112ba614628565b90506020028101906112cc91906146b1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123aa92505050565b84828151811061131857611318614628565b60200260200101819052505b600101611225565b6113346118c3565b6113505760405162461bcd60e51b8152600401610219906145a1565b610ff4816123cf565b611361613c4f565b61082a82611d23565b600061082a8183612538565b600080611381612298565b6000848152602091909152604081205491505b818110156113ee5760006113a6612298565b60008681526020918252604080822085835260010190925220546001600160a01b0316146113dc576113d9600184614654565b92505b6113e7600182614654565b9050611394565b506113fa836000610edb565b1561140d5761140a600183614654565b91505b50919050565b61094d6108596117f2565b6000807f0000000000000000000000001c292876b607cd5af869091f0fd8c601ca022801905060006114868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061220592505050565b905060006114948383612238565b90506001600160a01b0381163b156114b0579250610dc6915050565b6114ba838361255a565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614611513576114f76000826117dd565b6115135760405162461bcd60e51b815260040161021990614667565b61151f818888886125f1565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b6115716118c3565b61158d5760405162461bcd60e51b8152600401610219906145a1565b610ff481612659565b606081831080156115b057506115ac6000611fac565b8211155b6116085760405162461bcd60e51b815260206004820152602360248201527f426173654163636f756e74466163746f72793a20696e76616c696420696e646960448201526263657360e81b6064820152608401610219565b6000611614848461471f565b9050611620848461471f565b6001600160401b0381111561163757611637613e2b565b604051908082528060200260200182016040528015611660578160200160208202803683370190505b50915060005b818110156116bf5761168361167b8683614654565b600090612783565b83828151811061169557611695614628565b6001600160a01b03909216602092830291909101909101526116b8600182614654565b9050611666565b505092915050565b60606116d161278f565b80546116dc906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611708906145d8565b80156117555780601f1061172a57610100808354040283529160200191611755565b820191906000526020600020905b81548152906001019060200180831161173857829003601f168201915b5050505050905090565b6117676118c3565b6117835760405162461bcd60e51b8152600401610219906145a1565b610ff4816127b3565b60606000610dc683612afd565b6000806117c67f0000000000000000000000001c292876b607cd5af869091f0fd8c601ca02280184612238565b6001600160a01b0385811691161491505092915050565b6000610dc6836001600160a01b038416612b59565b7f0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e50090565b61181e6117f2565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166108f457611859816001600160a01b03166014612ba8565b611864836020612ba8565b604051602001611875929190614732565b60408051601f198184030181529082905262461bcd60e51b825261021991600401614557565b6118a58282612d43565b6108f48282612dac565b6118b98282612e6b565b6108f48282612ed4565b60006107697f55add213c41f3851b4506717b8af695a4256979dff496dcaae7789f6121331aa33610edb565b6000611903836118fd6119ee565b90612f63565b61191f5760405162461bcd60e51b81526004016102199061479f565b826040516020016119309190614557565b6040516020818303038152906040528051906020012061194e6119ee565b6001600160e01b0319841660009081526003919091016020908152604091829020915161197c9291016147ea565b60405160208183030381529060405280519060200120146111c75760405162461bcd60e51b815260206004820152602660248201527f457874656e73696f6e4d616e616765723a20696e636f727265637420657874656044820152653739b4b7b71760d11b6064820152608401610219565b6000610769612f6f565b6000611a026119ee565b60020183604051611a13919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b82821015611b215760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611a90906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611abc906145d8565b8015611b095780601f10611ade57610100808354040283529160200191611b09565b820191906000526020600020905b815481529060010190602001808311611aec57829003601f168201915b50505050508152505081526020019060010190611a44565b5050825192935060009150505b81811015611cbe57836001600160e01b031916838281518110611b5357611b53614628565b6020026020010151600001516001600160e01b03191603611cac57611b766119ee565b60020185604051611b87919061460c565b908152604051908190036020019020600301611ba460018461471f565b81548110611bb457611bb4614628565b9060005260206000209060020201611bca6119ee565b60020186604051611bdb919061460c565b90815260200160405180910390206003018281548110611bfd57611bfd614628565b600091825260209091208254600290920201805463ffffffff191663ffffffff909216919091178155600180820190611c38908401826148d7565b50905050611c446119ee565b60020185604051611c55919061460c565b9081526020016040518091039020600301805480611c7557611c756149ad565b600082815260208120600260001990930192830201805463ffffffff1916815590611ca36001830182613c99565b50509055611cbe565b611cb7600182614654565b9050611b2e565b5050505050565b611ccd6119ee565b6001600160e01b0319821660009081526003919091016020526040812090611cf58282613c99565b611d03600183016000613c99565b5060020180546001600160a01b031916905550565b606061082a82612fcd565b611d2b613c4f565b611d336119ee565b60020182604051611d44919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290611d73906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9f906145d8565b8015611dec5780601f10611dc157610100808354040283529160200191611dec565b820191906000526020600020905b815481529060010190602001808311611dcf57829003601f168201915b50505050508152602001600182018054611e05906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611e31906145d8565b8015611e7e5780601f10611e5357610100808354040283529160200191611e7e565b820191906000526020600020905b815481529060010190602001808311611e6157829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015611f9e5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191611f0d906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611f39906145d8565b8015611f865780601f10611f5b57610100808354040283529160200191611f86565b820191906000526020600020905b815481529060010190602001808311611f6957829003601f168201915b50505050508152505081526020019060010190611ec1565b505050915250909392505050565b600061082a825490565b611fc082826130aa565b61202c5760405162461bcd60e51b815260206004820152603760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742053746f72653a20604482015276333ab731ba34b7b7103337b91032bc3a32b739b4b7b71760491b6064820152608401610219565b61203682826130d4565b60006120406119ee565b60020183604051612051919061460c565b9081526040805191829003602001822060608301909152805482908290612077906145d8565b80601f01602080910402602001604051908101604052809291908181526020018280546120a3906145d8565b80156120f05780601f106120c5576101008083540402835291602001916120f0565b820191906000526020600020905b8154815290600101906020018083116120d357829003601f168201915b50505050508152602001600182018054612109906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612135906145d8565b80156121825780601f1061215757610100808354040283529160200191612182565b820191906000526020600020905b81548152906001019060200180831161216557829003601f168201915b5050509183525050600291909101546001600160a01b031660209091015282519091506121af9082613322565b81600001516001600160e01b031916836040516121cc919061460c565b60405180910390207f681115194e519bda23de4da5218f3bc38f5585eab7c6b7d5fa66caa4602f574d8484604051610bc19291906149c3565b6000828260405160200161221a9291906149e8565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090610dc6565b6000610769613399565b6000610dc6836001600160a01b0384166133fb565b60006107698133610edb565b60006122cd61278f565b80546122d8906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612304906145d8565b80156123515780601f1061232657610100808354040283529160200191612351565b820191906000526020600020905b81548152906001019060200180831161233457829003601f168201915b505050505090508161236161278f565b9061236c9082614a0c565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a16818360405161239e929190614abd565b60405180910390a15050565b6060610dc68383604051806060016040528060278152602001614b51602791396134ee565b6123d881613566565b6124385760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74207265706c61636560448201526a1032bc3a32b739b4b7b71760a91b6064820152608401610219565b805180516124459161361a565b80515161245190613651565b60208101515160005b818110156124d2576124918360000151600001518460200151838151811061248457612484614628565b60200260200101516130d4565b6124c0836020015182815181106124aa576124aa614628565b6020026020010151600001518460000151613322565b6124cb600182614654565b905061245a565b508151604080820151915190516001600160a01b03909216916124f5919061460c565b60405180910390207f5f1ef2b136db521971a88818ce904a8e310082338afdc100212a3127066421588460405161252c9190614544565b60405180910390a35050565b6001600160a01b03811660009081526001830160205260408120541515610dc6565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661082a5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610219565b60405163347d5e2560e21b81526001600160a01b0385169063d1f578949061262190869086908690600401614ae2565b600060405180830381600087803b15801561263b57600080fd5b505af115801561264f573d6000803e3d6000fd5b5050505050505050565b612662816137fa565b6126be5760405162461bcd60e51b815260206004820152602760248201527f457874656e73696f6e4d616e616765723a2063616e6e6f74206164642065787460448201526632b739b4b7b71760c91b6064820152608401610219565b805180516126cb9161361a565b60208101515160005b81811015612729576126fe8360000151600001518460200151838151811061248457612484614628565b612717836020015182815181106124aa576124aa614628565b612722600182614654565b90506126d4565b508151604080820151915190516001600160a01b039092169161274c919061460c565b60405180910390207fbb37a605de78ba6bc667aeaf438d0aae8247e6f48a8fad23730e4fbbb480abf38460405161252c9190614544565b6000610dc683836138c2565b7f4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da90090565b6127bc816138ec565b61281b5760405162461bcd60e51b815260206004820152602a60248201527f457874656e73696f6e4d616e616765723a2063616e6e6f742072656d6f76652060448201526932bc3a32b739b4b7b71760b11b6064820152608401610219565b60006128256119ee565b60020182604051612836919061460c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290612865906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612891906145d8565b80156128de5780601f106128b3576101008083540402835291602001916128de565b820191906000526020600020905b8154815290600101906020018083116128c157829003601f168201915b505050505081526020016001820180546128f7906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612923906145d8565b80156129705780601f1061294557610100808354040283529160200191612970565b820191906000526020600020905b81548152906001019060200180831161295357829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015612a905760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916129ff906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054612a2b906145d8565b8015612a785780601f10612a4d57610100808354040283529160200191612a78565b820191906000526020600020905b815481529060010190602001808311612a5b57829003601f168201915b505050505081525050815260200190600101906129b3565b50505050815250509050612aa38261391c565b612aac82613651565b81604051612aba919061460c565b60405180910390207f3169a23cec9ad1a25ab59bbe00ecf8973dd840c745775ea8877041ef5ce65bcc82604051612af19190614544565b60405180910390a25050565b606081600001805480602002602001604051908101604052809291908181526020018280548015612b4d57602002820191906000526020600020905b815481526020019060010190808311612b39575b50505050509050919050565b6000818152600183016020526040812054612ba05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561082a565b50600061082a565b60606000612bb7836002614b22565b612bc2906002614654565b6001600160401b03811115612bd957612bd9613e2b565b6040519080825280601f01601f191660200182016040528015612c03576020820181803683370190505b509050600360fc1b81600081518110612c1e57612c1e614628565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612c4d57612c4d614628565b60200101906001600160f81b031916908160001a9053506000612c71846002614b22565b612c7c906001614654565b90505b6001811115612cf4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612cb057612cb0614628565b1a60f81b828281518110612cc657612cc6614628565b60200101906001600160f81b031916908160001a90535060049490941c93612ced81614b39565b9050612c7f565b508315610dc65760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610219565b6001612d4d6117f2565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000612db6612298565b6000848152602091909152604090205490506001612dd2612298565b6000858152602091909152604081208054909190612df1908490614654565b90915550829050612e00612298565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580612e40612298565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b612e758282611816565b612e7d6117f2565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000612ede612298565b6000848152602091825260408082206001600160a01b038616835260020190925220549050612f0b612298565b6000848152602091825260408082208483526001019092522080546001600160a01b0319169055612f3a612298565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b6000610dc68383613950565b600080612f9d60017f775b9fab5634a62bb2a682c067408edbed43efd726183d2e2af744334d47acb761471f565b604051602001612faf91815260200190565b60408051601f19818403018152919052805160209091012092915050565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561309f578382906000526020600020018054613012906145d8565b80601f016020809104026020016040519081016040528092919081815260200182805461303e906145d8565b801561308b5780601f106130605761010080835404028352916020019161308b565b820191906000526020600020905b81548152906001019060200180831161306e57829003601f168201915b505050505081526020019060010190612ff3565b505050509050919050565b60006130b8836118fd6119ee565b6111c75760405162461bcd60e51b81526004016102199061479f565b80516000906001600160e01b03191661315e576040516020016131149060208082526009908201526872656365697665282960b81b604082015260600190565b60405160208183030381529060405280519060200120826020015160405160200161313f9190614557565b60405160208183030381529060405280519060200120141590506131a5565b602080830151604051613171920161460c565b604051602081830303815290604052805190602001206001600160e01b03191682600001516001600160e01b031916141590505b80156132115760405162461bcd60e51b815260206004820152603560248201527f457874656e73696f6e4d616e616765723a20666e2073656c6563746f7220616e604482015274321039b4b3b730ba3ab9329036b4b9b6b0ba31b41760591b6064820152608401610219565b600061321b6119ee565b83516001600160e01b031916600090815260039190910160205260409020600201546001600160a01b0316146132ab5760405162461bcd60e51b815260206004820152602f60248201527f457874656e73696f6e4d616e616765723a2066756e6374696f6e20696d706c2060448201526e30b63932b0b23c9032bc34b9ba399760891b6064820152608401610219565b6132b36119ee565b600201836040516132c4919061460c565b908152604051602091819003820190206003018054600180820183556000928352918390208551600290920201805463ffffffff191660e09290921c9190911781559184015184929182019061331a9082614a0c565b505050505050565b8061332b6119ee565b6001600160e01b03198416600090815260039190910160205260409020815181906133569082614a0c565b506020820151600182019061336b9082614a0c565b5060409190910151600290910180546001600160a01b0319166001600160a01b039092169190911790555050565b60008060ff196133ca60017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c61471f565b6040516020016133dc91815260200190565b60408051601f1981840301815291905280516020909101201692915050565b600081815260018301602052604081205480156134e457600061341f60018361471f565b85549091506000906134339060019061471f565b905081811461349857600086600001828154811061345357613453614628565b906000526020600020015490508087600001848154811061347657613476614628565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134a9576134a96149ad565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061082a565b600091505061082a565b6060600080856001600160a01b03168560405161350b919061460c565b600060405180830381855af49150503d8060008114613546576040519150601f19603f3d011682016040523d82523d6000602084013e61354b565b606091505b509150915061355c8683838761397d565b9695505050505050565b805151600090613578906118fd6119ee565b6135945760405162461bcd60e51b81526004016102199061479f565b8151604001516001600160a01b03166136125760405162461bcd60e51b815260206004820152603a60248201527f457874656e73696f6e4d616e616765723a20616464696e6720657874656e736960448201527937b7103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760311b6064820152608401610219565b506001919050565b806136236119ee565b60020183604051613634919061460c565b908152604051908190036020019020815181906133569082614a0c565b600061365b6119ee565b6002018260405161366c919061460c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b8282101561377a5760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916136e9906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613715906145d8565b80156137625780601f1061373757610100808354040283529160200191613762565b820191906000526020600020905b81548152906001019060200180831161374557829003601f168201915b5050505050815250508152602001906001019061369d565b5050505090506137886119ee565b60020182604051613799919061460c565b908152602001604051809103902060030160006137b69190613cd3565b60005b8151811015610758576137e88282815181106137d7576137d7614628565b602002602001015160000151611cc5565b6137f3600182614654565b90506137b9565b8051515160009061384d5760405162461bcd60e51b815260206004820152601d60248201527f457874656e73696f6e4d616e616765723a20656d707479206e616d652e0000006044820152606401610219565b8151516138629061385c6119ee565b906139fe565b6135945760405162461bcd60e51b815260206004820152602b60248201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20616c726560448201526a30b23c9032bc34b9ba399760a91b6064820152608401610219565b60008260000182815481106138d9576138d9614628565b9060005260206000200154905092915050565b6000613900826138fa6119ee565b90613a0a565b6136125760405162461bcd60e51b81526004016102199061479f565b6139246119ee565b60020181604051613935919061460c565b9081526040519081900360200190206000611cf58282613c99565b60008260010182604051613964919061460c565b9081526040519081900360200190205415159392505050565b606083156139ec5782516000036139e5576001600160a01b0385163b6139e55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610219565b50816139f6565b6139f68383613a16565b949350505050565b6000610dc68383613a40565b6000610dc68383613a9a565b815115613a265781518083602001fd5b8060405162461bcd60e51b81526004016102199190614557565b6000613a4c8383613950565b612ba057825460018101845560008481526020902001613a6c8382614a0c565b5082546040516001850190613a8290859061460c565b9081526040519081900360200190205550600161082a565b6000808360010183604051613aaf919061460c565b9081526020016040518091039020549050806000146134e4576000613ad560018361471f565b8554909150600090613ae99060019061471f565b9050818114613bf0576000866000018281548110613b0957613b09614628565b906000526020600020018054613b1e906145d8565b80601f0160208091040260200160405190810160405280929190818152602001828054613b4a906145d8565b8015613b975780601f10613b6c57610100808354040283529160200191613b97565b820191906000526020600020905b815481529060010190602001808311613b7a57829003601f168201915b5050505050905080876000018481548110613bb457613bb4614628565b906000526020600020019081613bca9190614a0c565b50838760010182604051613bde919061460c565b90815260405190819003602001902055505b8554869080613c0157613c016149ad565b600190038181906000526020600020016000613c1d9190613c99565b90558560010185604051613c31919061460c565b9081526020016040518091039020600090556001935050505061082a565b6040518060400160405280613c62613c6f565b8152602001606081525090565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b508054613ca5906145d8565b6000825580601f10613cb5575050565b601f016020900490600052602060002090810190610ff49190613cf4565b5080546000825560020290600052602060002090810190610ff49190613d0d565b5b80821115613d095760008155600101613cf5565b5090565b80821115613d0957805463ffffffff191681556000613d2f6001830182613c99565b50600201613d0d565b6020808252825182820181905260009190848201906040850190845b81811015613d795783516001600160a01b031683529284019291840191600101613d54565b50909695505050505050565b80356001600160a01b0381168114613d9c57600080fd5b919050565b60008060408385031215613db457600080fd5b613dbd83613d85565b946020939093013593505050565b600060208284031215613ddd57600080fd5b610dc682613d85565b600060208284031215613df857600080fd5b5035919050565b60008060408385031215613e1257600080fd5b82359150613e2260208401613d85565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715613e6357613e63613e2b565b60405290565b604051606081016001600160401b0381118282101715613e6357613e63613e2b565b604051601f8201601f191681016001600160401b0381118282101715613eb357613eb3613e2b565b604052919050565b600082601f830112613ecc57600080fd5b81356001600160401b03811115613ee557613ee5613e2b565b613ef8601f8201601f1916602001613e8b565b818152846020838601011115613f0d57600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160e01b031981168114613d9c57600080fd5b60008060408385031215613f5557600080fd5b82356001600160401b03811115613f6b57600080fd5b613f7785828601613ebb565b925050613e2260208401613f2a565b60005b83811015613fa1578181015183820152602001613f89565b50506000910152565b60008151808452613fc2816020860160208601613f86565b601f01601f19169290920160200192915050565b6000815160608452613feb6060850182613faa565b9050602083015184820360208601526140048282613faa565b6040948501516001600160a01b03169590940194909452509092915050565b63ffffffff60e01b815116825260006020820151604060208501526139f66040850182613faa565b60008151604084526140606040850182613fd6565b9050602080840151858303828701528281518085528385019150838160051b860101848401935060005b828110156140b857601f198783030184526140a6828651614023565b9486019493860193915060010161408a565b5098975050505050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f1988860301845261410a85835161404b565b945092850192908501906001016140ee565b5092979650505050505050565b60006040828403121561413b57600080fd5b614143613e41565b905061414e82613f2a565b815260208201356001600160401b0381111561416957600080fd5b61417584828501613ebb565b60208301525092915050565b6000806040838503121561419457600080fd5b82356001600160401b03808211156141ab57600080fd5b6141b786838701613ebb565b935060208501359150808211156141cd57600080fd5b506141da85828601614129565b9150509250929050565b6000806000604084860312156141f957600080fd5b61420284613d85565b925060208401356001600160401b038082111561421e57600080fd5b818601915086601f83011261423257600080fd5b81358181111561424157600080fd5b87602082850101111561425357600080fd5b6020830194508093505050509250925092565b6000806040838503121561427957600080fd5b50508035926020909101359150565b60006020828403121561429a57600080fd5b81356001600160401b038111156142b057600080fd5b6139f684828501613ebb565b6000602082840312156142ce57600080fd5b610dc682613f2a565b602081526000610dc66020830184613fd6565b600080602083850312156142fd57600080fd5b82356001600160401b038082111561431457600080fd5b818501915085601f83011261432857600080fd5b81358181111561433757600080fd5b8660208260051b850101111561434c57600080fd5b60209290920196919550909350505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561411c57603f198886030184526143a3858351613faa565b94509285019290850190600101614387565b600082601f8301126143c657600080fd5b813560206001600160401b03808311156143e2576143e2613e2b565b8260051b6143f1838201613e8b565b938452858101830193838101908886111561440b57600080fd5b84880192505b85831015614447578235848111156144295760008081fd5b6144378a87838c0101614129565b8352509184019190840190614411565b98975050505050505050565b60006020828403121561446557600080fd5b81356001600160401b038082111561447c57600080fd5b908301906040828603121561449057600080fd5b614498613e41565b8235828111156144a757600080fd5b8301606081880312156144b957600080fd5b6144c1613e69565b8135848111156144d057600080fd5b6144dc89828501613ebb565b8252506020820135848111156144f157600080fd5b6144fd89828501613ebb565b60208301525061450f60408301613d85565b604082015282525060208301358281111561452957600080fd5b614535878286016143b5565b60208301525095945050505050565b602081526000610dc6602083018461404b565b602081526000610dc66020830184613faa565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252601f908201527f457874656e73696f6e4d616e616765723a20756e617574686f72697a65642e00604082015260600190565b600181811c908216806145ec57607f821691505b60208210810361140d57634e487b7160e01b600052602260045260246000fd5b6000825161461e818460208701613f86565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561082a5761082a61463e565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b6000808335601e198436030181126146c857600080fd5b8301803591506001600160401b038211156146e257600080fd5b6020019150368190038213156146f757600080fd5b9250929050565b8284823760609190911b6001600160601b0319169101908152601401919050565b8181038181111561082a5761082a61463e565b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351614762816015850160208801613f86565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351614793816026840160208801613f86565b01602601949350505050565b6020808252602b908201527f457874656e73696f6e4d616e616765723a20657874656e73696f6e20646f657360408201526a103737ba1032bc34b9ba1760a91b606082015260800190565b60006020808352600084546147fe816145d8565b8060208701526040600180841660008114614820576001811461483c5761486c565b60ff19851660408a0152604084151560051b8a0101955061486c565b89600052602060002060005b858110156148635781548b8201860152908301908801614848565b8a016040019650505b509398975050505050505050565b601f821115610758576000816000526020600020601f850160051c810160208610156148a35750805b601f850160051c820191505b8181101561331a578281556001016148af565b600019600383901b1c191660019190911b1790565b8181036148e2575050565b6148ec82546145d8565b6001600160401b0381111561490357614903613e2b565b6149178161491184546145d8565b8461487a565b6000601f82116001811461494557600083156149335750848201545b61493d84826148c2565b855550611cbe565b600085815260209020601f19841690600086815260209020845b8381101561497f578286015482556001958601959091019060200161495f565b508583101561499d5781850154600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603160045260246000fd5b6040815260006149d66040830185614023565b8281036020840152610dc28185613fd6565b6001600160a01b03831681526040602082018190526000906139f690830184613faa565b81516001600160401b03811115614a2557614a25613e2b565b614a338161491184546145d8565b602080601f831160018114614a625760008415614a505750858301515b614a5a85826148c2565b86555061331a565b600085815260208120601f198616915b82811015614a9157888601518255948401946001909101908401614a72565b508582101561499d57939096015160001960f8600387901b161c19169092555050600190811b01905550565b604081526000614ad06040830185613faa565b8281036020840152610dc28185613faa565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761082a5761082a61463e565b600081614b4857614b4861463e565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ea0bf6593fb849f1c8bca9503fc128d4ca8a5664256139b4a63c87879333ff4a64736f6c63430008170033