Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
OPF7702v11
Compiler Version
v0.8.29+commit.ab55807c
Optimization Enabled:
Yes with 2000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░ ░ ░░░░░ ░ ░░░░░░ ░░░░░░ ░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ▒▒▒ ▒▒▒▒ ▒▒▒ ▒▒▒▒ ▒ ▒▒▒▒▒▒▒ ▒ ▒▒▒ ▒ ▒▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒ ▒▒▒▒ ▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒ ▒ ▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒ ▒ ▒▒▒ ▒ ▒▒▒▒▒▒▒▒ ▒ ▒▒▒▒ ▒ ▒▒▒▒▒▒▒ ▒ ▒▒ ▒ ▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒ ▒▒▒▒ ▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒ ▒▒▒▒▒ ▓ ▓▓▓▓▓▓▓▓ ▓ ▓▓▓ ▓▓▓ ▓▓ ▓ ▓ ▓▓▓ ▓▓▓▓▓▓▓▓ ▓ ▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓ ▓ ▓▓▓▓▓▓▓▓ ▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓ ▓ ▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓ ▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓ ▓ ▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓ █████ ██████ ████████ █ ██████ █ ███████████ ██████ ██████ █████ █████████ ████████ ████████ █████ █ █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ */ // SPDX-License-Identifier: MIT pragma solidity ^0.8.29; import {SpendLimit} from "src/utils/SpendLimit.sol"; import {IValidation} from "src/interfaces/IValidation.sol"; import {ISessionKey} from "src/interfaces/ISessionkey.sol"; import {WebAuthnVerifier} from "src/utils/WebAuthnVerifier.sol"; import {BaseAccount} from "lib/account-abstraction/contracts/core/BaseAccount.sol"; import {IAccount} from "lib/account-abstraction/contracts/interfaces/IAccount.sol"; import {SafeCast} from "lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; import {ECDSA} from "lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; import {IEntryPoint} from "lib/account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {ReentrancyGuard} from "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol"; import {Initializable} from "lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; import {PackedUserOperation} from "lib/account-abstraction/contracts/interfaces/PackedUserOperation.sol"; import {SIG_VALIDATION_FAILED, SIG_VALIDATION_SUCCESS, _packValidationData} from "lib/account-abstraction/contracts/core/Helpers.sol"; import "lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; import "lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol"; import "lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import "lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol"; /** * @title Openfort Base Account 7702 with ERC-4337 Support * @author Openfort@0xkoiner * @notice This contract implements an EIP-7702 compatible account with EIP-712 signatures and ERC-4337 support * @dev Implements EIP-7702, EIP-712, ERC-4337, and various token handling capabilities */ // address: 0xD24af0109E31F238440E2d6A6d49935d499274b7 14/05/2025 // keccak256("openfort.baseAccount.7702.v1") = 0x801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f368 contract OPF7702v11 layout at 0x801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f368 is IAccount, SpendLimit, BaseAccount, ISessionKey, Initializable, ReentrancyGuard, WebAuthnVerifier, IERC165, IERC1271, ERC1155Holder, ERC721Holder { using ECDSA for bytes32; /** * @notice Structure for representing a transaction to be executed by the account * @dev Contains destination address, ETH value, and calldata */ struct Transaction { address to; uint256 value; bytes data; } address public constant DEAD_ADDRESS = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; uint256 public constant MAX_SELECTORS = 10; bytes4 internal constant EXECUTE_SELECTOR = 0xb61d27f6; bytes4 internal constant EXECUTEBATCH_SELECTOR = 0x47e1da2a; bytes32 private constant P256_VERIFIER = 0x2562256225622562256225622562256225622562256225622562256225622562; /// @notice Address of the implementation contract address public immutable _OPENFORT_CONTRACT_ADDRESS; /// @notice The EntryPoint singleton contract address private immutable ENTRY_POINT; /// @notice Current transaction nonce, used to prevent replay attacks uint256 public nonce; uint256 public id; mapping(uint256 id => Key key) public idSessionKeys; mapping(bytes32 sessionKey => SessionKey sessionKeyData) public sessionKeys; mapping(address sessionKeyEOA => SessionKey sessionKeyData) public sessionKeysEOA; mapping(bytes challenge => bool isUsed) public usedChallenges; error OpenfortBaseAccount7702V1__InvalidNonce(); error OpenfortBaseAccount7702V1__InvalidSignature(); error OpenfortBaseAccount7702V1__ValidationExpired(); error OpenfortBaseAccount7702V1__InvalidTransactionLength(); error OpenfortBaseAccount7702V1__InvalidTransactionTarget(); error OpenfortBaseAccount7702V1__TransactionFailed(bytes returnData); error SessionKeyManager__InvalidTimestamp(); error SessionKeyManager__AddressCantBeZero(); error SessionKeyManager__SessionKeyInactive(); error SessionKeyManager__SelectorsListTooBig(); error SessionKeyManager__SessionKeyRegistered(); /// @notice Emitted when the account is initialized with an masterKey event Initialized(Key indexed masterKey); /// @notice Emitted when a transaction is executed event TransactionExecuted(address indexed target, uint256 value, bytes data); event SessionKeyRevoked(bytes32 indexed sessionKey); event SessionKeyRegistrated(bytes32 indexed sessionKey); /** * @notice Sets up the contract with EIP-712 domain and the EntryPoint * @param _entryPoint Address of the ERC-4337 EntryPoint contract */ constructor(address _entryPoint) { ENTRY_POINT = _entryPoint; _OPENFORT_CONTRACT_ADDRESS = address(this); _disableInitializers(); } fallback() external payable { } receive() external payable { } /** * @notice Initializes the account * @dev Can only be called via EntryPoint or during contract creation * @param _validUntil The timestamp until which the initialization is valid * @param _hash Hash of the user operation * @param _signature Signature to validate ownership * @param _nonce Nonce to prevent replay attacks */ function initialize(Key calldata _key, SpendTokenInfo calldata _spendTokenInfo, bytes4[] calldata _allowedSelectors, bytes32 _hash, bytes memory _signature, uint256 _validUntil, uint256 _nonce) external initializer { _requireForExecute(); _clearStorage(); _validateNonce(_nonce); _notExpired(_validUntil); if (!_checkSignature(_hash, _signature)) { revert OpenfortBaseAccount7702V1__InvalidSignature(); } nonce = _nonce; registerSessionKey(_key, uint48(block.timestamp + 10000), uint48(0), uint48(0), false, DEAD_ADDRESS, _spendTokenInfo, _allowedSelectors, 0); emit Initialized(_key); } /** * @notice Registers a new session key with specified permissions * @param _key Key information (EOA or WebAuthn) * @param _validUntil Timestamp until which the key is valid * @param _validAfter Timestamp after which the key becomes valid * @param _limit Number of transactions allowed (0 for unlimited/master key) * @param _whitelisting Whether contract address whitelisting is enabled * @param _contractAddress Initial whitelisted contract address * @param _spendTokenInfo Token spending limit information * @param _allowedSelectors List of allowed function selectors * @param _ethLimit Maximum amount of ETH that can be spent * @dev Only callable by accounts with ADMIN_ROLE */ function registerSessionKey( Key calldata _key, uint48 _validUntil, uint48 _validAfter, uint48 _limit, bool _whitelisting, address _contractAddress, SpendTokenInfo calldata _spendTokenInfo, bytes4[] calldata _allowedSelectors, uint256 _ethLimit ) public { _requireForExecute(); if (_validUntil <= block.timestamp) revert SessionKeyManager__InvalidTimestamp(); if (_validAfter > _validUntil) revert SessionKeyManager__InvalidTimestamp(); idSessionKeys[id] = _key; id++; if (_key.keyType == KeyType.WEBAUTHN) { bytes32 keyHash = keccak256(abi.encodePacked(_key.pubKey.x, _key.pubKey.y)); if (sessionKeys[keyHash].isActive) revert SessionKeyManager__SessionKeyRegistered(); SessionKey storage sKey = sessionKeys[keyHash]; _addSessionKey( sKey, _key, _validUntil, _validAfter, _limit, _whitelisting, _contractAddress, _spendTokenInfo, _allowedSelectors, _ethLimit ); emit SessionKeyRegistrated(keyHash); } else if (_key.keyType == KeyType.EOA) { if (_key.eoaAddress == address(0)) revert SessionKeyManager__AddressCantBeZero(); if (sessionKeysEOA[_key.eoaAddress].isActive) revert SessionKeyManager__SessionKeyRegistered(); SessionKey storage sKey = sessionKeysEOA[_key.eoaAddress]; _addSessionKey( sKey, _key, _validUntil, _validAfter, _limit, _whitelisting, _contractAddress, _spendTokenInfo, _allowedSelectors, _ethLimit ); emit SessionKeyRegistrated(keccak256(abi.encodePacked(_key.eoaAddress))); } } /** * @notice Internal function to add a session key with all parameters * @param sKey Storage reference to the session key data * @param _key Key information * @param _validUntil Timestamp until which the key is valid * @param _validAfter Timestamp after which the key becomes valid * @param _limit Number of transactions allowed * @param _whitelisting Whether contract address whitelisting is enabled * @param _contractAddress Initial whitelisted contract address * @param _spendTokenInfo Token spending limit information * @param _allowedSelectors List of allowed function selectors * @param _ethLimit Maximum amount of ETH that can be spent */ function _addSessionKey( SessionKey storage sKey, Key calldata _key, uint48 _validUntil, uint48 _validAfter, uint48 _limit, bool _whitelisting, address _contractAddress, SpendTokenInfo calldata _spendTokenInfo, bytes4[] calldata _allowedSelectors, uint256 _ethLimit ) internal { sKey.pubKey = _key.pubKey; sKey.isActive = true; sKey.validUntil = _validUntil; sKey.validAfter = _validAfter; sKey.limit = _limit; sKey.masterSessionKey = (_limit == 0); sKey.whoRegistrated = address(this); if (_limit > 0) { sKey.whitelisting = _whitelisting; sKey.ethLimit = _ethLimit; if (_whitelisting) { if (_contractAddress == address(0)) revert SessionKeyManager__AddressCantBeZero(); sKey.whitelist[_contractAddress] = true; sKey.whitelist[_spendTokenInfo.token] = true; uint256 len = _allowedSelectors.length; if (len > MAX_SELECTORS) revert SessionKeyManager__SelectorsListTooBig(); for (uint256 i = 0; i < len;) { sKey.allowedSelectors.push(_allowedSelectors[i]); unchecked { ++i; } } } if (_spendTokenInfo.token == address(0)) revert SessionKeyManager__AddressCantBeZero(); sKey.spendTokenInfo.token = _spendTokenInfo.token; sKey.spendTokenInfo.limit = _spendTokenInfo.limit; } } /** * @notice Revokes a specific session key * @param _key Key information of the session key to revoke * @dev Only callable by accounts with ADMIN_ROLE */ function revokeSessionKey(Key calldata _key) external { _requireForExecute(); if (_key.keyType == KeyType.WEBAUTHN) { bytes32 keyHash = keccak256(abi.encodePacked(_key.pubKey.x, _key.pubKey.y)); SessionKey storage sKey = sessionKeys[keyHash]; _revokeSessionKey(sKey); emit SessionKeyRevoked(keyHash); } else if (_key.keyType == KeyType.EOA) { if (_key.eoaAddress == address(0)) revert SessionKeyManager__AddressCantBeZero(); SessionKey storage sKey = sessionKeysEOA[_key.eoaAddress]; _revokeSessionKey(sKey); emit SessionKeyRevoked(keccak256(abi.encodePacked(_key.eoaAddress))); } } /** * @notice Internal function to revoke a session key * @param sKey Storage reference to the session key to revoke */ function _revokeSessionKey(SessionKey storage sKey) internal { if (!sKey.isActive) revert SessionKeyManager__SessionKeyInactive(); sKey.isActive = false; sKey.validUntil = 0; sKey.validAfter = 0; sKey.limit = 0; sKey.masterSessionKey = false; sKey.ethLimit = 0; sKey.whoRegistrated = address(0); sKey.spendTokenInfo.limit = 0; sKey.spendTokenInfo.token = address(0); delete sKey.allowedSelectors; } /** * @notice Revokes all registered session keys * @dev Only callable by accounts with ADMIN_ROLE */ function revokeAllSessionKeys() external { _requireForExecute(); for (uint256 i = 0; i < id; i++) { Key memory _key = getKeyById(i); if (_key.keyType == KeyType.WEBAUTHN) { bytes32 keyHash = keccak256(abi.encodePacked(_key.pubKey.x, _key.pubKey.y)); SessionKey storage sKey = sessionKeys[keyHash]; _revokeSessionKey(sKey); emit SessionKeyRevoked(keyHash); } else if (_key.keyType == KeyType.EOA) { if (_key.eoaAddress == address(0)) continue; SessionKey storage sKey = sessionKeysEOA[_key.eoaAddress]; _revokeSessionKey(sKey); emit SessionKeyRevoked(keccak256(abi.encodePacked(_key.eoaAddress))); } } } /** * @notice Executes a batch of transactions * @dev Can only be called via EntryPoint or by self * @param _transactions Array of transactions to execute */ function execute(Transaction[] calldata _transactions) payable external nonReentrant { _requireForExecute(); if (_transactions.length == 0 || _transactions.length > 9) { revert OpenfortBaseAccount7702V1__InvalidTransactionLength(); } uint256 transactionsLength = _transactions.length; Transaction calldata transactionCall; for (uint256 i = 0; i < transactionsLength; i++) { transactionCall = _transactions[i]; address target = transactionCall.to; uint256 value = transactionCall.value; bytes memory data = transactionCall.data; if (target == address(this)) { revert OpenfortBaseAccount7702V1__InvalidTransactionTarget(); } (bool success, bytes memory returnData) = target.call{value: value}(data); if (!success) { revert OpenfortBaseAccount7702V1__TransactionFailed(returnData); } emit TransactionExecuted(target, value, data); } } /** * Execute a transaction (called directly from owner, or by entryPoint) */ function execute(address _target, uint256 _value, bytes calldata _calldata) public payable virtual nonReentrant { _requireForExecute(); _call(_target, _value, _calldata); } /** * Execute a sequence of transactions. Maximum 9. */ function executeBatch(address[] calldata _target, uint256[] calldata _value, bytes[] calldata _calldata) public payable virtual nonReentrant { _requireForExecute(); if (_target.length > 9 || _target.length != _calldata.length || _target.length != _value.length) { revert OpenfortBaseAccount7702V1__InvalidTransactionLength(); } uint256 i; for (i; i < _target.length;) { _call(_target[i], _value[i], _calldata[i]); unchecked { ++i; } } } /** * @dev Call a target contract and reverts if it fails. */ function _call(address _target, uint256 _value, bytes calldata _calldata) internal virtual { emit TransactionExecuted(_target, _value, _calldata); (bool success, bytes memory result) = _target.call{value: _value}(_calldata); if (!success) { assembly { revert(add(result, 32), mload(result)) } } } /** * @notice ERC-4337 signature validation * @dev Validates the signature for a user operation * @param userOp The user operation to validate * @param userOpHash Hash of the user operation * @return validationData Packed validation data (success, validUntil, validAfter) or SIG_VALIDATION_SUCCESS | SIG_VALIDATION_FAILED */ function _validateSignature( PackedUserOperation calldata userOp, bytes32 userOpHash ) internal virtual override returns (uint256 validationData) { (KeyType sigType, bytes memory sigData) = abi.decode(userOp.signature, (KeyType, bytes)); if (sigType == KeyType.EOA) { bytes memory signature = sigData; address signer = ECDSA.recover(userOpHash, signature); if (address(this) == signer) return 0; SessionKey storage sKey = sessionKeysEOA[signer]; PubKey memory _pubKey = PubKey({x: sKey.pubKey.x, y: sKey.pubKey.y}); Key memory _key = Key({pubKey: _pubKey, eoaAddress: signer, keyType: KeyType.EOA}); if (isValidSessionKey(_key, userOp.callData)) { return _packValidationData(false, sKey.validUntil, sKey.validAfter); } } else if (sigType == KeyType.WEBAUTHN) { ( , bytes memory challenge, bool requireUserVerification, bytes memory authenticatorData, string memory clientDataJSON, uint256 challengeIndex, uint256 typeIndex, bytes32 r, bytes32 s, PubKey memory pubKey ) = abi.decode(userOp.signature, (KeyType, bytes, bool, bytes, string, uint256, uint256, bytes32, bytes32, PubKey)); if (usedChallenges[challenge]) return SIG_VALIDATION_FAILED; bool isValid = verifySoladySignature( challenge, requireUserVerification, authenticatorData, clientDataJSON, challengeIndex, typeIndex, r, s, pubKey.x, pubKey.y ); if (!isValid) return SIG_VALIDATION_FAILED; bytes32 keyHash = keccak256(abi.encodePacked(pubKey.x, pubKey.y)); SessionKey storage sKey = sessionKeys[keyHash]; Key memory _key = Key({ pubKey: PubKey({x: sKey.pubKey.x, y: sKey.pubKey.y}), eoaAddress: address(0), keyType: KeyType.WEBAUTHN }); if (sKey.masterSessionKey) return 0; if (isValidSessionKey(_key, userOp.callData)) { usedChallenges[challenge] = true; return _packValidationData(false, sKey.validUntil, sKey.validAfter); } } return SIG_VALIDATION_FAILED; } /** * @notice Validates if a session key is allowed to execute the given call data * @param _key Key information * @param _callData Call data to be executed * @return True if the session key is allowed to execute the call, false otherwise */ function isValidSessionKey(Key memory _key, bytes calldata _callData) internal virtual returns (bool) { // 1. Get the session key based on key type SessionKey storage sessionKey; if (_key.keyType == KeyType.WEBAUTHN) { bytes32 keyHash = keccak256(abi.encodePacked(_key.pubKey.x, _key.pubKey.y)); sessionKey = sessionKeys[keyHash]; } else if (_key.keyType == KeyType.EOA) { if (_key.eoaAddress == address(0)) return false; sessionKey = sessionKeysEOA[_key.eoaAddress]; } else { return false; } // 2. Basic validation for all key types if (sessionKey.validUntil == 0 || !sessionKey.isActive) return false; if (sessionKey.whoRegistrated != address(this)) return false; // 3. Extract function selector from callData bytes4 funcSelector = bytes4(_callData[:4]); // 4. Handle EXECUTE_SELECTOR if (funcSelector == EXECUTE_SELECTOR) { return _validateExecuteCall(sessionKey, _callData); } // 5. Handle EXECUTEBATCH_SELECTOR if (funcSelector == EXECUTEBATCH_SELECTOR) { return _validateExecuteBatchCall(sessionKey, _callData); } return false; } /** * @notice Validates a single execute call * @param sessionKey Session key data * @param _callData Call data to validate * @return True if the call is valid, false otherwise */ function _validateExecuteCall(SessionKey storage sessionKey, bytes calldata _callData) internal returns (bool) { // Decode the execute call parameters address toContract; bytes memory innerData; uint256 amount; (toContract, amount, innerData) = abi.decode(_callData[4:], (address, uint256, bytes)); // Basic validation if (toContract == address(this)) return false; if (sessionKey.masterSessionKey) return true; if (sessionKey.limit == 0) return false; if (sessionKey.ethLimit < amount) return false; // Validate selector bytes4 innerSelector = bytes4(innerData); if (!_isAllowedSelector(sessionKey.allowedSelectors, innerSelector)) { return false; } // Update limits unchecked { sessionKey.limit--; } if (amount > 0) sessionKey.ethLimit = sessionKey.ethLimit - amount; // Handle token spend limits if (sessionKey.spendTokenInfo.token == toContract) { bool validSpend = _validateTokenSpend(sessionKey, innerData); if (!validSpend) return false; } // Check whitelisting if (!sessionKey.whitelisting || sessionKey.whitelist[toContract]) { return true; } return false; } /** * @notice Validates a batch of execute calls * @param sessionKey Session key data * @param _callData Call data containing batch execution data * @return True if all calls in the batch are valid, false otherwise */ function _validateExecuteBatchCall(SessionKey storage sessionKey, bytes calldata _callData) internal returns (bool) { // Decode the batch call parameters (address[] memory toContracts, uint256[] memory amounts, bytes[] memory innerDataArray) = abi.decode(_callData[4:], (address[], uint256[], bytes[])); uint256 numberOfInteractions = toContracts.length; if (numberOfInteractions > 9) return false; // Check if session key has enough limit for all interactions if (!sessionKey.masterSessionKey) { if (sessionKey.limit < numberOfInteractions) return false; unchecked { sessionKey.limit = sessionKey.limit - SafeCast.toUint48(numberOfInteractions); } } // Validate each interaction for (uint256 i = 0; i < numberOfInteractions; ++i) { if (toContracts[i] == address(this)) return false; if (!sessionKey.masterSessionKey) { // Validate selector bytes4 innerSelector = bytes4(innerDataArray[i]); if (!_isAllowedSelector(sessionKey.allowedSelectors, innerSelector)) { return false; } // Check ETH limit if (sessionKey.ethLimit < amounts[i]) return false; if (amounts[i] > 0) sessionKey.ethLimit = sessionKey.ethLimit - amounts[i]; // Handle token spend limits if (sessionKey.spendTokenInfo.token == toContracts[i]) { bool validSpend = _validateTokenSpend(sessionKey, innerDataArray[i]); if (!validSpend) return false; } // Check whitelisting if (sessionKey.whitelisting && !sessionKey.whitelist[toContracts[i]]) { return false; } } } return true; } /** * @notice Validates token spending against limits * @param sessionKey Session key data * @param innerData Call data containing token transfer details * @return True if the token spend is valid, false otherwise */ function _validateTokenSpend(SessionKey storage sessionKey, bytes memory innerData) internal returns (bool) { uint256 startPos = innerData.length - 32; bytes32 value; assembly { value := mload(add(add(innerData, 0x20), startPos)) } if (uint256(value) > sessionKey.spendTokenInfo.limit) return false; if (uint256(value) > 0) { sessionKey.spendTokenInfo.limit = sessionKey.spendTokenInfo.limit - uint256(value); } return true; } /** * @notice Checks if a function selector is in the allowed list * @param selectors List of allowed selectors * @param selector Selector to check * @return True if the selector is allowed, false otherwise */ function _isAllowedSelector(bytes4[] storage selectors, bytes4 selector) internal view returns (bool) { for (uint256 i = 0; i < selectors.length; ++i) { if (selectors[i] == selector) { return true; } } return false; } /** * @notice Implements EIP-1271 signature validation * @param _hash Hash that was signed * @param _signature Signature to verify * @return magicValue Magic value indicating whether signature is valid */ function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue) { if (_hash == P256_VERIFIER && _signature.length > 65) { uint256 key; assembly { key := mload(add(_signature, 32)) } if (key == uint256(KeyType.WEBAUTHN)) { return _validateWebAuthnSignature(_signature); } } else if (_signature.length == 64 || _signature.length == 65) { address signer = ECDSA.recover(_hash, _signature); if (address(this) == signer) return this.isValidSignature.selector; SessionKey storage sessionKey = sessionKeysEOA[signer]; if ( sessionKey.validUntil == 0 || sessionKey.validAfter > block.timestamp || sessionKey.validUntil < block.timestamp || (!sessionKey.masterSessionKey && sessionKey.limit < 1) ) { return bytes4(0xffffffff); } else if (sessionKey.whoRegistrated != address(this)) { return bytes4(0xffffffff); } else { return this.isValidSignature.selector; } } return bytes4(0xffffffff); } /** * @notice Internal function to validate WebAuthn signatures * @param _signature WebAuthn signature data * @return Magic value if the signature is valid, otherwise 0xffffffff */ function _validateWebAuthnSignature(bytes memory _signature) internal view returns (bytes4) { ( KeyType sigType, bytes memory challenge, bool requireUserVerification, bytes memory authenticatorData, string memory clientDataJSON, uint256 challengeIndex, uint256 typeIndex, bytes32 r, bytes32 s, PubKey memory pubKey ) = abi.decode(_signature, (KeyType, bytes, bool, bytes, string, uint256, uint256, bytes32, bytes32, PubKey)); if (sigType != KeyType.WEBAUTHN) { return bytes4(0xffffffff); } if (usedChallenges[challenge]) return bytes4(0xffffffff); bool isValid = verifySoladySignature( challenge, requireUserVerification, authenticatorData, clientDataJSON, challengeIndex, typeIndex, r, s, pubKey.x, pubKey.y ); if (!isValid) return bytes4(0xffffffff); bytes32 keyHash = keccak256(abi.encodePacked(pubKey.x, pubKey.y)); SessionKey storage sessionKey = sessionKeys[keyHash]; if ( sessionKey.validUntil == 0 || sessionKey.validAfter > block.timestamp || sessionKey.validUntil < block.timestamp || (!sessionKey.masterSessionKey && sessionKey.limit < 1) ) { return bytes4(0xffffffff); } else if (sessionKey.whoRegistrated != address(this)) { return bytes4(0xffffffff); } else { return this.isValidSignature.selector; } } function _checkSignature(bytes32 hash, bytes memory signature) internal view returns (bool) { return ECDSA.recover(hash, signature) == address(this); } /** * @notice Verifies that the validation has not expired * @dev Compares current timestamp with validUntil timestamp * @param _validUntil The timestamp until which the validation is valid */ function _notExpired(uint256 _validUntil) internal view { if (block.timestamp > _validUntil) { revert OpenfortBaseAccount7702V1__ValidationExpired(); } } /** * @notice Validates that the provided nonce is not equal to the current nonce * @dev Ensures nonce is different to prevent replay attacks * @param _nonce The nonce to validate */ function _validateNonce(uint256 _nonce) internal override view { if (_nonce == nonce) { revert OpenfortBaseAccount7702V1__InvalidNonce(); } } /** * @notice Return the EntryPoint used by this account * @return The EntryPoint contract */ function entryPoint() public pure override returns (IEntryPoint) { return IEntryPoint(0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108); } /** * @notice Check if caller is authorized to execute functions * @dev Only self-calls and EntryPoint calls are allowed */ function _requireForExecute() internal view virtual override { require( msg.sender == address(this) || msg.sender == address(entryPoint()), "not from self or EntryPoint" ); } /** * @notice Clears the contract's storage slots for reinitialization * @dev Uses inline assembly to directly clear storage at specific slots */ function _clearStorage() internal { bytes32 baseSlot = keccak256("openfort.baseAccount.7702.v1"); for (uint256 i = 2; i < 6; i++) { bytes32 slot = bytes32(uint256(baseSlot) + i); assembly { sstore(slot, 0) } } } /** * @notice Retrieves registration information for a key * @param _id ID of the key * @return keyType Type of the key * @return registeredBy Address that registered the key * @return isActive Whether the key is active */ function getKeyRegistrationInfo(uint256 _id) external view returns (KeyType keyType, address registeredBy, bool isActive) { Key memory key = getKeyById(_id); if (key.keyType == KeyType.WEBAUTHN) { bytes32 keyHash = keccak256(abi.encodePacked(key.pubKey.x, key.pubKey.y)); return (key.keyType, sessionKeys[keyHash].whoRegistrated, sessionKeys[keyHash].isActive); } else if (key.keyType == KeyType.EOA) { return (key.keyType, sessionKeysEOA[key.eoaAddress].whoRegistrated, sessionKeysEOA[key.eoaAddress].isActive); } return (key.keyType, address(0), false); } /** * @notice Retrieves key information by ID * @param _id ID of the key to retrieve * @return Key information */ function getKeyById(uint256 _id) public view returns (Key memory) { Key storage _key = idSessionKeys[_id]; return _key; } /** * @notice Retrieves session key data for a WebAuthn key * @param _keyHash Hash of the WebAuthn public key * @return isActive Whether the key is active * @return validUntil Timestamp until which the key is valid * @return validAfter Timestamp after which the key becomes valid * @return limit Number of transactions allowed */ function getSessionKeyData(bytes32 _keyHash) external view returns (bool, uint48, uint48, uint48) { bool isActive = sessionKeys[_keyHash].isActive; uint48 validUntil = sessionKeys[_keyHash].validUntil; uint48 validAfter = sessionKeys[_keyHash].validAfter; uint48 limit = sessionKeys[_keyHash].limit; return (isActive, validUntil, validAfter, limit); } /** * @notice Retrieves session key data for a WebAuthn key * @param _key Address of EOA Session Key * @return isActive Whether the key is active * @return validUntil Timestamp until which the key is valid * @return validAfter Timestamp after which the key becomes valid * @return limit Number of transactions allowed */ function getSessionKeyData(address _key) external view returns (bool, uint48, uint48, uint48) { bool isActive = sessionKeysEOA[_key].isActive; uint48 validUntil = sessionKeysEOA[_key].validUntil; uint48 validAfter = sessionKeysEOA[_key].validAfter; uint48 limit = sessionKeysEOA[_key].limit; return (isActive, validUntil, validAfter, limit); } /** * @notice Checks if an EOA session key is active * @param eoaKey EOA address to check * @return True if the session key is active, false otherwise */ function isSessionKeyActive(address eoaKey) external view returns (bool) { return sessionKeysEOA[eoaKey].isActive; } /** * @notice Checks if a WebAuthn session key is active * @param keyHash Hash of the WebAuthn public key * @return True if the session key is active, false otherwise */ function isSessionKeyActive(bytes32 keyHash) external view returns (bool) { return sessionKeys[keyHash].isActive; } /** * @notice Encodes WebAuthn signature data for use in transaction submission * @param challenge Challenge that was signed * @param requireUserVerification Whether user verification is required * @param authenticatorData Authenticator data from WebAuthn * @param clientDataJSON Client data JSON from WebAuthn * @param challengeIndex Index of challenge in client data * @param typeIndex Index of type in client data * @param r R component of the signature * @param s S component of the signature * @param pubKey Public key used for signing * @return Encoded signature data */ function encodeWebAuthnSignature( bytes memory challenge, bool requireUserVerification, bytes memory authenticatorData, string memory clientDataJSON, uint256 challengeIndex, uint256 typeIndex, bytes32 r, bytes32 s, PubKey memory pubKey ) external pure returns (bytes memory) { return abi.encode( KeyType.WEBAUTHN, challenge, requireUserVerification, authenticatorData, clientDataJSON, challengeIndex, typeIndex, r, s, pubKey ); } /** * @notice Encodes EOA signature data for use in transaction submission * @param _signature Signed digest of UserOp * @return Encoded signature data */ function encodeEOASignature(bytes calldata _signature) external pure returns (bytes memory) { return abi.encode(KeyType.EOA, _signature); } function supportsInterface(bytes4 _interfaceId) public override(ERC1155Holder, IERC165) pure returns (bool) { return _interfaceId == type(IERC165).interfaceId || _interfaceId == type(IAccount).interfaceId || _interfaceId == type(IERC1271).interfaceId || _interfaceId == type(IERC1155Receiver).interfaceId || _interfaceId == type(IERC721Receiver).interfaceId; } }
// SPDX-License-Identifier: MIR pragma solidity ^0.8.0; import {ISessionKey} from "src/interfaces/ISessionKey.sol"; abstract contract SpendLimit { /** * @notice Token spending limit information * @param token ERC20 Token Address * @param limit Spending Limit */ struct SpendTokenInfo { address token; uint256 limit; } /** * @notice Validates token spending against limits * @param sessionKey Session key data * @param innerData Call data containing token transfer details * @return True if the token spend is valid, false otherwise */ function _validateTokenSpend(ISessionKey.SessionKey storage sessionKey, bytes memory innerData) internal returns (bool) { uint256 startPos = innerData.length - 32; bytes32 value; assembly { value := mload(add(add(innerData, 0x20), startPos)) } if (uint256(value) > sessionKey.spendTokenInfo.limit) return false; if (uint256(value) > 0) { sessionKey.spendTokenInfo.limit = sessionKey.spendTokenInfo.limit - uint256(value); } return true; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.29; /** * @title IValidation Interface * @author Openfort@0xkoiner * @notice Interface defining validation structures for signature verification * @dev Contains structs used for signature validation in account initialization */ interface IValidation { /** * @notice Structure containing signature and validation data * @dev Used for general signature validation */ struct Validation { uint256 nonce; uint8 v; bytes32 r; bytes32 s; uint256 validUntil; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.29; import {SpendLimit} from "src/utils/SpendLimit.sol"; interface ISessionKey { /** * @notice Types of session keys supported by the contract * @param EOA Standard Ethereum account key * @param WEBAUTHN WebAuthn-based key (using P256 curve) */ enum KeyType { EOA, WEBAUTHN } /** * @notice Public key structure for P256 curve used in WebAuthn * @param x X-coordinate of the public key * @param y Y-coordinate of the public key */ struct PubKey { bytes32 x; bytes32 y; } /** * @notice Key structure containing all necessary key information * @param pubKey Public key information for WebAuthn keys * @param eoaAddress EOA address for standard Ethereum accounts * @param keyType Type of the key (EOA or WebAuthn) */ struct Key { PubKey pubKey; address eoaAddress; KeyType keyType; } /** * @notice Session key data structure containing permissions and limits * @param pubKey Public key information * @param isActive Whether the session key is currently active * @param validUntil Timestamp until which the key is valid * @param validAfter Timestamp after which the key becomes valid * @param limit Number of transactions allowed (0 for unlimited/master key) * @param masterSessionKey Whether this is a master session key with unlimited permissions * @param whitelisting Whether contract address whitelisting is enabled * @param whitelist Mapping of whitelisted contract addresses * @param spendTokenInfo Token spending limit information * @param allowedSelectors List of allowed function selectors * @param ethLimit Maximum amount of ETH that can be spent * @param whoRegistrated Address that registered this session key */ struct SessionKey { PubKey pubKey; bool isActive; uint48 validUntil; uint48 validAfter; uint48 limit; bool masterSessionKey; bool whitelisting; mapping(address contractAddress => bool allowed) whitelist; SpendLimit.SpendTokenInfo spendTokenInfo; bytes4[] allowedSelectors; uint256 ethLimit; address whoRegistrated; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {WebAuthn} from "src/libs/WebAuthn.sol"; import {P256} from "src/libs/P256.sol"; /** * @title WebAuthnVerifier * @author openfort@0xkoiner * @notice A simple contract to verify WebAuthn signatures * @dev Uses Solady's WebAuthn and P256 libraries for verification */ contract WebAuthnVerifier { /** * @notice Verifies a WebAuthn signature using the Solady library * @param challenge The challenge that was signed * @param requireUserVerification Whether to require user verification * @param authenticatorData The authenticator data from the WebAuthn response * @param clientDataJSON The client data JSON from the WebAuthn response * @param challengeIndex Index of the challenge in the client data JSON * @param typeIndex Index of the type in the client data JSON * @param r The r-component of the signature * @param s The s-component of the signature * @param x The x-coordinate of the public key * @param y The y-coordinate of the public key * @return isValid Whether the signature is valid */ function verifySoladySignature( bytes memory challenge, bool requireUserVerification, bytes memory authenticatorData, string memory clientDataJSON, uint256 challengeIndex, uint256 typeIndex, bytes32 r, bytes32 s, bytes32 x, bytes32 y ) public view returns (bool isValid) { WebAuthn.WebAuthnAuth memory auth = WebAuthn.WebAuthnAuth({ authenticatorData: authenticatorData, clientDataJSON: clientDataJSON, challengeIndex: challengeIndex, typeIndex: typeIndex, r: r, s: s }); isValid = WebAuthn.verify(challenge, requireUserVerification, auth, x, y); return isValid; } /** * @notice Verifies a WebAuthn signature using encoded auth data * @param challenge The challenge that was signed * @param requireUserVerification Whether to require user verification * @param encodedAuth The encoded WebAuthn auth data * @param x The x-coordinate of the public key * @param y The y-coordinate of the public key * @return isValid Whether the signature is valid */ function verifyEncodedSignature( bytes memory challenge, bool requireUserVerification, bytes memory encodedAuth, bytes32 x, bytes32 y ) public view returns (bool isValid) { WebAuthn.WebAuthnAuth memory auth = WebAuthn.tryDecodeAuth(encodedAuth); isValid = WebAuthn.verify(challenge, requireUserVerification, auth, x, y); return isValid; } /** * @notice Verifies a WebAuthn signature using compact encoded auth data * @param challenge The challenge that was signed * @param requireUserVerification Whether to require user verification * @param encodedAuth The compact encoded WebAuthn auth data * @param x The x-coordinate of the public key * @param y The y-coordinate of the public key * @return isValid Whether the signature is valid */ function verifyCompactSignature( bytes memory challenge, bool requireUserVerification, bytes memory encodedAuth, bytes32 x, bytes32 y ) public view returns (bool isValid) { WebAuthn.WebAuthnAuth memory auth = WebAuthn.tryDecodeAuthCompact(encodedAuth); isValid = WebAuthn.verify(challenge, requireUserVerification, auth, x, y); return isValid; } /** * @notice Verifies a P256 signature directly (without WebAuthn) * @param hash The hash to verify * @param r The r-component of the signature * @param s The s-component of the signature * @param x The x-coordinate of the public key * @param y The y-coordinate of the public key * @return isValid Whether the signature is valid */ function verifyP256Signature(bytes32 hash, bytes32 r, bytes32 s, bytes32 x, bytes32 y) public view returns (bool isValid) { return P256.verifySignature(hash, r, s, x, y); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-empty-blocks */ /* solhint-disable no-inline-assembly */ import "../interfaces/IAccount.sol"; import "../interfaces/IEntryPoint.sol"; import "../utils/Exec.sol"; import "./UserOperationLib.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 PackedUserOperation; struct Call { address target; uint256 value; bytes data; } error ExecuteError(uint256 index, bytes error); /** * 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); /** * execute a single call from the account. */ // function execute(address target, uint256 value, bytes calldata data) virtual external { // _requireForExecute(); // bool ok = Exec.call(target, value, data, gasleft()); // if (!ok) { // Exec.revertWithReturnData(); // } // } /** * execute a batch of calls. * revert on the first call that fails. * If the batch reverts, and it contains more than a single call, then wrap the revert with ExecuteError, * to mark the failing call index. */ function executeBatch(Call[] calldata calls) virtual external { _requireForExecute(); uint256 callsLength = calls.length; for (uint256 i = 0; i < callsLength; i++) { Call calldata call = calls[i]; bool ok = Exec.call(call.target, call.value, call.data, gasleft()); if (!ok) { if (callsLength == 1) { Exec.revertWithReturnData(); } else { revert ExecuteError(i, Exec.getReturnData(0)); } } } } /// @inheritdoc IAccount function validateUserOp( PackedUserOperation 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" ); } function _requireForExecute() internal view virtual { _requireFromEntryPoint(); } /** * 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> aggregatorOrSigFail - 0 for valid signature, 1 to mark signature failure, * otherwise, an address of an aggregator contract. * <6-byte> validUntil - Last timestamp this operation is valid at, or 0 for "indefinitely" * <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( PackedUserOperation 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 }(""); (success); // Ignore failure (its EntryPoint's job to verify, not account.) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import "./PackedUserOperation.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> aggregatorOrSigFail - 0 for valid signature, 1 to mark signature failure, * otherwise, an address of an "aggregator" contract. * <6-byte> validUntil - Last timestamp this operation is valid at, or 0 for "indefinitely" * <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( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds ) external returns (uint256 validationData); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @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 } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile 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 {MessageHashUtils-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] */ function tryRecover( bytes32 hash, bytes memory signature ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { 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. assembly ("memory-safe") { 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, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile 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 {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); 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[ERC-2098 short signatures] */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. 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. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { // 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, s); } // 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, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @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, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
/** ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. ** Only one instance required on each chain. **/ // SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ import "./PackedUserOperation.sol"; import "./IStakeManager.sol"; import "./IAggregator.sol"; import "./INonceManager.sol"; import "./ISenderCreator.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 "callData" call. */ event UserOperationRevertReason( bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason ); /** * An event emitted if the UserOperation Paymaster's "postOp" call 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 "postOp". */ event PostOpRevertReason( bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason ); /** * UserOp consumed more than prefund. The UserOperation is reverted, and no refund is made. * @param userOpHash - The request unique identifier. * @param sender - The sender of this request. * @param nonce - The nonce used in the request. */ event UserOperationPrefundTooLow( bytes32 indexed userOpHash, address indexed sender, uint256 nonce ); /** * An event emitted by handleOps() and handleAggregatedOps(), 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. * @param aggregator - The aggregator used for the following UserOperationEvents. */ event SignatureAggregatorChanged(address indexed aggregator); /** * A custom revert error of handleOps andhandleAggregatedOps, to identify the offending op. * Should be caught in off-chain handleOps/handleAggregatedOps simulation and not happen on-chain. * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts. * 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. */ error FailedOp(uint256 opIndex, string reason); /** * A custom revert error of handleOps and handleAggregatedOps, to report a revert by account or paymaster. * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero). * @param reason - Revert reason. see FailedOp(uint256,string), above * @param inner - data from inner cought revert reason * @dev note that inner is truncated to 2048 bytes */ error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner); error PostOpReverted(bytes returnData); /** * Error case when a signature aggregator fails to verify the aggregated signature it had created. * @param aggregator The aggregator that failed to verify the signature */ error SignatureValidationFailed(address aggregator); // Return value of getSenderAddress. error SenderAddressResult(address sender); // UserOps handled, per aggregator. struct UserOpsPerAggregator { PackedUserOperation[] userOps; // Aggregator address IAggregator aggregator; // Aggregated signature bytes signature; } /** * Execute a batch of UserOperations. * 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( PackedUserOperation[] 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), entrypoint address, chainId and (optionally) 7702 delegate address * @param userOp - The user operation to generate the request ID for. * @return hash the hash of this UserOperation */ function getUserOpHash( PackedUserOperation calldata userOp ) external view returns (bytes32); /** * Gas and return values during simulation. * @param preOpGas - The gas used for validation (including preValidationGas) * @param prefund - The required prefund for this operation * @param accountValidationData - returned validationData from account. * @param paymasterValidationData - return validationData from paymaster. * @param paymasterContext - Returned by validatePaymasterUserOp (to be passed into postOp) */ struct ReturnInfo { uint256 preOpGas; uint256 prefund; uint256 accountValidationData; uint256 paymasterValidationData; bytes paymasterContext; } /** * 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. * @notice this method cannot be used for EIP-7702 derived contracts. * * @param initCode - The constructor code to be passed into the UserOperation. */ function getSenderAddress(bytes memory initCode) external; error DelegateAndRevert(bool success, bytes ret); /** * Helper method for dry-run testing. * @dev calling this method, the EntryPoint will make a delegatecall to the given data, and report (via revert) the result. * The method always revert, so is only useful off-chain for dry run calls, in cases where state-override to replace * actual EntryPoint code is less convenient. * @param target a target contract to make a delegatecall from entrypoint * @param data data to pass to target in a delegatecall */ function delegateAndRevert(address target, bytes calldata data) external; /** * @notice Retrieves the immutable SenderCreator contract which is responsible for deployment of sender contracts. */ function senderCreator() external view returns (ISenderCreator); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reinitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location. * * NOTE: Consider following the ERC-7201 formula to derive storage locations. */ function _initializableStorageSlot() internal pure virtual returns (bytes32) { return INITIALIZABLE_STORAGE; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { bytes32 slot = _initializableStorageSlot(); assembly { $.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /** * 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 accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call. * @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid. * Covers batch overhead. * @param gasFees - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters. * @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra 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 PackedUserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; bytes32 accountGasLimits; uint256 preVerificationGas; bytes32 gasFees; bytes paymasterAndData; bytes signature; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /* solhint-disable no-inline-assembly */ /* * For simulation purposes, validateUserOp (and validatePaymasterUserOp) * must return this value in case of signature failure, instead of revert. */ uint256 constant SIG_VALIDATION_FAILED = 1; /* * For simulation purposes, validateUserOp (and validatePaymasterUserOp) * return this value on success. */ uint256 constant SIG_VALIDATION_SUCCESS = 0; /** * Returned data from validateUserOp. * validateUserOp returns a uint256, which 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 validUntil - Last timestamp this operation is valid at, or 0 for "indefinitely". */ struct ValidationData { address aggregator; uint48 validAfter; uint48 validUntil; } /** * Extract aggregator/sigFailed, validAfter, validUntil. * Also convert zero validUntil to type(uint48).max. * @param validationData - The packed validation data. * @return data - The unpacked in-memory validation data. */ 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); } /** * Helper to pack the return value for validateUserOp. * @param data - The ValidationData to pack. * @return the packed validation data. */ 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 operation is valid at, or 0 for "indefinitely". * @param validAfter - First timestamp this UserOperation is valid. * @return the packed validation data. */ function _packValidationData( bool sigFailed, uint48 validUntil, uint48 validAfter ) pure returns (uint256) { return (sigFailed ? SIG_VALIDATION_FAILED : SIG_VALIDATION_SUCCESS) | (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. * * @param data - the calldata bytes array to perform keccak on. * @return ret - the keccak hash of the 'data' array. */ function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) { assembly ("memory-safe") { let mem := mload(0x40) let len := data.length calldatacopy(mem, data.offset, len) ret := keccak256(mem, len) } } /** * The minimum of two numbers. * @param a - First number. * @param b - Second number. * @return - the minimum value. */ function min(uint256 a, uint256 b) pure returns (uint256) { return a < b ? a : b; } /** * standard solidity memory allocation finalization. * copied from solidity generated code * @param memPointer - The current memory pointer * @param allocationSize - Bytes allocated from memPointer. */ function finalizeAllocation(uint256 memPointer, uint256 allocationSize) pure { assembly ("memory-safe"){ finalize_allocation(memPointer, allocationSize) function finalize_allocation(memPtr, size) { let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) mstore(64, newFreePtr) } function round_up_to_mul_of_32(value) -> result { result := and(add(value, 31), not(31)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with `hash` */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.20; import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; import {IERC1155Receiver} from "../IERC1155Receiver.sol"; /** * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. */ abstract contract ERC1155Holder 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); } 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 (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../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}. */ abstract contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.29; import {SpendLimit} from "src/utils/SpendLimit.sol"; interface ISessionKey { /** * @notice Types of session keys supported by the contract * @param EOA Standard Ethereum account key * @param WEBAUTHN WebAuthn-based key (using P256 curve) */ enum KeyType { EOA, WEBAUTHN } /** * @notice Public key structure for P256 curve used in WebAuthn * @param x X-coordinate of the public key * @param y Y-coordinate of the public key */ struct PubKey { bytes32 x; bytes32 y; } /** * @notice Key structure containing all necessary key information * @param pubKey Public key information for WebAuthn keys * @param eoaAddress EOA address for standard Ethereum accounts * @param keyType Type of the key (EOA or WebAuthn) */ struct Key { PubKey pubKey; address eoaAddress; KeyType keyType; } /** * @notice Session key data structure containing permissions and limits * @param pubKey Public key information * @param isActive Whether the session key is currently active * @param validUntil Timestamp until which the key is valid * @param validAfter Timestamp after which the key becomes valid * @param limit Number of transactions allowed (0 for unlimited/master key) * @param masterSessionKey Whether this is a master session key with unlimited permissions * @param whitelisting Whether contract address whitelisting is enabled * @param whitelist Mapping of whitelisted contract addresses * @param spendTokenInfo Token spending limit information * @param allowedSelectors List of allowed function selectors * @param ethLimit Maximum amount of ETH that can be spent * @param whoRegistrated Address that registered this session key */ struct SessionKey { PubKey pubKey; bool isActive; uint48 validUntil; uint48 validAfter; uint48 limit; bool masterSessionKey; bool whitelisting; mapping(address contractAddress => bool allowed) whitelist; SpendLimit.SpendTokenInfo spendTokenInfo; bytes4[] allowedSelectors; uint256 ethLimit; address whoRegistrated; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {Base64} from "src/libs/Base64.sol"; import {P256} from "src/libs/P256.sol"; /// @notice WebAuthn helper. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/WebAuthn.sol) /// @author Modified from Daimo WebAuthn (https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol) /// @author Modified from Coinbase WebAuthn (https://github.com/base-org/webauthn-sol/blob/main/src/WebAuthn.sol) library WebAuthn { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helps make encoding and decoding easier, alleviates stack-too-deep. struct WebAuthnAuth { // The WebAuthn authenticator data. // See: https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata. bytes authenticatorData; // The WebAuthn client data JSON. // See: https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson. string clientDataJSON; // Start index of "challenge":"..." in `clientDataJSON`. uint256 challengeIndex; // Start index of "type":"..." in `clientDataJSON`. uint256 typeIndex; // The r value of secp256r1 signature. bytes32 r; // The s value of secp256r1 signature. bytes32 s; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WEBAUTHN VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Verifies a Webauthn Authentication Assertion. /// See: https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. /// /// We do not verify all the steps as described in the specification, only ones /// relevant to our context. Please carefully read through this list before usage. /// /// Specifically, we do verify the following: /// - Verify that `authenticatorData` (which comes from the authenticator, /// such as iCloud Keychain) indicates a well-formed assertion with the /// "User Present" bit set. If `requireUserVerification` is set, checks that the /// authenticator enforced user verification. User verification should be required /// if, and only if, `options.userVerification` is set to required in the request. /// - Verifies that the client JSON is of type "webauthn.get", /// i.e. the client was responding to a request to assert authentication. /// - Verifies that the client JSON contains the requested challenge. /// - Verifies that (r, s) constitute a valid signature over both the /// `authData` and client JSON, for public key (x, y). /// /// We make some assumptions about the particular use case of this verifier, /// so we do NOT verify the following: /// - Does NOT verify that the origin in the `clientDataJSON` matches the /// Relying Party's origin: it is considered the authenticator's responsibility to /// ensure that the user is interacting with the correct RP. This is enforced by /// most high quality authenticators properly, particularly the iCloud Keychain /// and Google Password Manager were tested. /// - Does NOT verify That `topOrigin` in `clientDataJSON` is well-formed: /// We assume it would never be present, i.e. the credentials are never used in a /// cross-origin/iframe context. The website/app set up should disallow cross-origin /// usage of the credentials. This is the default behavior for created credentials /// in common settings. /// - Does NOT verify that the `rpIdHash` in `authenticatorData` is the SHA-256 hash /// of the RP ID expected by the Relying Party: /// this means that we rely on the authenticator to properly enforce /// credentials to be used only by the correct RP. /// This is generally enforced with features like Apple App Site Association /// and Google Asset Links. To protect from edge cases in which a previously-linked /// RP ID is removed from the authorized RP IDs, we recommend that messages /// signed by the authenticator include some expiry mechanism. /// - Does NOT verify the credential backup state: this assumes the credential backup /// state is NOT used as part of Relying Party business logic or policy. /// - Does NOT verify the values of the client extension outputs: /// this assumes that the Relying Party does not use client extension outputs. /// - Does NOT verify the signature counter: signature counters are intended to enable /// risk scoring for the Relying Party. This assumes risk scoring is not used as part /// of Relying Party business logic or policy. /// - Does NOT verify the attestation object: this assumes that /// response.attestationObject is NOT present in the response, /// i.e. the RP does not intend to verify an attestation. function verify( bytes memory challenge, bool requireUserVerification, WebAuthnAuth memory auth, bytes32 x, bytes32 y ) internal view returns (bool result) { bytes32 messageHash; string memory encoded = Base64.encode(challenge, true, true); /// @solidity memory-safe-assembly assembly { let clientDataJSON := mload(add(auth, 0x20)) let n := mload(clientDataJSON) // `clientDataJSON`'s length. let o := add(clientDataJSON, 0x20) // Start of `clientData`'s bytes. { let c := mload(add(auth, 0x40)) // Challenge index in `clientDataJSON`. let t := mload(add(auth, 0x60)) // Type index in `clientDataJSON`. let l := mload(encoded) // Cache `encoded`'s length. let q := add(l, 0x0d) // Length of `encoded` prefixed with '"challenge":"'. mstore(encoded, shr(152, '"challenge":"')) // Temp prefix with '"challenge":"'. result := and( // 11. Verify JSON's type. Also checks for possible addition overflows. and( eq(shr(88, mload(add(o, t))), shr(88, '"type":"webauthn.get"')), lt(shr(128, or(t, c)), lt(add(0x14, t), n)) ), // 12. Verify JSON's challenge. Includes a check for the closing '"'. and( eq(keccak256(add(o, c), q), keccak256(add(encoded, 0x13), q)), and(eq(byte(0, mload(add(add(o, c), q))), 34), lt(add(q, c), n)) ) ) mstore(encoded, l) // Restore `encoded`'s length, in case of string interning. } // Skip 13., 14., 15. let l := mload(mload(auth)) // Length of `authenticatorData`. // 16. Verify that the "User Present" flag is set (bit 0). // 17. Verify that the "User Verified" flag is set (bit 2), if required. // See: https://www.w3.org/TR/webauthn-2/#flags. let u := or(1, shl(2, iszero(iszero(requireUserVerification)))) result := and(and(result, gt(l, 0x20)), eq(and(mload(add(mload(auth), 0x21)), u), u)) if result { let p := add(mload(auth), 0x20) // Start of `authenticatorData`'s bytes. let e := add(p, l) // Location of the word after `authenticatorData`. let w := mload(e) // Cache the word after `authenticatorData`. // 19. Compute `sha256(clientDataJSON)`. // 20. Compute `sha256(authenticatorData ‖ sha256(clientDataJSON))`. // forgefmt: disable-next-item messageHash := mload(staticcall(gas(), shl(1, staticcall(gas(), 2, o, n, e, 0x20)), p, add(l, 0x20), 0x01, 0x20)) mstore(e, w) // Restore the word after `authenticatorData`, in case of reuse. // `returndatasize()` is `0x20` on `sha256` success, and `0x00` otherwise. if iszero(returndatasize()) { invalid() } } } // `P256.verifySignature` returns false if `s > N/2` due to the malleability check. if (result) result = P256.verifySignature(messageHash, auth.r, auth.s, x, y); } /// @dev Plain variant of verify. function verify( bytes memory challenge, bool requireUserVerification, bytes memory authenticatorData, string memory clientDataJSON, uint256 challengeIndex, uint256 typeIndex, bytes32 r, bytes32 s, bytes32 x, bytes32 y ) internal view returns (bool) { return verify( challenge, requireUserVerification, WebAuthnAuth(authenticatorData, clientDataJSON, challengeIndex, typeIndex, r, s), x, y ); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ENCODING / DECODING HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `abi.encode(auth)`. function encodeAuth(WebAuthnAuth memory auth) internal pure returns (bytes memory) { return abi.encode(auth); } /// @dev Performs a best-effort attempt to `abi.decode(auth)`. Won't revert. /// If any fields cannot be successfully extracted, `decoded` will not be populated, /// which will cause `verify` to return false (as `clientDataJSON` is empty). function tryDecodeAuth(bytes memory encodedAuth) internal pure returns (WebAuthnAuth memory decoded) { /// @solidity memory-safe-assembly assembly { for { let n := mload(encodedAuth) } iszero(lt(n, 0xc0)) {} { let o := add(encodedAuth, 0x20) // Start of `encodedAuth`'s bytes. let e := add(o, n) // End of `encodedAuth` in memory. let p := add(mload(o), o) // Start of `encodedAuth`. if or(gt(add(p, 0xc0), e), lt(p, o)) { break } let authenticatorData := add(mload(p), p) let clientDataJSON := add(mload(add(p, 0x20)), p) if or( or(gt(authenticatorData, e), lt(authenticatorData, p)), or(gt(clientDataJSON, e), lt(clientDataJSON, p)) ) { break } if or( gt(add(add(authenticatorData, 0x20), mload(authenticatorData)), e), gt(add(add(clientDataJSON, 0x20), mload(clientDataJSON)), e) ) { break } mstore(decoded, authenticatorData) // `authenticatorData`. mstore(add(decoded, 0x20), clientDataJSON) // `clientDataJSON`. mstore(add(decoded, 0x40), mload(add(p, 0x40))) // `challengeIndex`. mstore(add(decoded, 0x60), mload(add(p, 0x60))) // `typeIndex`. mstore(add(decoded, 0x80), mload(add(p, 0x80))) // `r`. mstore(add(decoded, 0xa0), mload(add(p, 0xa0))) // `s`. break } } } /// @dev Returns the compact encoding of `auth`: /// ``` /// abi.encodePacked( /// uint16(auth.authenticatorData.length), /// bytes(auth.authenticatorData), /// bytes(auth.clientDataJSON), /// uint16(auth.challengeIndex), /// uint16(auth.typeIndex), /// bytes32(auth.r), /// bytes32(auth.s) /// ) /// ``` /// Returns the empty string if any length or index exceeds 16 bits. function tryEncodeAuthCompact(WebAuthnAuth memory auth) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function copyBytes(o_, s_, c_) -> _e { mstore(o_, shl(240, mload(s_))) o_ := add(o_, c_) _e := add(o_, mload(s_)) // The end of the bytes. for { let d_ := sub(add(0x20, s_), o_) } 1 {} { mstore(o_, mload(add(d_, o_))) o_ := add(o_, 0x20) if iszero(lt(o_, _e)) { break } } } let clientDataJSON := mload(add(0x20, auth)) let c := mload(add(0x40, auth)) // `challengeIndex`. let t := mload(add(0x60, auth)) // `typeIndex`. // If none of the lengths are more than `0xffff`. if iszero(shr(16, or(or(t, c), or(mload(mload(auth)), mload(clientDataJSON))))) { result := mload(0x40) // `authenticatorData`, `clientDataJSON`. let o := copyBytes(copyBytes(add(result, 0x20), mload(auth), 2), clientDataJSON, 0) mstore(o, or(shl(240, c), shl(224, t))) // `challengeIndex`, `typeIndex`. mstore(add(o, 0x04), mload(add(0x80, auth))) // `r`. mstore(add(o, 0x24), mload(add(0xa0, auth))) // `s`. mstore(result, sub(add(o, 0x24), result)) // Store the length. mstore(add(o, 0x44), 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x64)) // Allocate memory . } } } /// @dev Approximately the same gas as `tryDecodeAuth`, but helps save on calldata. /// If any fields cannot be successfully extracted, `decoded` will not be populated, /// which will cause `verify` to return false (as `clientDataJSON` is empty). function tryDecodeAuthCompact(bytes memory encodedAuth) internal pure returns (WebAuthnAuth memory decoded) { /// @solidity memory-safe-assembly assembly { function extractBytes(o_, l_) -> _m { _m := mload(0x40) // Grab the free memory pointer. let s_ := add(_m, 0x20) for { let i_ := 0 } 1 {} { mstore(add(s_, i_), mload(add(o_, i_))) i_ := add(i_, 0x20) if iszero(lt(i_, l_)) { break } } mstore(_m, l_) // Store the length. mstore(add(l_, s_), 0) // Zeroize the slot after the string. mstore(0x40, add(0x20, add(l_, s_))) // Allocate memory. } let n := mload(encodedAuth) if iszero(lt(n, 0x46)) { let o := add(encodedAuth, 0x20) // Start of `encodedAuth`'s bytes. let e := add(o, n) // End of `encodedAuth` in memory. n := shr(240, mload(o)) // Length of `authenticatorData`. let a := add(o, 0x02) // Start of `authenticatorData`. let c := add(a, n) // Start of `clientDataJSON`. let j := sub(e, 0x44) // Start of `challengeIndex`. if iszero(gt(c, j)) { mstore(decoded, extractBytes(a, n)) // `authenticatorData`. mstore(add(decoded, 0x20), extractBytes(c, sub(j, c))) // `clientDataJSON`. mstore(add(decoded, 0x40), shr(240, mload(j))) // `challengeIndex`. mstore(add(decoded, 0x60), shr(240, mload(add(j, 0x02)))) // `typeIndex`. mstore(add(decoded, 0x80), mload(add(j, 0x04))) // `r`. mstore(add(decoded, 0xa0), mload(add(j, 0x24))) // `s`. } } } } /// @dev Calldata variant of `tryDecodeAuthCompact`. function tryDecodeAuthCompactCalldata(bytes calldata encodedAuth) internal pure returns (WebAuthnAuth memory decoded) { /// @solidity memory-safe-assembly assembly { function extractBytes(o_, l_) -> _m { _m := mload(0x40) // Grab the free memory pointer. let s_ := add(_m, 0x20) calldatacopy(s_, o_, l_) mstore(_m, l_) // Store the length. mstore(add(l_, s_), 0) // Zeroize the slot after the string. mstore(0x40, add(0x20, add(l_, s_))) // Allocate memory. } if iszero(lt(encodedAuth.length, 0x46)) { let e := add(encodedAuth.offset, encodedAuth.length) // End of `encodedAuth`. let n := shr(240, calldataload(encodedAuth.offset)) // Length of `authenticatorData`. let a := add(encodedAuth.offset, 0x02) // Start of `authenticatorData`. let c := add(a, n) // Start of `clientDataJSON`. let j := sub(e, 0x44) // Start of `challengeIndex`. if iszero(gt(c, j)) { mstore(decoded, extractBytes(a, n)) // `authenticatorData`. mstore(add(decoded, 0x20), extractBytes(c, sub(j, c))) // `clientDataJSON`. mstore(add(decoded, 0x40), shr(240, calldataload(j))) // `challengeIndex`. mstore(add(decoded, 0x60), shr(240, calldataload(add(j, 0x02)))) // `typeIndex`. mstore(add(decoded, 0x80), calldataload(add(j, 0x04))) // `r`. mstore(add(decoded, 0xa0), calldataload(add(j, 0x24))) // `s`. } } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized P256 wrapper. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/P256.sol) /// @author Modified from Daimo P256 Verifier (https://github.com/daimo-eth/p256-verifier/blob/master/src/P256.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/P256.sol) library P256 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to verify the P256 signature, due to missing /// RIP-7212 P256 verifier precompile and missing Solidity P256 verifier. error P256VerificationFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Address of the Solidity P256 verifier. /// Please make sure the contract is deployed onto the chain you are working on. /// See: https://gist.github.com/Vectorized/599b0d8a94d21bc74700eb1354e2f55c /// Unlike RIP-7212, this verifier returns `uint256(0)` on failure, to /// facilitate easier existence check. This verifier will also never revert. address internal constant VERIFIER = 0x000000000000D01eA45F9eFD5c54f037Fa57Ea1a; /// @dev Address of the RIP-7212 P256 verifier precompile. /// Currently, we don't support EIP-7212's precompile at 0x0b as it has not been finalized. /// See: https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md address internal constant RIP_PRECOMPILE = 0x0000000000000000000000000000000000000100; /// @dev The order of the secp256r1 elliptic curve. uint256 internal constant N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551; /// @dev `N/2`. Used for checking the malleability of the signature. uint256 private constant _HALF_N = 0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* P256 VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if the signature (`r`, `s`) is valid for `hash` and public key (`x`, `y`). /// Does NOT include the malleability check. function verifySignatureAllowMalleability(bytes32 hash, bytes32 r, bytes32 s, bytes32 x, bytes32 y) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(m, hash) mstore(add(m, 0x20), r) mstore(add(m, 0x40), s) mstore(add(m, 0x60), x) mstore(add(m, 0x80), y) mstore(0x00, 0) // Zeroize the return slot before the staticcalls. pop(staticcall(gas(), RIP_PRECOMPILE, m, 0xa0, 0x00, 0x20)) // RIP-7212 dictates that success returns `uint256(1)`. // But failure returns zero returndata, which is ambiguous. if iszero(returndatasize()) { pop(staticcall(gas(), VERIFIER, m, 0xa0, returndatasize(), 0x20)) // Unlike RIP-7212, the verifier returns `uint256(0)` on failure, // allowing us to use the returndatasize to determine existence. if iszero(returndatasize()) { mstore(returndatasize(), 0xd0d5039b) // `P256VerificationFailed()`. revert(0x1c, 0x04) } } isValid := eq(1, mload(0x00)) } } /// @dev Returns if the signature (`r`, `s`) is valid for `hash` and public key (`x`, `y`). /// Includes the malleability check. function verifySignature(bytes32 hash, bytes32 r, bytes32 s, bytes32 x, bytes32 y) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(m, hash) mstore(add(m, 0x20), r) mstore(add(m, 0x40), s) mstore(add(m, 0x60), x) mstore(add(m, 0x80), y) mstore(0x00, 0) // Zeroize the return slot before the staticcalls. pop(staticcall(gas(), RIP_PRECOMPILE, m, 0xa0, 0x00, 0x20)) // RIP-7212 dictates that success returns `uint256(1)`. // But failure returns zero returndata, which is ambiguous. if iszero(returndatasize()) { pop(staticcall(gas(), VERIFIER, m, 0xa0, returndatasize(), 0x20)) // Unlike RIP-7212, the verifier returns `uint256(0)` on failure, // allowing us to use the returndatasize to determine existence. if iszero(returndatasize()) { mstore(returndatasize(), 0xd0d5039b) // `P256VerificationFailed()`. revert(0x1c, 0x04) } } // Optimize for happy path. Users are unlikely to pass in malleable signatures. isValid := lt(gt(s, _HALF_N), eq(1, mload(0x00))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `s` normalized to the lower half of the curve. function normalized(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := xor(s, mul(xor(sub(N, s), s), gt(s, _HALF_N))) } } /// @dev Helper function for `abi.decode(encoded, (bytes32, bytes32))`. /// If `encoded.length < 64`, `(x, y)` will be `(0, 0)`, which is an invalid point. function tryDecodePoint(bytes memory encoded) internal pure returns (bytes32 x, bytes32 y) { /// @solidity memory-safe-assembly assembly { let t := gt(mload(encoded), 0x3f) x := mul(mload(add(encoded, 0x20)), t) y := mul(mload(add(encoded, 0x40)), t) } } /// @dev Helper function for `abi.decode(encoded, (bytes32, bytes32))`. /// If `encoded.length < 64`, `(x, y)` will be `(0, 0)`, which is an invalid point. function tryDecodePointCalldata(bytes calldata encoded) internal pure returns (bytes32 x, bytes32 y) { /// @solidity memory-safe-assembly assembly { let t := gt(encoded.length, 0x3f) x := mul(calldataload(encoded.offset), t) y := mul(calldataload(add(encoded.offset, 0x20)), t) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; // solhint-disable no-inline-assembly /** * Utility functions helpful when making different kinds of contract calls in Solidity. */ library Exec { function call( address to, uint256 value, bytes memory data, uint256 txGas ) internal returns (bool success) { assembly ("memory-safe") { success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0) } } function staticcall( address to, bytes memory data, uint256 txGas ) internal view returns (bool success) { assembly ("memory-safe") { success := staticcall(txGas, to, add(data, 0x20), mload(data), 0, 0) } } function delegateCall( address to, bytes memory data, uint256 txGas ) internal returns (bool success) { assembly ("memory-safe") { success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0) } } // get returned data from last call or delegateCall // maxLen - maximum length of data to return, or zero, for the full length function getReturnData(uint256 maxLen) internal pure returns (bytes memory returnData) { assembly ("memory-safe") { let len := returndatasize() if gt(maxLen,0) { if gt(len, maxLen) { len := maxLen } } let ptr := mload(0x40) mstore(0x40, add(ptr, add(len, 0x20))) mstore(ptr, len) returndatacopy(add(ptr, 0x20), 0, len) returnData := ptr } } // revert with explicit byte array (probably reverted info from call) function revertWithData(bytes memory returnData) internal pure { assembly ("memory-safe") { revert(add(returnData, 32), mload(returnData)) } } // Propagate revert data from last call function revertWithReturnData() internal pure { revertWithData(getReturnData(0)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /* solhint-disable no-inline-assembly */ import "../interfaces/PackedUserOperation.sol"; import {calldataKeccak, min} from "./Helpers.sol"; /** * Utility functions helpful when working with UserOperation structs. */ library UserOperationLib { uint256 public constant PAYMASTER_VALIDATION_GAS_OFFSET = 20; uint256 public constant PAYMASTER_POSTOP_GAS_OFFSET = 36; uint256 public constant PAYMASTER_DATA_OFFSET = 52; /** * Relayer/block builder might submit the TX with higher priorityFee, * but the user should not pay above what he signed for. * @param userOp - The user operation data. */ function gasPrice( PackedUserOperation calldata userOp ) internal view returns (uint256) { unchecked { (uint256 maxPriorityFeePerGas, uint256 maxFeePerGas) = unpackUints(userOp.gasFees); return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); } } bytes32 internal constant PACKED_USEROP_TYPEHASH = keccak256( "PackedUserOperation(address sender,uint256 nonce,bytes initCode,bytes callData,bytes32 accountGasLimits,uint256 preVerificationGas,bytes32 gasFees,bytes paymasterAndData)" ); /** * Pack the user operation data into bytes for hashing. * @param userOp - The user operation data. * @param overrideInitCodeHash - If set, encode this instead of the initCode field in the userOp. */ function encode( PackedUserOperation calldata userOp, bytes32 overrideInitCodeHash ) internal pure returns (bytes memory ret) { address sender = userOp.sender; uint256 nonce = userOp.nonce; bytes32 hashInitCode = overrideInitCodeHash != 0 ? overrideInitCodeHash : calldataKeccak(userOp.initCode); bytes32 hashCallData = calldataKeccak(userOp.callData); bytes32 accountGasLimits = userOp.accountGasLimits; uint256 preVerificationGas = userOp.preVerificationGas; bytes32 gasFees = userOp.gasFees; bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); return abi.encode( UserOperationLib.PACKED_USEROP_TYPEHASH, sender, nonce, hashInitCode, hashCallData, accountGasLimits, preVerificationGas, gasFees, hashPaymasterAndData ); } function unpackUints( bytes32 packed ) internal pure returns (uint256 high128, uint256 low128) { return (unpackHigh128(packed), unpackLow128(packed)); } // Unpack just the high 128-bits from a packed value function unpackHigh128(bytes32 packed) internal pure returns (uint256) { return uint256(packed) >> 128; } // Unpack just the low 128-bits from a packed value function unpackLow128(bytes32 packed) internal pure returns (uint256) { return uint128(uint256(packed)); } function unpackMaxPriorityFeePerGas(PackedUserOperation calldata userOp) internal pure returns (uint256) { return unpackHigh128(userOp.gasFees); } function unpackMaxFeePerGas(PackedUserOperation calldata userOp) internal pure returns (uint256) { return unpackLow128(userOp.gasFees); } function unpackVerificationGasLimit(PackedUserOperation calldata userOp) internal pure returns (uint256) { return unpackHigh128(userOp.accountGasLimits); } function unpackCallGasLimit(PackedUserOperation calldata userOp) internal pure returns (uint256) { return unpackLow128(userOp.accountGasLimits); } function unpackPaymasterVerificationGasLimit(PackedUserOperation calldata userOp) internal pure returns (uint256) { return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET])); } function unpackPostOpGasLimit(PackedUserOperation calldata userOp) internal pure returns (uint256) { return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET])); } function unpackPaymasterStaticFields( bytes calldata paymasterAndData ) internal pure returns (address paymaster, uint256 validationGasLimit, uint256 postOpGasLimit) { return ( address(bytes20(paymasterAndData[: PAYMASTER_VALIDATION_GAS_OFFSET])), uint128(bytes16(paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET])), uint128(bytes16(paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET])) ); } /** * Hash the user operation data. * @param userOp - The user operation data. * @param overrideInitCodeHash - If set, the initCode hash will be replaced with this value just for UserOp hashing. */ function hash( PackedUserOperation calldata userOp, bytes32 overrideInitCodeHash ) internal pure returns (bytes32) { return keccak256(encode(userOp, overrideInitCodeHash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /** * 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 fits into one cell (used during handleOp) * and the rest fit into a 2nd cell (used during stake/unstake) * - 112 bit allows for 10^15 eth * - 48 bit for full timestamp * - 32 bit allows 150 years for unstake delay */ struct DepositInfo { uint256 deposit; bool staked; uint112 stake; uint32 unstakeDelaySec; uint48 withdrawTime; } // API struct used by getStakeInfo and simulateValidation. struct StakeInfo { uint256 stake; uint256 unstakeDelaySec; } /** * Get deposit info. * @param account - The account to query. * @return info - Full deposit information of given account. */ function getDepositInfo( address account ) external view returns (DepositInfo memory info); /** * Get account balance. * @param account - The account to query. * @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. * @param account - The account to add to. */ 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: MIT pragma solidity ^0.8.28; import "./PackedUserOperation.sol"; /** * Aggregated Signatures validator. */ interface IAggregator { /** * Validate an aggregated signature. * Reverts if the aggregated signature does not match the given list of operations. * @param userOps - An array of UserOperations to validate the signature for. * @param signature - The aggregated signature. */ function validateSignatures( PackedUserOperation[] calldata userOps, bytes calldata signature ) external; /** * Validate the signature of a single userOp. * This method should be called by bundler after EntryPointSimulation.simulateValidation() returns * the aggregator this account uses. * 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( PackedUserOperation 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 to perform this aggregation. * @param userOps - An array of UserOperations to collect the signatures from. * @return aggregatedSignature - The aggregated signature. */ function aggregateSignatures( PackedUserOperation[] calldata userOps ) external view returns (bytes memory aggregatedSignature); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; 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. * * @param key - the "nonce key" to increment the "nonce sequence" for. */ function incrementNonce(uint192 key) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface ISenderCreator { /** * @dev Creates a new sender contract. * @return sender Address of the newly created sender contract. */ function createSender(bytes calldata initCode) external returns (address sender); /** * Use initCallData to initialize an EIP-7702 account. * The caller is the EntryPoint contract and it is already verified to be an EIP-7702 account. * Note: Can be called multiple times as long as an appropriate initCode is supplied * * @param sender - the 'sender' EIP-7702 account to be initialized. * @param initCallData - the call data to be passed to the sender account call. */ function initEip7702Sender(address sender, bytes calldata initCallData) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC-1155 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 ERC-1155 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 v5.1.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC-721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC-721 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 `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) let dataEnd := add(add(0x20, data), dataLength) let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot. mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits. // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`. mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "account-abstraction/=lib/account-abstraction/contracts/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 2000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_entryPoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes","name":"error","type":"bytes"}],"name":"ExecuteError","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OpenfortBaseAccount7702V1__InvalidNonce","type":"error"},{"inputs":[],"name":"OpenfortBaseAccount7702V1__InvalidSignature","type":"error"},{"inputs":[],"name":"OpenfortBaseAccount7702V1__InvalidTransactionLength","type":"error"},{"inputs":[],"name":"OpenfortBaseAccount7702V1__InvalidTransactionTarget","type":"error"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"OpenfortBaseAccount7702V1__TransactionFailed","type":"error"},{"inputs":[],"name":"OpenfortBaseAccount7702V1__ValidationExpired","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"SessionKeyManager__AddressCantBeZero","type":"error"},{"inputs":[],"name":"SessionKeyManager__InvalidTimestamp","type":"error"},{"inputs":[],"name":"SessionKeyManager__SelectorsListTooBig","type":"error"},{"inputs":[],"name":"SessionKeyManager__SessionKeyInactive","type":"error"},{"inputs":[],"name":"SessionKeyManager__SessionKeyRegistered","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"address","name":"eoaAddress","type":"address"},{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"}],"indexed":true,"internalType":"struct ISessionKey.Key","name":"masterKey","type":"tuple"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"sessionKey","type":"bytes32"}],"name":"SessionKeyRegistrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"sessionKey","type":"bytes32"}],"name":"SessionKeyRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"TransactionExecuted","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEAD_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SELECTORS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_OPENFORT_CONTRACT_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"encodeEOASignature","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"challenge","type":"bytes"},{"internalType":"bool","name":"requireUserVerification","type":"bool"},{"internalType":"bytes","name":"authenticatorData","type":"bytes"},{"internalType":"string","name":"clientDataJSON","type":"string"},{"internalType":"uint256","name":"challengeIndex","type":"uint256"},{"internalType":"uint256","name":"typeIndex","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"}],"name":"encodeWebAuthnSignature","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct OPF7702v11.Transaction[]","name":"_transactions","type":"tuple[]"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BaseAccount.Call[]","name":"calls","type":"tuple[]"}],"name":"executeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_target","type":"address[]"},{"internalType":"uint256[]","name":"_value","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldata","type":"bytes[]"}],"name":"executeBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getKeyById","outputs":[{"components":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"address","name":"eoaAddress","type":"address"},{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"}],"internalType":"struct ISessionKey.Key","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getKeyRegistrationInfo","outputs":[{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"},{"internalType":"address","name":"registeredBy","type":"address"},{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_key","type":"address"}],"name":"getSessionKeyData","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint48","name":"","type":"uint48"},{"internalType":"uint48","name":"","type":"uint48"},{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_keyHash","type":"bytes32"}],"name":"getSessionKeyData","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint48","name":"","type":"uint48"},{"internalType":"uint48","name":"","type":"uint48"},{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"id","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"idSessionKeys","outputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"address","name":"eoaAddress","type":"address"},{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"address","name":"eoaAddress","type":"address"},{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"}],"internalType":"struct ISessionKey.Key","name":"_key","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"internalType":"struct SpendLimit.SpendTokenInfo","name":"_spendTokenInfo","type":"tuple"},{"internalType":"bytes4[]","name":"_allowedSelectors","type":"bytes4[]"},{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"uint256","name":"_validUntil","type":"uint256"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash","type":"bytes32"}],"name":"isSessionKeyActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"eoaKey","type":"address"}],"name":"isSessionKeyActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"address","name":"eoaAddress","type":"address"},{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"}],"internalType":"struct ISessionKey.Key","name":"_key","type":"tuple"},{"internalType":"uint48","name":"_validUntil","type":"uint48"},{"internalType":"uint48","name":"_validAfter","type":"uint48"},{"internalType":"uint48","name":"_limit","type":"uint48"},{"internalType":"bool","name":"_whitelisting","type":"bool"},{"internalType":"address","name":"_contractAddress","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"internalType":"struct SpendLimit.SpendTokenInfo","name":"_spendTokenInfo","type":"tuple"},{"internalType":"bytes4[]","name":"_allowedSelectors","type":"bytes4[]"},{"internalType":"uint256","name":"_ethLimit","type":"uint256"}],"name":"registerSessionKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeAllSessionKeys","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"address","name":"eoaAddress","type":"address"},{"internalType":"enum ISessionKey.KeyType","name":"keyType","type":"uint8"}],"internalType":"struct ISessionKey.Key","name":"_key","type":"tuple"}],"name":"revokeSessionKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sessionKey","type":"bytes32"}],"name":"sessionKeys","outputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint48","name":"validAfter","type":"uint48"},{"internalType":"uint48","name":"limit","type":"uint48"},{"internalType":"bool","name":"masterSessionKey","type":"bool"},{"internalType":"bool","name":"whitelisting","type":"bool"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"internalType":"struct SpendLimit.SpendTokenInfo","name":"spendTokenInfo","type":"tuple"},{"internalType":"uint256","name":"ethLimit","type":"uint256"},{"internalType":"address","name":"whoRegistrated","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sessionKeyEOA","type":"address"}],"name":"sessionKeysEOA","outputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct ISessionKey.PubKey","name":"pubKey","type":"tuple"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint48","name":"validAfter","type":"uint48"},{"internalType":"uint48","name":"limit","type":"uint48"},{"internalType":"bool","name":"masterSessionKey","type":"bool"},{"internalType":"bool","name":"whitelisting","type":"bool"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"internalType":"struct SpendLimit.SpendTokenInfo","name":"spendTokenInfo","type":"tuple"},{"internalType":"uint256","name":"ethLimit","type":"uint256"},{"internalType":"address","name":"whoRegistrated","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"challenge","type":"bytes"}],"name":"usedChallenges","outputs":[{"internalType":"bool","name":"isUsed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"missingAccountFunds","type":"uint256"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"challenge","type":"bytes"},{"internalType":"bool","name":"requireUserVerification","type":"bool"},{"internalType":"bytes","name":"encodedAuth","type":"bytes"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"verifyCompactSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"challenge","type":"bytes"},{"internalType":"bool","name":"requireUserVerification","type":"bool"},{"internalType":"bytes","name":"encodedAuth","type":"bytes"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"verifyEncodedSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"verifyP256Signature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"challenge","type":"bytes"},{"internalType":"bool","name":"requireUserVerification","type":"bool"},{"internalType":"bytes","name":"authenticatorData","type":"bytes"},{"internalType":"string","name":"clientDataJSON","type":"string"},{"internalType":"uint256","name":"challengeIndex","type":"uint256"},{"internalType":"uint256","name":"typeIndex","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"verifySoladySignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c03461013057601f6149e038819003918201601f19168301916001600160401b038311848410176101345780849260209460405283398101031261013057516001600160a01b03811681036101305760017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f3685560a052306080525f5160206149c05f395f51905f525460ff8160401c16610121576002600160401b03196001600160401b038216016100cb575b60405161487790816101498239608051816107e4015260a051815050f35b6001600160401b0319166001600160401b039081175f5160206149c05f395f51905f52556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f6100ad565b63f92ee8a960e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610010575b005b5f3560e01c806301ffc9a71461025f5780630c3b1ae91461025a578063110891c114610255578063150b7a02146102505780631626ba7e1461024b57806317f976721461024657806318f991021461024157806319822f7c1461023c57806325c1c3c31461023757806334fcd5be146102325780633f707e6b1461022d57806347e1da2a146102285780634e6fd6c4146102235780635a880de31461021e57806369d3c8651461021957806394c11608146102145780639c241abd1461020f578063a04b3e161461020a578063a2e8cf4014610205578063a7dc0fe614610200578063af640d0f146101fb578063affed0e0146101f6578063b0d691fe146101f1578063b2aa3f13146101ec578063b3ee7f11146101e7578063b61d27f6146101e2578063b75c8b78146101dd578063bc197c81146101d8578063bed5df4a146101d3578063c77d7805146101ce578063ce9124f3146101c9578063d087d288146101c4578063d180b1fc146101bf578063d86c2585146101ba578063eaf0188f146101b5578063f23a6e61146101b05763f4d2a1940361000e57611ea6565b611e34565b611d93565b611d42565b611c31565b611b7d565b6119ba565b61194d565b611904565b611811565b6116fe565b61166c565b61159d565b61145d565b6113cc565b611390565b611354565b6112cd565b611299565b611229565b61117c565b611099565b611054565b610ff9565b610f9b565b610e68565b610cdf565b610c20565b6109dd565b6108df565b610808565b6107c5565b610773565b610701565b6105df565b61050c565b61027a565b6001600160e01b031981160361027657565b5f80fd5b34610276576020600319360112610276576001600160e01b03196004356102a081610264565b167f01ffc9a7000000000000000000000000000000000000000000000000000000008114908115610354575b8115610343575b8115610319575b81156102ef575b506040519015158152602090f35b7f150b7a02000000000000000000000000000000000000000000000000000000009150145f6102e1565b7f4e2312e000000000000000000000000000000000000000000000000000000000811491506102da565b630b135d3f60e11b811491506102d3565b7f19822f7c00000000000000000000000000000000000000000000000000000000811491506102cc565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176103ae57604052565b61037e565b6060810190811067ffffffffffffffff8211176103ae57604052565b60c0810190811067ffffffffffffffff8211176103ae57604052565b90601f601f19910116810190811067ffffffffffffffff8211176103ae57604052565b6040519061041d6040836103eb565b565b6040519061041d6060836103eb565b9060405161043b81610392565b602060018294805484520154910152565b9060405161045981610392565b6020600182946001600160a01b0381541684520154910152565b9a999896949290918b989694926101808a019c6104999160208091805184520151910152565b1515604089015265ffffffffffff16606088015265ffffffffffff16608087015265ffffffffffff1660a0860152151560c0850152151560e084015261010083019080516001600160a01b031682526020015190602001526101408201526101600161041d916001600160a01b03169052565b34610276576020600319360112610276576004355f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f206105538161042e565b6105ca6002830154926105686004820161044c565b90610582600860078301549201546001600160a01b031690565b9160405195869560ff8260a01c169160ff8160981c169165ffffffffffff8260681c169165ffffffffffff8160381c169160ff65ffffffffffff8360081c169216908b610473565b0390f35b6001600160a01b0381160361027657565b34610276576020600319360112610276576004356105fc816105ce565b6001600160a01b03165f9081527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d602052604090206002015465ffffffffffff600882901c81169160ff8116916105ca91603881901c82169160689190911c165b9060405194859485929365ffffffffffff809296958160609560808801991515885216602087015216604085015216910152565b67ffffffffffffffff81116103ae57601f01601f191660200190565b9291926106b982610691565b916106c760405193846103eb565b829481845281830111610276578281602093845f960137010152565b9080601f83011215610276578160206106fe933591016106ad565b90565b346102765760806003193601126102765761071d6004356105ce565b6107286024356105ce565b60643567ffffffffffffffff8111610276576107489036906004016106e3565b5060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b346102765760406003193601126102765760043560243567ffffffffffffffff8111610276576020916107ad6107b39236906004016106e3565b90611f09565b6001600160e01b031960405191168152f35b34610276575f6003193601126102765760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610276576020600319360112610276576001600160a01b0360043561082d816105ce565b165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f206108618161042e565b906105ca6002820154916108798360ff9060a01c1690565b906108866004820161044c565b61089f600860078401549301546001600160a01b031690565b92604051968660ff899860981c169165ffffffffffff8260681c169165ffffffffffff8160381c169160ff65ffffffffffff8360081c169216908b610473565b346102765760606003193601126102765760043567ffffffffffffffff81116102765761012060031982360301126102765760243590604435734337084d9e255ff0702461cf8895ce9e3b5ff108330361097f5761095060246109486105ca958560040161326d565b930135613507565b80610967575b506040519081529081906020820190565b5f80808093335af150610978612181565b505f610956565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e74000000006044820152fd5b34610276575f600319360112610276576109f5613558565b5f5b7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a5481101561000e5780610a2c6001926121c0565b60408101838151610a3c81610fdd565b610a4581610fdd565b03610ae057505180516020918201516040805193840192835283015290610a7981606081015b03601f1981018352826103eb565b519020610ab5610ab0825f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b61361a565b7fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a25b016109f7565b51610aea81610fdd565b610af381610fdd565b15610aff575b50610ada565b60200180516001600160a01b0316908115610bb957610b54610ab0610b61936001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b516001600160a01b031690565b604051610b8c81610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a25f610af9565b5050610ada565b9181601f840112156102765782359167ffffffffffffffff8311610276576020808501948460051b01011161027657565b6020600319820112610276576004359067ffffffffffffffff821161027657610c1c91600401610bc0565b9091565b3461027657610c2e36610bf1565b610c36613558565b5f5b818110610c4157005b610c87610c83610c7d610c558486886120cf565b610c5e8161210f565b90610c726020820135916040810190612119565b93905a9436916106ad565b916136b7565b1590565b610c9357600101610c38565b600182145f036136e357610ca56136c9565b90610cdb6040519283927f5a1546750000000000000000000000000000000000000000000000000000000084526004840161216a565b0390fd5b610ce836610bf1565b610cf06136f3565b610cf8613558565b80158015610e5e575b610e36575f5b818110610d375761000e60017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855565b610d428183856120cf565b610d4b8161210f565b90610d69610d626020830135926040810190612119565b36916106ad565b906001600160a01b03831692308414610e0e575f80918451908460208701915af1610d92612181565b9015610dd8575060019392917f47d99ad340f52da66535aff7e10da1ceb85a32bcbd9fa1c42314d194545e14d291610dcf6040519283928361216a565b0390a201610d07565b610cdb906040519182917faf05250e0000000000000000000000000000000000000000000000000000000083526004830161116b565b7f793426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1d453126000000000000000000000000000000000000000000000000000000005f5260045ffd5b5060098111610d01565b60606003193601126102765760043567ffffffffffffffff811161027657610e94903690600401610bc0565b9060243567ffffffffffffffff811161027657610eb5903690600401610bc0565b91909260443567ffffffffffffffff811161027657610ed8903690600401610bc0565b919092610ee36136f3565b610eeb613558565b600982118015610f91575b8015610f87575b610e36575f5b828110610f335761000e60017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855565b610f3e8184846121b0565b3590610f49826105ce565b610f5481888a6121b0565b359185821015610f8257600192610f7c91610f748460051b8a018a612119565b92909161376a565b01610f03565b6120bb565b5084821415610efd565b5082821415610ef6565b34610276575f60031936011261027657602060405173deadbeefdeadbeefdeadbeefdeadbeefdeadbeef8152f35b634e487b7160e01b5f52602160045260245ffd5b60021115610fe757565b610fc9565b906002821015610fe75752565b346102765760206003193601126102765760806110176004356121c0565b611052604080519261103484825160208091805184520151910152565b6001600160a01b036020820151168285015201516060830190610fec565bf35b346102765760206003193601126102765760606001600160a01b0361107a600435612258565b91929061108a6040518095610fec565b16602083015215156040820152f35b34610276575f600319360112610276576020604051600a8152f35b8015150361027657565b6024359061041d826110b4565b359061041d826110b4565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc6040910112610276576040519061110d82610392565b610104358252610124356020830152565b91908260409103126102765760405161113681610392565b6020808294803584520135910152565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9060206106fe928181520190611146565b34610276576101406003193601126102765760043567ffffffffffffffff8111610276576111ae9036906004016106e3565b6111b66110be565b60443567ffffffffffffffff8111610276576111d69036906004016106e3565b916064359167ffffffffffffffff8311610276576105ca936111ff61121d9436906004016106e3565b60843560a4359160c4359360e43595611217366110d6565b976123ad565b6040519182918261116b565b34610276576020600319360112610276576004355f9081527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c602052604090206002015465ffffffffffff600882901c81169160ff8116916105ca91603881901c82169160689190911c1661065d565b346102765760a06003193601126102765760206112c36084356064356044356024356004356137de565b6040519015158152f35b34610276576020600319360112610276576004355f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b602052608060405f20611052600261131b8361042e565b920154611335604051809460208091805184520151910152565b6001600160a01b038116604084015260ff606084019160a01c16610fec565b34610276575f6003193601126102765760207f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a54604051908152f35b34610276575f6003193601126102765760207f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36954604051908152f35b34610276575f600319360112610276576020604051734337084d9e255ff0702461cf8895ce9e3b5ff1088152f35b60a06003198201126102765760043567ffffffffffffffff81116102765781611425916004016106e3565b91602435611432816110b4565b916044359067ffffffffffffffff821161027657611452916004016106e3565b906064359060843590565b34610276576105ca6114ba611471366113fa565b9361147d939193613873565b92805160c08110906020860190604087016060880190608089019260a08a019660208082019282010196156114cc575b50505050505050506138a5565b60405190151581529081906020820190565b81510194602086019182108760e08801111761154f5785825101602081019787604081015101602081019480861083871117908b10838c1117176115545760208281808094895101010111938b51010101111761154f5760c0968b5252606084015190526080830151905260a08201519052015190525f808080808080806114ad565b6114ad565b5050506114ad565b600319608091011261027657600490565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc60409101126102765761012490565b3461027657610160600319360112610276576115b83661155c565b60407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c3601126102765760c43567ffffffffffffffff811161027657611602903690600401610bc0565b6101043592919060e43567ffffffffffffffff85116102765761162c61000e9536906004016106e3565b91610124359360846101443596612443565b9181601f840112156102765782359167ffffffffffffffff8311610276576020838186019501011161027657565b606060031936011261027657600435611684816105ce565b6024356044359167ffffffffffffffff8311610276576116ab6116c393369060040161163e565b9290916116b66136f3565b6116be613558565b61376a565b60017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855005b60c4359065ffffffffffff8216820361027657565b34610276576101a0600319360112610276576117193661155c565b6084359065ffffffffffff821682036102765760a43565ffffffffffff81168103610276576117466116e9565b9260e435611753816110b4565b61010435611760816105ce565b6117693661156d565b91610164359667ffffffffffffffff88116102765761178f61000e983690600401610bc0565b9690956101843598612c00565b67ffffffffffffffff81116103ae5760051b60200190565b9080601f830112156102765781356117cb8161179c565b926117d960405194856103eb565b81845260208085019260051b82010192831161027657602001905b8282106118015750505090565b81358152602091820191016117f4565b346102765760a06003193601126102765761182d6004356105ce565b6118386024356105ce565b60443567ffffffffffffffff8111610276576118589036906004016117b4565b5060643567ffffffffffffffff8111610276576118799036906004016117b4565b5060843567ffffffffffffffff81116102765761189a9036906004016106e3565b506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b60208091604051928184925191829101835e81017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36e81520301902090565b346102765760206003193601126102765760043567ffffffffffffffff81116102765760ff61194161193c60209336906004016106e3565b6118c6565b54166040519015158152f35b346102765760206003193601126102765760043567ffffffffffffffff8111610276576119a66119846105ca92369060040161163e565b610a6b6040939293519384925f60208501526040808501526060840191612e40565b604051918291602083526020830190611146565b34610276576080600319360112610276576119d43661155c565b6119dc613558565b6060810160016119eb8261284c565b6119f481610fdd565b03611a805750610a6b611a23602083359301356040519283916020830195869091604092825260208201520190565b519020611a5a610ab0825f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b7fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a2005b611a899061284c565b611a9281610fdd565b15611a9957005b6040016001600160a01b03611aad8261210f565b1615611b555780611afc610ab0611ac6611b019461210f565b6001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b61210f565b604051611b2c81610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a2005b7faa093569000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610276575f600319360112610276576040517f35567e1a0000000000000000000000000000000000000000000000000000000081523060048201525f6024820152602081604481734337084d9e255ff0702461cf8895ce9e3b5ff1085afa8015611c2c576105ca915f91611bfd57506040519081529081906020820190565b611c1f915060203d602011611c25575b611c1781836103eb565b810190612e60565b5f610956565b503d611c0d565b612e6f565b34610276576105ca6114ba611c45366113fa565b93611c51939193613873565b9280516046811015611c65575b50506138a5565b810190602081015160f01c908181019160228301907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc85019384831115611cb0575b50505050611c5e565b611ce17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffba926022611cec9601613d46565b895285030190613d46565b60208601525160f01c60408501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde81015160f01c6060850152601f1981015160808501525160a08401525f8080808080611ca7565b34610276576020600319360112610276576004355f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c602052602060ff600260405f200154166040519015158152f35b34610276576101406003193601126102765760043567ffffffffffffffff811161027657611dc59036906004016106e3565b611dcd6110be565b60443567ffffffffffffffff811161027657611ded9036906004016106e3565b916064359167ffffffffffffffff8311610276576105ca93611e166114ba9436906004016106e3565b60843560a4359060c4359260e4359461010435966101243598612e7a565b346102765760a060031936011261027657611e506004356105ce565b611e5b6024356105ce565b60843567ffffffffffffffff811161027657611e7b9036906004016106e3565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b34610276576020600319360112610276576001600160a01b03600435611ecb816105ce565b165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d602052602060ff600260405f200154166040519015158152f35b7f25622562256225622562256225622562256225622562256225622562256225628114806120b0575b15611f5b57506001602082015114611f5257505b6001600160e01b031990565b6106fe90612ff7565b908051604081149081156120a5575b50611f76575050611f46565b611f7f91612eb5565b6001600160a01b038116301461209957611fc9906001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b6002810154600881901c65ffffffffffff16801591908215612083575b8215612079575b508115612048575b501561200857506001600160e01b031990565b61202c6120206008309301546001600160a01b031690565b6001600160a01b031690565b1461203d576001600160e01b031990565b630b135d3f60e11b90565b609881901c60ff1615915081612060575b505f611ff5565b6001915065ffffffffffff9060681c811616105f612059565b421191505f611fed565b4265ffffffffffff603884901c16119250611fe6565b50630b135d3f60e11b90565b60419150145f611f6a565b506041825111611f32565b634e487b7160e01b5f52603260045260245ffd5b9190811015610f825760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa181360301821215610276570190565b356106fe816105ce565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610276570180359067ffffffffffffffff82116102765760200191813603831361027657565b6040906106fe939281528160208201520190611146565b3d156121ab573d9061219282610691565b916121a060405193846103eb565b82523d5f602084013e565b606090565b9190811015610f825760051b0190565b5f604080516121ce816103b3565b81516121d981610392565b838152836020820152815282602082015201525f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b60205260405f2060ff600260405192612227846103b3565b6122308161042e565b845201546001600160a01b038116602084015260a01c166002811015610fe757604082015290565b612261906121c0565b9060408201916001835161227481610fdd565b61227d81610fdd565b0361233d5751805160209182015160408051938401928352830152906122a68160608101610a6b565b5190209151906122b582610fdd565b612337600261232f61230160086122f3885f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b01546001600160a01b031690565b955f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b015460ff1690565b91929190565b8291925161234a81610fdd565b61235381610fdd565b1561236a57505161236381610fdd565b905f905f90565b90602090519161237983610fdd565b0191612337600261232f611ac661239f60086122f3611ac68a516001600160a01b031690565b96516001600160a01b031690565b979294612416610a6b959661240461018099946106fe9b966123eb6040519e8f9d8e6123dc6020820160019052565b61016060408201520190611146565b91151560608d0152601f198c83030160808d0152611146565b90601f198a83030160a08b0152611146565b60c088019690965260e0870152610100860152610120850152805161014085015260200151610160840152565b95939196949290967ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549767ffffffffffffffff61249861248a60ff8c60401c1615151590565b9a67ffffffffffffffff1690565b168015908161265f575b6001149081612655575b15908161264c575b5061262457612535978961252c60017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000007ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b6125bf576126f3565b61253b57565b61259068ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b61261f6801000000000000000068ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b6126f3565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b9050155f6124b4565b303b1591506124ac565b8a91506124a2565b634e487b7160e01b5f52601160045260245ffd5b90612710820180921161268a57565b612667565b6002111561027657565b359061041d8261268f565b6080906126ef60606040519280358452602081013560208501526001600160a01b0360408201356126d4816105ce565b16604085015201356126e58161268f565b6060830190610fec565b2090565b9596949192939096612703613558565b60025b600681106127f6575061271886613507565b42116127ce5761272b91610c83916139ee565b6127a6576127809461275e61277b947f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36955565b61277561276a4261267b565b65ffffffffffff1690565b8561290d565b6126a4565b7f9be0ddb3ac5d6261cc8d736bf39c29feb13498533b6c9f960d8e175bf70e6a1a5f80a2565b7f91cc5825000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f032c52a5000000000000000000000000000000000000000000000000000000005f5260045ffd5b807ff3acd96a9d0e27e4323229f52dd3234ce23fb8133871d002e7cbb32c4a47a5c40190817ff3acd96a9d0e27e4323229f52dd3234ce23fb8133871d002e7cbb32c4a47a5c41161268a575f6001925501612706565b356106fe8161268f565b6002606091833581556020840135600182015501916128a5604082013561287c816105ce565b84906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b01356128b08161268f565b6002811015610fe75781547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1660a09190911b74ff000000000000000000000000000000000000000016179055565b5f19811461268a5760010190565b909193612918613558565b4265ffffffffffff84161115612bd8576129838261297e7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a545f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b60205260405f2090565b612856565b6129d46129b07f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a546128ff565b7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a55565b6060820160016129e38261284c565b6129ec81610fdd565b03612afe57509091928235610a6b612a1e60208601356040519283916020830195869091604092825260208201520190565b51902094612a58600261232f885f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b612ad65773deadbeefdeadbeefdeadbeefdeadbeefdeadbeef5f8080612ab0988198612aab8c5f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b613a72565b7fcd7f4163a8248a579c58031f40b757bb4998ed5f01c78bfb6ae1cd42edb95fb05f80a2565b7f2eb93649000000000000000000000000000000000000000000000000000000005f5260045ffd5b612b079061284c565b612b1081610fdd565b15612b1d575b5050505050565b60408201936001600160a01b03612b338661210f565b1615611b5557612b4a600261232f611ac68861210f565b612ad657612b7c9573deadbeefdeadbeefdeadbeefdeadbeefdeadbeef5f8080611afc988198612aab611ac68d61210f565b604051612ba781610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fcd7f4163a8248a579c58031f40b757bb4998ed5f01c78bfb6ae1cd42edb95fb05f80a25f80808080612b16565b7ff5bab791000000000000000000000000000000000000000000000000000000005f5260045ffd5b96939098959297949197612c12613558565b65ffffffffffff8a1642811115612bd85765ffffffffffff8a1611612bd857612c878861297e7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a545f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b60205260405f2090565b612cb46129b07f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a546128ff565b606088016001612cc38261284c565b612ccc81610fdd565b03612d76575090919293949596978835610a6b612d0360208c01356040519283916020830195869091604092825260208201520190565b51902099612d3d600261232f8d5f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b612ad657612ab099612aab8c5f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b612d7f9061284c565b612d8881610fdd565b15612d9a575b50505050505050505050565b60408801986001600160a01b03612db08b61210f565b1615611b5557612dc7600261232f611ac68d61210f565b612ad657612ddf9a611afc99612aab611ac68d61210f565b604051612e0a81610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fcd7f4163a8248a579c58031f40b757bb4998ed5f01c78bfb6ae1cd42edb95fb05f80a25f808080808080808080612d8e565b601f8260209493601f1993818652868601375f8582860101520116010190565b90816020910312610276575190565b6040513d5f823e3d90fd5b936106fe9998979396929695919560405197612e95896103cf565b8852602088015260408701526060860152608085015260a08401526138a5565b6106fe91612ec291613d85565b90929192613dc9565b519061041d8261268f565b81601f8201121561027657602081519101612ef082610691565b92612efe60405194856103eb565b8284528282011161027657815f926020928386015e8301015290565b519061041d826110b4565b919082604091031261027657604051612f3d81610392565b6020808294805184520151910152565b6101608183031261027657612f6181612ecb565b92602082015167ffffffffffffffff81116102765783612f82918401612ed6565b92612f8f60408401612f1a565b92606081015167ffffffffffffffff81116102765782612fb0918301612ed6565b92608082015167ffffffffffffffff81116102765783612fd1918401612ed6565b9260a08301519260c0810151926106fe60e0830151936101206101008501519401612f25565b61300c60019160208082518301019101612f4d565b999093979594969861302081949394610fdd565b0361317757613038613031866118c6565b5460ff1690565b6131775761305496610c83968a519560208c019a8b5198612e7a565b61316957610a6b6130816130b1935192516040519283916020830195869091604092825260208201520190565b5190205f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b6002810154600881901c65ffffffffffff16801591908215613153575b8215613149575b508115613118575b50156130f057506001600160e01b031990565b600801546001600160a01b03166001600160a01b0316301461203d576001600160e01b031990565b609881901c60ff1615915081613130575b505f6130dd565b6001915065ffffffffffff9060681c811616105f613129565b421191505f6130d5565b4265ffffffffffff603884901c161192506130ce565b50506001600160e01b031990565b5050505050505050506001600160e01b031990565b9190916040818403126102765780356131a48161268f565b92602082013567ffffffffffffffff8111610276576106fe92016106e3565b61016081830312610276576131d781612699565b92602082013567ffffffffffffffff811161027657836131f89184016106e3565b92613205604084016110cb565b92606081013567ffffffffffffffff811161027657826132269183016106e3565b92608082013567ffffffffffffffff811161027657836132479184016106e3565b9260a08301359260c0810135926106fe60e083013593610120610100850135940161111e565b906101008201906132896132818385612119565b81019061318c565b919061329481610fdd565b806133c457506132a49250612eb5565b6001600160a01b03811630146133be578061333c6132f5613342936001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b9361332c855493600187015461330961040e565b958652602086015261331961041f565b9485526001600160a01b03166020850152565b5f60408401526060810190612119565b91613ef1565b61334c5750600190565b600201546106fe90613374600882901c65ffffffffffff165b9160381c65ffffffffffff1690565b7fffffffffffff000000000000000000000000000000000000000000000000000079ffffffffffff00000000000000000000000000000000000000009160d01b169160a01b161790565b50505f90565b9050600191506133d381610fdd565b146133e0575b5050600190565b6133ed6133f59183612119565b8101906131c3565b979998509061340c6130318b9794979695966118c6565b6134f85761342a95610c83958b958a519560208c019a8b5198612e7a565b6134ef57610a6b613081613457935192516040519283916020830195869091604092825260208201520190565b906002825492600181015461346a61040e565b948552602085015261347a61041f565b9384525f602085015260016040850152019161349b835460ff9060981c1690565b6134e75761333c8260606134b0940190612119565b156133d9576134d16134c46106fe936118c6565b600160ff19825416179055565b54613374600882901c65ffffffffffff16613365565b505050505f90565b50505050600190565b50505050505050505050600190565b7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f369541461353057565b7f42a22abd000000000000000000000000000000000000000000000000000000005f5260045ffd5b30331480156135c7575b1561356957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6e6f742066726f6d2073656c66206f7220456e747279506f696e7400000000006044820152fd5b50734337084d9e255ff0702461cf8895ce9e3b5ff1083314613562565b8054905f8155816135f3575050565b5f52600760205f20910160031c8101905b81811061360f575050565b5f8155600101613604565b600281019081549060ff82161561368f5773ffffffffffffffffffffffffffffffffffffffff199182169092555f6007830155600882018054909116905561041d906006905f60058201556136896004820173ffffffffffffffffffffffffffffffffffffffff198154169055565b016135e4565b7fc5b98844000000000000000000000000000000000000000000000000000000005f5260045ffd5b925f939184939260208451940192f190565b3d604051906020818301016040528082525f602083013e90565b6136eb6136c9565b602081519101fd5b60027f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36854146137425760027f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90925f938493604051828152604060208201527f47d99ad340f52da66535aff7e10da1ceb85a32bcbd9fa1c42314d194545e14d26001600160a01b03861691806137b8604082018887612e40565b0390a2826040519384928337810185815203925af16137d5612181565b90156136eb5750565b92909391936040519384526020840152836040840152606083015260808201525f805260205f60a0836101005afa503d15613841575b507f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a85f5160011491111090565b60209060a03d916dd01ea45f9efd5c54f037fa57ea1a5afa503d15613866575f613814565b63d0d5039b3d526004601cfd5b60405190613880826103cf565b5f60a08360608152606060208201528260408201528260608201528260808201520152565b90949392916138b45f92614074565b9560208201519081519060408401516060850151908a51918b600d84017f226368616c6c656e6765223a220000000000000000000000000000000000000060981c82528388019060208160138a600d898b0101106022602d8b880101515f1a141695012092012014169185826014011090821760801c109060207f2274797065223a22776562617574686e2e67657422000000000000000000000060581c918801015160581c1416169952835198895191151560021b6001178060218c0151161490602083111616988993846139b4575b50505050613994575b50505050565b6139aa94955060a06080820151910151916137de565b905f80808061398e565b60208080959850846001959750840101809882808084519a019601940160025afa831b5afa5192523d156139ec57855f808080613985565bfe5b6139fb91612ec291613d85565b6001600160a01b0316301490565b356106fe81610264565b9190918054831015610f82575f52601c60205f208360031c019260021b1690565b8054680100000000000000008110156103ae57613a5691600182018155613a13565b63ffffffff829392549160031b9260e01c831b921b1916179055565b99939065ffffffffffff9293613a9a613b29929b999b8d906020600191803584550135910155565b613aeb60028d0195613ab387600160ff19825416179055565b86547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ff1660089190911b66ffffffffffff0016178655565b84547fffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffff1660389190911b6cffffffffffff0000000000000016178455565b825472ffffffffffff000000000000000000000000001916606882901b72ffffffffffff000000000000000000000000001617835582547fffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff16911615609881901b73ff000000000000000000000000000000000000001691909117825560088901805473ffffffffffffffffffffffffffffffffffffffff19163017905515613bd7575b5050505050505050565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1683151560a01b74ff0000000000000000000000000000000000000000161790556007870155613c8e575b5050506001600160a01b03613c398261210f565b1615611b5557602081613c7c613c5060059461210f565b60048601906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b01359101555f80808080808080613bcd565b6001600160a01b03811615611b55576134c4613ce491613cc66134c4600389019283906001600160a01b03165f5260205260405f2090565b613ccf8661210f565b6001600160a01b03165f5260205260405f2090565b600a8111613d1e575f5b81811015613c255780613d18613d0f613d0a60019486886121b0565b613a09565b60068801613a34565b01613cee565b7f3c147f37000000000000000000000000000000000000000000000000000000005f5260045ffd5b91906040519260205f5b8083015182828801015201908483831015613d6f575090602090613d50565b915050604091808252015f602082015201604052565b8151919060418303613db557613dae9250602082015190606060408401519301515f1a9061417d565b9192909190565b50505f9160029190565b60041115610fe757565b613dd281613dbf565b80613ddb575050565b613de481613dbf565b60018103613e14577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b613e1d81613dbf565b60028103613e5157507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b80613e5d600392613dbf565b14613e655750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906004116102765790600490565b909291928360041161027657831161027657600401916003190190565b919091356001600160e01b031981169260048110613ed7575050565b6001600160e01b0319929350829060040360031b1b161690565b9190916040810160018151613f0581610fdd565b613f0e81610fdd565b0361400a575051805160209182015160408051938401928352830152613f3b916130818160608101610a6b565b915b6002830154600881901c65ffffffffffff1615908115613ffe575b50613ff7576008830154306001600160a01b0390911603613ff7576001600160e01b0319613f8f613f898484613e90565b90613ebb565b167fb61d27f6000000000000000000000000000000000000000000000000000000008114613fed577f47e1da2a0000000000000000000000000000000000000000000000000000000014613fe4575050505f90565b6106fe9261454d565b506106fe92614267565b5050505f90565b60ff161590505f613f58565b5161401481610fdd565b61401d81610fdd565b613ff757602001516001600160a01b03168015613ff75761406e906001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b91613f3d565b80516060929181614083575050565b9092506003600284010460021b604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f603f52602085019282860191602083019460208284010190600460038351955f85525b0191603f8351818160121c16515f538181600c1c1651600153818160061c165160025316516003535f51815201908782101561413d576004906003906140fc565b5095505f936003936040925201604052066002048093037f3d3d000000000000000000000000000000000000000000000000000000000000815252038252565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116141f4579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15611c2c575f516001600160a01b038116156141ea57905f905f90565b505f906001905f90565b5050505f9160039190565b91606083830312610276578235614215816105ce565b92602081013592604082013567ffffffffffffffff8111610276576106fe92016106e3565b90602082519201516001600160e01b031981169260048110613ed7575050565b9190820391821161268a57565b9161427e81614286926001600160a01b0394613e9e565b8101906141ff565b92909116913083146134e757600284019182546142a78160ff9060981c1690565b6143ec5760681c65ffffffffffff169065ffffffffffff8216156143e2576007860191818354106143d7576142ea610c836142e18661423a565b60068a01614778565b6143d757614335905f190165ffffffffffff16855472ffffffffffff00000000000000000000000000191660689190911b72ffffffffffff0000000000000000000000000016178555565b806143c3575b50508261435561202060048701546001600160a01b031690565b146143ac575b505461436b9060a01c60ff161590565b918215614382575b505061437d575f90565b600190565b6143a592509060036130319201906001600160a01b03165f5260205260405f2090565b5f80614373565b610c836143b991856147bb565b613ff7575f61435b565b6143ce90825461425a565b90555f8061433b565b505050505050505f90565b5050505050505f90565b505050505050600190565b9080601f8301121561027657813561440e8161179c565b9261441c60405194856103eb565b81845260208085019260051b820101918383116102765760208201905b83821061444857505050505090565b813567ffffffffffffffff81116102765760209161446b878480948801016106e3565b815201910190614439565b9160608383031261027657823567ffffffffffffffff811161027657830182601f82011215610276578035906144ab8261179c565b916144b960405193846103eb565b80835260208084019160051b8301019185831161027657602001905b82821061451f5750505092602081013567ffffffffffffffff811161027657836145009183016117b4565b92604082013567ffffffffffffffff8111610276576106fe92016143f7565b60208091833561452e816105ce565b8152019101906144d5565b8051821015610f825760209160051b010190565b918061455c9161456493613e9e565b810190614476565b92908251936009851161476f5760028301908154614589610c838260ff9060981c1690565b6146fa575b505f5b8681106145a45750505050505050600190565b306145b5612020610b54848a614539565b146143d75782546145ca9060981c60ff161590565b6145d7575b600101614591565b6145f9610c836145f06145ea8486614539565b5161423a565b60068801614778565b6143d75760078501805461460d8387614539565b5181106146ed5761461e8387614539565b516146cf575b505060048501546001600160a01b03166001600160a01b0361464c612020610b54858b614539565b9116146146a8575b825460a01c60ff1680614672575b156145cf57505050505050505f90565b506146a3610c83613031614689610b54858b614539565b60038901906001600160a01b03165f5260205260405f2090565b614662565b6146bf610c836146b88385614539565b51876147bb565b1561465457505050505050505f90565b6146e4906146dd8488614539565b519061425a565b90555f80614624565b5050505050505050505f90565b60681c65ffffffffffff168665ffffffffffff8216106143d75761473161476991614724896147f9565b65ffffffffffff91031690565b835472ffffffffffff00000000000000000000000000191660689190911b72ffffffffffff0000000000000000000000000016178355565b5f61458e565b50505050505f90565b905f5b8254811015613ff75761478e8184613a13565b90549060031b1c60e01b6001600160e01b03198084169116146147b35760010161477b565b505050600190565b90805180601f1981011161268a5760059101519101805491828111613ff757806147e757505050600190565b820391821161268a57555f80806147b3565b65ffffffffffff81116148115765ffffffffffff1690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52603060045260245260445ffdfea26469706673582212202ed48e20985b1a043e9d3f207cd8c1690cf99301b78ad59f31b7230d3252bb1664736f6c634300081d0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a000000000000000000000000004337084d9e255ff0702461cf8895ce9e3b5ff108
Deployed Bytecode
0x60806040526004361015610010575b005b5f3560e01c806301ffc9a71461025f5780630c3b1ae91461025a578063110891c114610255578063150b7a02146102505780631626ba7e1461024b57806317f976721461024657806318f991021461024157806319822f7c1461023c57806325c1c3c31461023757806334fcd5be146102325780633f707e6b1461022d57806347e1da2a146102285780634e6fd6c4146102235780635a880de31461021e57806369d3c8651461021957806394c11608146102145780639c241abd1461020f578063a04b3e161461020a578063a2e8cf4014610205578063a7dc0fe614610200578063af640d0f146101fb578063affed0e0146101f6578063b0d691fe146101f1578063b2aa3f13146101ec578063b3ee7f11146101e7578063b61d27f6146101e2578063b75c8b78146101dd578063bc197c81146101d8578063bed5df4a146101d3578063c77d7805146101ce578063ce9124f3146101c9578063d087d288146101c4578063d180b1fc146101bf578063d86c2585146101ba578063eaf0188f146101b5578063f23a6e61146101b05763f4d2a1940361000e57611ea6565b611e34565b611d93565b611d42565b611c31565b611b7d565b6119ba565b61194d565b611904565b611811565b6116fe565b61166c565b61159d565b61145d565b6113cc565b611390565b611354565b6112cd565b611299565b611229565b61117c565b611099565b611054565b610ff9565b610f9b565b610e68565b610cdf565b610c20565b6109dd565b6108df565b610808565b6107c5565b610773565b610701565b6105df565b61050c565b61027a565b6001600160e01b031981160361027657565b5f80fd5b34610276576020600319360112610276576001600160e01b03196004356102a081610264565b167f01ffc9a7000000000000000000000000000000000000000000000000000000008114908115610354575b8115610343575b8115610319575b81156102ef575b506040519015158152602090f35b7f150b7a02000000000000000000000000000000000000000000000000000000009150145f6102e1565b7f4e2312e000000000000000000000000000000000000000000000000000000000811491506102da565b630b135d3f60e11b811491506102d3565b7f19822f7c00000000000000000000000000000000000000000000000000000000811491506102cc565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176103ae57604052565b61037e565b6060810190811067ffffffffffffffff8211176103ae57604052565b60c0810190811067ffffffffffffffff8211176103ae57604052565b90601f601f19910116810190811067ffffffffffffffff8211176103ae57604052565b6040519061041d6040836103eb565b565b6040519061041d6060836103eb565b9060405161043b81610392565b602060018294805484520154910152565b9060405161045981610392565b6020600182946001600160a01b0381541684520154910152565b9a999896949290918b989694926101808a019c6104999160208091805184520151910152565b1515604089015265ffffffffffff16606088015265ffffffffffff16608087015265ffffffffffff1660a0860152151560c0850152151560e084015261010083019080516001600160a01b031682526020015190602001526101408201526101600161041d916001600160a01b03169052565b34610276576020600319360112610276576004355f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f206105538161042e565b6105ca6002830154926105686004820161044c565b90610582600860078301549201546001600160a01b031690565b9160405195869560ff8260a01c169160ff8160981c169165ffffffffffff8260681c169165ffffffffffff8160381c169160ff65ffffffffffff8360081c169216908b610473565b0390f35b6001600160a01b0381160361027657565b34610276576020600319360112610276576004356105fc816105ce565b6001600160a01b03165f9081527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d602052604090206002015465ffffffffffff600882901c81169160ff8116916105ca91603881901c82169160689190911c165b9060405194859485929365ffffffffffff809296958160609560808801991515885216602087015216604085015216910152565b67ffffffffffffffff81116103ae57601f01601f191660200190565b9291926106b982610691565b916106c760405193846103eb565b829481845281830111610276578281602093845f960137010152565b9080601f83011215610276578160206106fe933591016106ad565b90565b346102765760806003193601126102765761071d6004356105ce565b6107286024356105ce565b60643567ffffffffffffffff8111610276576107489036906004016106e3565b5060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b346102765760406003193601126102765760043560243567ffffffffffffffff8111610276576020916107ad6107b39236906004016106e3565b90611f09565b6001600160e01b031960405191168152f35b34610276575f6003193601126102765760206040516001600160a01b037f000000000000000000000000bc8c14d7f4640f52f3a1ccec27164340215da74c168152f35b34610276576020600319360112610276576001600160a01b0360043561082d816105ce565b165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f206108618161042e565b906105ca6002820154916108798360ff9060a01c1690565b906108866004820161044c565b61089f600860078401549301546001600160a01b031690565b92604051968660ff899860981c169165ffffffffffff8260681c169165ffffffffffff8160381c169160ff65ffffffffffff8360081c169216908b610473565b346102765760606003193601126102765760043567ffffffffffffffff81116102765761012060031982360301126102765760243590604435734337084d9e255ff0702461cf8895ce9e3b5ff108330361097f5761095060246109486105ca958560040161326d565b930135613507565b80610967575b506040519081529081906020820190565b5f80808093335af150610978612181565b505f610956565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e74000000006044820152fd5b34610276575f600319360112610276576109f5613558565b5f5b7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a5481101561000e5780610a2c6001926121c0565b60408101838151610a3c81610fdd565b610a4581610fdd565b03610ae057505180516020918201516040805193840192835283015290610a7981606081015b03601f1981018352826103eb565b519020610ab5610ab0825f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b61361a565b7fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a25b016109f7565b51610aea81610fdd565b610af381610fdd565b15610aff575b50610ada565b60200180516001600160a01b0316908115610bb957610b54610ab0610b61936001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b516001600160a01b031690565b604051610b8c81610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a25f610af9565b5050610ada565b9181601f840112156102765782359167ffffffffffffffff8311610276576020808501948460051b01011161027657565b6020600319820112610276576004359067ffffffffffffffff821161027657610c1c91600401610bc0565b9091565b3461027657610c2e36610bf1565b610c36613558565b5f5b818110610c4157005b610c87610c83610c7d610c558486886120cf565b610c5e8161210f565b90610c726020820135916040810190612119565b93905a9436916106ad565b916136b7565b1590565b610c9357600101610c38565b600182145f036136e357610ca56136c9565b90610cdb6040519283927f5a1546750000000000000000000000000000000000000000000000000000000084526004840161216a565b0390fd5b610ce836610bf1565b610cf06136f3565b610cf8613558565b80158015610e5e575b610e36575f5b818110610d375761000e60017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855565b610d428183856120cf565b610d4b8161210f565b90610d69610d626020830135926040810190612119565b36916106ad565b906001600160a01b03831692308414610e0e575f80918451908460208701915af1610d92612181565b9015610dd8575060019392917f47d99ad340f52da66535aff7e10da1ceb85a32bcbd9fa1c42314d194545e14d291610dcf6040519283928361216a565b0390a201610d07565b610cdb906040519182917faf05250e0000000000000000000000000000000000000000000000000000000083526004830161116b565b7f793426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1d453126000000000000000000000000000000000000000000000000000000005f5260045ffd5b5060098111610d01565b60606003193601126102765760043567ffffffffffffffff811161027657610e94903690600401610bc0565b9060243567ffffffffffffffff811161027657610eb5903690600401610bc0565b91909260443567ffffffffffffffff811161027657610ed8903690600401610bc0565b919092610ee36136f3565b610eeb613558565b600982118015610f91575b8015610f87575b610e36575f5b828110610f335761000e60017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855565b610f3e8184846121b0565b3590610f49826105ce565b610f5481888a6121b0565b359185821015610f8257600192610f7c91610f748460051b8a018a612119565b92909161376a565b01610f03565b6120bb565b5084821415610efd565b5082821415610ef6565b34610276575f60031936011261027657602060405173deadbeefdeadbeefdeadbeefdeadbeefdeadbeef8152f35b634e487b7160e01b5f52602160045260245ffd5b60021115610fe757565b610fc9565b906002821015610fe75752565b346102765760206003193601126102765760806110176004356121c0565b611052604080519261103484825160208091805184520151910152565b6001600160a01b036020820151168285015201516060830190610fec565bf35b346102765760206003193601126102765760606001600160a01b0361107a600435612258565b91929061108a6040518095610fec565b16602083015215156040820152f35b34610276575f600319360112610276576020604051600a8152f35b8015150361027657565b6024359061041d826110b4565b359061041d826110b4565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc6040910112610276576040519061110d82610392565b610104358252610124356020830152565b91908260409103126102765760405161113681610392565b6020808294803584520135910152565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9060206106fe928181520190611146565b34610276576101406003193601126102765760043567ffffffffffffffff8111610276576111ae9036906004016106e3565b6111b66110be565b60443567ffffffffffffffff8111610276576111d69036906004016106e3565b916064359167ffffffffffffffff8311610276576105ca936111ff61121d9436906004016106e3565b60843560a4359160c4359360e43595611217366110d6565b976123ad565b6040519182918261116b565b34610276576020600319360112610276576004355f9081527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c602052604090206002015465ffffffffffff600882901c81169160ff8116916105ca91603881901c82169160689190911c1661065d565b346102765760a06003193601126102765760206112c36084356064356044356024356004356137de565b6040519015158152f35b34610276576020600319360112610276576004355f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b602052608060405f20611052600261131b8361042e565b920154611335604051809460208091805184520151910152565b6001600160a01b038116604084015260ff606084019160a01c16610fec565b34610276575f6003193601126102765760207f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a54604051908152f35b34610276575f6003193601126102765760207f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36954604051908152f35b34610276575f600319360112610276576020604051734337084d9e255ff0702461cf8895ce9e3b5ff1088152f35b60a06003198201126102765760043567ffffffffffffffff81116102765781611425916004016106e3565b91602435611432816110b4565b916044359067ffffffffffffffff821161027657611452916004016106e3565b906064359060843590565b34610276576105ca6114ba611471366113fa565b9361147d939193613873565b92805160c08110906020860190604087016060880190608089019260a08a019660208082019282010196156114cc575b50505050505050506138a5565b60405190151581529081906020820190565b81510194602086019182108760e08801111761154f5785825101602081019787604081015101602081019480861083871117908b10838c1117176115545760208281808094895101010111938b51010101111761154f5760c0968b5252606084015190526080830151905260a08201519052015190525f808080808080806114ad565b6114ad565b5050506114ad565b600319608091011261027657600490565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc60409101126102765761012490565b3461027657610160600319360112610276576115b83661155c565b60407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c3601126102765760c43567ffffffffffffffff811161027657611602903690600401610bc0565b6101043592919060e43567ffffffffffffffff85116102765761162c61000e9536906004016106e3565b91610124359360846101443596612443565b9181601f840112156102765782359167ffffffffffffffff8311610276576020838186019501011161027657565b606060031936011261027657600435611684816105ce565b6024356044359167ffffffffffffffff8311610276576116ab6116c393369060040161163e565b9290916116b66136f3565b6116be613558565b61376a565b60017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855005b60c4359065ffffffffffff8216820361027657565b34610276576101a0600319360112610276576117193661155c565b6084359065ffffffffffff821682036102765760a43565ffffffffffff81168103610276576117466116e9565b9260e435611753816110b4565b61010435611760816105ce565b6117693661156d565b91610164359667ffffffffffffffff88116102765761178f61000e983690600401610bc0565b9690956101843598612c00565b67ffffffffffffffff81116103ae5760051b60200190565b9080601f830112156102765781356117cb8161179c565b926117d960405194856103eb565b81845260208085019260051b82010192831161027657602001905b8282106118015750505090565b81358152602091820191016117f4565b346102765760a06003193601126102765761182d6004356105ce565b6118386024356105ce565b60443567ffffffffffffffff8111610276576118589036906004016117b4565b5060643567ffffffffffffffff8111610276576118799036906004016117b4565b5060843567ffffffffffffffff81116102765761189a9036906004016106e3565b506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b60208091604051928184925191829101835e81017f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36e81520301902090565b346102765760206003193601126102765760043567ffffffffffffffff81116102765760ff61194161193c60209336906004016106e3565b6118c6565b54166040519015158152f35b346102765760206003193601126102765760043567ffffffffffffffff8111610276576119a66119846105ca92369060040161163e565b610a6b6040939293519384925f60208501526040808501526060840191612e40565b604051918291602083526020830190611146565b34610276576080600319360112610276576119d43661155c565b6119dc613558565b6060810160016119eb8261284c565b6119f481610fdd565b03611a805750610a6b611a23602083359301356040519283916020830195869091604092825260208201520190565b519020611a5a610ab0825f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b7fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a2005b611a899061284c565b611a9281610fdd565b15611a9957005b6040016001600160a01b03611aad8261210f565b1615611b555780611afc610ab0611ac6611b019461210f565b6001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b61210f565b604051611b2c81610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fa6293d3e6a2b62cf1a2218754c516fcf944f744d8794bb85842d57f0b1aa38a75f80a2005b7faa093569000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610276575f600319360112610276576040517f35567e1a0000000000000000000000000000000000000000000000000000000081523060048201525f6024820152602081604481734337084d9e255ff0702461cf8895ce9e3b5ff1085afa8015611c2c576105ca915f91611bfd57506040519081529081906020820190565b611c1f915060203d602011611c25575b611c1781836103eb565b810190612e60565b5f610956565b503d611c0d565b612e6f565b34610276576105ca6114ba611c45366113fa565b93611c51939193613873565b9280516046811015611c65575b50506138a5565b810190602081015160f01c908181019160228301907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc85019384831115611cb0575b50505050611c5e565b611ce17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffba926022611cec9601613d46565b895285030190613d46565b60208601525160f01c60408501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde81015160f01c6060850152601f1981015160808501525160a08401525f8080808080611ca7565b34610276576020600319360112610276576004355f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c602052602060ff600260405f200154166040519015158152f35b34610276576101406003193601126102765760043567ffffffffffffffff811161027657611dc59036906004016106e3565b611dcd6110be565b60443567ffffffffffffffff811161027657611ded9036906004016106e3565b916064359167ffffffffffffffff8311610276576105ca93611e166114ba9436906004016106e3565b60843560a4359060c4359260e4359461010435966101243598612e7a565b346102765760a060031936011261027657611e506004356105ce565b611e5b6024356105ce565b60843567ffffffffffffffff811161027657611e7b9036906004016106e3565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b34610276576020600319360112610276576001600160a01b03600435611ecb816105ce565b165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d602052602060ff600260405f200154166040519015158152f35b7f25622562256225622562256225622562256225622562256225622562256225628114806120b0575b15611f5b57506001602082015114611f5257505b6001600160e01b031990565b6106fe90612ff7565b908051604081149081156120a5575b50611f76575050611f46565b611f7f91612eb5565b6001600160a01b038116301461209957611fc9906001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b6002810154600881901c65ffffffffffff16801591908215612083575b8215612079575b508115612048575b501561200857506001600160e01b031990565b61202c6120206008309301546001600160a01b031690565b6001600160a01b031690565b1461203d576001600160e01b031990565b630b135d3f60e11b90565b609881901c60ff1615915081612060575b505f611ff5565b6001915065ffffffffffff9060681c811616105f612059565b421191505f611fed565b4265ffffffffffff603884901c16119250611fe6565b50630b135d3f60e11b90565b60419150145f611f6a565b506041825111611f32565b634e487b7160e01b5f52603260045260245ffd5b9190811015610f825760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa181360301821215610276570190565b356106fe816105ce565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610276570180359067ffffffffffffffff82116102765760200191813603831361027657565b6040906106fe939281528160208201520190611146565b3d156121ab573d9061219282610691565b916121a060405193846103eb565b82523d5f602084013e565b606090565b9190811015610f825760051b0190565b5f604080516121ce816103b3565b81516121d981610392565b838152836020820152815282602082015201525f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b60205260405f2060ff600260405192612227846103b3565b6122308161042e565b845201546001600160a01b038116602084015260a01c166002811015610fe757604082015290565b612261906121c0565b9060408201916001835161227481610fdd565b61227d81610fdd565b0361233d5751805160209182015160408051938401928352830152906122a68160608101610a6b565b5190209151906122b582610fdd565b612337600261232f61230160086122f3885f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b01546001600160a01b031690565b955f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b015460ff1690565b91929190565b8291925161234a81610fdd565b61235381610fdd565b1561236a57505161236381610fdd565b905f905f90565b90602090519161237983610fdd565b0191612337600261232f611ac661239f60086122f3611ac68a516001600160a01b031690565b96516001600160a01b031690565b979294612416610a6b959661240461018099946106fe9b966123eb6040519e8f9d8e6123dc6020820160019052565b61016060408201520190611146565b91151560608d0152601f198c83030160808d0152611146565b90601f198a83030160a08b0152611146565b60c088019690965260e0870152610100860152610120850152805161014085015260200151610160840152565b95939196949290967ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549767ffffffffffffffff61249861248a60ff8c60401c1615151590565b9a67ffffffffffffffff1690565b168015908161265f575b6001149081612655575b15908161264c575b5061262457612535978961252c60017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000007ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b6125bf576126f3565b61253b57565b61259068ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1565b61261f6801000000000000000068ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055565b6126f3565b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b9050155f6124b4565b303b1591506124ac565b8a91506124a2565b634e487b7160e01b5f52601160045260245ffd5b90612710820180921161268a57565b612667565b6002111561027657565b359061041d8261268f565b6080906126ef60606040519280358452602081013560208501526001600160a01b0360408201356126d4816105ce565b16604085015201356126e58161268f565b6060830190610fec565b2090565b9596949192939096612703613558565b60025b600681106127f6575061271886613507565b42116127ce5761272b91610c83916139ee565b6127a6576127809461275e61277b947f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36955565b61277561276a4261267b565b65ffffffffffff1690565b8561290d565b6126a4565b7f9be0ddb3ac5d6261cc8d736bf39c29feb13498533b6c9f960d8e175bf70e6a1a5f80a2565b7f91cc5825000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f032c52a5000000000000000000000000000000000000000000000000000000005f5260045ffd5b807ff3acd96a9d0e27e4323229f52dd3234ce23fb8133871d002e7cbb32c4a47a5c40190817ff3acd96a9d0e27e4323229f52dd3234ce23fb8133871d002e7cbb32c4a47a5c41161268a575f6001925501612706565b356106fe8161268f565b6002606091833581556020840135600182015501916128a5604082013561287c816105ce565b84906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b01356128b08161268f565b6002811015610fe75781547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1660a09190911b74ff000000000000000000000000000000000000000016179055565b5f19811461268a5760010190565b909193612918613558565b4265ffffffffffff84161115612bd8576129838261297e7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a545f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b60205260405f2090565b612856565b6129d46129b07f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a546128ff565b7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a55565b6060820160016129e38261284c565b6129ec81610fdd565b03612afe57509091928235610a6b612a1e60208601356040519283916020830195869091604092825260208201520190565b51902094612a58600261232f885f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b612ad65773deadbeefdeadbeefdeadbeefdeadbeefdeadbeef5f8080612ab0988198612aab8c5f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b613a72565b7fcd7f4163a8248a579c58031f40b757bb4998ed5f01c78bfb6ae1cd42edb95fb05f80a2565b7f2eb93649000000000000000000000000000000000000000000000000000000005f5260045ffd5b612b079061284c565b612b1081610fdd565b15612b1d575b5050505050565b60408201936001600160a01b03612b338661210f565b1615611b5557612b4a600261232f611ac68861210f565b612ad657612b7c9573deadbeefdeadbeefdeadbeefdeadbeefdeadbeef5f8080611afc988198612aab611ac68d61210f565b604051612ba781610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fcd7f4163a8248a579c58031f40b757bb4998ed5f01c78bfb6ae1cd42edb95fb05f80a25f80808080612b16565b7ff5bab791000000000000000000000000000000000000000000000000000000005f5260045ffd5b96939098959297949197612c12613558565b65ffffffffffff8a1642811115612bd85765ffffffffffff8a1611612bd857612c878861297e7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a545f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36b60205260405f2090565b612cb46129b07f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36a546128ff565b606088016001612cc38261284c565b612ccc81610fdd565b03612d76575090919293949596978835610a6b612d0360208c01356040519283916020830195869091604092825260208201520190565b51902099612d3d600261232f8d5f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b612ad657612ab099612aab8c5f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b612d7f9061284c565b612d8881610fdd565b15612d9a575b50505050505050505050565b60408801986001600160a01b03612db08b61210f565b1615611b5557612dc7600261232f611ac68d61210f565b612ad657612ddf9a611afc99612aab611ac68d61210f565b604051612e0a81610a6b6020820194856bffffffffffffffffffffffff1960149260601b1681520190565b5190207fcd7f4163a8248a579c58031f40b757bb4998ed5f01c78bfb6ae1cd42edb95fb05f80a25f808080808080808080612d8e565b601f8260209493601f1993818652868601375f8582860101520116010190565b90816020910312610276575190565b6040513d5f823e3d90fd5b936106fe9998979396929695919560405197612e95896103cf565b8852602088015260408701526060860152608085015260a08401526138a5565b6106fe91612ec291613d85565b90929192613dc9565b519061041d8261268f565b81601f8201121561027657602081519101612ef082610691565b92612efe60405194856103eb565b8284528282011161027657815f926020928386015e8301015290565b519061041d826110b4565b919082604091031261027657604051612f3d81610392565b6020808294805184520151910152565b6101608183031261027657612f6181612ecb565b92602082015167ffffffffffffffff81116102765783612f82918401612ed6565b92612f8f60408401612f1a565b92606081015167ffffffffffffffff81116102765782612fb0918301612ed6565b92608082015167ffffffffffffffff81116102765783612fd1918401612ed6565b9260a08301519260c0810151926106fe60e0830151936101206101008501519401612f25565b61300c60019160208082518301019101612f4d565b999093979594969861302081949394610fdd565b0361317757613038613031866118c6565b5460ff1690565b6131775761305496610c83968a519560208c019a8b5198612e7a565b61316957610a6b6130816130b1935192516040519283916020830195869091604092825260208201520190565b5190205f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36c60205260405f2090565b6002810154600881901c65ffffffffffff16801591908215613153575b8215613149575b508115613118575b50156130f057506001600160e01b031990565b600801546001600160a01b03166001600160a01b0316301461203d576001600160e01b031990565b609881901c60ff1615915081613130575b505f6130dd565b6001915065ffffffffffff9060681c811616105f613129565b421191505f6130d5565b4265ffffffffffff603884901c161192506130ce565b50506001600160e01b031990565b5050505050505050506001600160e01b031990565b9190916040818403126102765780356131a48161268f565b92602082013567ffffffffffffffff8111610276576106fe92016106e3565b61016081830312610276576131d781612699565b92602082013567ffffffffffffffff811161027657836131f89184016106e3565b92613205604084016110cb565b92606081013567ffffffffffffffff811161027657826132269183016106e3565b92608082013567ffffffffffffffff811161027657836132479184016106e3565b9260a08301359260c0810135926106fe60e083013593610120610100850135940161111e565b906101008201906132896132818385612119565b81019061318c565b919061329481610fdd565b806133c457506132a49250612eb5565b6001600160a01b03811630146133be578061333c6132f5613342936001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b9361332c855493600187015461330961040e565b958652602086015261331961041f565b9485526001600160a01b03166020850152565b5f60408401526060810190612119565b91613ef1565b61334c5750600190565b600201546106fe90613374600882901c65ffffffffffff165b9160381c65ffffffffffff1690565b7fffffffffffff000000000000000000000000000000000000000000000000000079ffffffffffff00000000000000000000000000000000000000009160d01b169160a01b161790565b50505f90565b9050600191506133d381610fdd565b146133e0575b5050600190565b6133ed6133f59183612119565b8101906131c3565b979998509061340c6130318b9794979695966118c6565b6134f85761342a95610c83958b958a519560208c019a8b5198612e7a565b6134ef57610a6b613081613457935192516040519283916020830195869091604092825260208201520190565b906002825492600181015461346a61040e565b948552602085015261347a61041f565b9384525f602085015260016040850152019161349b835460ff9060981c1690565b6134e75761333c8260606134b0940190612119565b156133d9576134d16134c46106fe936118c6565b600160ff19825416179055565b54613374600882901c65ffffffffffff16613365565b505050505f90565b50505050600190565b50505050505050505050600190565b7f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f369541461353057565b7f42a22abd000000000000000000000000000000000000000000000000000000005f5260045ffd5b30331480156135c7575b1561356957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6e6f742066726f6d2073656c66206f7220456e747279506f696e7400000000006044820152fd5b50734337084d9e255ff0702461cf8895ce9e3b5ff1083314613562565b8054905f8155816135f3575050565b5f52600760205f20910160031c8101905b81811061360f575050565b5f8155600101613604565b600281019081549060ff82161561368f5773ffffffffffffffffffffffffffffffffffffffff199182169092555f6007830155600882018054909116905561041d906006905f60058201556136896004820173ffffffffffffffffffffffffffffffffffffffff198154169055565b016135e4565b7fc5b98844000000000000000000000000000000000000000000000000000000005f5260045ffd5b925f939184939260208451940192f190565b3d604051906020818301016040528082525f602083013e90565b6136eb6136c9565b602081519101fd5b60027f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36854146137425760027f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36855565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90925f938493604051828152604060208201527f47d99ad340f52da66535aff7e10da1ceb85a32bcbd9fa1c42314d194545e14d26001600160a01b03861691806137b8604082018887612e40565b0390a2826040519384928337810185815203925af16137d5612181565b90156136eb5750565b92909391936040519384526020840152836040840152606083015260808201525f805260205f60a0836101005afa503d15613841575b507f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a85f5160011491111090565b60209060a03d916dd01ea45f9efd5c54f037fa57ea1a5afa503d15613866575f613814565b63d0d5039b3d526004601cfd5b60405190613880826103cf565b5f60a08360608152606060208201528260408201528260608201528260808201520152565b90949392916138b45f92614074565b9560208201519081519060408401516060850151908a51918b600d84017f226368616c6c656e6765223a220000000000000000000000000000000000000060981c82528388019060208160138a600d898b0101106022602d8b880101515f1a141695012092012014169185826014011090821760801c109060207f2274797065223a22776562617574686e2e67657422000000000000000000000060581c918801015160581c1416169952835198895191151560021b6001178060218c0151161490602083111616988993846139b4575b50505050613994575b50505050565b6139aa94955060a06080820151910151916137de565b905f80808061398e565b60208080959850846001959750840101809882808084519a019601940160025afa831b5afa5192523d156139ec57855f808080613985565bfe5b6139fb91612ec291613d85565b6001600160a01b0316301490565b356106fe81610264565b9190918054831015610f82575f52601c60205f208360031c019260021b1690565b8054680100000000000000008110156103ae57613a5691600182018155613a13565b63ffffffff829392549160031b9260e01c831b921b1916179055565b99939065ffffffffffff9293613a9a613b29929b999b8d906020600191803584550135910155565b613aeb60028d0195613ab387600160ff19825416179055565b86547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ff1660089190911b66ffffffffffff0016178655565b84547fffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffff1660389190911b6cffffffffffff0000000000000016178455565b825472ffffffffffff000000000000000000000000001916606882901b72ffffffffffff000000000000000000000000001617835582547fffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff16911615609881901b73ff000000000000000000000000000000000000001691909117825560088901805473ffffffffffffffffffffffffffffffffffffffff19163017905515613bd7575b5050505050505050565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1683151560a01b74ff0000000000000000000000000000000000000000161790556007870155613c8e575b5050506001600160a01b03613c398261210f565b1615611b5557602081613c7c613c5060059461210f565b60048601906001600160a01b031673ffffffffffffffffffffffffffffffffffffffff19825416179055565b01359101555f80808080808080613bcd565b6001600160a01b03811615611b55576134c4613ce491613cc66134c4600389019283906001600160a01b03165f5260205260405f2090565b613ccf8661210f565b6001600160a01b03165f5260205260405f2090565b600a8111613d1e575f5b81811015613c255780613d18613d0f613d0a60019486886121b0565b613a09565b60068801613a34565b01613cee565b7f3c147f37000000000000000000000000000000000000000000000000000000005f5260045ffd5b91906040519260205f5b8083015182828801015201908483831015613d6f575090602090613d50565b915050604091808252015f602082015201604052565b8151919060418303613db557613dae9250602082015190606060408401519301515f1a9061417d565b9192909190565b50505f9160029190565b60041115610fe757565b613dd281613dbf565b80613ddb575050565b613de481613dbf565b60018103613e14577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b613e1d81613dbf565b60028103613e5157507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b80613e5d600392613dbf565b14613e655750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906004116102765790600490565b909291928360041161027657831161027657600401916003190190565b919091356001600160e01b031981169260048110613ed7575050565b6001600160e01b0319929350829060040360031b1b161690565b9190916040810160018151613f0581610fdd565b613f0e81610fdd565b0361400a575051805160209182015160408051938401928352830152613f3b916130818160608101610a6b565b915b6002830154600881901c65ffffffffffff1615908115613ffe575b50613ff7576008830154306001600160a01b0390911603613ff7576001600160e01b0319613f8f613f898484613e90565b90613ebb565b167fb61d27f6000000000000000000000000000000000000000000000000000000008114613fed577f47e1da2a0000000000000000000000000000000000000000000000000000000014613fe4575050505f90565b6106fe9261454d565b506106fe92614267565b5050505f90565b60ff161590505f613f58565b5161401481610fdd565b61401d81610fdd565b613ff757602001516001600160a01b03168015613ff75761406e906001600160a01b03165f527f801ae8efc2175d3d963e799b27e0e948b9a3fa84e2ce105a370245c8c127f36d60205260405f2090565b91613f3d565b80516060929181614083575050565b9092506003600284010460021b604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f603f52602085019282860191602083019460208284010190600460038351955f85525b0191603f8351818160121c16515f538181600c1c1651600153818160061c165160025316516003535f51815201908782101561413d576004906003906140fc565b5095505f936003936040925201604052066002048093037f3d3d000000000000000000000000000000000000000000000000000000000000815252038252565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116141f4579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15611c2c575f516001600160a01b038116156141ea57905f905f90565b505f906001905f90565b5050505f9160039190565b91606083830312610276578235614215816105ce565b92602081013592604082013567ffffffffffffffff8111610276576106fe92016106e3565b90602082519201516001600160e01b031981169260048110613ed7575050565b9190820391821161268a57565b9161427e81614286926001600160a01b0394613e9e565b8101906141ff565b92909116913083146134e757600284019182546142a78160ff9060981c1690565b6143ec5760681c65ffffffffffff169065ffffffffffff8216156143e2576007860191818354106143d7576142ea610c836142e18661423a565b60068a01614778565b6143d757614335905f190165ffffffffffff16855472ffffffffffff00000000000000000000000000191660689190911b72ffffffffffff0000000000000000000000000016178555565b806143c3575b50508261435561202060048701546001600160a01b031690565b146143ac575b505461436b9060a01c60ff161590565b918215614382575b505061437d575f90565b600190565b6143a592509060036130319201906001600160a01b03165f5260205260405f2090565b5f80614373565b610c836143b991856147bb565b613ff7575f61435b565b6143ce90825461425a565b90555f8061433b565b505050505050505f90565b5050505050505f90565b505050505050600190565b9080601f8301121561027657813561440e8161179c565b9261441c60405194856103eb565b81845260208085019260051b820101918383116102765760208201905b83821061444857505050505090565b813567ffffffffffffffff81116102765760209161446b878480948801016106e3565b815201910190614439565b9160608383031261027657823567ffffffffffffffff811161027657830182601f82011215610276578035906144ab8261179c565b916144b960405193846103eb565b80835260208084019160051b8301019185831161027657602001905b82821061451f5750505092602081013567ffffffffffffffff811161027657836145009183016117b4565b92604082013567ffffffffffffffff8111610276576106fe92016143f7565b60208091833561452e816105ce565b8152019101906144d5565b8051821015610f825760209160051b010190565b918061455c9161456493613e9e565b810190614476565b92908251936009851161476f5760028301908154614589610c838260ff9060981c1690565b6146fa575b505f5b8681106145a45750505050505050600190565b306145b5612020610b54848a614539565b146143d75782546145ca9060981c60ff161590565b6145d7575b600101614591565b6145f9610c836145f06145ea8486614539565b5161423a565b60068801614778565b6143d75760078501805461460d8387614539565b5181106146ed5761461e8387614539565b516146cf575b505060048501546001600160a01b03166001600160a01b0361464c612020610b54858b614539565b9116146146a8575b825460a01c60ff1680614672575b156145cf57505050505050505f90565b506146a3610c83613031614689610b54858b614539565b60038901906001600160a01b03165f5260205260405f2090565b614662565b6146bf610c836146b88385614539565b51876147bb565b1561465457505050505050505f90565b6146e4906146dd8488614539565b519061425a565b90555f80614624565b5050505050505050505f90565b60681c65ffffffffffff168665ffffffffffff8216106143d75761473161476991614724896147f9565b65ffffffffffff91031690565b835472ffffffffffff00000000000000000000000000191660689190911b72ffffffffffff0000000000000000000000000016178355565b5f61458e565b50505050505f90565b905f5b8254811015613ff75761478e8184613a13565b90549060031b1c60e01b6001600160e01b03198084169116146147b35760010161477b565b505050600190565b90805180601f1981011161268a5760059101519101805491828111613ff757806147e757505050600190565b820391821161268a57555f80806147b3565b65ffffffffffff81116148115765ffffffffffff1690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52603060045260245260445ffdfea26469706673582212202ed48e20985b1a043e9d3f207cd8c1690cf99301b78ad59f31b7230d3252bb1664736f6c634300081d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004337084d9e255ff0702461cf8895ce9e3b5ff108
-----Decoded View---------------
Arg [0] : _entryPoint (address): 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004337084d9e255ff0702461cf8895ce9e3b5ff108
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.