Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 24422872 | 106 days ago | 0 ETH | ||||
| 24422833 | 106 days ago | 0 ETH | ||||
| 24422801 | 106 days ago | 0 ETH | ||||
| 24243413 | 111 days ago | 0 ETH | ||||
| 24154209 | 113 days ago | 0 ETH | ||||
| 24004268 | 117 days ago | 0 ETH | ||||
| 23979861 | 117 days ago | 0 ETH | ||||
| 23942837 | 118 days ago | 0 ETH | ||||
| 23942700 | 118 days ago | 0 ETH | ||||
| 23942679 | 118 days ago | 0 ETH | ||||
| 23942669 | 118 days ago | 0 ETH | ||||
| 23942654 | 118 days ago | 0 ETH | ||||
| 23942642 | 118 days ago | 0 ETH | ||||
| 23942598 | 118 days ago | 0 ETH | ||||
| 23942584 | 118 days ago | 0 ETH | ||||
| 23942567 | 118 days ago | 0 ETH | ||||
| 23942554 | 118 days ago | 0 ETH | ||||
| 23942442 | 118 days ago | 0 ETH | ||||
| 23942428 | 118 days ago | 0 ETH | ||||
| 23942405 | 118 days ago | 0 ETH | ||||
| 23942387 | 118 days ago | 0 ETH | ||||
| 23942374 | 118 days ago | 0 ETH | ||||
| 23942365 | 118 days ago | 0 ETH | ||||
| 23942353 | 118 days ago | 0 ETH | ||||
| 23942340 | 118 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AccountFactory
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 20 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
// Utils
import "../utils/BaseAccountFactory.sol";
import "../utils/BaseAccount.sol";
import "../../../external-deps/openzeppelin/proxy/Clones.sol";
// Extensions
import "../../../extension/upgradeable//PermissionsEnumerable.sol";
import "../../../extension/upgradeable//ContractMetadata.sol";
// Interface
import "../interface/IEntrypoint.sol";
// Smart wallet implementation
import { Account } from "./Account.sol";
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
contract AccountFactory is BaseAccountFactory, ContractMetadata, PermissionsEnumerable {
/*///////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor(IEntryPoint _entrypoint)
BaseAccountFactory(address(new Account(_entrypoint, address(this))), address(_entrypoint))
{
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Called in `createAccount`. Initializes the account contract created in `createAccount`.
function _initializeAccount(
address _account,
address _admin,
bytes calldata _data
) internal override {
Account(payable(_account)).initialize(_admin, _data);
}
/// @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);
}
}// 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./interface/IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-165).
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: 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.
*/
struct SignerPermissionRequest {
address signer;
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 Adds / removes an account as an admin.
function setAdmin(address account, bool isAdmin) external;
/// @notice Sets the permissions for a given signer.
function setPermissionsForSigner(SignerPermissionRequest calldata req, bytes calldata signature) external;
}// 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);
}// 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);
}// 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;
}// 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);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../lib/TWAddress.sol";
import "./interface/IMulticall.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
contract Multicall is IMulticall {
/**
* @notice Receives and executes a batch of function calls on this contract.
* @dev Receives and executes a batch of function calls on this contract.
*
* @param data The bytes data that makes up the batch of function calls to execute.
* @return results The bytes data that makes up the result of the batch of function calls executed.
*/
function multicall(bytes[] calldata data) external virtual override returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = TWAddress.functionDelegateCall(address(this), data[i]);
}
return results;
}
}// SPDX-License-Identifier: 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:extension.manager.storage
bytes32 public constant ACCOUNT_PERMISSIONS_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("account.permissions.storage")) - 1));
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,address[] approvedTargets,uint256 nativeTokenLimitPerTransaction,uint128 permissionStartTimestamp,uint128 permissionEndTimestamp,uint128 reqValidityStartTimestamp,uint128 reqValidityEndTimestamp,bytes32 uid)"
);
modifier onlyAdmin() virtual {
require(isAdmin(msg.sender), "AccountPermissions: caller is not an admin");
_;
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Adds / removes an account as an admin.
function setAdmin(address _account, bool _isAdmin) external virtual onlyAdmin {
_setAdmin(_account, _isAdmin);
}
/// @notice Sets the permissions for a given signer.
function setPermissionsForSigner(SignerPermissionRequest calldata _req, bytes calldata _signature) external {
address targetSigner = _req.signer;
require(!isAdmin(targetSigner), "AccountPermissions: signer is already an admin");
require(
_req.reqValidityStartTimestamp <= block.timestamp && block.timestamp < _req.reqValidityEndTimestamp,
"AccountPermissions: invalid request validity period"
);
(bool success, address signer) = verifySignerPermissionRequest(_req, _signature);
require(success, "AccountPermissions: invalid signature");
_accountPermissionsStorage().allSigners.add(targetSigner);
_accountPermissionsStorage().executed[_req.uid] = true;
_accountPermissionsStorage().signerPermissions[targetSigner] = SignerPermissionsStatic(
_req.nativeTokenLimitPerTransaction,
_req.permissionStartTimestamp,
_req.permissionEndTimestamp
);
address[] memory currentTargets = _accountPermissionsStorage().approvedTargets[targetSigner].values();
uint256 currentLen = currentTargets.length;
for (uint256 i = 0; i < currentLen; i += 1) {
_accountPermissionsStorage().approvedTargets[targetSigner].remove(currentTargets[i]);
}
uint256 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(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;
bool[] memory isSignerActive = new bool[](len);
for (uint256 i = 0; i < len; i += 1) {
address signer = allSigners[i];
bool isActive = isActiveSigner(signer);
isSignerActive[i] = isActive;
if (isActive) {
numOfActiveSigners++;
}
}
signers = new SignerPermissions[](numOfActiveSigners);
uint256 index = 0;
for (uint256 i = 0; i < len; i += 1) {
if (!isSignerActive[i]) {
continue;
}
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(SignerPermissionRequest calldata _req, bytes calldata _signature)
internal
view
virtual
returns (address)
{
return _hashTypedDataV4(keccak256(_encodeRequest(_req))).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,
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();
}
}// 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:extension.manager.storage
bytes32 public constant CONTRACT_METADATA_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("contract.metadata.storage")) - 1));
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);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "../../lib/TWAddress.sol";
library InitStorage {
/// @custom:storage-location erc7201:extension.manager.storage
bytes32 constant INIT_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("init.storage")) - 1));
/// @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) || (!TWAddress.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();
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IPermissions.sol";
import "../../lib/TWStrings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/
library PermissionsStorage {
/// @custom:storage-location erc7201:extension.manager.storage
bytes32 public constant PERMISSIONS_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("permissions.storage")) - 1));
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 ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
function _msgSender() internal view virtual returns (address sender) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/// @dev Returns the Permissions storage.
function _permissionsStorage() internal pure returns (PermissionsStorage.Data storage data) {
data = PermissionsStorage.data();
}
}// 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));
/**
* @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();
}
}// 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));
}
}// 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);
}// 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;
}
}// 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);
}
}// 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);
}// 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../../../../lib/TWStrings.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", TWStrings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: Apache 2.0 /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. * * Credits: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol */ pragma solidity >=0.8.0 <0.9.0; 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; } }
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev Collection of functions related to the address type
*/
library TWAddress {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* [EIP1884](https://eips.ethereum.org/EIPS/eip-1884) increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev String operations.
*/
library TWStrings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: 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);
}// 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);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
interface IAccountFactory {
/*///////////////////////////////////////////////////////////////
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);
/// @notice Callback function for an Account to register its signers.
function onSignerAdded(
address signer,
address creatorAdmin,
bytes memory data
) external;
/// @notice Callback function for an Account to un-register its signers.
function onSignerRemoved(
address signer,
address creatorAdmin,
bytes memory data
) external;
/*///////////////////////////////////////////////////////////////
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);
}// 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);
}/**
** 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 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;
}// 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;
}// 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;
}// 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";
// Extensions
import "../utils/AccountCore.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 "../utils/Helpers.sol";
import "../../../external-deps/openzeppelin/utils/cryptography/ECDSA.sol";
import "../utils/BaseAccountFactory.sol";
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC1155Holder {
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.AddressSet;
/*///////////////////////////////////////////////////////////////
Constructor, Initializer, Modifiers
//////////////////////////////////////////////////////////////*/
constructor(IEntryPoint _entrypoint, address _factory) AccountCore(_entrypoint, _factory) {}
/// @notice Checks whether the caller is the EntryPoint contract or the admin.
modifier onlyAdminOrEntrypoint() virtual {
require(msg.sender == address(entryPoint()) || isAdmin(msg.sender), "Account: not admin or EntryPoint.");
_;
}
/// @notice Lets the account receive native tokens.
receive() external payable {}
/*///////////////////////////////////////////////////////////////
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
function isValidSignature(bytes32 _hash, bytes memory _signature)
public
view
virtual
override
returns (bytes4 magicValue)
{
address signer = _hash.recover(_signature);
if (isAdmin(signer)) {
return MAGICVALUE;
}
address caller = msg.sender;
require(
_accountPermissionsStorage().approvedTargets[signer].contains(caller),
"Account: caller not approved target."
);
if (isActiveSigner(signer)) {
magicValue = MAGICVALUE;
}
}
/*///////////////////////////////////////////////////////////////
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]);
}
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Registers the account on the factory if it hasn't been registered yet.
function _registerOnFactory() internal virtual {
BaseAccountFactory factoryContract = BaseAccountFactory(factory);
if (!factoryContract.isRegistered(address(this))) {
factoryContract.onRegister(AccountCoreStorage.data().firstAdmin, "");
}
}
/// @dev Calls a target contract and reverts if it fails.
function _call(
address _target,
uint256 value,
bytes memory _calldata
) internal virtual 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);
}
}// 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) public virtual initializer {
// This is passed as data in the `_registerOnFactory()` call in `AccountExtension` / `Account`.
AccountCoreStorage.data().firstAdmin = _defaultAdmin;
_setAdmin(_defaultAdmin, true);
}
/*///////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
event EntrypointOverride(IEntryPoint entrypointOverride);
/*///////////////////////////////////////////////////////////////
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 the balance of the account in Entrypoint.
function getDeposit() public view returns (uint256) {
return entryPoint().balanceOf(address(this));
}
/// @notice Returns whether a signer is authorized to perform transactions using the wallet.
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];
// If not an admin, check if the signer is active.
if (
permissions.startTimestamp > block.timestamp ||
block.timestamp >= permissions.endTimestamp ||
_accountPermissionsStorage().approvedTargets[_signer].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 (sig == AccountExtension.execute.selector) {
// Extract the `target` and `value` arguments from the calldata for `execute`.
(address target, uint256 value) = decodeExecuteCalldata(_userOp.callData);
// Check if the value is within the allowed range and if the target is approved.
if (
permissions.nativeTokenLimitPerTransaction < value ||
!_accountPermissionsStorage().approvedTargets[_signer].contains(target)
) {
// Account: value too high OR Account: target not approved.
return false;
}
} 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);
// For each target+value pair, check if the value is within the allowed range and if the target is approved.
for (uint256 i = 0; i < targets.length; i++) {
if (
permissions.nativeTokenLimitPerTransaction < values[i] ||
!_accountPermissionsStorage().approvedTargets[_signer].contains(targets[i])
) {
// Account: value too high OR Account: target not approved.
return false;
}
}
} else {
// Account: calling invalid fn.
return false;
}
return true;
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Deposit funds for this account in Entrypoint.
function addDeposit() public payable {
entryPoint().depositTo{ value: msg.value }(address(this));
}
/// @notice Withdraw funds for this account from Entrypoint.
function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public onlyAdmin {
entryPoint().withdrawTo(withdrawAddress, amount);
}
/// @notice Overrides the Entrypoint contract being used.
function setEntrypointOverride(IEntryPoint _entrypointOverride) public virtual onlyAdmin {
AccountCoreStorage.data().entrypointOverride = address(_entrypointOverride);
emit EntrypointOverride(_entrypointOverride);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
function getFunctionSignature(bytes calldata data) internal pure returns (bytes4 functionSelector) {
require(data.length >= 4, "Data too short");
return bytes4(data[:4]);
}
function decodeExecuteCalldata(bytes calldata data) internal pure returns (address _target, uint256 _value) {
require(data.length >= 4 + 32 + 32, "Data too short");
// 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 too short");
(_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;
uint48 validAfter = uint48(_accountPermissionsStorage().signerPermissions[signer].startTimestamp);
uint48 validUntil = uint48(_accountPermissionsStorage().signerPermissions[signer].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().firstAdmin, "");
} else {
BaseAccountFactory(factory).onSignerRemoved(_account, AccountCoreStorage.data().firstAdmin, "");
}
}
}
/// @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().firstAdmin, "");
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
library AccountCoreStorage {
bytes32 public constant ACCOUNT_CORE_STORAGE_POSITION = keccak256("account.core.storage");
struct Data {
address entrypointOverride;
address firstAdmin;
}
function data() internal pure returns (Data storage acountCoreData) {
bytes32 position = ACCOUNT_CORE_STORAGE_POSITION;
assembly {
acountCoreData.slot := position
}
}
}// 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;
/*///////////////////////////////////////////////////////////////
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
function isValidSignature(bytes32 _hash, bytes memory _signature)
public
view
virtual
override
returns (bytes4 magicValue)
{
address signer = _hash.recover(_signature);
if (isAdmin(signer)) {
return MAGICVALUE;
}
address caller = msg.sender;
require(
_accountPermissionsStorage().approvedTargets[signer].contains(caller),
"Account: caller not approved target."
);
if (isActiveSigner(signer)) {
magicValue = MAGICVALUE;
}
}
/*///////////////////////////////////////////////////////////////
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]);
}
}
/*///////////////////////////////////////////////////////////////
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().firstAdmin, "");
}
}
/// @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);
}
function _afterSignerPermissionsUpdate(SignerPermissionRequest calldata _req) internal virtual override {}
}// 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.)
}
}
}// 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(address _defaultAdmin, bytes memory _data) external {
address account = msg.sender;
require(_isAccountOfFactory(account, _defaultAdmin, _data), "AccountFactory: not an account.");
require(allAccounts.add(account), "AccountFactory: account already registered");
}
function onSignerAdded(
address _signer,
address _defaultAdmin,
bytes memory _data
) external {
address account = msg.sender;
require(_isAccountOfFactory(account, _defaultAdmin, _data), "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,
address _defaultAdmin,
bytes memory _data
) external {
address account = msg.sender;
require(_isAccountOfFactory(account, _defaultAdmin, _data), "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 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,
address _admin,
bytes memory _data
) internal view virtual returns (bool) {
bytes32 salt = _generateSalt(_admin, _data);
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) internal view virtual returns (bytes32) {
return keccak256(abi.encode(_admin));
}
/// @dev Called in `createAccount`. Initializes the account contract created in `createAccount`.
function _initializeAccount(
address _account,
address _admin,
bytes calldata _data
) internal virtual;
}// 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)
}
}// 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;
}
}{
"optimizer": {
"enabled": true,
"runs": 20
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IEntryPoint","name":"_entrypoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"accountAdmin","type":"address"}],"name":"AccountCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"SignerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"SignerRemoved","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accountImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"createAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entrypoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"getAccountsOfSigner","outputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_adminSigner","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"member","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRoleWithSwitch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onSignerAdded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onSignerRemoved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b50604051620064bb380380620064bb8339810160408190526200003491620002e8565b80306040516200004490620002da565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801562000078573d6000803e3d6000fd5b506001600160a01b03908116608052811660a05262000099600033620000a0565b5062000365565b620000b78282620000c760201b62000c0b1760201c565b620000c382826200014d565b5050565b6001620000d362000216565b6000848152602091825260408082206001600160a01b038616835290925220805460ff1916911515919091179055620001093390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006200015962000232565b60008481526020919091526040902054905060016200017762000232565b60008581526020919091526040812080549091906200019890849062000330565b90915550829050620001a962000232565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b039290921691909117905580620001eb62000232565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b60006200022d6200024960201b62000c741760201c565b905090565b60006200022d620002aa60201b62000cd21760201c565b6000806200027960017fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed56200034b565b6040516020016200028c91815260200190565b60408051601f19818403018152919052805160209091012092915050565b6000806200027960017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c6200034b565b6141a8806200231383390190565b600060208284031215620002fb57600080fd5b81516001600160a01b03811681146200031357600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156200034657620003466200031a565b500190565b6000828210156200036057620003606200031a565b500390565b60805160a051611f6c620003a76000396000818161027a0152610ad1015260008181610162015281816105c001528181610a2d0152610d230152611f6c6000f3fe608060405234801561001057600080fd5b50600436106101125760003560e01c806308e93d0a146101175780630db33003146101355780630e6254fd1461014a57806311464fbe1461015d578063248a9ca3146101915780632f2ff15d146101b257806336568abe146101c557806367793cc6146101d85780638878ed33146101eb5780639010d07c146101fe57806391d1485414610211578063938e3d7b146102345780639ddbb9d814610247578063a217fddf1461025a578063a32fa5b314610262578063a65d69d414610275578063ac9650d81461029c578063c3c5a547146102bc578063ca15c873146102cf578063d547741f146102e2578063d8fd8f44146102f5578063e8a3d48514610308575b600080fd5b61011f61031d565b60405161012c91906117f1565b60405180910390f35b610148610143366004611905565b61032e565b005b61011f610158366004611962565b6103d1565b6101847f000000000000000000000000000000000000000000000000000000000000000081565b60405161012c919061197d565b6101a461019f366004611991565b6103fb565b60405190815260200161012c565b6101486101c03660046119aa565b610419565b6101486101d33660046119aa565b6104c3565b6101486101e63660046119d6565b610522565b6101846101f9366004611a23565b610576565b61018461020c366004611aa5565b6105f0565b61022461021f3660046119aa565b6106ff565b604051901515815260200161012c565b610148610242366004611ac7565b610733565b610148610255366004611905565b610784565b6101a4600081565b6102246102703660046119aa565b61081d565b6101847f000000000000000000000000000000000000000000000000000000000000000081565b6102af6102aa366004611b17565b610880565b60405161012c9190611be7565b6102246102ca366004611962565b610974565b6101a46102dd366004611991565b610980565b6101486102f03660046119aa565b610a1d565b610184610303366004611a23565b610a28565b610310610b73565b60405161012c9190611c49565b60606103296000610d00565b905090565b3361033a818484610d0d565b61035f5760405162461bcd60e51b815260040161035690611c5c565b60405180910390fd5b6001600160a01b03841660009081526002602052604081206103819083610d61565b905080156103ca57846001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a35b5050505050565b6001600160a01b03811660009081526002602052604090206060906103f590610d00565b92915050565b6000610405610d76565b600092835260010160205250604090205490565b61043d610424610d76565b6000848152600191909101602052604090205433610d80565b610445610d76565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104b55760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610356565b6104bf8282610e05565b5050565b336001600160a01b038216146105185760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610356565b6104bf8282610e19565b3361052e818484610d0d565b61054a5760405162461bcd60e51b815260040161035690611c5c565b610555600082610e2d565b6105715760405162461bcd60e51b815260040161035690611c93565b505050565b6000806105b98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4292505050565b90506105e57f000000000000000000000000000000000000000000000000000000000000000082610e73565b9150505b9392505050565b6000806105fb610ed3565b600085815260209190915260408120549150805b828110156106f6576000610621610ed3565b60008881526020918252604080822085835260010190925220546001600160a01b03161461069a578482141561068857610659610ed3565b600087815260209182526040808220938252600190930190915220546001600160a01b031692506103f5915050565b610693600183611cf3565b91506106e4565b6106a58660006106ff565b80156106d157506106b4610ed3565b600087815260209182526040808220828052600201909252205481145b156106e4576106e1600183611cf3565b91505b6106ef600182611cf3565b905061060f565b50505092915050565b6000610709610d76565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b61073b610edd565b6107785760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610356565b61078181610ee9565b50565b33610790818484610d0d565b6107ac5760405162461bcd60e51b815260040161035690611c5c565b6001600160a01b03841660009081526002602052604081206107ce9083610e2d565b905080156103ca57846001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35050505050565b6000610827610d76565b600084815260209182526040808220828052909252205460ff166108775761084d610d76565b6000848152602091825260408082206001600160a01b0386168352909252205460ff1690506103f5565b50600192915050565b6060816001600160401b0381111561089a5761089a61185a565b6040519080825280602002602001820160405280156108cd57816020015b60608152602001906001900390816108b85790505b50905060005b8281101561096d5761093d308585848181106108f1576108f1611d0b565b90506020028101906109039190611d21565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fd492505050565b82828151811061094f5761094f611d0b565b6020026020010181905250808061096590611d6e565b9150506108d3565b5092915050565b60006103f58183610ff9565b60008061098b610ed3565b6000848152602091909152604081205491505b818110156109f85760006109b0610ed3565b60008681526020918252604080822085835260010190925220546001600160a01b0316146109e6576109e3600184611cf3565b92505b6109f1600182611cf3565b905061099e565b50610a048360006106ff565b15610a1757610a14600183611cf3565b91505b50919050565b610518610424610d76565b6000807f000000000000000000000000000000000000000000000000000000000000000090506000610a908686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4292505050565b90506000610a9e8383610e73565b90506001600160a01b0381163b15610aba5792506105e9915050565b610ac4838361101b565b9050336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b1d57610b01600082610e2d565b610b1d5760405162461bcd60e51b815260040161035690611c93565b610b29818888886110b2565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b6060610b7d61111a565b8054610b8890611d89565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb490611d89565b8015610c015780601f10610bd657610100808354040283529160200191610c01565b820191906000526020600020905b815481529060010190602001808311610be457829003601f168201915b5050505050905090565b6001610c15610d76565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600080610ca260017fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5611dbe565b604051602001610cb491815260200190565b60408051601f19818403018152919052805160209091012092915050565b600080610ca260017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611dbe565b606060006105e983611124565b600080610d1a8484610e42565b90506000610d487f000000000000000000000000000000000000000000000000000000000000000083610e73565b6001600160a01b03878116911614925050509392505050565b60006105e9836001600160a01b038416611180565b6000610329610c74565b610d88610d76565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104bf57610dc3816001600160a01b03166014611273565b610dce836020611273565b604051602001610ddf929190611dd5565b60408051601f198184030181529082905262461bcd60e51b825261035691600401611c49565b610e0f8282610c0b565b6104bf828261140e565b610e2382826114cd565b6104bf8282611536565b60006105e9836001600160a01b0384166115c5565b600082604051602001610e55919061197d565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c820120607882015260556043909101206000906105e9565b6000610329610cd2565b600061032981336106ff565b6000610ef361111a565b8054610efe90611d89565b80601f0160208091040260200160405190810160405280929190818152602001828054610f2a90611d89565b8015610f775780601f10610f4c57610100808354040283529160200191610f77565b820191906000526020600020905b815481529060010190602001808311610f5a57829003601f168201915b5050505050905081610f8761111a565b8151610f969260200190611758565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051610fc8929190611e42565b60405180910390a15050565b60606105e98383604051806060016040528060278152602001611f1060279139611614565b6001600160a01b038116600090815260018301602052604081205415156105e9565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166103f55760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610356565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906110e290869086908690600401611e67565b600060405180830381600087803b1580156110fc57600080fd5b505af1158015611110573d6000803e3d6000fd5b5050505050505050565b60006103296116f1565b60608160000180548060200260200160405190810160405280929190818152602001828054801561117457602002820191906000526020600020905b815481526020019060010190808311611160575b50505050509050919050565b600081815260018301602052604081205480156112695760006111a4600183611dbe565b85549091506000906111b890600190611dbe565b905081811461121d5760008660000182815481106111d8576111d8611d0b565b90600052602060002001549050808760000184815481106111fb576111fb611d0b565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061122e5761122e611ea7565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103f5565b60009150506103f5565b60606000611282836002611ebd565b61128d906002611cf3565b6001600160401b038111156112a4576112a461185a565b6040519080825280601f01601f1916602001820160405280156112ce576020820181803683370190505b509050600360fc1b816000815181106112e9576112e9611d0b565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061131857611318611d0b565b60200101906001600160f81b031916908160001a905350600061133c846002611ebd565b611347906001611cf3565b90505b60018111156113bf576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061137b5761137b611d0b565b1a60f81b82828151811061139157611391611d0b565b60200101906001600160f81b031916908160001a90535060049490941c936113b881611edc565b905061134a565b5083156105e95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610356565b6000611418610ed3565b6000848152602091909152604090205490506001611434610ed3565b6000858152602091909152604081208054909190611453908490611cf3565b90915550829050611462610ed3565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b0392909216919091179055806114a2610ed3565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6114d78282610d80565b6114df610d76565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611540610ed3565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061156d610ed3565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561159c610ed3565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b600081815260018301602052604081205461160c575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103f5565b5060006103f5565b60606001600160a01b0384163b61167c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610356565b600080856001600160a01b0316856040516116979190611ef3565b600060405180830381855af49150503d80600081146116d2576040519150601f19603f3d011682016040523d82523d6000602084013e6116d7565b606091505b50915091506116e782828661171f565b9695505050505050565b600080610ca260017fa7d40346e44ca145e94a946aa34a7d4a67245577dc18699a626fe0ffc6ce3281611dbe565b6060831561172e5750816105e9565b82511561173e5782518084602001fd5b8160405162461bcd60e51b81526004016103569190611c49565b82805461176490611d89565b90600052602060002090601f01602090048101928261178657600085556117cc565b82601f1061179f57805160ff19168380011785556117cc565b828001600101855582156117cc579182015b828111156117cc5782518255916020019190600101906117b1565b506117d89291506117dc565b5090565b5b808211156117d857600081556001016117dd565b6020808252825182820181905260009190848201906040850190845b818110156118325783516001600160a01b03168352928401929184019160010161180d565b50909695505050505050565b80356001600160a01b038116811461185557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60006001600160401b038084111561188a5761188a61185a565b604051601f8501601f19908116603f011681019082821181831017156118b2576118b261185a565b816040528093508581528686860111156118cb57600080fd5b858560208301376000602087830101525050509392505050565b600082601f8301126118f657600080fd5b6105e983833560208501611870565b60008060006060848603121561191a57600080fd5b6119238461183e565b92506119316020850161183e565b915060408401356001600160401b0381111561194c57600080fd5b611958868287016118e5565b9150509250925092565b60006020828403121561197457600080fd5b6105e98261183e565b6001600160a01b0391909116815260200190565b6000602082840312156119a357600080fd5b5035919050565b600080604083850312156119bd57600080fd5b823591506119cd6020840161183e565b90509250929050565b600080604083850312156119e957600080fd5b6119f28361183e565b915060208301356001600160401b03811115611a0d57600080fd5b611a19858286016118e5565b9150509250929050565b600080600060408486031215611a3857600080fd5b611a418461183e565b925060208401356001600160401b0380821115611a5d57600080fd5b818601915086601f830112611a7157600080fd5b813581811115611a8057600080fd5b876020828501011115611a9257600080fd5b6020830194508093505050509250925092565b60008060408385031215611ab857600080fd5b50508035926020909101359150565b600060208284031215611ad957600080fd5b81356001600160401b03811115611aef57600080fd5b8201601f81018413611b0057600080fd5b611b0f84823560208401611870565b949350505050565b60008060208385031215611b2a57600080fd5b82356001600160401b0380821115611b4157600080fd5b818501915085601f830112611b5557600080fd5b813581811115611b6457600080fd5b8660208260051b8501011115611b7957600080fd5b60209290920196919550909350505050565b60005b83811015611ba6578181015183820152602001611b8e565b83811115611bb5576000848401525b50505050565b60008151808452611bd3816020860160208601611b8b565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611c3c57603f19888603018452611c2a858351611bbb565b94509285019290850190600101611c0e565b5092979650505050505050565b6020815260006105e96020830184611bbb565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611d0657611d06611cdd565b500190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611d3857600080fd5b8301803591506001600160401b03821115611d5257600080fd5b602001915036819003821315611d6757600080fd5b9250929050565b6000600019821415611d8257611d82611cdd565b5060010190565b600181811c90821680611d9d57607f821691505b60208210811415610a1757634e487b7160e01b600052602260045260246000fd5b600082821015611dd057611dd0611cdd565b500390565b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e05816015850160208801611b8b565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611e36816026840160208801611b8b565b01602601949350505050565b604081526000611e556040830185611bbb565b82810360208401526105e58185611bbb565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b600052603160045260246000fd5b6000816000190483118215151615611ed757611ed7611cdd565b500290565b600081611eeb57611eeb611cdd565b506000190190565b60008251611f05818460208701611b8b565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220166ed2502b5745ba98b70960840410f117dccfc372805c2deaca45df8782311864736f6c634300080c00336101806040523480156200001257600080fd5b50604051620041a8380380620041a88339810160408190526200003591620002b4565b60408051808201825260078152661058d8dbdd5b9d60ca1b60208083019182528351808501855260018152603160f81b908201529151902060e08190527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101008190524660a081815285517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818701819052818801959095526060810193909352608080840192909252308382018190528651808503909201825260c093840190965280519401939093209092529190526101205281816200011762000134565b6001600160a01b0390811661014052166101605250620003199050565b6000620001406200021e565b5460ff1690506000620001526200021e565b54610100900460ff1690508015620001c05760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60ff82811610156200021a5760ff620001d86200021e565b805460ff191660ff9283161790556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6000620002356200023a60201b62001b731760201c565b905090565b6000806200026a60017f627d6cbb4eb558f37de3c2ec08b04710e54e06be936a302f087f7bfb80f39ae0620002f3565b6040516020016200027d91815260200190565b60408051601f19818403018152919052805160209091012092915050565b6001600160a01b0381168114620002b157600080fd5b50565b60008060408385031215620002c857600080fd5b8251620002d5816200029b565b6020840151909250620002e8816200029b565b809150509250929050565b6000828210156200031457634e487b7160e01b600052601160045260246000fd5b500390565b60805160a05160c05160e05161010051610120516101405161016051613dff620003a960003960006114f101526000818161047601528181611fa101528181611fd101528181612063015281816121c0015281816121ee015261225501526000612bfe01526000612c4d01526000612c2801526000612b8101526000612bab01526000612bd50152613dff6000f3fe6080604052600436106101565760003560e01c806301ffc9a714610162578063150b7a02146101975780631626ba7e146101db5780631dd756c5146101fb57806324d7806c1461021b5780633a871cdd1461023b57806340053da61461026957806347e1da2a1461028b5780634a58db19146102ab5780634b0bddd2146102b35780634d44560d146102d357806373e925d6146102f35780637dff5a79146103325780638b52d72314610352578063938e3d7b14610374578063ac9650d814610394578063b0d691fe146103c1578063b61d27f6146103e3578063b76464d514610403578063bc197c8114610423578063c399ec881461044f578063c45a015514610464578063d087d28814610498578063d1f57894146104ad578063d42f2f35146104cd578063e8a3d485146104e2578063e9523c9714610504578063f15d424e14610526578063f23a6e611461055357600080fd5b3661015d57005b600080fd5b34801561016e57600080fd5b5061018261017d366004612db7565b61057f565b60405190151581526020015b60405180910390f35b3480156101a357600080fd5b506101c26101b2366004612eb3565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161018e565b3480156101e757600080fd5b506101c26101f6366004612f1e565b6105c5565b34801561020757600080fd5b50610182610216366004612f7d565b61069f565b34801561022757600080fd5b50610182610236366004612fc2565b61092b565b34801561024757600080fd5b5061025b610256366004612fdf565b61095a565b60405190815260200161018e565b34801561027557600080fd5b5061028961028436600461306d565b610980565b005b34801561029757600080fd5b506102896102a6366004613122565b610d8b565b610289610efc565b3480156102bf57600080fd5b506102896102ce3660046131c9565b610f64565b3480156102df57600080fd5b506102896102ee366004613202565b610f97565b3480156102ff57600080fd5b5061031361030e36600461306d565b61102d565b6040805192151583526001600160a01b0390911660208301520161018e565b34801561033e57600080fd5b5061018261034d366004612fc2565b61107b565b34801561035e57600080fd5b50610367611113565b60405161018e91906132c5565b34801561038057600080fd5b5061028961038f366004613327565b611388565b3480156103a057600080fd5b506103b46103af36600461336f565b6113d9565b60405161018e919061340c565b3480156103cd57600080fd5b506103d66114cd565b60405161018e9190613461565b3480156103ef57600080fd5b506102896103fe366004613475565b611516565b34801561040f57600080fd5b5061028961041e366004612fc2565b6115a6565b34801561042f57600080fd5b506101c261043e36600461355e565b63bc197c8160e01b95945050505050565b34801561045b57600080fd5b5061025b61162d565b34801561047057600080fd5b506103d67f000000000000000000000000000000000000000000000000000000000000000081565b3480156104a457600080fd5b5061025b6116a8565b3480156104b957600080fd5b506102896104c836600461360b565b6116e7565b3480156104d957600080fd5b50610367611880565b3480156104ee57600080fd5b506104f76119f1565b60405161018e9190613652565b34801561051057600080fd5b50610519611a89565b60405161018e9190613665565b34801561053257600080fd5b50610546610541366004612fc2565b611a9b565b60405161018e91906136b2565b34801561055f57600080fd5b506101c261056e3660046136c5565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b14806105b057506001600160e01b03198216630a85bd0160e11b145b806105bf57506105bf82611bd1565b92915050565b6000806105d28484611c06565b90506105dd8161092b565b156105f25750630b135d3f60e11b90506105bf565b33610621816105ff611c2a565b6001600160a01b03851660009081526006919091016020526040902090611c34565b61067e5760405162461bcd60e51b8152602060048201526024808201527f4163636f756e743a2063616c6c6572206e6f7420617070726f7665642074617260448201526333b2ba1760e11b60648201526084015b60405180910390fd5b6106878261107b565b1561069757630b135d3f60e11b92505b505092915050565b60006106a9611c2a565b6001600160a01b0384166000908152600491909101602052604090205460ff16156106d6575060016105bf565b60006106e0611c2a565b6001600160a01b038516600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b9091041692810192909252909150421080610750575080604001516001600160801b03164210155b806107845750610782610761611c2a565b6001600160a01b038616600090815260069190910160205260409020611c56565b155b156107935760009150506105bf565b60006107aa6107a5606086018661372d565b611c60565b90506001600160e01b03198116635b0e93fb60e11b1415610837576000806107dd6107d8606088018861372d565b611c9a565b91509150808460000151108061081e575061081c826107fa611c2a565b6001600160a01b038a1660009081526006919091016020526040902090611c34565b155b156108305760009450505050506105bf565b5050610920565b6001600160e01b031981166323f0ed1560e11b141561091557600080610868610863606088018861372d565b611cff565b509150915060005b825181101561090d5781818151811061088b5761088b613773565b6020026020010151856000015110806108e857506108e68382815181106108b4576108b4613773565b60200260200101516108c4611c2a565b6001600160a01b038b1660009081526006919091016020526040902090611c34565b155b156108fb576000955050505050506105bf565b806109058161379f565b915050610870565b505050610920565b6000925050506105bf565b506001949350505050565b6000610935611c2a565b6001600160a01b03909216600090815260049290920160205250604090205460ff1690565b6000610964611d4c565b61096e8484611db5565b905061097982611f13565b9392505050565b600061098f6020850185612fc2565b905061099a8161092b565b156109fe5760405162461bcd60e51b815260206004820152602e60248201527f4163636f756e745065726d697373696f6e733a207369676e657220697320616c60448201526d3932b0b23c9030b71030b236b4b760911b6064820152608401610675565b42610a0f60c0860160a087016137d6565b6001600160801b031611158015610a3d5750610a3160e0850160c086016137d6565b6001600160801b031642105b610aa55760405162461bcd60e51b815260206004820152603360248201527f4163636f756e745065726d697373696f6e733a20696e76616c69642072657175604482015272195cdd081d985b1a591a5d1e481c195c9a5bd9606a1b6064820152608401610675565b600080610ab386868661102d565b9150915081610b125760405162461bcd60e51b815260206004820152602560248201527f4163636f756e745065726d697373696f6e733a20696e76616c6964207369676e604482015264617475726560d81b6064820152608401610675565b610b2783610b1e611c2a565b60020190611f60565b506001610b32611c2a565b60070160008860e00135815260200190815260200160002060006101000a81548160ff021916908315150217905550604051806060016040528087604001358152602001876060016020810190610b8991906137d6565b6001600160801b03168152602001610ba760a0890160808a016137d6565b6001600160801b03169052610bba611c2a565b6001600160a01b03851660009081526005919091016020908152604080832084518155918401519301516001600160801b03908116600160801b02931692909217600190920191909155610c30610c0f611c2a565b6001600160a01b038616600090815260069190910160205260409020611f75565b805190915060005b81811015610c9a57610c87838281518110610c5557610c55613773565b6020026020010151610c65611c2a565b6001600160a01b03891660009081526006919091016020526040902090611f82565b50610c936001826137f1565b9050610c38565b506000610caa60208a018a613809565b9050905060005b81811015610d2b57610d18610cc960208c018c613809565b83818110610cd957610cd9613773565b9050602002016020810190610cee9190612fc2565b610cf6611c2a565b6001600160a01b038a1660009081526006919091016020526040902090611f60565b50610d246001826137f1565b9050610cb1565b50610d3589611f97565b856001600160a01b0316846001600160a01b03167f09ac2cdf09c127af4eedd5aab0a6ca1224c4ae5586d5339657f7fa675d079b948b604051610d7891906138e3565b60405180910390a3505050505050505050565b610d936114cd565b6001600160a01b0316336001600160a01b03161480610db65750610db63361092b565b610dd25760405162461bcd60e51b8152600401610675906139b7565b610dda612054565b8481148015610de857508483145b610e345760405162461bcd60e51b815260206004820152601d60248201527f4163636f756e743a2077726f6e67206172726179206c656e677468732e0000006044820152606401610675565b60005b85811015610ef357610ee0878783818110610e5457610e54613773565b9050602002016020810190610e699190612fc2565b868684818110610e7b57610e7b613773565b90506020020135858585818110610e9457610e94613773565b9050602002810190610ea6919061372d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061213b92505050565b5080610eeb8161379f565b915050610e37565b50505050505050565b610f046114cd565b6001600160a01b031663b760faf934306040518363ffffffff1660e01b8152600401610f309190613461565b6000604051808303818588803b158015610f4957600080fd5b505af1158015610f5d573d6000803e3d6000fd5b5050505050565b610f6d3361092b565b610f895760405162461bcd60e51b8152600401610675906139f8565b610f9382826121ac565b5050565b610fa03361092b565b610fbc5760405162461bcd60e51b8152600401610675906139f8565b610fc46114cd565b60405163040b850f60e31b81526001600160a01b03848116600483015260248201849052919091169063205c2878906044015b600060405180830381600087803b15801561101157600080fd5b505af1158015611025573d6000803e3d6000fd5b505050505050565b60008061103b85858561228b565b9050611045611c2a565b60e08601356000908152600791909101602052604090205460ff1615801561107157506110718161092b565b9150935093915050565b600080611086611c2a565b6001600160a01b038416600090815260059190910160209081526040918290208251606081018452815481526001909101546001600160801b03808216938301849052600160801b909104169281019290925290915042108015906110f7575080604001516001600160801b031642105b80156109795750600061110b610761611c2a565b119392505050565b6060600061112a611122611c2a565b600201611f75565b8051909150600080826001600160401b0381111561114a5761114a612df6565b604051908082528060200260200182016040528015611173578160200160208202803683370190505b50905060005b838110156111f857600085828151811061119557611195613773565b6020026020010151905060006111aa8261107b565b9050808484815181106111bf576111bf613773565b9115156020928302919091019091015280156111e357846111df8161379f565b9550505b506111f190506001826137f1565b9050611179565b50816001600160401b0381111561121157611211612df6565b60405190808252806020026020018201604052801561124a57816020015b611237612cd4565b81526020019060019003908161122f5790505b5094506000805b8481101561137f5782818151811061126b5761126b613773565b602002602001015161127c5761136d565b600086828151811061129057611290613773565b6020026020010151905060006112a4611c2a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a08101909452918352909250810161130e610c0f611c2a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b031681525089858061134d9061379f565b96508151811061135f5761135f613773565b602002602001018190525050505b6113786001826137f1565b9050611251565b50505050505090565b6113906122ef565b6113cd5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610675565b6113d6816122fa565b50565b6060816001600160401b038111156113f3576113f3612df6565b60405190808252806020026020018201604052801561142657816020015b60608152602001906001900390816114115790505b50905060005b828110156114c6576114963085858481811061144a5761144a613773565b905060200281019061145c919061372d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123e592505050565b8282815181106114a8576114a8613773565b602002602001018190525080806114be9061379f565b91505061142c565b5092915050565b6000806114d861240a565b546001600160a01b0316905080156114ef57919050565b7f000000000000000000000000000000000000000000000000000000000000000091505090565b61151e6114cd565b6001600160a01b0316336001600160a01b0316148061154157506115413361092b565b61155d5760405162461bcd60e51b8152600401610675906139b7565b611565612054565b610f5d848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061213b92505050565b6115af3361092b565b6115cb5760405162461bcd60e51b8152600401610675906139f8565b806115d461240a565b80546001600160a01b0319166001600160a01b03929092169190911790556040517f6ff561b49f3fdec222aba62ccb04fdc5b86bacd71d71d235aa769b289d5e8f1b90611622908390613461565b60405180910390a150565b60006116376114cd565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116629190613461565b602060405180830381865afa15801561167f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a39190613a42565b905090565b60006116b26114cd565b604051631aab3f0d60e11b8152306004820152600060248201526001600160a01b0391909116906335567e1a90604401611662565b60006116f161242e565b5460ff169050600061170161242e565b54610100900460ff169050801580801561171e575060018360ff16105b8061173d575061172d30612438565b15801561173d57508260ff166001145b6117a05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610675565b60016117aa61242e565b805460ff191660ff9290921691909117905580156117e35760016117cc61242e565b80549115156101000261ff00199092169190911790555b856117ec61240a565b60010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061181e8660016121ac565b801561102557600061182e61242e565b80549115156101000261ff0019909216919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b6060600061188f611122611c2a565b8051909150806001600160401b038111156118ac576118ac612df6565b6040519080825280602002602001820160405280156118e557816020015b6118d2612cd4565b8152602001906001900390816118ca5790505b50925060005b818110156119eb57600083828151811061190757611907613773565b60200260200101519050600061191b611c2a565b6001600160a01b038316600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611985610c0f611c2a565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b03168152508684815181106119ca576119ca613773565b602002602001018190525050506001816119e491906137f1565b90506118eb565b50505090565b60606119fb612447565b8054611a0690613a5b565b80601f0160208091040260200160405190810160405280929190818152602001828054611a3290613a5b565b8015611a7f5780601f10611a5457610100808354040283529160200191611a7f565b820191906000526020600020905b815481529060010190602001808311611a6257829003601f168201915b5050505050905090565b60606116a3611a96611c2a565b611f75565b611aa3612cd4565b6000611aad611c2a565b6001600160a01b038416600081815260059290920160209081526040928390208351606081018552815481526001909101546001600160801b0380821683850152600160801b9091041681850152835160a081019094529183529092508101611b38611b17611c2a565b6001600160a01b038716600090815260069190910160205260409020611f75565b81526020018260000151815260200182602001516001600160801b0316815260200182604001516001600160801b0316815250915050919050565b600080611ba160017f627d6cbb4eb558f37de3c2ec08b04710e54e06be936a302f087f7bfb80f39ae0613a90565b604051602001611bb391815260200190565b60408051601f19818403018152919052805160209091012092915050565b60006001600160e01b03198216630271189760e51b14806105bf57506301ffc9a760e01b6001600160e01b03198316146105bf565b6000806000611c158585612451565b91509150611c2281612497565b509392505050565b60006116a36125e0565b6001600160a01b03811660009081526001830160205260408120541515610979565b60006105bf825490565b60006004821015611c835760405162461bcd60e51b815260040161067590613aa7565b611c91600460008486613acf565b61097991613af9565b6000806044831015611cbe5760405162461bcd60e51b815260040161067590613aa7565b611ccc602460048587613acf565b810190611cd99190612fc2565b9150611ce9604460248587613acf565b810190611cf69190613b27565b90509250929050565b606080806064841015611d245760405162461bcd60e51b815260040161067590613aa7565b611d318460048188613acf565b810190611d3e9190613bbf565b919790965090945092505050565b611d546114cd565b6001600160a01b0316336001600160a01b031614611db35760405162461bcd60e51b815260206004820152601c60248201527b1858d8dbdd5b9d0e881b9bdd08199c9bdb48115b9d1c9e541bda5b9d60221b6044820152606401610675565b565b7b0ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d05199960211b6000908152601c829052603c81206000611e33611df661014087018761372d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611c069050565b9050611e3f818661069f565b611e4e576001925050506105bf565b6000611e58611c2a565b6001600160a01b038316600090815260059190910160205260408120600101546001600160801b03169150611e8b611c2a565b6001600160a01b03841660009081526005919091016020908152604080832060010154815160608101835293845265ffffffffffff86811693850193909352600160801b90049182169201919091526001600160801b038116915065ffffffffffff60a01b60a09190911b166001600160d01b031960d084901b16175b979650505050505050565b80156113d657604051600090339060001990849084818181858888f193505050503d8060008114610f5d576040519150601f19603f3d011682016040523d82523d6000602084013e610f5d565b6000610979836001600160a01b03841661260e565b606060006109798361265d565b6000610979836001600160a01b0384166126b9565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156113d6576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016639ddbb9d86120036020840184612fc2565b61200b61240a565b600101546040516001600160e01b031960e085901b16815261203a92916001600160a01b031690600401613ca4565b600060405180830381600087803b158015610f4957600080fd5b60405163c3c5a54760e01b81527f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b0382169063c3c5a547906120a2903090600401613461565b602060405180830381865afa1580156120bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e39190613ccd565b6113d657806001600160a01b03166367793cc66120fe61240a565b600101546040805160e084901b6001600160e01b03191681526001600160a01b03909216600483015260248201526000604482015260640161203a565b60606000846001600160a01b031684846040516121589190613cea565b60006040518083038185875af1925050503d8060008114612195576040519150601f19603f3d011682016040523d82523d6000602084013e61219a565b606091505b509250905080611c2257815160208301fd5b6121b682826127ac565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b15610f93578015612253577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639ddbb9d88361222461240a565b600101546040516001600160e01b031960e085901b168152610ff792916001600160a01b031690600401613ca4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630db330038361222461240a565b60006122e783838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122e192506122d5915088905061285b565b80519060200120612984565b90611c06565b949350505050565b60006116a33361092b565b6000612304612447565b805461230f90613a5b565b80601f016020809104026020016040519081016040528092919081815260200182805461233b90613a5b565b80156123885780601f1061235d57610100808354040283529160200191612388565b820191906000526020600020905b81548152906001019060200180831161236b57829003601f168201915b5050505050905081612398612447565b81516123a79260200190612d1e565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a1681836040516123d9929190613d06565b60405180910390a15050565b60606109798383604051806060016040528060278152602001613da3602791396129b1565b7f78603d74dd787387002a0ebde2404195d07dd9588f0016ffe10a44a12946111590565b60006116a3611b73565b6001600160a01b03163b151590565b60006116a3612a8c565b6000808251604114156124885760208301516040840151606085015160001a61247c87828585612aba565b94509450505050612490565b506000905060025b9250929050565b60008160048111156124ab576124ab613d34565b14156124b45750565b60018160048111156124c8576124c8613d34565b14156125115760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610675565b600281600481111561252557612525613d34565b14156125735760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610675565b600381600481111561258757612587613d34565b14156113d65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610675565b600080611ba160017ff2776159535489b2c8217c06dac58993e45cb245272f968642d4d3ef6aa76150613a90565b6000818152600183016020526040812054612655575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105bf565b5060006105bf565b6060816000018054806020026020016040519081016040528092919081815260200182805480156126ad57602002820191906000526020600020905b815481526020019060010190808311612699575b50505050509050919050565b600081815260018301602052604081205480156127a25760006126dd600183613a90565b85549091506000906126f190600190613a90565b905081811461275657600086600001828154811061271157612711613773565b906000526020600020015490508087600001848154811061273457612734613773565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061276757612767613d4a565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105bf565b60009150506105bf565b806127b5611c2a565b6001600160a01b038416600090815260049190910160205260409020805460ff191691151591909117905580156127fe576127f8826127f2611c2a565b90611f60565b50612812565b6128108261280a611c2a565b90611f82565b505b816001600160a01b03167f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a111338260405161284f911515815260200190565b60405180910390a25050565b60607f1652558f82172f3162b9e179c9f4ce0654bac7c4802d6326a2868cc56afae20261288b6020840184612fc2565b6128986020850185613809565b6040516020016128a9929190613d60565b6040516020818303038152906040528051906020012084604001358560600160208101906128d791906137d6565b6128e760a08801608089016137d6565b6128f760c0890160a08a016137d6565b61290760e08a0160c08b016137d6565b6040805160208101999099526001600160a01b0390971696880196909652606087019490945260808601929092526001600160801b0390811660a086015290811660c085015290811660e0848101919091529116610100830152830135610120820152610140016040516020818303038152906040529050919050565b60006105bf612991612b74565b8360405161190160f01b8152600281019290925260228201526042902090565b60606129bc84612438565b612a175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610675565b600080856001600160a01b031685604051612a329190613cea565b600060405180830381855af49150503d8060008114612a6d576040519150601f19603f3d011682016040523d82523d6000602084013e612a72565b606091505b5091509150612a82828286612c9b565b9695505050505050565b600080611ba160017fa7d40346e44ca145e94a946aa34a7d4a67245577dc18699a626fe0ffc6ce3281613a90565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612ae75750600090506003612b6b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612b3b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612b6457600060019250925050612b6b565b9150600090505b94509492505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015612bcd57507f000000000000000000000000000000000000000000000000000000000000000046145b15612bf757507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60608315612caa575081610979565b825115612cba5782518084602001fd5b8160405162461bcd60e51b81526004016106759190613652565b6040518060a0016040528060006001600160a01b03168152602001606081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b828054612d2a90613a5b565b90600052602060002090601f016020900481019282612d4c5760008555612d92565b82601f10612d6557805160ff1916838001178555612d92565b82800160010185558215612d92579182015b82811115612d92578251825591602001919060010190612d77565b50612d9e929150612da2565b5090565b5b80821115612d9e5760008155600101612da3565b600060208284031215612dc957600080fd5b81356001600160e01b03198116811461097957600080fd5b6001600160a01b03811681146113d657600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612e3457612e34612df6565b604052919050565b60006001600160401b03831115612e5557612e55612df6565b612e68601f8401601f1916602001612e0c565b9050828152838383011115612e7c57600080fd5b828260208301376000602084830101529392505050565b600082601f830112612ea457600080fd5b61097983833560208501612e3c565b60008060008060808587031215612ec957600080fd5b8435612ed481612de1565b93506020850135612ee481612de1565b92506040850135915060608501356001600160401b03811115612f0657600080fd5b612f1287828801612e93565b91505092959194509250565b60008060408385031215612f3157600080fd5b8235915060208301356001600160401b03811115612f4e57600080fd5b612f5a85828601612e93565b9150509250929050565b60006101608284031215612f7757600080fd5b50919050565b60008060408385031215612f9057600080fd5b8235612f9b81612de1565b915060208301356001600160401b03811115612fb657600080fd5b612f5a85828601612f64565b600060208284031215612fd457600080fd5b813561097981612de1565b600080600060608486031215612ff457600080fd5b83356001600160401b0381111561300a57600080fd5b61301686828701612f64565b9660208601359650604090950135949350505050565b60008083601f84011261303e57600080fd5b5081356001600160401b0381111561305557600080fd5b60208301915083602082850101111561249057600080fd5b60008060006040848603121561308257600080fd5b83356001600160401b038082111561309957600080fd5b9085019061010082880312156130ae57600080fd5b909350602085013590808211156130c457600080fd5b506130d18682870161302c565b9497909650939450505050565b60008083601f8401126130f057600080fd5b5081356001600160401b0381111561310757600080fd5b6020830191508360208260051b850101111561249057600080fd5b6000806000806000806060878903121561313b57600080fd5b86356001600160401b038082111561315257600080fd5b61315e8a838b016130de565b9098509650602089013591508082111561317757600080fd5b6131838a838b016130de565b9096509450604089013591508082111561319c57600080fd5b506131a989828a016130de565b979a9699509497509295939492505050565b80151581146113d657600080fd5b600080604083850312156131dc57600080fd5b82356131e781612de1565b915060208301356131f7816131bb565b809150509250929050565b6000806040838503121561321557600080fd5b823561322081612de1565b946020939093013593505050565b6001600160801b03169052565b80516001600160a01b03908116835260208083015160a082860181905281519086018190526000939183019290849060c08801905b8083101561329257855185168252948301946001929092019190830190613270565b5060408701516040890152606087015194506132b1606089018661322e565b60808701519450611f08608089018661322e565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561331a57603f1988860301845261330885835161323b565b945092850192908501906001016132ec565b5092979650505050505050565b60006020828403121561333957600080fd5b81356001600160401b0381111561334f57600080fd5b8201601f8101841361336057600080fd5b6122e784823560208401612e3c565b6000806020838503121561338257600080fd5b82356001600160401b0381111561339857600080fd5b6133a4858286016130de565b90969095509350505050565b60005b838110156133cb5781810151838201526020016133b3565b838111156133da576000848401525b50505050565b600081518084526133f88160208601602086016133b0565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561331a57603f1988860301845261344f8583516133e0565b94509285019290850190600101613433565b6001600160a01b0391909116815260200190565b6000806000806060858703121561348b57600080fd5b843561349681612de1565b93506020850135925060408501356001600160401b038111156134b857600080fd5b6134c48782880161302c565b95989497509550505050565b60006001600160401b038211156134e9576134e9612df6565b5060051b60200190565b600082601f83011261350457600080fd5b81356020613519613514836134d0565b612e0c565b82815260059290921b8401810191818101908684111561353857600080fd5b8286015b84811015613553578035835291830191830161353c565b509695505050505050565b600080600080600060a0868803121561357657600080fd5b853561358181612de1565b9450602086013561359181612de1565b935060408601356001600160401b03808211156135ad57600080fd5b6135b989838a016134f3565b945060608801359150808211156135cf57600080fd5b6135db89838a016134f3565b935060808801359150808211156135f157600080fd5b506135fe88828901612e93565b9150509295509295909350565b60008060006040848603121561362057600080fd5b833561362b81612de1565b925060208401356001600160401b0381111561364657600080fd5b6130d18682870161302c565b60208152600061097960208301846133e0565b6020808252825182820181905260009190848201906040850190845b818110156136a65783516001600160a01b031683529284019291840191600101613681565b50909695505050505050565b602081526000610979602083018461323b565b600080600080600060a086880312156136dd57600080fd5b85356136e881612de1565b945060208601356136f881612de1565b9350604086013592506060860135915060808601356001600160401b0381111561372157600080fd5b6135fe88828901612e93565b6000808335601e1984360301811261374457600080fd5b8301803591506001600160401b0382111561375e57600080fd5b60200191503681900382131561249057600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156137b3576137b3613789565b5060010190565b80356001600160801b03811681146137d157600080fd5b919050565b6000602082840312156137e857600080fd5b610979826137ba565b6000821982111561380457613804613789565b500190565b6000808335601e1984360301811261382057600080fd5b8301803591506001600160401b0382111561383a57600080fd5b6020019150600581901b360382131561249057600080fd5b6000808335601e1984360301811261386957600080fd5b83016020810192503590506001600160401b0381111561388857600080fd5b8060051b360383131561249057600080fd5b8183526000602080850194508260005b858110156138d85781356138bd81612de1565b6001600160a01b0316875295820195908201906001016138aa565b509495945050505050565b60208152600082356138f481612de1565b6001600160a01b031660208381019190915261391290840184613852565b61010080604086015261392a6101208601838561389a565b925060408601356060860152613942606087016137ba565b9150613951608086018361322e565b61395d608087016137ba565b915061396c60a086018361322e565b61397860a087016137ba565b915061398760c086018361322e565b61399360c087016137ba565b91506139a260e086018361322e565b60e08601358186015250508091505092915050565b60208082526021908201527f4163636f756e743a206e6f742061646d696e206f7220456e747279506f696e746040820152601760f91b606082015260800190565b6020808252602a908201527f4163636f756e745065726d697373696f6e733a2063616c6c6572206973206e6f6040820152693a1030b71030b236b4b760b11b606082015260800190565b600060208284031215613a5457600080fd5b5051919050565b600181811c90821680613a6f57607f821691505b60208210811415612f7757634e487b7160e01b600052602260045260246000fd5b600082821015613aa257613aa2613789565b500390565b6020808252600e908201526d11185d18481d1bdbc81cda1bdc9d60921b604082015260600190565b60008085851115613adf57600080fd5b83861115613aec57600080fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156106975760049490940360031b84901b1690921692915050565b600060208284031215613b3957600080fd5b5035919050565b600082601f830112613b5157600080fd5b81356020613b61613514836134d0565b82815260059290921b84018101918181019086841115613b8057600080fd5b8286015b848110156135535780356001600160401b03811115613ba35760008081fd5b613bb18986838b0101612e93565b845250918301918301613b84565b600080600060608486031215613bd457600080fd5b83356001600160401b0380821115613beb57600080fd5b818601915086601f830112613bff57600080fd5b81356020613c0f613514836134d0565b82815260059290921b8401810191818101908a841115613c2e57600080fd5b948201945b83861015613c55578535613c4681612de1565b82529482019490820190613c33565b97505087013592505080821115613c6b57600080fd5b613c77878388016134f3565b93506040860135915080821115613c8d57600080fd5b50613c9a86828701613b40565b9150509250925092565b6001600160a01b0392831681529116602082015260606040820181905260009082015260800190565b600060208284031215613cdf57600080fd5b8151610979816131bb565b60008251613cfc8184602087016133b0565b9190910192915050565b604081526000613d1960408301856133e0565b8281036020840152613d2b81856133e0565b95945050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60008184825b85811015613d97578135613d7981612de1565b6001600160a01b031683526020928301929190910190600101613d66565b50909594505050505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ac0f25405b339ee0e9383ce73281af74d507baad9ddb8fb5ecbb7dc67b8a7c1064736f6c634300080c00330000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101125760003560e01c806308e93d0a146101175780630db33003146101355780630e6254fd1461014a57806311464fbe1461015d578063248a9ca3146101915780632f2ff15d146101b257806336568abe146101c557806367793cc6146101d85780638878ed33146101eb5780639010d07c146101fe57806391d1485414610211578063938e3d7b146102345780639ddbb9d814610247578063a217fddf1461025a578063a32fa5b314610262578063a65d69d414610275578063ac9650d81461029c578063c3c5a547146102bc578063ca15c873146102cf578063d547741f146102e2578063d8fd8f44146102f5578063e8a3d48514610308575b600080fd5b61011f61031d565b60405161012c91906117f1565b60405180910390f35b610148610143366004611905565b61032e565b005b61011f610158366004611962565b6103d1565b6101847f0000000000000000000000000f8705688ac8cf7829c1387331bf048e9af65c6c81565b60405161012c919061197d565b6101a461019f366004611991565b6103fb565b60405190815260200161012c565b6101486101c03660046119aa565b610419565b6101486101d33660046119aa565b6104c3565b6101486101e63660046119d6565b610522565b6101846101f9366004611a23565b610576565b61018461020c366004611aa5565b6105f0565b61022461021f3660046119aa565b6106ff565b604051901515815260200161012c565b610148610242366004611ac7565b610733565b610148610255366004611905565b610784565b6101a4600081565b6102246102703660046119aa565b61081d565b6101847f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b6102af6102aa366004611b17565b610880565b60405161012c9190611be7565b6102246102ca366004611962565b610974565b6101a46102dd366004611991565b610980565b6101486102f03660046119aa565b610a1d565b610184610303366004611a23565b610a28565b610310610b73565b60405161012c9190611c49565b60606103296000610d00565b905090565b3361033a818484610d0d565b61035f5760405162461bcd60e51b815260040161035690611c5c565b60405180910390fd5b6001600160a01b03841660009081526002602052604081206103819083610d61565b905080156103ca57846001600160a01b0316826001600160a01b03167f98d1ebbe00ae92a5de96a0f49742a8afa89f42363592bc2e7cfaaed68b45e7a660405160405180910390a35b5050505050565b6001600160a01b03811660009081526002602052604090206060906103f590610d00565b92915050565b6000610405610d76565b600092835260010160205250604090205490565b61043d610424610d76565b6000848152600191909101602052604090205433610d80565b610445610d76565b6000838152602091825260408082206001600160a01b0385168352909252205460ff16156104b55760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610356565b6104bf8282610e05565b5050565b336001600160a01b038216146105185760405162461bcd60e51b815260206004820152601a60248201527921b0b71037b7363c903932b737bab731b2903337b91039b2b63360311b6044820152606401610356565b6104bf8282610e19565b3361052e818484610d0d565b61054a5760405162461bcd60e51b815260040161035690611c5c565b610555600082610e2d565b6105715760405162461bcd60e51b815260040161035690611c93565b505050565b6000806105b98585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4292505050565b90506105e57f0000000000000000000000000f8705688ac8cf7829c1387331bf048e9af65c6c82610e73565b9150505b9392505050565b6000806105fb610ed3565b600085815260209190915260408120549150805b828110156106f6576000610621610ed3565b60008881526020918252604080822085835260010190925220546001600160a01b03161461069a578482141561068857610659610ed3565b600087815260209182526040808220938252600190930190915220546001600160a01b031692506103f5915050565b610693600183611cf3565b91506106e4565b6106a58660006106ff565b80156106d157506106b4610ed3565b600087815260209182526040808220828052600201909252205481145b156106e4576106e1600183611cf3565b91505b6106ef600182611cf3565b905061060f565b50505092915050565b6000610709610d76565b6000938452602090815260408085206001600160a01b039490941685529290525090205460ff1690565b61073b610edd565b6107785760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610356565b61078181610ee9565b50565b33610790818484610d0d565b6107ac5760405162461bcd60e51b815260040161035690611c5c565b6001600160a01b03841660009081526002602052604081206107ce9083610e2d565b905080156103ca57846001600160a01b0316826001600160a01b03167f12146497b3b826918ec47f0cac7272a09ed06b30c16c030e99ec48ff5dd60b4760405160405180910390a35050505050565b6000610827610d76565b600084815260209182526040808220828052909252205460ff166108775761084d610d76565b6000848152602091825260408082206001600160a01b0386168352909252205460ff1690506103f5565b50600192915050565b6060816001600160401b0381111561089a5761089a61185a565b6040519080825280602002602001820160405280156108cd57816020015b60608152602001906001900390816108b85790505b50905060005b8281101561096d5761093d308585848181106108f1576108f1611d0b565b90506020028101906109039190611d21565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fd492505050565b82828151811061094f5761094f611d0b565b6020026020010181905250808061096590611d6e565b9150506108d3565b5092915050565b60006103f58183610ff9565b60008061098b610ed3565b6000848152602091909152604081205491505b818110156109f85760006109b0610ed3565b60008681526020918252604080822085835260010190925220546001600160a01b0316146109e6576109e3600184611cf3565b92505b6109f1600182611cf3565b905061099e565b50610a048360006106ff565b15610a1757610a14600183611cf3565b91505b50919050565b610518610424610d76565b6000807f0000000000000000000000000f8705688ac8cf7829c1387331bf048e9af65c6c90506000610a908686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4292505050565b90506000610a9e8383610e73565b90506001600160a01b0381163b15610aba5792506105e9915050565b610ac4838361101b565b9050336001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891614610b1d57610b01600082610e2d565b610b1d5760405162461bcd60e51b815260040161035690611c93565b610b29818888886110b2565b866001600160a01b0316816001600160a01b03167fac631f3001b55ea1509cf3d7e74898f85392a61a76e8149181ae1259622dabc860405160405180910390a39695505050505050565b6060610b7d61111a565b8054610b8890611d89565b80601f0160208091040260200160405190810160405280929190818152602001828054610bb490611d89565b8015610c015780601f10610bd657610100808354040283529160200191610c01565b820191906000526020600020905b815481529060010190602001808311610be457829003601f168201915b5050505050905090565b6001610c15610d76565b6000848152602091825260408082206001600160a01b0386168084529352808220805460ff1916941515949094179093559151339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600080610ca260017fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5611dbe565b604051602001610cb491815260200190565b60408051601f19818403018152919052805160209091012092915050565b600080610ca260017f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c611dbe565b606060006105e983611124565b600080610d1a8484610e42565b90506000610d487f0000000000000000000000000f8705688ac8cf7829c1387331bf048e9af65c6c83610e73565b6001600160a01b03878116911614925050509392505050565b60006105e9836001600160a01b038416611180565b6000610329610c74565b610d88610d76565b6000838152602091825260408082206001600160a01b0385168352909252205460ff166104bf57610dc3816001600160a01b03166014611273565b610dce836020611273565b604051602001610ddf929190611dd5565b60408051601f198184030181529082905262461bcd60e51b825261035691600401611c49565b610e0f8282610c0b565b6104bf828261140e565b610e2382826114cd565b6104bf8282611536565b60006105e9836001600160a01b0384166115c5565b600082604051602001610e55919061197d565b60405160208183030381529060405280519060200120905092915050565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c820120607882015260556043909101206000906105e9565b6000610329610cd2565b600061032981336106ff565b6000610ef361111a565b8054610efe90611d89565b80601f0160208091040260200160405190810160405280929190818152602001828054610f2a90611d89565b8015610f775780601f10610f4c57610100808354040283529160200191610f77565b820191906000526020600020905b815481529060010190602001808311610f5a57829003601f168201915b5050505050905081610f8761111a565b8151610f969260200190611758565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051610fc8929190611e42565b60405180910390a15050565b60606105e98383604051806060016040528060278152602001611f1060279139611614565b6001600160a01b038116600090815260018301602052604081205415156105e9565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166103f55760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610356565b60405163347d5e2560e21b81526001600160a01b0385169063d1f57894906110e290869086908690600401611e67565b600060405180830381600087803b1580156110fc57600080fd5b505af1158015611110573d6000803e3d6000fd5b5050505050505050565b60006103296116f1565b60608160000180548060200260200160405190810160405280929190818152602001828054801561117457602002820191906000526020600020905b815481526020019060010190808311611160575b50505050509050919050565b600081815260018301602052604081205480156112695760006111a4600183611dbe565b85549091506000906111b890600190611dbe565b905081811461121d5760008660000182815481106111d8576111d8611d0b565b90600052602060002001549050808760000184815481106111fb576111fb611d0b565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061122e5761122e611ea7565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103f5565b60009150506103f5565b60606000611282836002611ebd565b61128d906002611cf3565b6001600160401b038111156112a4576112a461185a565b6040519080825280601f01601f1916602001820160405280156112ce576020820181803683370190505b509050600360fc1b816000815181106112e9576112e9611d0b565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061131857611318611d0b565b60200101906001600160f81b031916908160001a905350600061133c846002611ebd565b611347906001611cf3565b90505b60018111156113bf576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061137b5761137b611d0b565b1a60f81b82828151811061139157611391611d0b565b60200101906001600160f81b031916908160001a90535060049490941c936113b881611edc565b905061134a565b5083156105e95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610356565b6000611418610ed3565b6000848152602091909152604090205490506001611434610ed3565b6000858152602091909152604081208054909190611453908490611cf3565b90915550829050611462610ed3565b6000858152602091825260408082208583526001019092522080546001600160a01b0319166001600160a01b0392909216919091179055806114a2610ed3565b6000948552602090815260408086206001600160a01b03909516865260029094019052919092205550565b6114d78282610d80565b6114df610d76565b6000838152602091825260408082206001600160a01b0385168084529352808220805460ff191690555133929185917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611540610ed3565b6000848152602091825260408082206001600160a01b03861683526002019092522054905061156d610ed3565b6000848152602091825260408082208483526001019092522080546001600160a01b031916905561159c610ed3565b6000938452602090815260408085206001600160a01b0390941685526002909301905250812055565b600081815260018301602052604081205461160c575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103f5565b5060006103f5565b60606001600160a01b0384163b61167c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610356565b600080856001600160a01b0316856040516116979190611ef3565b600060405180830381855af49150503d80600081146116d2576040519150601f19603f3d011682016040523d82523d6000602084013e6116d7565b606091505b50915091506116e782828661171f565b9695505050505050565b600080610ca260017fa7d40346e44ca145e94a946aa34a7d4a67245577dc18699a626fe0ffc6ce3281611dbe565b6060831561172e5750816105e9565b82511561173e5782518084602001fd5b8160405162461bcd60e51b81526004016103569190611c49565b82805461176490611d89565b90600052602060002090601f01602090048101928261178657600085556117cc565b82601f1061179f57805160ff19168380011785556117cc565b828001600101855582156117cc579182015b828111156117cc5782518255916020019190600101906117b1565b506117d89291506117dc565b5090565b5b808211156117d857600081556001016117dd565b6020808252825182820181905260009190848201906040850190845b818110156118325783516001600160a01b03168352928401929184019160010161180d565b50909695505050505050565b80356001600160a01b038116811461185557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60006001600160401b038084111561188a5761188a61185a565b604051601f8501601f19908116603f011681019082821181831017156118b2576118b261185a565b816040528093508581528686860111156118cb57600080fd5b858560208301376000602087830101525050509392505050565b600082601f8301126118f657600080fd5b6105e983833560208501611870565b60008060006060848603121561191a57600080fd5b6119238461183e565b92506119316020850161183e565b915060408401356001600160401b0381111561194c57600080fd5b611958868287016118e5565b9150509250925092565b60006020828403121561197457600080fd5b6105e98261183e565b6001600160a01b0391909116815260200190565b6000602082840312156119a357600080fd5b5035919050565b600080604083850312156119bd57600080fd5b823591506119cd6020840161183e565b90509250929050565b600080604083850312156119e957600080fd5b6119f28361183e565b915060208301356001600160401b03811115611a0d57600080fd5b611a19858286016118e5565b9150509250929050565b600080600060408486031215611a3857600080fd5b611a418461183e565b925060208401356001600160401b0380821115611a5d57600080fd5b818601915086601f830112611a7157600080fd5b813581811115611a8057600080fd5b876020828501011115611a9257600080fd5b6020830194508093505050509250925092565b60008060408385031215611ab857600080fd5b50508035926020909101359150565b600060208284031215611ad957600080fd5b81356001600160401b03811115611aef57600080fd5b8201601f81018413611b0057600080fd5b611b0f84823560208401611870565b949350505050565b60008060208385031215611b2a57600080fd5b82356001600160401b0380821115611b4157600080fd5b818501915085601f830112611b5557600080fd5b813581811115611b6457600080fd5b8660208260051b8501011115611b7957600080fd5b60209290920196919550909350505050565b60005b83811015611ba6578181015183820152602001611b8e565b83811115611bb5576000848401525b50505050565b60008151808452611bd3816020860160208601611b8b565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611c3c57603f19888603018452611c2a858351611bbb565b94509285019290850190600101611c0e565b5092979650505050505050565b6020815260006105e96020830184611bbb565b6020808252601f908201527f4163636f756e74466163746f72793a206e6f7420616e206163636f756e742e00604082015260600190565b6020808252602a908201527f4163636f756e74466163746f72793a206163636f756e7420616c7265616479206040820152691c9959da5cdd195c995960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611d0657611d06611cdd565b500190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611d3857600080fd5b8301803591506001600160401b03821115611d5257600080fd5b602001915036819003821315611d6757600080fd5b9250929050565b6000600019821415611d8257611d82611cdd565b5060010190565b600181811c90821680611d9d57607f821691505b60208210811415610a1757634e487b7160e01b600052602260045260246000fd5b600082821015611dd057611dd0611cdd565b500390565b7402832b936b4b9b9b4b7b7399d1030b1b1b7bab73a1605d1b815260008351611e05816015850160208801611b8b565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351611e36816026840160208801611b8b565b01602601949350505050565b604081526000611e556040830185611bbb565b82810360208401526105e58185611bbb565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b600052603160045260246000fd5b6000816000190483118215151615611ed757611ed7611cdd565b500290565b600081611eeb57611eeb611cdd565b506000190190565b60008251611f05818460208701611b8b565b919091019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220166ed2502b5745ba98b70960840410f117dccfc372805c2deaca45df8782311864736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
-----Decoded View---------------
Arg [0] : _entrypoint (address): 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.