Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61014034 | 19633973 | 681 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Kernel
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {PackedUserOperation} from "./interfaces/PackedUserOperation.sol";
import {IAccount, ValidationData, ValidAfter, ValidUntil, parseValidationData} from "./interfaces/IAccount.sol";
import {IEntryPoint} from "./interfaces/IEntryPoint.sol";
import {IAccountExecute} from "./interfaces/IAccountExecute.sol";
import {IERC7579Account} from "./interfaces/IERC7579Account.sol";
import {ModuleLib} from "./utils/ModuleLib.sol";
import {
ValidationManager,
ValidationMode,
ValidationId,
ValidatorLib,
ValidationType,
PermissionId,
PassFlag,
SKIP_SIGNATURE
} from "./core/ValidationManager.sol";
import {HookManager} from "./core/HookManager.sol";
import {ExecutorManager} from "./core/ExecutorManager.sol";
import {SelectorManager} from "./core/SelectorManager.sol";
import {IModule, IValidator, IHook, IExecutor, IFallback, IPolicy, ISigner} from "./interfaces/IERC7579Modules.sol";
import {EIP712} from "solady/utils/EIP712.sol";
import {ExecLib, ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload} from "./utils/ExecLib.sol";
import {
CALLTYPE_SINGLE,
CALLTYPE_DELEGATECALL,
ERC1967_IMPLEMENTATION_SLOT,
VALIDATION_TYPE_ROOT,
VALIDATION_TYPE_VALIDATOR,
VALIDATION_TYPE_PERMISSION,
MODULE_TYPE_VALIDATOR,
MODULE_TYPE_EXECUTOR,
MODULE_TYPE_FALLBACK,
MODULE_TYPE_HOOK,
MODULE_TYPE_POLICY,
MODULE_TYPE_SIGNER,
EXECTYPE_TRY,
EXECTYPE_DEFAULT,
EXEC_MODE_DEFAULT,
CALLTYPE_DELEGATECALL,
CALLTYPE_SINGLE,
CALLTYPE_BATCH,
CALLTYPE_STATIC
} from "./types/Constants.sol";
contract Kernel is IAccount, IAccountExecute, IERC7579Account, ValidationManager {
error ExecutionReverted();
error InvalidExecutor();
error InvalidFallback();
error InvalidCallType();
error OnlyExecuteUserOp();
error InvalidModuleType();
error InvalidCaller();
error InvalidSelector();
event Received(address sender, uint256 amount);
event Upgraded(address indexed implementation);
IEntryPoint public immutable entrypoint;
// NOTE : when eip 1153 has been enabled, this can be transient storage
mapping(bytes32 userOpHash => IHook) internal executionHook;
constructor(IEntryPoint _entrypoint) {
entrypoint = _entrypoint;
_validationStorage().rootValidator = ValidationId.wrap(bytes21(abi.encodePacked(hex"deadbeef")));
}
modifier onlyEntryPoint() {
if (msg.sender != address(entrypoint)) {
revert InvalidCaller();
}
_;
}
modifier onlyEntryPointOrSelf() {
if (msg.sender != address(entrypoint) && msg.sender != address(this)) {
revert InvalidCaller();
}
_;
}
modifier onlyEntryPointOrSelfOrRoot() {
IValidator validator = ValidatorLib.getValidator(_validationStorage().rootValidator);
if (
msg.sender != address(entrypoint) && msg.sender != address(this) // do rootValidator hook
) {
if (validator.isModuleType(4)) {
bytes memory ret = IHook(address(validator)).preCheck(msg.sender, msg.value, msg.data);
_;
IHook(address(validator)).postCheck(ret, true, hex""); // TODO don't support try catch hook here
} else {
revert InvalidCaller();
}
} else {
_;
}
}
function initialize(ValidationId _rootValidator, IHook hook, bytes calldata validatorData, bytes calldata hookData)
external
{
ValidationStorage storage vs = _validationStorage();
require(ValidationId.unwrap(vs.rootValidator) == bytes21(0), "already initialized");
if (ValidationId.unwrap(_rootValidator) == bytes21(0)) {
revert InvalidValidator();
}
ValidationType vType = ValidatorLib.getType(_rootValidator);
if (vType != VALIDATION_TYPE_VALIDATOR && vType != VALIDATION_TYPE_PERMISSION) {
revert InvalidValidationType();
}
_setRootValidator(_rootValidator);
ValidationConfig memory config = ValidationConfig({nonce: uint32(1), hook: hook});
vs.currentNonce = 1;
_installValidation(_rootValidator, config, validatorData, hookData);
}
function upgradeTo(address _newImplementation) external payable onlyEntryPointOrSelfOrRoot {
assembly {
sstore(ERC1967_IMPLEMENTATION_SLOT, _newImplementation)
}
emit Upgraded(_newImplementation);
}
function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) {
name = "Kernel";
version = "0.3.0-beta";
}
receive() external payable {
emit Received(msg.sender, msg.value);
}
fallback() external payable {
SelectorConfig memory config = _selectorConfig(msg.sig);
bool success;
bytes memory result;
if (address(config.hook) == address(0)) {
revert InvalidSelector();
} else {
// action installed
bytes memory context;
if (address(config.hook) != address(1)) {
context = _doPreHook(config.hook, msg.value, msg.data);
}
// execute action
if (config.callType == CALLTYPE_SINGLE) {
(success, result) = ExecLib.doFallback2771Call(config.target);
} else if (config.callType == CALLTYPE_DELEGATECALL) {
(success, result) = ExecLib.executeDelegatecall(config.target, msg.data);
} else {
revert NotSupportedCallType();
}
if (address(config.hook) != address(1)) {
_doPostHook(config.hook, context, success, result);
}
}
if (!success) {
assembly {
revert(add(result, 0x20), mload(result))
}
} else {
assembly {
return(add(result, 0x20), mload(result))
}
}
}
// validation part
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
payable
override
onlyEntryPoint
returns (ValidationData validationData)
{
ValidationStorage storage vs = _validationStorage();
// ONLY ENTRYPOINT
// Major change for v2 => v3
// 1. instead of packing 4 bytes prefix to userOp.signature to determine the mode, v3 uses userOp.nonce's first 2 bytes to check the mode
// 2. instead of packing 20 bytes in userOp.signature for enable mode to provide the validator address, v3 uses userOp.nonce[2:22]
// 3. In v2, only 1 plugin validator(aside from root validator) can access the selector.
// In v3, you can use more than 1 plugin to use the exact selector, you need to specify the validator address in userOp.nonce[2:22] to use the validator
(ValidationMode vMode, ValidationType vType, ValidationId vId) = ValidatorLib.decodeNonce(userOp.nonce);
if (vType == VALIDATION_TYPE_ROOT) {
vId = vs.rootValidator;
}
validationData = _doValidation(vMode, vId, userOp, userOpHash);
ValidationConfig memory vc = vs.validationConfig[vId];
// allow when nonce is not revoked or vType is sudo
if (vType != VALIDATION_TYPE_ROOT && vc.nonce < vs.validNonceFrom) {
revert InvalidNonce();
}
IHook execHook = vc.hook;
if (address(execHook) == address(0)) {
revert InvalidValidator();
}
executionHook[userOpHash] = execHook;
if (address(execHook) == address(1)) {
// does not require hook
if (vType != VALIDATION_TYPE_ROOT && !vs.allowedSelectors[vId][bytes4(userOp.callData[0:4])]) {
revert InvalidValidator();
}
} else {
// requires hook
if (vType != VALIDATION_TYPE_ROOT && !vs.allowedSelectors[vId][bytes4(userOp.callData[4:8])]) {
revert InvalidValidator();
}
if (bytes4(userOp.callData[0:4]) != this.executeUserOp.selector) {
revert OnlyExecuteUserOp();
}
}
assembly {
if missingAccountFunds {
pop(call(gas(), caller(), missingAccountFunds, callvalue(), callvalue(), callvalue(), callvalue()))
//ignore failure (its EntryPoint's job to verify, not account.)
}
}
}
// --- Execution ---
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
override
onlyEntryPoint
{
bytes memory context;
IHook hook = executionHook[userOpHash];
if (address(hook) != address(1)) {
// removed 4bytes selector
context = _doPreHook(hook, msg.value, userOp.callData[4:]);
}
(bool success, bytes memory ret) = ExecLib.executeDelegatecall(address(this), userOp.callData[4:]);
if (address(hook) != address(1)) {
_doPostHook(hook, context, success, ret);
} else if (!success) {
revert ExecutionReverted();
}
}
function executeFromExecutor(ExecMode execMode, bytes calldata executionCalldata)
external
payable
returns (bytes[] memory returnData)
{
// no modifier needed, checking if msg.sender is registered executor will replace the modifier
IHook hook = _executorConfig(IExecutor(msg.sender)).hook;
if (address(hook) == address(0)) {
revert InvalidExecutor();
}
bytes memory context;
if (address(hook) != address(1)) {
context = _doPreHook(hook, msg.value, msg.data);
}
returnData = ExecLib.execute(execMode, executionCalldata);
if (address(hook) != address(1)) {
_doPostHook(hook, context, true, abi.encode(returnData));
}
}
function execute(ExecMode execMode, bytes calldata executionCalldata) external payable onlyEntryPointOrSelfOrRoot {
ExecLib.execute(execMode, executionCalldata);
}
function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4) {
ValidationStorage storage vs = _validationStorage();
(ValidationId vId, bytes calldata sig) = ValidatorLib.decodeSignature(signature);
if (ValidatorLib.getType(vId) == VALIDATION_TYPE_ROOT) {
vId = vs.rootValidator;
}
if (address(vs.validationConfig[vId].hook) == address(0)) {
revert InvalidValidator();
}
if (ValidatorLib.getType(vId) == VALIDATION_TYPE_VALIDATOR) {
IValidator validator = ValidatorLib.getValidator(vId);
return validator.isValidSignatureWithSender(msg.sender, _toWrappedHash(hash), sig);
} else {
PermissionId pId = ValidatorLib.getPermissionId(vId);
PassFlag permissionFlag = vs.permissionConfig[pId].permissionFlag;
if (PassFlag.unwrap(permissionFlag) & PassFlag.unwrap(SKIP_SIGNATURE) != 0) {
revert PermissionNotAlllowedForSignature();
}
return _checkPermissionSignature(pId, msg.sender, hash, sig);
}
}
function installModule(uint256 moduleType, address module, bytes calldata initData)
external
payable
override
onlyEntryPointOrSelfOrRoot
{
if (moduleType == MODULE_TYPE_VALIDATOR) {
ValidationStorage storage vs = _validationStorage();
ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(module));
ValidationConfig memory config =
ValidationConfig({nonce: vs.currentNonce, hook: IHook(address(bytes20(initData[0:20])))});
bytes calldata validatorData;
bytes calldata hookData;
assembly {
validatorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 20)))
validatorData.length := calldataload(sub(validatorData.offset, 32))
hookData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 52)))
hookData.length := calldataload(sub(hookData.offset, 32))
}
_installValidation(vId, config, validatorData, hookData);
//_installHook(config.hook, hookData); hook install is handled inside installvalidation
} else if (moduleType == MODULE_TYPE_EXECUTOR) {
bytes calldata executorData;
bytes calldata hookData;
assembly {
executorData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 20)))
executorData.length := calldataload(sub(executorData.offset, 32))
hookData.offset := add(add(initData.offset, 52), calldataload(add(initData.offset, 52)))
hookData.length := calldataload(sub(hookData.offset, 32))
}
IHook hook = IHook(address(bytes20(initData[0:20])));
_installExecutor(IExecutor(module), executorData, hook);
_installHook(hook, hookData);
} else if (moduleType == MODULE_TYPE_FALLBACK) {
bytes calldata selectorData;
bytes calldata hookData;
assembly {
selectorData.offset := add(add(initData.offset, 56), calldataload(add(initData.offset, 24)))
selectorData.length := calldataload(sub(selectorData.offset, 32))
hookData.offset := add(add(initData.offset, 56), calldataload(add(initData.offset, 56)))
hookData.length := calldataload(sub(hookData.offset, 32))
}
_installSelector(bytes4(initData[0:4]), module, IHook(address(bytes20(initData[4:24]))), selectorData);
_installHook(IHook(address(bytes20(initData[4:24]))), hookData);
} else if (moduleType == MODULE_TYPE_HOOK) {
// force call onInstall for hook
// NOTE: for hook, kernel does not support independant hook install,
// hook is expected to be paired with proper validator/executor/selector
IHook(module).onInstall(initData);
} else if (moduleType == MODULE_TYPE_POLICY) {
// force call onInstall for policy
// NOTE: for policy, kernel does not support independant policy install,
// policy is expected to be paired with proper permissionId
// to "ADD" permission, use "installValidations()" function
IPolicy(module).onInstall(initData);
} else if (moduleType == MODULE_TYPE_SIGNER) {
// force call onInstall for signer
// NOTE: for signer, kernel does not support independant signer install,
// signer is expected to be paired with proper permissionId
// to "ADD" permission, use "installValidations()" function
ISigner(module).onInstall(initData);
} else {
revert InvalidModuleType();
}
}
function installValidations(
ValidationId[] calldata vIds,
ValidationConfig[] memory configs,
bytes[] calldata validationData,
bytes[] calldata hookData
) external payable onlyEntryPointOrSelfOrRoot {
_installValidations(vIds, configs, validationData, hookData);
}
function uninstallValidation(ValidationId vId, bytes calldata deinitData, bytes calldata hookDeinitData)
external
payable
onlyEntryPointOrSelfOrRoot
{
IHook hook = _uninstallValidation(vId, deinitData);
_uninstallHook(hook, hookDeinitData);
}
function invalidateNonce(uint32 nonce) external payable onlyEntryPointOrSelfOrRoot {
_invalidateNonce(nonce);
}
function uninstallModule(uint256 moduleType, address module, bytes calldata deInitData)
external
payable
override
onlyEntryPointOrSelfOrRoot
{
if (moduleType == 1) {
ValidationId vId = ValidatorLib.validatorToIdentifier(IValidator(module));
_uninstallValidation(vId, deInitData);
} else if (moduleType == 2) {
_uninstallExecutor(IExecutor(module), deInitData);
} else if (moduleType == 3) {
bytes4 selector = bytes4(deInitData[0:4]);
_uninstallSelector(selector, deInitData[4:]);
} else if (moduleType == 4) {
ValidationId vId = _validationStorage().rootValidator;
if (_validationStorage().validationConfig[vId].hook == IHook(module)) {
// when root validator hook is being removed
// remove hook on root validator to prevent kernel from being locked
_validationStorage().validationConfig[vId].hook = IHook(address(1));
}
// force call onInstall for hook
// NOTE: for hook, kernel does not support independant hook install,
// hook is expected to be paired with proper validator/executor/selector
ModuleLib.uninstallModule(module, deInitData);
} else if (moduleType == 5) {
ValidationId rootValidator = _validationStorage().rootValidator;
bytes32 permissionId = bytes32(deInitData[0:32]);
if (ValidatorLib.getType(rootValidator) == VALIDATION_TYPE_PERMISSION) {
if (permissionId == bytes32(PermissionId.unwrap(ValidatorLib.getPermissionId(rootValidator)))) {
revert RootValidatorCannotBeRemoved();
}
}
// force call onInstall for policy
// NOTE: for policy, kernel does not support independant policy install,
// policy is expected to be paired with proper permissionId
// to "REMOVE" permission, use "uninstallValidation()" function
ModuleLib.uninstallModule(module, deInitData);
} else if (moduleType == 6) {
ValidationId rootValidator = _validationStorage().rootValidator;
bytes32 permissionId = bytes32(deInitData[0:32]);
if (ValidatorLib.getType(rootValidator) == VALIDATION_TYPE_PERMISSION) {
if (permissionId == bytes32(PermissionId.unwrap(ValidatorLib.getPermissionId(rootValidator)))) {
revert RootValidatorCannotBeRemoved();
}
}
// force call onInstall for signer
// NOTE: for signer, kernel does not support independant signer install,
// signer is expected to be paired with proper permissionId
// to "REMOVE" permission, use "uninstallValidation()" function
ModuleLib.uninstallModule(module, deInitData);
} else {
revert InvalidModuleType();
}
}
function supportsModule(uint256 moduleTypeId) external pure override returns (bool) {
if (moduleTypeId < 7) {
return true;
} else {
return false;
}
}
function isModuleInstalled(uint256 moduleType, address module, bytes calldata additionalContext)
external
view
override
returns (bool)
{
if (moduleType == MODULE_TYPE_VALIDATOR) {
return _validationStorage().validationConfig[ValidatorLib.validatorToIdentifier(IValidator(module))].hook
!= IHook(address(0));
} else if (moduleType == MODULE_TYPE_EXECUTOR) {
return address(_executorConfig(IExecutor(module)).hook) != address(0);
} else if (moduleType == MODULE_TYPE_FALLBACK) {
return _selectorConfig(bytes4(additionalContext[0:4])).target == module;
} else {
return false;
}
}
function accountId() external pure override returns (string memory accountImplementationId) {
return "kernel.advanced.v0.3.0-beta";
}
function supportsExecutionMode(ExecMode mode) external pure override returns (bool) {
(CallType callType, ExecType execType, ExecModeSelector selector, ExecModePayload payload) =
ExecLib.decode(mode);
if (
callType != CALLTYPE_BATCH && callType != CALLTYPE_SINGLE && callType != CALLTYPE_DELEGATECALL
&& callType != CALLTYPE_STATIC
) {
return false;
}
if (
ExecType.unwrap(execType) != ExecType.unwrap(EXECTYPE_TRY)
&& ExecType.unwrap(execType) != ExecType.unwrap(EXECTYPE_DEFAULT)
) {
return false;
}
if (ExecModeSelector.unwrap(selector) != ExecModeSelector.unwrap(EXEC_MODE_DEFAULT)) {
return false;
}
if (ExecModePayload.unwrap(payload) != bytes22(0)) {
return false;
}
return true;
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;
/**
* 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 maxFeePerGas and maxPriorityFeePerGas - Same as EIP-1559 gas parameter.
* @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; //maxPriorityFee and maxFeePerGas;
bytes paymasterAndData;
bytes signature;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;
import "./PackedUserOperation.sol";
import "../types/Types.sol";
interface IAccount {
/**
* Validate user's signature and nonce
* the entryPoint will make the call to the recipient only if this validation call returns successfully.
* signature failure should be reported by returning SIG_VALIDATION_FAILED (1).
* This allows making a "simulation call" without a valid signature
* Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.
*
* @dev Must validate caller is the entryPoint.
* Must validate the signature and nonce
* @param userOp - The operation that is about to be executed.
* @param userOpHash - Hash of the user's request data. can be used as the basis for signature.
* @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint.
* This is the minimum amount to transfer to the sender(entryPoint) to be
* able to make the call. The excess is left as a deposit in the entrypoint
* for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()".
* In case there is a paymaster in the request (or the current deposit is high
* enough), this value will be zero.
* @return validationData - Packaged ValidationData structure. use `_packValidationData` and
* `_unpackValidationData` to encode and decode.
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - Last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - First timestamp this operation is valid
* If an account doesn't use time-range, it is enough to
* return SIG_VALIDATION_FAILED value (1) for signature failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
payable
returns (ValidationData validationData);
}// SPDX-License-Identifier: GPL-3.0
/**
* Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
* Only one instance required on each chain.
*
*/
pragma solidity >=0.7.5;
/* 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";
interface IEntryPoint is IStakeManager, INonceManager {
/**
*
* An event emitted after each successful request.
* @param userOpHash - Unique identifier for the request (hash its entire content, except signature).
* @param sender - The account that generates this request.
* @param paymaster - If non-null, the paymaster that pays for this request.
* @param nonce - The nonce value from the request.
* @param success - True if the sender transaction succeeded, false if reverted.
* @param actualGasCost - Actual amount paid (by account or paymaster) for this UserOperation.
* @param actualGasUsed - Total gas used by this UserOperation (including preVerification, creation,
* validation and execution).
*/
event UserOperationEvent(
bytes32 indexed userOpHash,
address indexed sender,
address indexed paymaster,
uint256 nonce,
bool success,
uint256 actualGasCost,
uint256 actualGasUsed
);
/**
* Account "sender" was deployed.
* @param userOpHash - The userOp that deployed this account. UserOperationEvent will follow.
* @param sender - The account that is deployed
* @param factory - The factory used to deploy this account (in the initCode)
* @param paymaster - The paymaster used by this UserOp
*/
event AccountDeployed(bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster);
/**
* An event emitted if the UserOperation "callData" reverted with non-zero length.
* @param userOpHash - The request unique identifier.
* @param sender - The sender of this request.
* @param nonce - The nonce used in the request.
* @param revertReason - The return bytes from the (reverted) call to "callData".
*/
event UserOperationRevertReason(
bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason
);
/**
* An event emitted 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 "callData".
*/
event PostOpRevertReason(bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason);
/**
* An event emitted by handleOps(), before starting the execution loop.
* Any event emitted before this event, is part of the validation.
*/
event BeforeExecution();
/**
* Signature aggregator used by the following UserOperationEvents within this bundle.
* @param aggregator - The aggregator used for the following UserOperationEvents.
*/
event SignatureAggregatorChanged(address indexed aggregator);
/**
* A custom revert error of handleOps, to identify the offending op.
* Should be caught in off-chain handleOps simulation and not happen on-chain.
* Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts.
* 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, 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), the entrypoint and the chainid.
* @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;
}
/**
* Returned aggregated signature info:
* The aggregator returned by the account, and its current stake.
*/
struct AggregatorStakeInfo {
address aggregator;
StakeInfo stakeInfo;
}
/**
* Get counterfactual sender address.
* Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation.
* This method always revert, and returns the address in SenderAddressResult error
* @param initCode - The constructor code to be passed into the UserOperation.
*/
function getSenderAddress(bytes memory initCode) external;
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;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;
import "./PackedUserOperation.sol";
interface IAccountExecute {
/**
* Account may implement this execute method.
* passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash)
* to the account.
* The account should skip the methodSig, and use the callData (and optionally, other UserOp fields)
*
* @param userOp - The operation that was just validated.
* @param userOpHash - Hash of the user's request data.
*/
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {CallType, ExecType, ExecMode} from "../utils/ExecLib.sol";
import {PackedUserOperation} from "./PackedUserOperation.sol";
struct Execution {
address target;
uint256 value;
bytes callData;
}
interface IERC7579Account {
event ModuleInstalled(uint256 moduleTypeId, address module);
event ModuleUninstalled(uint256 moduleTypeId, address module);
/**
* @dev Executes a transaction on behalf of the account.
* This function is intended to be called by ERC-4337 EntryPoint.sol
* @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf
*
* @dev MSA MUST implement this function signature.
* If a mode is requested that is not supported by the Account, it MUST revert
* @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
* @param executionCalldata The encoded execution call data
*/
function execute(ExecMode mode, bytes calldata executionCalldata) external payable;
/**
* @dev Executes a transaction on behalf of the account.
* This function is intended to be called by Executor Modules
* @dev Ensure adequate authorization control: i.e. onlyExecutorModule
*
* @dev MSA MUST implement this function signature.
* If a mode is requested that is not supported by the Account, it MUST revert
* @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
* @param executionCalldata The encoded execution call data
*/
function executeFromExecutor(ExecMode mode, bytes calldata executionCalldata)
external
payable
returns (bytes[] memory returnData);
/**
* @dev ERC-1271 isValidSignature
* This function is intended to be used to validate a smart account signature
* and may forward the call to a validator module
*
* @param hash The hash of the data that is signed
* @param data The data that is signed
*/
function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);
/**
* @dev installs a Module of a certain type on the smart account
* @dev Implement Authorization control of your chosing
* @param moduleTypeId the module type ID according the ERC-7579 spec
* @param module the module address
* @param initData arbitrary data that may be required on the module during `onInstall`
* initialization.
*/
function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable;
/**
* @dev uninstalls a Module of a certain type on the smart account
* @dev Implement Authorization control of your chosing
* @param moduleTypeId the module type ID according the ERC-7579 spec
* @param module the module address
* @param deInitData arbitrary data that may be required on the module during `onUninstall`
* de-initialization.
*/
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable;
/**
* Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)
* @param encodedMode the encoded mode
*/
function supportsExecutionMode(ExecMode encodedMode) external view returns (bool);
/**
* Function to check if the account supports installation of a certain module type Id
* @param moduleTypeId the module type ID according the ERC-7579 spec
*/
function supportsModule(uint256 moduleTypeId) external view returns (bool);
/**
* Function to check if the account has a certain module installed
* @param moduleTypeId the module type ID according the ERC-7579 spec
* Note: keep in mind that some contracts can be multiple module types at the same time. It
* thus may be necessary to query multiple module types
* @param module the module address
* @param additionalContext additional context data that the smart account may interpret to
* identifiy conditions under which the module is installed.
* usually this is not necessary, but for some special hooks that
* are stored in mappings, this param might be needed
*/
function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext)
external
view
returns (bool);
/**
* @dev Returns the account id of the smart account
* @return accountImplementationId the account id of the smart account
* the accountId should be structured like so:
* "vendorname.accountname.semver"
*/
function accountId() external view returns (string memory accountImplementationId);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ExcessivelySafeCall} from "ExcessivelySafeCall/ExcessivelySafeCall.sol";
import {IModule} from "../interfaces/IERC7579Modules.sol";
library ModuleLib {
event ModuleUninstallResult(address module, bool result);
function uninstallModule(address module, bytes memory deinitData) internal returns (bool result) {
(result,) = ExcessivelySafeCall.excessivelySafeCall(
module, gasleft(), 0, 0, abi.encodeWithSelector(IModule.onUninstall.selector, deinitData)
);
emit ModuleUninstallResult(module, result);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IValidator, IModule, IExecutor, IHook, IPolicy, ISigner, IFallback} from "../interfaces/IERC7579Modules.sol";
import {PackedUserOperation} from "../interfaces/PackedUserOperation.sol";
import {SelectorManager} from "./SelectorManager.sol";
import {HookManager} from "./HookManager.sol";
import {ExecutorManager} from "./ExecutorManager.sol";
import {ValidationData, ValidAfter, ValidUntil, parseValidationData} from "../interfaces/IAccount.sol";
import {IAccountExecute} from "../interfaces/IAccountExecute.sol";
import {EIP712} from "solady/utils/EIP712.sol";
import {ModuleLib} from "../utils/ModuleLib.sol";
import {
ValidationId,
PolicyData,
ValidationMode,
ValidationType,
ValidatorLib,
PassFlag
} from "../utils/ValidationTypeLib.sol";
import {CallType} from "../utils/ExecLib.sol";
import {CALLTYPE_SINGLE} from "../types/Constants.sol";
import {PermissionId, getValidationResult} from "../types/Types.sol";
import {_intersectValidationData} from "../utils/KernelValidationResult.sol";
import {
VALIDATION_MODE_DEFAULT,
VALIDATION_MODE_ENABLE,
VALIDATION_TYPE_ROOT,
VALIDATION_TYPE_VALIDATOR,
VALIDATION_TYPE_PERMISSION,
SKIP_USEROP,
SKIP_SIGNATURE,
VALIDATION_MANAGER_STORAGE_SLOT,
MAX_NONCE_INCREMENT_SIZE,
ENABLE_TYPE_HASH,
KERNEL_WRAPPER_TYPE_HASH
} from "../types/Constants.sol";
abstract contract ValidationManager is EIP712, SelectorManager, HookManager, ExecutorManager {
event RootValidatorUpdated(ValidationId rootValidator);
event ValidatorInstalled(IValidator validator, uint32 nonce);
event PermissionInstalled(PermissionId permission, uint32 nonce);
event NonceInvalidated(uint32 nonce);
event ValidatorUninstalled(IValidator validator);
event PermissionUninstalled(PermissionId permission);
event SelectorSet(bytes4 selector, ValidationId vId, bool allowed);
error InvalidMode();
error InvalidValidator();
error InvalidSignature();
error EnableNotApproved();
error PolicySignatureOrderError();
error SignerPrefixNotPresent();
error PolicyDataTooLarge();
error InvalidValidationType();
error InvalidNonce();
error PolicyFailed(uint256 i);
error PermissionNotAlllowedForUserOp();
error PermissionNotAlllowedForSignature();
error PermissionDataLengthMismatch();
error NonceInvalidationError();
error RootValidatorCannotBeRemoved();
// erc7579 plugins
struct ValidationConfig {
uint32 nonce; // 4 bytes
IHook hook; // 20 bytes address(1) : hook not required, address(0) : validator not installed
}
struct PermissionConfig {
PassFlag permissionFlag;
ISigner signer;
PolicyData[] policyData;
}
struct ValidationStorage {
ValidationId rootValidator;
uint32 currentNonce;
uint32 validNonceFrom;
mapping(ValidationId => ValidationConfig) validationConfig;
mapping(ValidationId => mapping(bytes4 => bool)) allowedSelectors;
// validation = validator | permission
// validator == 1 validator
// permission == 1 signer + N policies
mapping(PermissionId => PermissionConfig) permissionConfig;
}
function rootValidator() external view returns (ValidationId) {
return _validationStorage().rootValidator;
}
function currentNonce() external view returns (uint32) {
return _validationStorage().currentNonce;
}
function validNonceFrom() external view returns (uint32) {
return _validationStorage().validNonceFrom;
}
function isAllowedSelector(ValidationId vId, bytes4 selector) external view returns (bool) {
return _validationStorage().allowedSelectors[vId][selector];
}
function validationConfig(ValidationId vId) external view returns (ValidationConfig memory) {
return _validationStorage().validationConfig[vId];
}
function permissionConfig(PermissionId pId) external view returns (PermissionConfig memory) {
return (_validationStorage().permissionConfig[pId]);
}
function _validationStorage() internal pure returns (ValidationStorage storage state) {
assembly {
state.slot := VALIDATION_MANAGER_STORAGE_SLOT
}
}
function _setRootValidator(ValidationId _rootValidator) internal {
ValidationStorage storage vs = _validationStorage();
vs.rootValidator = _rootValidator;
emit RootValidatorUpdated(_rootValidator);
}
function _invalidateNonce(uint32 nonce) internal {
ValidationStorage storage state = _validationStorage();
if (state.currentNonce + MAX_NONCE_INCREMENT_SIZE < nonce) {
revert NonceInvalidationError();
}
if (nonce <= state.validNonceFrom) {
revert InvalidNonce();
}
state.validNonceFrom = nonce;
if (state.currentNonce < state.validNonceFrom) {
state.currentNonce = state.validNonceFrom;
}
}
// allow installing multiple validators with same nonce
function _installValidations(
ValidationId[] calldata validators,
ValidationConfig[] memory configs,
bytes[] calldata validatorData,
bytes[] calldata hookData
) internal {
unchecked {
for (uint256 i = 0; i < validators.length; i++) {
_installValidation(validators[i], configs[i], validatorData[i], hookData[i]);
}
}
}
function _setSelector(ValidationId vId, bytes4 selector, bool allowed) internal {
ValidationStorage storage state = _validationStorage();
state.allowedSelectors[vId][selector] = allowed;
emit SelectorSet(selector, vId, allowed);
}
// for uninstall, we support uninstall for validator mode by calling onUninstall
// but for permission mode, we do it naively by setting hook to address(0).
// it is more recommended to use a nonce revoke to make sure the validator has been revoked
// also, we are not calling hook.onInstall here
function _uninstallValidation(ValidationId vId, bytes calldata validatorData) internal returns (IHook hook) {
ValidationStorage storage state = _validationStorage();
if (vId == state.rootValidator) {
revert RootValidatorCannotBeRemoved();
}
hook = state.validationConfig[vId].hook;
state.validationConfig[vId].hook = IHook(address(0));
ValidationType vType = ValidatorLib.getType(vId);
if (vType == VALIDATION_TYPE_VALIDATOR) {
IValidator validator = ValidatorLib.getValidator(vId);
ModuleLib.uninstallModule(address(validator), validatorData);
} else if (vType == VALIDATION_TYPE_PERMISSION) {
PermissionId permission = ValidatorLib.getPermissionId(vId);
_uninstallPermission(permission, validatorData);
} else {
revert InvalidValidationType();
}
}
function _uninstallPermission(PermissionId pId, bytes calldata data) internal {
bytes[] calldata permissionDisableData;
assembly {
permissionDisableData.offset := add(add(data.offset, 32), calldataload(data.offset))
permissionDisableData.length := calldataload(sub(permissionDisableData.offset, 32))
}
PermissionConfig storage config = _validationStorage().permissionConfig[pId];
unchecked {
if (permissionDisableData.length != config.policyData.length + 1) {
revert PermissionDataLengthMismatch();
}
PolicyData[] storage policyData = config.policyData;
for (uint256 i = 0; i < policyData.length; i++) {
(, IPolicy policy) = ValidatorLib.decodePolicyData(policyData[i]);
ModuleLib.uninstallModule(
address(policy), abi.encodePacked(bytes32(PermissionId.unwrap(pId)), permissionDisableData[i])
);
}
delete _validationStorage().permissionConfig[pId].policyData;
ModuleLib.uninstallModule(
address(config.signer),
abi.encodePacked(
bytes32(PermissionId.unwrap(pId)), permissionDisableData[permissionDisableData.length - 1]
)
);
}
config.signer = ISigner(address(0));
config.permissionFlag = PassFlag.wrap(bytes2(0));
}
function _installValidation(
ValidationId vId,
ValidationConfig memory config,
bytes calldata validatorData,
bytes calldata hookData
) internal {
ValidationStorage storage state = _validationStorage();
if (state.validationConfig[vId].nonce == state.currentNonce) {
// only increase currentNonce when vId's currentNonce is same
unchecked {
state.currentNonce++;
}
}
if (config.hook == IHook(address(0))) {
config.hook = IHook(address(1));
}
if (state.currentNonce != config.nonce || state.validationConfig[vId].nonce >= config.nonce) {
revert InvalidNonce();
}
state.validationConfig[vId] = config;
if (config.hook != IHook(address(1))) {
_installHook(config.hook, hookData);
}
ValidationType vType = ValidatorLib.getType(vId);
if (vType == VALIDATION_TYPE_VALIDATOR) {
IValidator validator = ValidatorLib.getValidator(vId);
validator.onInstall(validatorData);
} else if (vType == VALIDATION_TYPE_PERMISSION) {
PermissionId permission = ValidatorLib.getPermissionId(vId);
_installPermission(permission, validatorData);
} else {
revert InvalidValidationType();
}
}
function _installPermission(PermissionId permission, bytes calldata data) internal {
ValidationStorage storage state = _validationStorage();
bytes[] calldata permissionEnableData;
assembly {
permissionEnableData.offset := add(add(data.offset, 32), calldataload(data.offset))
permissionEnableData.length := calldataload(sub(permissionEnableData.offset, 32))
}
// allow up to 0xfe, 0xff is dedicated for signer
if (permissionEnableData.length > 254 || permissionEnableData.length == 0) {
revert PolicyDataTooLarge();
}
// clean up the policyData
if (state.permissionConfig[permission].policyData.length > 0) {
delete state.permissionConfig[permission].policyData;
}
unchecked {
for (uint256 i = 0; i < permissionEnableData.length - 1; i++) {
state.permissionConfig[permission].policyData.push(
PolicyData.wrap(bytes22(permissionEnableData[i][0:22]))
);
IPolicy(address(bytes20(permissionEnableData[i][2:22]))).onInstall(
abi.encodePacked(bytes32(PermissionId.unwrap(permission)), permissionEnableData[i][22:])
);
}
// last permission data will be signer
ISigner signer = ISigner(address(bytes20(permissionEnableData[permissionEnableData.length - 1][2:22])));
state.permissionConfig[permission].signer = signer;
state.permissionConfig[permission].permissionFlag =
PassFlag.wrap(bytes2(permissionEnableData[permissionEnableData.length - 1][0:2]));
signer.onInstall(
abi.encodePacked(
bytes32(PermissionId.unwrap(permission)), permissionEnableData[permissionEnableData.length - 1][22:]
)
);
}
}
function _doValidation(ValidationMode vMode, ValidationId vId, PackedUserOperation calldata op, bytes32 userOpHash)
internal
returns (ValidationData validationData)
{
ValidationStorage storage state = _validationStorage();
PackedUserOperation memory userOp = op;
bytes calldata userOpSig = op.signature;
unchecked {
if (vMode == VALIDATION_MODE_ENABLE) {
(validationData, userOpSig) = _enableMode(vId, op.signature);
userOp.signature = userOpSig;
}
ValidationType vType = ValidatorLib.getType(vId);
if (vType == VALIDATION_TYPE_VALIDATOR) {
validationData = _intersectValidationData(
validationData,
ValidationData.wrap(ValidatorLib.getValidator(vId).validateUserOp(userOp, userOpHash))
);
} else {
PermissionId pId = ValidatorLib.getPermissionId(vId);
if (PassFlag.unwrap(state.permissionConfig[pId].permissionFlag) & PassFlag.unwrap(SKIP_USEROP) != 0) {
revert PermissionNotAlllowedForUserOp();
}
(ValidationData policyCheck, ISigner signer) = _checkUserOpPolicy(pId, userOp, userOpSig);
validationData = _intersectValidationData(validationData, policyCheck);
validationData = _intersectValidationData(
validationData,
ValidationData.wrap(
signer.checkUserOpSignature(bytes32(PermissionId.unwrap(pId)), userOp, userOpHash)
)
);
}
}
}
function _enableMode(ValidationId vId, bytes calldata packedData)
internal
returns (ValidationData validationData, bytes calldata userOpSig)
{
validationData = _enableValidationWithSig(vId, packedData);
assembly {
userOpSig.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 148)))
userOpSig.length := calldataload(sub(userOpSig.offset, 32))
}
return (validationData, userOpSig);
}
function _enableValidationWithSig(ValidationId vId, bytes calldata packedData)
internal
returns (ValidationData validationData)
{
bytes calldata enableSig;
(
ValidationConfig memory config,
bytes calldata validatorData,
bytes calldata hookData,
bytes calldata selectorData,
bytes32 digest
) = _enableDigest(vId, packedData);
assembly {
enableSig.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 116)))
enableSig.length := calldataload(sub(enableSig.offset, 32))
}
validationData = _checkEnableSig(digest, enableSig);
_installValidation(vId, config, validatorData, hookData);
_configureSelector(selectorData);
_setSelector(vId, bytes4(selectorData[0:4]), true);
}
function _checkEnableSig(bytes32 digest, bytes calldata enableSig)
internal
view
returns (ValidationData validationData)
{
ValidationStorage storage state = _validationStorage();
ValidationType vType = ValidatorLib.getType(state.rootValidator);
bytes4 result;
if (vType == VALIDATION_TYPE_VALIDATOR) {
IValidator validator = ValidatorLib.getValidator(state.rootValidator);
result = validator.isValidSignatureWithSender(address(this), digest, enableSig);
} else if (vType == VALIDATION_TYPE_PERMISSION) {
PermissionId pId = ValidatorLib.getPermissionId(state.rootValidator);
ISigner signer;
(signer, validationData, enableSig) = _checkSignaturePolicy(pId, address(this), digest, enableSig);
result = signer.checkSignature(bytes32(PermissionId.unwrap(pId)), address(this), digest, enableSig);
} else {
revert InvalidValidationType();
}
if (result != 0x1626ba7e) {
revert EnableNotApproved();
}
}
function _configureSelector(bytes calldata selectorData) internal {
bytes4 selector = bytes4(selectorData[0:4]);
if (selectorData.length >= 4) {
if (selectorData.length >= 44) {
// install selector with hook and target contract
bytes calldata selectorInitData;
bytes calldata hookInitData;
IModule selectorModule = IModule(address(bytes20(selectorData[4:24])));
assembly {
selectorInitData.offset :=
add(add(selectorData.offset, 76), calldataload(add(selectorData.offset, 44)))
selectorInitData.length := calldataload(sub(selectorInitData.offset, 32))
hookInitData.offset := add(add(selectorData.offset, 76), calldataload(add(selectorData.offset, 76)))
hookInitData.length := calldataload(sub(hookInitData.offset, 32))
}
if (CallType.wrap(bytes1(selectorInitData[0])) == CALLTYPE_SINGLE && selectorModule.isModuleType(2)) {
// also adds as executor when fallback module is also a executor
bytes calldata executorHookData;
assembly {
executorHookData.offset :=
add(add(selectorData.offset, 76), calldataload(add(selectorData.offset, 108)))
executorHookData.length := calldataload(sub(executorHookData.offset, 32))
}
IHook executorHook = IHook(address(bytes20(executorHookData[0:20])));
// if module is also executor, install as executor
_installExecutorWithoutInit(IExecutor(address(selectorModule)), executorHook);
_installHook(executorHook, executorHookData[20:]);
}
_installSelector(
selector, address(selectorModule), IHook(address(bytes20(selectorData[24:44]))), selectorInitData
);
_installHook(IHook(address(bytes20(selectorData[24:44]))), hookInitData);
} else {
// set without install
require(selectorData.length == 4, "Invalid selectorData");
}
}
}
function _enableDigest(ValidationId vId, bytes calldata packedData)
internal
view
returns (
ValidationConfig memory config,
bytes calldata validatorData,
bytes calldata hookData,
bytes calldata selectorData,
bytes32 digest
)
{
ValidationStorage storage state = _validationStorage();
config.hook = IHook(address(bytes20(packedData[0:20])));
config.nonce = state.currentNonce;
assembly {
validatorData.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 20)))
validatorData.length := calldataload(sub(validatorData.offset, 32))
hookData.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 52)))
hookData.length := calldataload(sub(hookData.offset, 32))
selectorData.offset := add(add(packedData.offset, 52), calldataload(add(packedData.offset, 84)))
selectorData.length := calldataload(sub(selectorData.offset, 32))
}
digest = _hashTypedData(
keccak256(
abi.encode(
ENABLE_TYPE_HASH,
ValidationId.unwrap(vId),
state.currentNonce,
config.hook,
keccak256(validatorData),
keccak256(hookData),
keccak256(selectorData)
)
)
);
}
struct PermissionSigMemory {
uint8 idx;
uint256 length;
ValidationData validationData;
PermissionId permission;
PassFlag flag;
IPolicy policy;
bytes permSig;
address caller;
bytes32 digest;
}
function _checkUserOpPolicy(PermissionId pId, PackedUserOperation memory userOp, bytes calldata userOpSig)
internal
returns (ValidationData validationData, ISigner signer)
{
ValidationStorage storage state = _validationStorage();
PolicyData[] storage policyData = state.permissionConfig[pId].policyData;
unchecked {
for (uint256 i = 0; i < policyData.length; i++) {
(PassFlag flag, IPolicy policy) = ValidatorLib.decodePolicyData(policyData[i]);
uint8 idx = uint8(bytes1(userOpSig[0]));
if (idx == i) {
// we are using uint64 length
uint256 length = uint64(bytes8(userOpSig[1:9]));
userOp.signature = userOpSig[9:9 + length];
userOpSig = userOpSig[9 + length:];
} else if (idx < i) {
// signature is not in order
revert PolicySignatureOrderError();
} else {
userOp.signature = "";
}
if (PassFlag.unwrap(flag) & PassFlag.unwrap(SKIP_USEROP) == 0) {
ValidationData vd =
ValidationData.wrap(policy.checkUserOpPolicy(bytes32(PermissionId.unwrap(pId)), userOp));
address result = getValidationResult(vd);
if (result != address(0)) {
revert PolicyFailed(i);
}
validationData = _intersectValidationData(validationData, vd);
}
}
if (uint8(bytes1(userOpSig[0])) != 255) {
revert SignerPrefixNotPresent();
}
userOp.signature = userOpSig[1:];
return (validationData, state.permissionConfig[pId].signer);
}
}
function _checkSignaturePolicy(PermissionId pId, address caller, bytes32 digest, bytes calldata sig)
internal
view
returns (ISigner, ValidationData, bytes calldata)
{
ValidationStorage storage state = _validationStorage();
PermissionSigMemory memory mSig;
mSig.permission = pId;
mSig.caller = caller;
mSig.digest = digest;
_checkPermissionPolicy(mSig, state, sig);
if (uint8(bytes1(sig[0])) != 255) {
revert SignerPrefixNotPresent();
}
sig = sig[1:];
return (state.permissionConfig[mSig.permission].signer, mSig.validationData, sig);
}
function _checkPermissionPolicy(
PermissionSigMemory memory mSig,
ValidationStorage storage state,
bytes calldata sig
) internal view {
PolicyData[] storage policyData = state.permissionConfig[mSig.permission].policyData;
unchecked {
for (uint256 i = 0; i < policyData.length; i++) {
(mSig.flag, mSig.policy) = ValidatorLib.decodePolicyData(policyData[i]);
mSig.idx = uint8(bytes1(sig[0]));
if (mSig.idx == i) {
// we are using uint64 length
mSig.length = uint64(bytes8(sig[1:9]));
mSig.permSig = sig[9:9 + mSig.length];
sig = sig[9 + mSig.length:];
} else if (mSig.idx < i) {
// signature is not in order
revert PolicySignatureOrderError();
} else {
mSig.permSig = sig[0:0];
}
if (PassFlag.unwrap(mSig.flag) & PassFlag.unwrap(SKIP_SIGNATURE) == 0) {
ValidationData vd = ValidationData.wrap(
mSig.policy.checkSignaturePolicy(
bytes32(PermissionId.unwrap(mSig.permission)), mSig.caller, mSig.digest, mSig.permSig
)
);
address result = getValidationResult(vd);
if (result != address(0)) {
revert PolicyFailed(i);
}
mSig.validationData = _intersectValidationData(mSig.validationData, vd);
}
}
}
}
function _checkPermissionSignature(PermissionId pId, address caller, bytes32 hash, bytes calldata sig)
internal
view
returns (bytes4)
{
(ISigner signer, ValidationData valdiationData, bytes calldata validatorSig) =
_checkSignaturePolicy(pId, caller, hash, sig);
(ValidAfter validAfter, ValidUntil validUntil,) = parseValidationData(ValidationData.unwrap(valdiationData));
if (block.timestamp < ValidAfter.unwrap(validAfter) || block.timestamp > ValidUntil.unwrap(validUntil)) {
return 0xffffffff;
}
return signer.checkSignature(bytes32(PermissionId.unwrap(pId)), caller, _toWrappedHash(hash), validatorSig);
}
function _toWrappedHash(bytes32 hash) internal view returns (bytes32) {
return _hashTypedData(keccak256(abi.encode(KERNEL_WRAPPER_TYPE_HASH, hash)));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IHook} from "../interfaces/IERC7579Modules.sol";
import {ModuleLib} from "../utils/ModuleLib.sol";
abstract contract HookManager {
// NOTE: currently, all install/uninstall calls onInstall/onUninstall
// I assume this does not pose any security risks, but there should be a way to branch if hook needs call to onInstall/onUninstall
// --- Hook ---
// Hook is activated on these scenarios
// - on 4337 flow, userOp.calldata starts with executeUserOp.selector && validator requires hook
// - executeFromExecutor() is invoked and executor requires hook
// - when fallback function has been invoked and fallback requires hook => native functions will not invoke hook
function _doPreHook(IHook hook, uint256 value, bytes calldata callData) internal returns (bytes memory context) {
context = hook.preCheck(msg.sender, value, callData);
}
function _doPostHook(IHook hook, bytes memory context, bool success, bytes memory result) internal {
// bool success,
// bytes memory result
hook.postCheck(context, success, result);
}
// @notice if hook is not initialized before, kernel will call hook.onInstall no matter what flag it shows, with hookData[1:]
// @param hookData is encoded into (1bytes flag + actual hookdata) flag is for identifying if the hook has to be initialized or not
function _installHook(IHook hook, bytes calldata hookData) internal {
if (address(hook) == address(0) || address(hook) == address(1)) {
return;
}
if (!hook.isInitialized(address(this))) {
// if hook is not installed, it should call onInstall
hook.onInstall(hookData[1:]);
return;
}
if (bytes1(hookData[0]) == bytes1(0xff)) {
// 0xff means you want to explicitly call install hook
hook.onInstall(hookData[1:]);
}
}
// @param hookData encoded as (1bytes flag + actual hookdata) flag is for identifying if the hook has to be initialized or not
function _uninstallHook(IHook hook, bytes calldata hookData) internal {
if (address(hook) == address(0) || address(hook) == address(1)) {
return;
}
if (bytes1(hookData[0]) == bytes1(0xff)) {
// 0xff means you want to call uninstall hook
ModuleLib.uninstallModule(address(hook), hookData[1:]);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IHook, IExecutor} from "../interfaces/IERC7579Modules.sol";
import {ModuleLib} from "../utils/ModuleLib.sol";
import {EXECUTOR_MANAGER_STORAGE_SLOT} from "../types/Constants.sol";
abstract contract ExecutorManager {
struct ExecutorConfig {
IHook hook; // address(1) : hook not required, address(0) : validator not installed
}
struct ExecutorStorage {
mapping(IExecutor => ExecutorConfig) executorConfig;
}
function executorConfig(IExecutor executor) external view returns (ExecutorConfig memory) {
return _executorConfig(executor);
}
function _executorConfig(IExecutor executor) internal view returns (ExecutorConfig storage config) {
ExecutorStorage storage es;
bytes32 slot = EXECUTOR_MANAGER_STORAGE_SLOT;
assembly {
es.slot := slot
}
config = es.executorConfig[executor];
}
function _installExecutor(IExecutor executor, bytes calldata executorData, IHook hook) internal {
if (address(hook) == address(0)) {
hook = IHook(address(1));
}
ExecutorConfig storage config = _executorConfig(executor);
config.hook = hook;
executor.onInstall(executorData);
}
function _installExecutorWithoutInit(IExecutor executor, IHook hook) internal {
if (address(hook) == address(0)) {
hook = IHook(address(1));
}
ExecutorConfig storage config = _executorConfig(executor);
config.hook = hook;
}
function _uninstallExecutor(IExecutor executor, bytes calldata executorData) internal returns (IHook hook) {
ExecutorConfig storage config = _executorConfig(executor);
hook = config.hook;
config.hook = IHook(address(0));
ModuleLib.uninstallModule(address(executor), executorData);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IHook, IFallback, IModule} from "../interfaces/IERC7579Modules.sol";
import {CallType} from "../utils/ExecLib.sol";
import {SELECTOR_MANAGER_STORAGE_SLOT, CALLTYPE_DELEGATECALL, CALLTYPE_SINGLE} from "../types/Constants.sol";
import {ModuleLib} from "../utils/ModuleLib.sol";
abstract contract SelectorManager {
error NotSupportedCallType();
struct SelectorConfig {
IHook hook; // 20 bytes for hook address
address target; // 20 bytes target will be fallback module, called with call
CallType callType;
}
struct SelectorStorage {
mapping(bytes4 => SelectorConfig) selectorConfig;
}
function selectorConfig(bytes4 selector) external view returns (SelectorConfig memory) {
return _selectorConfig(selector);
}
function _selectorConfig(bytes4 selector) internal view returns (SelectorConfig storage config) {
config = _selectorStorage().selectorConfig[selector];
}
function _selectorStorage() internal pure returns (SelectorStorage storage ss) {
bytes32 slot = SELECTOR_MANAGER_STORAGE_SLOT;
assembly {
ss.slot := slot
}
}
function _installSelector(bytes4 selector, address target, IHook hook, bytes calldata selectorData) internal {
if (address(hook) == address(0)) {
hook = IHook(address(1));
}
SelectorConfig storage ss = _selectorConfig(selector);
// we are going to install only through call/delegatecall
CallType callType = CallType.wrap(bytes1(selectorData[0]));
if (callType == CALLTYPE_SINGLE) {
IModule(target).onInstall(selectorData[1:]);
} else if (callType != CALLTYPE_DELEGATECALL) {
// NOTE : we are not going to call onInstall for delegatecall, and we support only CALL & DELEGATECALL
revert NotSupportedCallType();
}
ss.hook = hook;
ss.target = target;
ss.callType = callType;
}
function _uninstallSelector(bytes4 selector, bytes calldata selectorDeinitData) internal returns (IHook hook) {
SelectorConfig storage ss = _selectorConfig(selector);
hook = ss.hook;
ss.hook = IHook(address(0));
ModuleLib.uninstallModule(ss.target, selectorDeinitData);
ss.target = address(0);
ss.callType = CallType.wrap(bytes1(0xff));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {PackedUserOperation} from "./PackedUserOperation.sol";
interface IModule {
error AlreadyInitialized(address smartAccount);
error NotInitialized(address smartAccount);
/**
* @dev This function is called by the smart account during installation of the module
* @param data arbitrary data that may be required on the module during `onInstall`
* initialization
*
* MUST revert on error (i.e. if module is already enabled)
*/
function onInstall(bytes calldata data) external payable;
/**
* @dev This function is called by the smart account during uninstallation of the module
* @param data arbitrary data that may be required on the module during `onUninstall`
* de-initialization
*
* MUST revert on error
*/
function onUninstall(bytes calldata data) external payable;
/**
* @dev Returns boolean value if module is a certain type
* @param moduleTypeId the module type ID according the ERC-7579 spec
*
* MUST return true if the module is of the given type and false otherwise
*/
function isModuleType(uint256 moduleTypeId) external view returns (bool);
/**
* @dev Returns if the module was already initialized for a provided smartaccount
*/
function isInitialized(address smartAccount) external view returns (bool);
}
interface IValidator is IModule {
error InvalidTargetAddress(address target);
/**
* @dev Validates a transaction on behalf of the account.
* This function is intended to be called by the MSA during the ERC-4337 validaton phase
* Note: solely relying on bytes32 hash and signature is not suffcient for some
* validation implementations (i.e. SessionKeys often need access to userOp.calldata)
* @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata.
* The MSA MUST clean up the userOp before sending it to the validator.
* @param userOpHash The hash of the user operation to be validated
* @return return value according to ERC-4337
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
returns (uint256);
/**
* Validator can be used for ERC-1271 validation
*/
function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data)
external
view
returns (bytes4);
}
interface IExecutor is IModule {}
interface IHook is IModule {
/**
* @dev Called by the smart account before execution
* @param msgSender the address that called the smart account
* @param value the value that was sent to the smart account
* @param msgData the data that was sent to the smart account
*
* MAY return arbitrary data in the `hookData` return value
*/
function preCheck(address msgSender, uint256 value, bytes calldata msgData)
external
payable
returns (bytes memory hookData);
/**
* @dev Called by the smart account after execution
* @param hookData the data that was returned by the `preCheck` function
* @param executionSuccess whether the execution(s) was (were) successful
* @param executionReturn the return/revert data of the execution(s)
*
* MAY validate the `hookData` to validate transaction context of the `preCheck` function
*/
function postCheck(bytes calldata hookData, bool executionSuccess, bytes calldata executionReturn)
external
payable;
}
interface IFallback is IModule {}
interface IPolicy is IModule {
function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp) external payable returns (uint256);
function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
external
view
returns (uint256);
}
interface ISigner is IModule {
function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
returns (uint256);
function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
external
view
returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS AND IMMUTABLES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 internal constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
uint256 private immutable _cachedThis;
uint256 private immutable _cachedChainId;
bytes32 private immutable _cachedNameHash;
bytes32 private immutable _cachedVersionHash;
bytes32 private immutable _cachedDomainSeparator;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTRUCTOR */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cache the hashes for cheaper runtime gas costs.
/// In the case of upgradeable contracts (i.e. proxies),
/// or if the chain id changes due to a hard fork,
/// the domain separator will be seamlessly calculated on-the-fly.
constructor() {
_cachedThis = uint256(uint160(address(this)));
_cachedChainId = block.chainid;
string memory name;
string memory version;
if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
bytes32 versionHash =
_domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
_cachedNameHash = nameHash;
_cachedVersionHash = versionHash;
bytes32 separator;
if (!_domainNameAndVersionMayChange()) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), versionHash)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
_cachedDomainSeparator = separator;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Please override this function to return the domain name and version.
/// ```
/// function _domainNameAndVersion()
/// internal
/// pure
/// virtual
/// returns (string memory name, string memory version)
/// {
/// name = "Solady";
/// version = "1";
/// }
/// ```
///
/// Note: If the returned result may change after the contract has been deployed,
/// you must override `_domainNameAndVersionMayChange()` to return true.
function _domainNameAndVersion()
internal
view
virtual
returns (string memory name, string memory version);
/// @dev Returns if `_domainNameAndVersion()` may change
/// after the contract has been deployed (i.e. after the constructor).
/// Default: false.
function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the EIP-712 domain separator.
function _domainSeparator() internal view virtual returns (bytes32 separator) {
if (_domainNameAndVersionMayChange()) {
separator = _buildDomainSeparator();
} else {
separator = _cachedDomainSeparator;
if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
}
}
/// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
/// given `structHash`, as defined in
/// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
///
/// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
/// ```
/// bytes32 digest = _hashTypedData(keccak256(abi.encode(
/// keccak256("Mail(address to,string contents)"),
/// mailTo,
/// keccak256(bytes(mailContents))
/// )));
/// address signer = ECDSA.recover(digest, signature);
/// ```
function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
// We will use `digest` to store the domain separator to save a bit of gas.
if (_domainNameAndVersionMayChange()) {
digest = _buildDomainSeparator();
} else {
digest = _cachedDomainSeparator;
if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator();
}
/// @solidity memory-safe-assembly
assembly {
// Compute the digest.
mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
mstore(0x1a, digest) // Store the domain separator.
mstore(0x3a, structHash) // Store the struct hash.
digest := keccak256(0x18, 0x42)
// Restore the part of the free memory slot that was overwritten.
mstore(0x3a, 0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-5267 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev See: https://eips.ethereum.org/EIPS/eip-5267
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
fields = hex"0f"; // `0b01111`.
(name, version) = _domainNameAndVersion();
chainId = block.chainid;
verifyingContract = address(this);
salt = salt; // `bytes32(0)`.
extensions = extensions; // `new uint256[](0)`.
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the EIP-712 domain separator.
function _buildDomainSeparator() private view returns (bytes32 separator) {
// We will use `separator` to store the name hash to save a bit of gas.
bytes32 versionHash;
if (_domainNameAndVersionMayChange()) {
(string memory name, string memory version) = _domainNameAndVersion();
separator = keccak256(bytes(name));
versionHash = keccak256(bytes(version));
} else {
separator = _cachedNameHash;
versionHash = _cachedVersionHash;
}
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), separator) // Name hash.
mstore(add(m, 0x40), versionHash)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
/// @dev Returns if the cached domain separator has been invalidated.
function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
uint256 cachedChainId = _cachedChainId;
uint256 cachedThis = _cachedThis;
/// @solidity memory-safe-assembly
assembly {
result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload} from "../types/Types.sol";
import {
CALLTYPE_SINGLE,
CALLTYPE_BATCH,
EXECTYPE_DEFAULT,
EXEC_MODE_DEFAULT,
EXECTYPE_TRY,
CALLTYPE_DELEGATECALL
} from "../types/Constants.sol";
import {Execution} from "../types/Structs.sol";
/**
* @dev ExecLib is a helper library for execution
*/
library ExecLib {
error ExecutionFailed();
event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result);
function execute(ExecMode execMode, bytes calldata executionCalldata)
internal
returns (bytes[] memory returnData)
{
(CallType callType, ExecType execType,,) = decode(execMode);
// check if calltype is batch or single
if (callType == CALLTYPE_BATCH) {
// destructure executionCallData according to batched exec
Execution[] calldata executions = decodeBatch(executionCalldata);
// check if execType is revert or try
if (execType == EXECTYPE_DEFAULT) returnData = execute(executions);
else if (execType == EXECTYPE_TRY) returnData = tryExecute(executions);
else revert("Unsupported");
} else if (callType == CALLTYPE_SINGLE) {
// destructure executionCallData according to single exec
(address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata);
returnData = new bytes[](1);
bool success;
// check if execType is revert or try
if (execType == EXECTYPE_DEFAULT) {
returnData[0] = execute(target, value, callData);
} else if (execType == EXECTYPE_TRY) {
(success, returnData[0]) = tryExecute(target, value, callData);
if (!success) emit TryExecuteUnsuccessful(0, returnData[0]);
} else {
revert("Unsupported");
}
} else if (callType == CALLTYPE_DELEGATECALL) {
address delegate = address(bytes20(executionCalldata[0:20]));
bytes calldata callData = executionCalldata[20:];
executeDelegatecall(delegate, callData);
} else {
revert("Unsupported");
}
}
function execute(Execution[] calldata executions) internal returns (bytes[] memory result) {
uint256 length = executions.length;
result = new bytes[](length);
for (uint256 i; i < length; i++) {
Execution calldata _exec = executions[i];
result[i] = execute(_exec.target, _exec.value, _exec.callData);
}
}
function tryExecute(Execution[] calldata executions) internal returns (bytes[] memory result) {
uint256 length = executions.length;
result = new bytes[](length);
for (uint256 i; i < length; i++) {
Execution calldata _exec = executions[i];
bool success;
(success, result[i]) = tryExecute(_exec.target, _exec.value, _exec.callData);
if (!success) emit TryExecuteUnsuccessful(i, result[i]);
}
}
function execute(address target, uint256 value, bytes calldata callData) internal returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
calldatacopy(result, callData.offset, callData.length)
if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) {
// Bubble up the revert if the call reverts.
returndatacopy(result, 0x00, returndatasize())
revert(result, returndatasize())
}
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
function tryExecute(address target, uint256 value, bytes calldata callData)
internal
returns (bool success, bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
calldatacopy(result, callData.offset, callData.length)
success := call(gas(), target, value, result, callData.length, codesize(), 0x00)
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
/// @dev Execute a delegatecall with `delegate` on this account.
function executeDelegatecall(address delegate, bytes calldata callData)
internal
returns (bool success, bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
calldatacopy(result, callData.offset, callData.length)
// Forwards the `data` to `delegate` via delegatecall.
success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00)
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
function decode(ExecMode mode)
internal
pure
returns (CallType _calltype, ExecType _execType, ExecModeSelector _modeSelector, ExecModePayload _modePayload)
{
assembly {
_calltype := mode
_execType := shl(8, mode)
_modeSelector := shl(48, mode)
_modePayload := shl(80, mode)
}
}
function encode(CallType callType, ExecType execType, ExecModeSelector mode, ExecModePayload payload)
internal
pure
returns (ExecMode)
{
return ExecMode.wrap(
bytes32(abi.encodePacked(callType, execType, bytes4(0), ExecModeSelector.unwrap(mode), payload))
);
}
function encodeSimpleBatch() internal pure returns (ExecMode mode) {
mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00));
}
function encodeSimpleSingle() internal pure returns (ExecMode mode) {
mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00));
}
function getCallType(ExecMode mode) internal pure returns (CallType calltype) {
assembly {
calltype := mode
}
}
function decodeBatch(bytes calldata callData) internal pure returns (Execution[] calldata executionBatch) {
/*
* Batch Call Calldata Layout
* Offset (in bytes) | Length (in bytes) | Contents
* 0x0 | 0x4 | bytes4 function selector
* 0x4 | - |
abi.encode(IERC7579Execution.Execution[])
*/
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
let dataPointer := add(callData.offset, calldataload(callData.offset))
// Extract the ERC7579 Executions
executionBatch.offset := add(dataPointer, 32)
executionBatch.length := calldataload(dataPointer)
}
}
function encodeBatch(Execution[] memory executions) internal pure returns (bytes memory callData) {
callData = abi.encode(executions);
}
function decodeSingle(bytes calldata executionCalldata)
internal
pure
returns (address target, uint256 value, bytes calldata callData)
{
target = address(bytes20(executionCalldata[0:20]));
value = uint256(bytes32(executionCalldata[20:52]));
callData = executionCalldata[52:];
}
function encodeSingle(address target, uint256 value, bytes memory callData)
internal
pure
returns (bytes memory userOpCalldata)
{
userOpCalldata = abi.encodePacked(target, value, callData);
}
function doFallback2771Static(address fallbackHandler) internal view returns (bool success, bytes memory result) {
assembly {
function allocate(length) -> pos {
pos := mload(0x40)
mstore(0x40, add(pos, length))
}
let calldataPtr := allocate(calldatasize())
calldatacopy(calldataPtr, 0, calldatasize())
// The msg.sender address is shifted to the left by 12 bytes to remove the padding
// Then the address without padding is stored right after the calldata
let senderPtr := allocate(20)
mstore(senderPtr, shl(96, caller()))
// Add 20 bytes for the address appended add the end
success := staticcall(gas(), fallbackHandler, calldataPtr, add(calldatasize(), 20), 0, 0)
result := mload(0x40)
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
function doFallback2771Call(address target) internal returns (bool success, bytes memory result) {
assembly {
function allocate(length) -> pos {
pos := mload(0x40)
mstore(0x40, add(pos, length))
}
let calldataPtr := allocate(calldatasize())
calldatacopy(calldataPtr, 0, calldatasize())
// The msg.sender address is shifted to the left by 12 bytes to remove the padding
// Then the address without padding is stored right after the calldata
let senderPtr := allocate(20)
mstore(senderPtr, shl(96, caller()))
// Add 20 bytes for the address appended add the end
success := call(gas(), target, 0, calldataPtr, add(calldatasize(), 20), 0, 0)
result := mload(0x40)
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {CallType, ExecType, ExecModeSelector} from "./Types.sol";
import {PassFlag, ValidationMode, ValidationType} from "./Types.sol";
import {ValidationData} from "./Types.sol";
// --- ERC7579 calltypes ---
// Default CallType
CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);
// Batched CallType
CallType constant CALLTYPE_BATCH = CallType.wrap(0x01);
CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);
// @dev Implementing delegatecall is OPTIONAL!
// implement delegatecall with extreme care.
CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);
// --- ERC7579 exectypes ---
// @dev default behavior is to revert on failure
// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure
// Since this is value 0x00, no additional encoding is required for simple accounts
ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
// @dev account may elect to change execution behavior. For example "try exec" / "allow fail"
ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);
// --- ERC7579 mode selector ---
ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000));
// --- Kernel permission skip flags ---
PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001);
PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002);
// --- Kernel validation modes ---
ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00);
ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01);
ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02);
// --- Kernel validation types ---
ValidationType constant VALIDATION_TYPE_ROOT = ValidationType.wrap(0x00);
ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01);
ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02);
// --- storage slots ---
// bytes32(uint256(keccak256('kernel.v3.selector')) - 1)
bytes32 constant SELECTOR_MANAGER_STORAGE_SLOT = 0x7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b;
// bytes32(uint256(keccak256('kernel.v3.executor')) - 1)
bytes32 constant EXECUTOR_MANAGER_STORAGE_SLOT = 0x1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b86;
// bytes32(uint256(keccak256('kernel.v3.hook')) - 1)
bytes32 constant HOOK_MANAGER_STORAGE_SLOT = 0x4605d5f70bb605094b2e761eccdc27bed9a362d8612792676bf3fb9b12832ffc;
// bytes32(uint256(keccak256('kernel.v3.validation')) - 1)
bytes32 constant VALIDATION_MANAGER_STORAGE_SLOT = 0x7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f;
bytes32 constant ERC1967_IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
// --- Kernel validation nonce incremental size limit ---
uint32 constant MAX_NONCE_INCREMENT_SIZE = 10;
// -- EIP712 type hash ---
bytes32 constant ENABLE_TYPE_HASH = 0xb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c505;
bytes32 constant KERNEL_WRAPPER_TYPE_HASH = 0x1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c83;
// --- ERC constants ---
// ERC4337 constants
uint256 constant SIG_VALIDATION_FAILED_UINT = 1;
uint256 constant SIG_VALIDATION_SUCCESS_UINT = 0;
ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT);
// ERC-1271 constants
bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e;
bytes4 constant ERC1271_INVALID = 0xffffffff;
uint256 constant MODULE_TYPE_VALIDATOR = 1;
uint256 constant MODULE_TYPE_EXECUTOR = 2;
uint256 constant MODULE_TYPE_FALLBACK = 3;
uint256 constant MODULE_TYPE_HOOK = 4;
uint256 constant MODULE_TYPE_POLICY = 5;
uint256 constant MODULE_TYPE_SIGNER = 6;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
// Custom type for improved developer experience
type ExecMode is bytes32;
type CallType is bytes1;
type ExecType is bytes1;
type ExecModeSelector is bytes4;
type ExecModePayload is bytes22;
using {eqModeSelector as ==} for ExecModeSelector global;
using {eqCallType as ==} for CallType global;
using {notEqCallType as !=} for CallType global;
using {eqExecType as ==} for ExecType global;
function eqCallType(CallType a, CallType b) pure returns (bool) {
return CallType.unwrap(a) == CallType.unwrap(b);
}
function notEqCallType(CallType a, CallType b) pure returns (bool) {
return CallType.unwrap(a) != CallType.unwrap(b);
}
function eqExecType(ExecType a, ExecType b) pure returns (bool) {
return ExecType.unwrap(a) == ExecType.unwrap(b);
}
function eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) {
return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b);
}
type ValidationMode is bytes1;
type ValidationId is bytes21;
type ValidationType is bytes1;
type PermissionId is bytes4;
type PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address
type PassFlag is bytes2;
using {vModeEqual as ==} for ValidationMode global;
using {vTypeEqual as ==} for ValidationType global;
using {vIdentifierEqual as ==} for ValidationId global;
using {vModeNotEqual as !=} for ValidationMode global;
using {vTypeNotEqual as !=} for ValidationType global;
using {vIdentifierNotEqual as !=} for ValidationId global;
// nonce = uint192(key) + nonce
// key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey
// key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000
// key = 0x00 + 0x01 + 0x1234...ff + 0x0000
// key = 0x00 + 0x02 + ( ) + 0x000
function vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) {
return ValidationMode.unwrap(a) == ValidationMode.unwrap(b);
}
function vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) {
return ValidationMode.unwrap(a) != ValidationMode.unwrap(b);
}
function vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) {
return ValidationType.unwrap(a) == ValidationType.unwrap(b);
}
function vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) {
return ValidationType.unwrap(a) != ValidationType.unwrap(b);
}
function vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) {
return ValidationId.unwrap(a) == ValidationId.unwrap(b);
}
function vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) {
return ValidationId.unwrap(a) != ValidationId.unwrap(b);
}
type ValidationData is uint256;
type ValidAfter is uint48;
type ValidUntil is uint48;
function getValidationResult(ValidationData validationData) pure returns (address result) {
assembly {
result := validationData
}
}
function packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) {
return uint256(ValidAfter.unwrap(validAfter)) << 208 | uint256(ValidUntil.unwrap(validUntil)) << 160;
}
function parseValidationData(uint256 validationData)
pure
returns (ValidAfter validAfter, ValidUntil validUntil, address result)
{
assembly {
result := validationData
validUntil := and(shr(160, validationData), 0xffffffffffff)
switch iszero(validUntil)
case 1 { validUntil := 0xffffffffffff }
validAfter := shr(208, validationData)
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.5;
/**
* 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: GPL-3.0
pragma solidity >=0.7.5;
import "./PackedUserOperation.sol";
/**
* Aggregated Signatures validator.
*/
interface IAggregator {
/**
* Validate aggregated signature.
* Revert if the aggregated signature does not match the given list of operations.
* @param userOps - Array of UserOperations to validate the signature for.
* @param signature - The aggregated signature.
*/
function validateSignatures(PackedUserOperation[] calldata userOps, bytes calldata signature) external view;
/**
* Validate 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 perform this aggregation.
* @param userOps - 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: GPL-3.0
pragma solidity >=0.7.5;
interface INonceManager {
/**
* Return the next nonce for this sender.
* Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop)
* But UserOp with different keys can come with arbitrary order.
*
* @param sender the account address
* @param key the high 192 bit of the nonce
* @return nonce a full nonce to pass for next UserOp with this sender.
*/
function getNonce(address sender, uint192 key) external view returns (uint256 nonce);
/**
* Manually increment the nonce of the sender.
* This method is exposed just for completeness..
* Account does NOT need to call it, neither during validation, nor elsewhere,
* as the EntryPoint will update the nonce regardless.
* Possible use-case is call it with various keys to "initialize" their nonces to one, so that future
* UserOperations will not pay extra for the first transaction with a given key.
*/
function incrementNonce(uint192 key) external;
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.7.6;
library ExcessivelySafeCall {
uint256 constant LOW_28_MASK =
0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @notice Use when you _really_ really _really_ don't trust the called
/// contract. This prevents the called contract from causing reversion of
/// the caller in as many ways as we can.
/// @dev The main difference between this and a solidity low-level call is
/// that we limit the number of bytes that the callee can cause to be
/// copied to caller memory. This prevents stupid things like malicious
/// contracts returning 10,000,000 bytes causing a local OOG when copying
/// to memory.
/// @param _target The address to call
/// @param _gas The amount of gas to forward to the remote contract
/// @param _value The value in wei to send to the remote contract
/// @param _maxCopy The maximum number of bytes of returndata to copy
/// to memory.
/// @param _calldata The data to send to the remote contract
/// @return success and returndata, as `.call()`. Returndata is capped to
/// `_maxCopy` bytes.
function excessivelySafeCall(
address _target,
uint256 _gas,
uint256 _value,
uint16 _maxCopy,
bytes memory _calldata
) internal returns (bool, bytes memory) {
// set up for assembly call
uint256 _toCopy;
bool _success;
bytes memory _returnData = new bytes(_maxCopy);
// dispatch message to recipient
// by assembly calling "handle" function
// we call via assembly to avoid memcopying a very large returndata
// returned by a malicious contract
assembly {
_success := call(
_gas, // gas
_target, // recipient
_value, // ether value
add(_calldata, 0x20), // inloc
mload(_calldata), // inlen
0, // outloc
0 // outlen
)
// limit our copy to 256 bytes
_toCopy := returndatasize()
if gt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
// Store the length of the copied bytes
mstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
/// @notice Use when you _really_ really _really_ don't trust the called
/// contract. This prevents the called contract from causing reversion of
/// the caller in as many ways as we can.
/// @dev The main difference between this and a solidity low-level call is
/// that we limit the number of bytes that the callee can cause to be
/// copied to caller memory. This prevents stupid things like malicious
/// contracts returning 10,000,000 bytes causing a local OOG when copying
/// to memory.
/// @param _target The address to call
/// @param _gas The amount of gas to forward to the remote contract
/// @param _maxCopy The maximum number of bytes of returndata to copy
/// to memory.
/// @param _calldata The data to send to the remote contract
/// @return success and returndata, as `.call()`. Returndata is capped to
/// `_maxCopy` bytes.
function excessivelySafeStaticCall(
address _target,
uint256 _gas,
uint16 _maxCopy,
bytes memory _calldata
) internal view returns (bool, bytes memory) {
// set up for assembly call
uint256 _toCopy;
bool _success;
bytes memory _returnData = new bytes(_maxCopy);
// dispatch message to recipient
// by assembly calling "handle" function
// we call via assembly to avoid memcopying a very large returndata
// returned by a malicious contract
assembly {
_success := staticcall(
_gas, // gas
_target, // recipient
add(_calldata, 0x20), // inloc
mload(_calldata), // inlen
0, // outloc
0 // outlen
)
// limit our copy to 256 bytes
_toCopy := returndatasize()
if gt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
// Store the length of the copied bytes
mstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
/**
* @notice Swaps function selectors in encoded contract calls
* @dev Allows reuse of encoded calldata for functions with identical
* argument types but different names. It simply swaps out the first 4 bytes
* for the new selector. This function modifies memory in place, and should
* only be used with caution.
* @param _newSelector The new 4-byte selector
* @param _buf The encoded contract args
*/
function swapSelector(bytes4 _newSelector, bytes memory _buf)
internal
pure
{
require(_buf.length >= 4);
uint256 _mask = LOW_28_MASK;
assembly {
// load the first word of
let _word := mload(add(_buf, 0x20))
// mask out the top 4 bytes
// /x
_word := and(_word, _mask)
_word := or(_newSelector, _word)
mstore(add(_buf, 0x20), _word)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IValidator, IPolicy} from "../interfaces/IERC7579Modules.sol";
import {PassFlag, ValidationType, ValidationId, ValidationMode, PolicyData, PermissionId} from "../types/Types.sol";
import {VALIDATION_TYPE_PERMISSION} from "../types/Constants.sol";
library ValidatorLib {
function encodeFlag(bool skipUserOp, bool skipSignature) internal pure returns (PassFlag flag) {
assembly {
if skipUserOp { flag := 0x0001000000000000000000000000000000000000000000000000000000000000 }
if skipSignature { flag := or(flag, 0x0002000000000000000000000000000000000000000000000000000000000000) }
}
}
function encodePolicyData(bool skipUserOp, bool skipSig, address policy) internal pure returns (PolicyData data) {
assembly {
if skipUserOp { data := 0x0001000000000000000000000000000000000000000000000000000000000000 }
if skipSig { data := or(data, 0x0002000000000000000000000000000000000000000000000000000000000000) }
data := or(data, shl(80, policy))
}
}
function encodePermissionAsNonce(bytes1 mode, bytes4 permissionId, uint16 nonceKey, uint64 nonce)
internal
pure
returns (uint256 res)
{
return encodeAsNonce(
mode, ValidationType.unwrap(VALIDATION_TYPE_PERMISSION), bytes20(permissionId), nonceKey, nonce
);
}
function encodeAsNonce(bytes1 mode, bytes1 vType, bytes20 ValidationIdWithoutType, uint16 nonceKey, uint64 nonce)
internal
pure
returns (uint256 res)
{
assembly {
res := nonce
res := or(res, shl(64, nonceKey))
res := or(res, shr(16, ValidationIdWithoutType))
res := or(res, shr(8, vType))
res := or(res, mode)
}
}
function encodeAsNonceKey(bytes1 mode, bytes1 vType, bytes20 ValidationIdWithoutType, uint16 nonceKey)
internal
pure
returns (uint192 res)
{
assembly {
res := or(nonceKey, shr(80, ValidationIdWithoutType))
res := or(res, shr(72, vType))
res := or(res, shr(64, mode))
}
}
function decodeNonce(uint256 nonce)
internal
pure
returns (ValidationMode mode, ValidationType vType, ValidationId identifier)
{
// 2bytes mode (1byte currentMode, 1byte type)
// 21bytes identifier
// 1byte mode | 1byte type | 20bytes identifierWithoutType | 2byte nonceKey | 8byte nonce == 32bytes
assembly {
mode := nonce
vType := shl(8, nonce)
identifier := shl(8, nonce)
switch shr(248, identifier)
case 0x0000000000000000000000000000000000000000000000000000000000000002 {
identifier := and(identifier, 0xffffffffff000000000000000000000000000000000000000000000000000000)
}
}
}
function decodeSignature(bytes calldata signature) internal pure returns (ValidationId vId, bytes calldata sig) {
assembly {
vId := calldataload(signature.offset)
switch shr(248, vId)
case 0 {
// sudo mode
vId := 0x00
sig.offset := add(signature.offset, 1)
sig.length := sub(signature.length, 1)
}
case 1 {
// validator mode
sig.offset := add(signature.offset, 21)
sig.length := sub(signature.length, 21)
}
case 2 {
vId := and(vId, 0xffffffffff000000000000000000000000000000000000000000000000000000)
sig.offset := add(signature.offset, 5)
sig.length := sub(signature.length, 5)
}
default {
revert(0x00, 0x00)
}
}
}
function decodePolicyData(PolicyData data) internal pure returns (PassFlag flag, IPolicy policy) {
assembly {
flag := data
policy := shr(80, data)
}
}
function validatorToIdentifier(IValidator validator) internal pure returns (ValidationId vId) {
assembly {
vId := 0x0100000000000000000000000000000000000000000000000000000000000000
vId := or(vId, shl(88, validator))
}
}
function getType(ValidationId validator) internal pure returns (ValidationType vType) {
assembly {
vType := validator
}
}
function getValidator(ValidationId validator) internal pure returns (IValidator v) {
assembly {
v := shr(88, validator)
}
}
function getPermissionId(ValidationId validator) internal pure returns (PermissionId id) {
assembly {
id := shl(8, validator)
}
}
function permissionToIdentifier(PermissionId permissionId) internal pure returns (ValidationId vId) {
assembly {
vId := 0x0200000000000000000000000000000000000000000000000000000000000000
vId := or(vId, shr(8, permissionId))
}
}
function getPolicy(PolicyData data) internal pure returns (IPolicy vId) {
assembly {
vId := shr(80, data)
}
}
function getPermissionSkip(PolicyData data) internal pure returns (PassFlag flag) {
assembly {
flag := data
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {SIG_VALIDATION_FAILED_UINT} from "../types/Constants.sol";
import {ValidationData, getValidationResult} from "../types/Types.sol";
function _intersectValidationData(ValidationData a, ValidationData b) pure returns (ValidationData validationData) {
assembly {
// xor(a,b) == shows only matching bits
// and(xor(a,b), 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff) == filters out the validAfter and validUntil bits
// if the result is not zero, then aggregator part is not matching
// validCase :
// a == 0 || b == 0 || xor(a,b) == 0
// invalidCase :
// a mul b != 0 && xor(a,b) != 0
let sum := shl(96, add(a, b))
switch or(
iszero(and(xor(a, b), 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff)),
or(eq(sum, shl(96, a)), eq(sum, shl(96, b)))
)
case 1 {
validationData := and(or(a, b), 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff)
// validAfter
let a_vd := and(0xffffffffffff0000000000000000000000000000000000000000000000000000, a)
let b_vd := and(0xffffffffffff0000000000000000000000000000000000000000000000000000, b)
validationData := or(validationData, xor(a_vd, mul(xor(a_vd, b_vd), gt(b_vd, a_vd))))
// validUntil
a_vd := and(0x000000000000ffffffffffff0000000000000000000000000000000000000000, a)
if iszero(a_vd) { a_vd := 0x000000000000ffffffffffff0000000000000000000000000000000000000000 }
b_vd := and(0x000000000000ffffffffffff0000000000000000000000000000000000000000, b)
if iszero(b_vd) { b_vd := 0x000000000000ffffffffffff0000000000000000000000000000000000000000 }
let until := xor(a_vd, mul(xor(a_vd, b_vd), lt(b_vd, a_vd)))
if iszero(until) { until := 0x000000000000ffffffffffff0000000000000000000000000000000000000000 }
validationData := or(validationData, until)
}
default { validationData := SIG_VALIDATION_FAILED_UINT }
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
struct Execution {
address target;
uint256 value;
bytes callData;
}{
"remappings": [
"ExcessivelySafeCall/=src/lib/ExcessivelySafeCall/src/",
"ds-test/=src/lib/forge-std/lib/ds-test/src/",
"forge-std/=src/lib/forge-std/src/",
"solady/=src/lib/solady/src/",
"lib/=src/lib/",
"src/types/=src/types/",
"src/core/=src/core/",
"src/utils/=src/utils/",
"src/Kernel.sol/=src/Kernel.sol/",
"src/interfaces/=src/interfaces/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IEntryPoint","name":"_entrypoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EnableNotApproved","type":"error"},{"inputs":[],"name":"ExecutionReverted","type":"error"},{"inputs":[],"name":"InvalidCallType","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidExecutor","type":"error"},{"inputs":[],"name":"InvalidFallback","type":"error"},{"inputs":[],"name":"InvalidMode","type":"error"},{"inputs":[],"name":"InvalidModuleType","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSelector","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidValidationType","type":"error"},{"inputs":[],"name":"InvalidValidator","type":"error"},{"inputs":[],"name":"NonceInvalidationError","type":"error"},{"inputs":[],"name":"NotSupportedCallType","type":"error"},{"inputs":[],"name":"OnlyExecuteUserOp","type":"error"},{"inputs":[],"name":"PermissionDataLengthMismatch","type":"error"},{"inputs":[],"name":"PermissionNotAlllowedForSignature","type":"error"},{"inputs":[],"name":"PermissionNotAlllowedForUserOp","type":"error"},{"inputs":[],"name":"PolicyDataTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"PolicyFailed","type":"error"},{"inputs":[],"name":"PolicySignatureOrderError","type":"error"},{"inputs":[],"name":"RootValidatorCannotBeRemoved","type":"error"},{"inputs":[],"name":"SignerPrefixNotPresent","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"ModuleInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"module","type":"address"},{"indexed":false,"internalType":"bool","name":"result","type":"bool"}],"name":"ModuleUninstallResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"moduleTypeId","type":"uint256"},{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"ModuleUninstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"NonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"PermissionId","name":"permission","type":"bytes4"},{"indexed":false,"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"PermissionInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"PermissionId","name":"permission","type":"bytes4"}],"name":"PermissionUninstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"ValidationId","name":"rootValidator","type":"bytes21"}],"name":"RootValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"ValidationId","name":"vId","type":"bytes21"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"SelectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"batchExecutionindex","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"result","type":"bytes"}],"name":"TryExecuteUnsuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IValidator","name":"validator","type":"address"},{"indexed":false,"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"ValidatorInstalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IValidator","name":"validator","type":"address"}],"name":"ValidatorUninstalled","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"accountId","outputs":[{"internalType":"string","name":"accountImplementationId","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"currentNonce","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"entrypoint","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ExecMode","name":"execMode","type":"bytes32"},{"internalType":"bytes","name":"executionCalldata","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ExecMode","name":"execMode","type":"bytes32"},{"internalType":"bytes","name":"executionCalldata","type":"bytes"}],"name":"executeFromExecutor","outputs":[{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"payable","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"}],"name":"executeUserOp","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IExecutor","name":"executor","type":"address"}],"name":"executorConfig","outputs":[{"components":[{"internalType":"contract IHook","name":"hook","type":"address"}],"internalType":"struct ExecutorManager.ExecutorConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"_rootValidator","type":"bytes21"},{"internalType":"contract IHook","name":"hook","type":"address"},{"internalType":"bytes","name":"validatorData","type":"bytes"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"initData","type":"bytes"}],"name":"installModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId[]","name":"vIds","type":"bytes21[]"},{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"contract IHook","name":"hook","type":"address"}],"internalType":"struct ValidationManager.ValidationConfig[]","name":"configs","type":"tuple[]"},{"internalType":"bytes[]","name":"validationData","type":"bytes[]"},{"internalType":"bytes[]","name":"hookData","type":"bytes[]"}],"name":"installValidations","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"nonce","type":"uint32"}],"name":"invalidateNonce","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"vId","type":"bytes21"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"isAllowedSelector","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"additionalContext","type":"bytes"}],"name":"isModuleInstalled","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":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PermissionId","name":"pId","type":"bytes4"}],"name":"permissionConfig","outputs":[{"components":[{"internalType":"PassFlag","name":"permissionFlag","type":"bytes2"},{"internalType":"contract ISigner","name":"signer","type":"address"},{"internalType":"PolicyData[]","name":"policyData","type":"bytes22[]"}],"internalType":"struct ValidationManager.PermissionConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootValidator","outputs":[{"internalType":"ValidationId","name":"","type":"bytes21"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"selectorConfig","outputs":[{"components":[{"internalType":"contract IHook","name":"hook","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"CallType","name":"callType","type":"bytes1"}],"internalType":"struct SelectorManager.SelectorConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"ExecMode","name":"mode","type":"bytes32"}],"name":"supportsExecutionMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleTypeId","type":"uint256"}],"name":"supportsModule","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleType","type":"uint256"},{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes","name":"deInitData","type":"bytes"}],"name":"uninstallModule","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"vId","type":"bytes21"},{"internalType":"bytes","name":"deinitData","type":"bytes"},{"internalType":"bytes","name":"hookDeinitData","type":"bytes"}],"name":"uninstallValidation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"validNonceFrom","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":"ValidationData","name":"validationData","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"ValidationId","name":"vId","type":"bytes21"}],"name":"validationConfig","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"contract IHook","name":"hook","type":"address"}],"internalType":"struct ValidationManager.ValidationConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610140346200020957601f6200520c38819003918201601f191683019291906001600160401b038411838510176200020e5781602092849260409687528339810103126200020957516001600160a01b03811681036200020957306080524660a05260a08251620000708162000224565b60068152600a602082016512d95c9b995b60d21b815260208651620000958162000224565b838152019269302e332e302d6265746160b01b845251902091208160c0528060e0528451917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f835260208301528482015246606082015230608082015220916101009283526101209182528051602081019063deadbeef60e01b825260048152620001208162000224565b5190516001600160581b031991828216919060158110620001f3575b505090507f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f9060581c60018060a81b03198254161790555190614fcb928362000241843960805183614093015260a051836140b6015260c05183614128015260e0518361414e0152518261407201525181818161047a0152818161079e0152818161095401528181610cec01528181611053015281816111c2015281816112220152818161174a015281816118b901526121180152f35b8391925060150360031b1b16168038806200013c565b600080fd5b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b038211176200020e5760405256fe6080604052600436101561001d575b366128595761001b612828565b005b60003560e01c8063112d3a7d146101bd57806312af322c146101b85780631626ba7e146101b357806319822f7c146101ae5780631f1b92e3146101a95780633659cfe6146101a457806357b3a5f41461019f5780636e6fa0c61461019a578063721e67f41461019557806384b0196e146101905780638dd7712f1461018b57806390ef8862146101865780639198bdf5146101815780639517e29f1461017c5780639cfd7cff14610177578063a65d69d414610172578063a71763a81461016d578063adb610a314610168578063b8afe17d14610163578063c3e589781461015e578063d03c791414610159578063d691c96414610154578063e6f3d50a1461014f578063e9ae5c531461014a578063f1f7f0f9146101455763f2dc691d0361000e576119ec565b6119b4565b611888565b6116cf565b6115c0565b61150f565b611433565b611351565b61131d565b6111f1565b6111ac565b61114e565b611022565b610f1b565b610dca565b610cb6565b610c14565b610b68565b610b0b565b610a5d565b610914565b61075c565b61043c565b6103dc565b610289565b610251565b6001600160a01b038116036101d357565b600080fd5b35906101e3826101c2565b565b9181601f840112156101d3578235916001600160401b0383116101d357602083818601950101116101d357565b60606003198201126101d3576004359160243561022e816101c2565b91604435906001600160401b0382116101d35761024d916004016101e5565b9091565b346101d357602061026d61026436610212565b92919091611bec565b6040519015158152f35b6001600160581b03198116036101d357565b346101d35760803660031901126101d3576004356102a681610277565b6024356102b2816101c2565b6001600160401b03906044358281116101d3576102d39036906004016101e5565b90926064359081116101d3576102ed9036906004016101e5565b9390926001600160581b031961032d81610326610319600080516020614fab8339815191525460581b90565b6001600160581b03191690565b1615611cb6565b8616156103ca576001600160f81b03198616600160f81b81141590816103bb575b506103a9578561036061001b976129b9565b61038161036b610eea565b60018152925b6001600160a01b03166020840152565b600080516020614fab833981519152805463ffffffff60a81b1916600160a81b179055612a14565b6040516361c4e91b60e11b8152600490fd5b600160f91b141590503861034e565b604051631a0a9b9f60e21b8152600490fd5b346101d35760403660031901126101d3576024356001600160401b0381116101d35761041a61041160209236906004016101e5565b90600435611dd1565b6040516001600160e01b03199091168152f35b90816101209103126101d35790565b60603660031901126101d357600480356001600160401b0381116101d357610467903690830161042d565b60243590604435906001600160a01b03907f000000000000000000000000000000000000000000000000000000000000000082163303610727578084926104b16020830135612d80565b6001600160f81b0319909116159590939091866106fd575b90846104d59392612f65565b956104e76104e284611b7a565b611efe565b94159485806106bb575b6106aa57602001516001600160a01b031691821690811561069957600192610526610545926000526000602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b036105f8578261059a575b5050610589576105739250805b610577575b506040519081529081906020820190565b0390f35b3490349034903490335af15038610562565b604051631a0a9b9f60e21b81528390fd5b6105f192506105ed916105cf6105c96105c36105b86105e695611bb3565b936060810190611f2a565b90611a1b565b90611b4e565b63ffffffff60e01b16600052602052604060002090565b5460ff1690565b1590565b3880610550565b82919291610666575b50610655576105c3816060610617930190611f2a565b638dd7712f60e01b916001600160e01b03199161063391611b4e565b16036106445761057392508061055d565b60405163dbbb044b60e01b81528390fd5b604051631a0a9b9f60e21b81528490fd5b61069391506105e661067a6105ed92611bb3565b6105cf6105c961068d6060880188611f2a565b90611a0a565b38610601565b604051631a0a9b9f60e21b81528990fd5b604051633ab3447f60e11b81528990fd5b50805163ffffffff1663ffffffff6106f56106ec600080516020614fab8339815191525463ffffffff9060c81c1690565b63ffffffff1690565b9116106104f1565b9350906104d59161071d600080516020614fab8339815191525460581b90565b94909192506104c9565b6040516348f5c3ed60e01b81528590fd5b6004359063ffffffff821682036101d357565b359063ffffffff821682036101d357565b60203660031901126101d357610770610738565b61079261078c600080516020614fab8339815191525460581b90565b60581c90565b6001600160a01b0390337f0000000000000000000000000000000000000000000000000000000000000000831614158061090a575b156108ff5760405163ecd0596160e01b8152600480820152911690602081602481855afa908115610890576000916108d0575b50156108be5760405163d68f602560e01b8152916000838061082136343360048501611fed565b038183865af192831561089057600093610895575b506108409061310c565b803b156101d357604051635565eb9560e11b815291600091839182908490829061086d9060048301612029565b03925af180156108905761087d57005b8061088a61001b92610e44565b80610bc1565b611dc5565b6108409193506108b7903d806000833e6108af8183610ec9565b810190611f8f565b9290610836565b6040516348f5c3ed60e01b8152600490fd5b6108f2915060203d6020116108f8575b6108ea8183610ec9565b810190611f5c565b386107fa565b503d6108e0565b505061001b9061310c565b50303314156107c7565b60203660031901126101d35760043561092c816101c2565b61094861078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580610a41575b15610a365760405163ecd0596160e01b8152600480820152911690602081602481855afa90811561089057600091610a17575b50156108be5760405163d68f602560e01b815291600083806109d736343360048501611fed565b038183865af1928315610890576000936109f6575b5061084090612054565b610840919350610a10903d806000833e6108af8183610ec9565b92906109ec565b610a30915060203d6020116108f8576108ea8183610ec9565b386109b0565b505061001b90612054565b503033141561097d565b6001600160e01b03198116036101d357565b346101d35760203660031901126101d357610573610a9f600435610a8081610a4b565b600060408051610a8f81610e5c565b8281528260208201520152611cf8565b60405190610aac82610e5c565b80546001600160a01b0390811680845260019092015480821660208086019182526001600160f81b031960589390931b831660409687019081528651958652915190931692840192909252905116918101919091529081906060820190565b346101d35760403660031901126101d357602060ff610b5c600435610b2f81610277565b610b4460243591610b3f83610a4b565b611bb3565b9063ffffffff60e01b16600052602052604060002090565b54166040519015158152f35b346101d35760203660031901126101d3576020610b9e600435610b8a816101c2565b6000604051610b9881610e77565b52612992565b60405190610bab82610e77565b546001600160a01b031690819052604051908152f35b60009103126101d357565b60005b838110610bdf5750506000910152565b8181015183820152602001610bcf565b90602091610c0881518092818552858086019101610bcc565b601f01601f1916010190565b346101d35760003660031901126101d357610c63610c306131ec565b90604051928392600f60f81b8452610c5560209360e0602087015260e0860190610bef565b908482036040860152610bef565b90466060840152306080840152600060a084015282820360c0840152602060605192838152019160809160005b828110610c9f57505050500390f35b835185528695509381019392810192600101610c90565b60403660031901126101d3576004356001600160401b0381116101d357610ce190369060040161042d565b6001600160a01b03907f0000000000000000000000000000000000000000000000000000000000000000821633036108be576060906001610d3e610d316024356000526000602052604060002090565b546001600160a01b031690565b93841614159081610d9a575b610d65610d5e826060610d6c940190611f2a565b8091611a29565b9030613338565b92909115610d7d5761001b9361335f565b5091505015610d8857005b60405163f21e646b60e01b8152600490fd5b9150610d6c610d65610d5e610dc0610db8610d5e6060880188611f2a565b9034896132b6565b9492505050610d4a565b346101d35760003660031901126101d357602063ffffffff600080516020614fab8339815191525460c81c16604051908152f35b9181601f840112156101d3578235916001600160401b0383116101d3576020808501948460051b0101116101d357565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111610e5757604052565b610e2e565b606081019081106001600160401b03821117610e5757604052565b602081019081106001600160401b03821117610e5757604052565b604081019081106001600160401b03821117610e5757604052565b61012081019081106001600160401b03821117610e5757604052565b90601f801991011681019081106001600160401b03821117610e5757604052565b604051906101e382610e92565b604051906101e382610ead565b6001600160401b038111610e575760051b60200190565b60803660031901126101d3576001600160401b036004358181116101d357610f47903690600401610dfe565b906024358381116101d357366023820112156101d3578060040135610f6b81610f04565b91604091610f7c6040519485610ec9565b8084526020906024602086019160061b840101923684116101d357602401905b838210610fe45750505050506044358481116101d357610fc0903690600401610dfe565b916064359586116101d357610fdc61001b963690600401610dfe565b9590946120e9565b84823603126101d3578285918251610ffb81610e92565b6110048561074b565b815282850135611013816101c2565b83820152815201910190610f9c565b61102b36610212565b61104761078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580611144575b156111385760405163ecd0596160e01b815260048082015291169290602081602481875afa90811561089057600091611119575b50156108be5760405163d68f602560e01b815293600085806110d736343360048501611fed565b038183885af1948515610890576000956110f8575b506108409394956122a5565b610840949550611112903d806000833e6108af8183610ec9565b94936110ec565b611132915060203d6020116108f8576108ea8183610ec9565b386110b0565b50509161001b936122a5565b503033141561107c565b346101d35760003660031901126101d35761057360405161116e81610e92565b601b81527f6b65726e656c2e616476616e6365642e76302e332e302d6265746100000000006020820152604051918291602083526020830190610bef565b346101d35760003660031901126101d3576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b6111fa36610212565b61121661078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580611313575b156113075760405163ecd0596160e01b815260048082015291169290602081602481875afa908115610890576000916112e8575b50156108be5760405163d68f602560e01b815293600085806112a636343360048501611fed565b038183885af1948515610890576000956112c7575b50610840939495612584565b6108409495506112e1903d806000833e6108af8183610ec9565b94936112bb565b611301915060203d6020116108f8576108ea8183610ec9565b3861127f565b50509161001b93612584565b503033141561124b565b346101d35760003660031901126101d357602063ffffffff600080516020614fab8339815191525460a81c16604051908152f35b346101d35760203660031901126101d357604061138160043561137381610277565b61137b612720565b50611b7a565b602082519161138f83610e92565b5463ffffffff81169283815260018060a01b03928391019160201c168152835192835251166020820152f35b602080825282516001600160f01b03191681830152808301516001600160a01b03166040808401919091529092015160608083015280516080830181905260a090920192908101919060005b828110611415575050505090565b83516001600160501b03191685529381019392810192600101611407565b346101d3576020806003193601126101d35760043561145181610a4b565b611476604091606083805161146581610e5c565b600081526000878201520152611d30565b9080519161148383610e5c565b805460f081901b6001600160f01b031916845260101c6001600160a01b031684840152815160019182018054808352600091825286822083880197939490939092905b8282106114ed576105738888886114df818e0382610ec9565b8183015251918291826113bb565b845460501b6001600160501b03191689529788019793830193908301906114c6565b346101d35760203660031901126101d357602061026d600435612739565b9060406003198301126101d35760043591602435906001600160401b0382116101d35761024d916004016101e5565b6020808201906020835283518092526040830192602060408460051b8301019501936000915b8483106115925750505050505090565b90919293949584806115b0600193603f198682030187528a51610bef565b9801930193019194939290611582565b6115c93661152d565b916001600160a01b036115db33612992565b54169283156116bd57606090600185141593846116a6575b6115fd92936139ed565b91611611575b60405180610573848261155c565b60405161163381611625856020830161155c565b03601f198101835282610ec9565b833b156101d3576116839361166a6000809460405197889586948593635565eb9560e11b8552606060048601526064850190610bef565b6001602485015283810360031901604485015290610bef565b03925af1918215610890576105739215611603576116a090610e44565b38611603565b6115fd92506116b6363488613232565b92506115f3565b60405163710c949760e01b8152600490fd5b60603660031901126101d35760048035906116e982610277565b6001600160401b03916024358381116101d35761170990369084016101e5565b936044359081116101d35761172190369085016101e5565b9061173e61078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000000000000000000000000000000000000831614158061187e575b1561186e57169560405163ecd0596160e01b81526020818061179c8a8201906004602083019252565b03818b5afa9081156108905760009161184f575b501561183e5760405163d68f602560e01b815293600085806117d63634338d8501611fed565b0381838c5af19485156108905760009561181f575b506117f694956127fb565b823b156101d35761086d9260009283604051809681958294635565eb9560e11b84528301612029565b6117f69550611838903d806000833e6108af8183610ec9565b946117eb565b6040516348f5c3ed60e01b81528690fd5b611868915060203d6020116108f8576108ea8183610ec9565b386117b0565b50509261001b95929194506127fb565b5030331415611773565b6118913661152d565b6118ad61078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f000000000000000000000000000000000000000000000000000000000000000083161415806119aa575b1561199e5760405163ecd0596160e01b815260048082015291169190602081602481865afa9081156108905760009161197f575b50156108be5760405163d68f602560e01b8152926000848061193d36343360048501611fed565b038183875af19384156108905760009461195e575b50610840929394612810565b610840939450611978903d806000833e6108af8183610ec9565b9392611952565b611998915060203d6020116108f8576108ea8183610ec9565b38611916565b50509061001b92612810565b50303314156118e2565b346101d35760003660031901126101d3576020600080516020614fab8339815191525460581b604051906001600160581b0319168152f35b346101d35760203660031901126101d357602061026d60043561281b565b906008116101d35760040190600490565b906004116101d35790600490565b90929192836004116101d35783116101d357600401916003190190565b906018116101d35760040190601490565b906014116101d35790601490565b906020116101d35790602090565b90929192836001116101d35783116101d357600101916000190190565b90929192836014116101d35783116101d357601401916013190190565b906016116101d35790601690565b906016116101d35760020190601490565b90929192836016116101d35783116101d357601601916015190190565b906002116101d35790600290565b906009116101d35760010190600890565b90929192836009116101d35783116101d357600901916008190190565b90602c116101d35760180190601490565b909392938483116101d35784116101d3578101920390565b6001600160e01b03199035818116939260048110611b6b57505050565b60040360031b82901b16169150565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f850602052604060002090565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f851602052604060002090565b90929060018103611c3b57506001600160a01b0392611c359250611c25915060581b600160581b600160f81b0316600160f81b17611b7a565b5460201c6001600160a01b031690565b16151590565b60028103611c6e57506001600160a01b0392611c359250611c629150610d31908416612992565b6001600160a01b031690565b600303611cae57611c8f611c8a6105c9600193611c9d95611a1b565b611cf8565b01546001600160a01b031690565b6001600160a01b0390811691161490565b505050600090565b15611cbd57565b60405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606490fd5b63ffffffff60e01b166000527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b602052604060002090565b63ffffffff60e01b166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f852602052604060002090565b908160209103126101d35751611d7d81610a4b565b90565b908060209392818452848401376000828201840152601f01601f1916010190565b611d7d949260609260018060a01b0316825260208201528160408201520191611d80565b6040513d6000823e3d90fd5b91611ddb91612c05565b91906001600160f81b031980831615611edd575b6001600160a01b039081611e08611c62611c2587611b7a565b16156103ca578316600160f81b03611e8d57906020939291611e2c611e4a96612d37565b604051637aa8f17760e11b8152968795869485933360048601611da1565b039260581c165afa90811561089057600091611e64575090565b611d7d915060203d602011611e86575b611e7e8183610ec9565b810190611d68565b503d611e74565b509060081b92600160f11b611ebb611eae611ea787611d30565b5460f01b90565b6001600160f01b03191690565b16611ecb57611d7d933390612c86565b604051635b71057960e01b8152600490fd5b9150611ef8600080516020614fab8339815191525460581b90565b91611def565b90604051611f0b81610e92565b915463ffffffff81168352602090811c6001600160a01b031690830152565b903590601e19813603018212156101d357018035906001600160401b0382116101d3576020019181360383136101d357565b908160209103126101d3575180151581036101d35790565b6001600160401b038111610e5757601f01601f191660200190565b6020818303126101d3578051906001600160401b0382116101d3570181601f820112156101d3578051611fc181611f74565b92611fcf6040519485610ec9565b818452602082840101116101d357611d7d9160208085019101610bcc565b916080939160018060a01b03168352602083015260606040830152806060830152806000848401376000828201840152601f01601f1916010190565b61203d602092606083526060830190610bef565b906001838201526040818303910152600081520190565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8190556001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2565b906040516120b581610e5c565b82546001600160a01b039081168252600190930154928316602082015260589290921b6001600160f81b0319166040830152565b9592949193909461210c61078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f00000000000000000000000000000000000000000000000000000000000000008316141580612259575b156122495760405163ecd0596160e01b8152600480820152911695906020816024818a5afa9081156108905760009161222a575b50156108be5760405163d68f602560e01b8152966000888061219c36343360048501611fed565b0381838b5af197881561089057600098612209575b506121bd969798613428565b803b156101d357604051635565eb9560e11b81529160009183918290849082906121ea9060048301612029565b03925af18015610890576121fc575b50565b8061088a6101e392610e44565b6121bd979850612223903d806000833e6108af8183610ec9565b97966121b1565b612243915060203d6020116108f8576108ea8183610ec9565b38612175565b505091939092946101e396613428565b5030331415612141565b916020611d7d938181520191611d80565b6bffffffffffffffffffffffff19903581811693926014811061229657505050565b60140360031b82901b16169150565b9290916001840361234b576101e3935061230e6122f7611c626122f16122eb6122e4600080516020614fab8339815191525463ffffffff9060a81c1690565b9686611a57565b90612274565b60601c90565b610371612302610eea565b63ffffffff9095168552565b603480820135820160148181013595918301948482013590940190810135939201919060581b600160581b600160f81b0316600160f81b17612a14565b919092600281146000146123ad57509161239e6101e393612383611c626122f16122eb60148801358801966034890135890198611a57565b928391601482013591603401906001600160a01b03166136af565b603460148301359201906135e2565b9091906003810361242d5750612428611c626124186101e3958461241360186122f197013582016122f160388401358401996123ec6105c98787611a1b565b9061240d611c626123fd8989611a46565b6018880135976038019691612274565b91613496565b611a46565b6018860135956038019491612274565b6135e2565b9091906004810361246e57506001600160a01b031691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b600581036124ac57506001600160a01b031691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b6006036124e8576001600160a01b031691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b604051631092ef5760e11b8152600490fd5b6040519061250782610e77565b60008252565b35906020811061251b575090565b6000199060200360031b1b1690565b91906040519061253982610e77565b819360008352116101d35760206000910152565b92919261255982611f74565b916125676040519384610ec9565b8294818452818301116101d3578281602093846000960137010152565b929190600184036125ae576121f9935060581b600160581b600160f81b0316600160f81b176138a1565b600284036125c9576121f993506001600160a01b0316613857565b909190600384036125f857506121f9925080806125ec6105c96125f29486611a1b565b93611a29565b916137fd565b91926004810361267e57506121f99261264b91612624600080516020614fab8339815191525460581b90565b612630611c2582611b7a565b6001600160a01b03868116911614612651575b50369161254d565b9061374e565b61265d61267891611b7a565b8054640100000000600160c01b031916640100000000179055565b38612643565b600581036127015750600080516020614fab8339815191525460581b5b6126ae6126a88386611a65565b9061250d565b906001600160f81b03198116600160f91b146126d6575b50506121f99261264b91369161254d565b60081b6001600160e01b031916146126ef5738806126c5565b6040516313002bdd60e31b8152600490fd5b6006036124e857600080516020614fab8339815191525460581b61269b565b6040519061272d82610e92565b60006020838281520152565b61274d818060081b918160301b9160501b90565b929091600160f81b916001600160f81b0319919082168381141590816127f1575b816127e6575b816127d7575b506127cd57169081141590816127c3575b506127bc576001600160e01b0319166127b6576001600160501b0319166127b157600190565b600090565b50600090565b5050600090565b905015153861278b565b5050505050600090565b607f60f91b141590503861277a565b838114159150612774565b801515915061276e565b9161280b916101e39594936138a1565b613b57565b906121f992916139ed565b600711156127b157600190565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460408051338152346020820152a1565b6128766128716000356001600160e01b031916611cf8565b6120a8565b80516001600160a01b03908116918260008161289e57604051631cd4b64760e21b8152600490fd5b5060016060940361297c575b5060408101516001600160f81b03199081168061293257505060208101516001936128fb939290916128e4906001600160a01b0316613bb4565b9290929586939586935b516001600160a01b031690565b94851603612920575b505050501560001461291857602081519101fd5b602081519101f35b6129299361335f565b38828282612904565b9192910361296a5760208201516001936128fb93909161295c906001600160a01b03163690613311565b9290929586939586936128ee565b604051632d6a6bb760e01b8152600490fd5b61298b91935036903490613232565b91386128aa565b6001600160a01b03166000908152600080516020614f8b8339815191526020526040902090565b60207f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae8891600080516020614fab8339815191528160581c6001600160581b0360a81b825416179055604051906001600160581b0319168152a1565b9193909294612a2f612a2584611b7a565b5463ffffffff1690565b93600080516020614fab83398151915294612a52865463ffffffff9060a81c1690565b63ffffffff809281808416911614612bc7575b50506020820180516001600160a01b0397919291612a9291891615612bbe575b5460a81c63ffffffff1690565b81612aa46106ec865163ffffffff1690565b91161490811591612b94575b50612b82576128ee612aff92612ac587611b7a565b815181546020938401516001600160c01b031990911663ffffffff9290921691909117921b640100000000600160c01b0316919091179055565b91600185841603612b71575b5050506001600160f81b03198116600160f81b8103612b55575060581c1691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b909350600160f91b141590506103a9576101e39160081b613cf3565b612b7a926135e2565b388080612b0b565b604051633ab3447f60e11b8152600490fd5b9050612ba2612a2587611b7a565b90612bb46106ec855163ffffffff1690565b9116101538612ab0565b60018452612a85565b600080516020614fab833981519152805463ffffffff60a81b19166001939093019190911660a81b63ffffffff60a81b169190911790553881612a65565b9182358060f81c80600014612c4b5780600114612c3e57600214612c2857600080fd5b6001600160d81b03191692600501916004190190565b5092601501916014190190565b5050600160009301916000190190565b9092608092611d7d9694835260018060a01b0316602083015260408201528160608201520191611d80565b909192612ca594612c9991858585613f53565b94929391969096614047565b509065ffffffffffff8091164210918215612d2b575b5050612d1857612cf9612ccf602096612d37565b60405163392dffaf60e01b8152978896879586959193916001600160e01b03191660048701612c5b565b03916001600160a01b03165afa90811561089057600091611e64575090565b506001600160e01b031995945050505050565b16421190503880612cbb565b611d7d9060405160208101917f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c838352604082015260408152612d7881610e5c565b519020614070565b90818060081b9160ff839260f01c16600214612d9857565b6001600160d81b031983169150565b9080601f830112156101d357816020611d7d9335910161254d565b9190610120838203126101d357612dd7610ef7565b92612de1816101d8565b8452602081013560208501526040810135916001600160401b03928381116101d35781612e0f918401612da7565b604086015260608201358381116101d35781612e2c918401612da7565b60608601526080820135608086015260a082013560a086015260c082013560c086015260e08201358381116101d35781612e67918401612da7565b60e086015261010092838301359081116101d357612e859201612da7565b90830152565b908160209103126101d3575190565b80516001600160a01b03168252611d7d9190612f18612ee8612ed661012060208501516020870152604085015190806040880152860190610bef565b60608401518582036060870152610bef565b6080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152610bef565b916101008092015191818403910152610bef565b939291612f49906040928652606060208701526060860190612e9a565b930152565b929190612f49602091604086526040860190612e9a565b929092600092612f753682612dc2565b916101009182810191612f888383611f2a565b90949093600160f81b936001600160f81b031993841685146130d1575b505050871603613032575050604051639700320360e01b815293602092859283916000918391612fd89160048401612f4e565b039260581c6001600160a01b03165af190811561089057611d7d92600092613001575b5061456e565b61302491925060203d60201161302b575b61301c8183610ec9565b810190612e8b565b9038612ffb565b503d613012565b909460081b93909291600160f01b61304f611eae611ea788611d30565b166130bf57600061307061306a60209661309a99858a61436e565b9461456e565b604051630ccab7a160e01b8152979096889586948593926001600160e01b03191660048501612f2c565b03926001600160a01b03165af190811561089057611d7d92600092613001575061456e565b6040516314b9743f60e01b8152600490fd5b909195506130ed9398506130e6929450611f2a565b9088614184565b969192909361310085899599369161254d565b90860152388080612fa5565b600080516020614fab83398151915280549163ffffffff92600a848260a81c1601908482116131d65782851691851682116131c45760c81c84161015612b8257600080516020614fab833981519152805463ffffffff60c81b191660c89290921b63ffffffff60c81b1691909117905554818160c81c1691829160a81c16106131925750565b600080516020614fab833981519152805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b60405163e60fd64760e01b8152600490fd5b634e487b7160e01b600052601160045260246000fd5b6040516131f881610e92565b600681526512d95c9b995b60d21b60208201529060405161321881610e92565b600a815269302e332e302d6265746160b01b602082015290565b60405163d68f602560e01b815233600482015260248101929092526060604483015260648201839052600092839183918290849060849083908084838501378181018301849052601f01601f191681010301926001600160a01b03165af19182156108905780926132a257505090565b611d7d92503d8091833e6108af8183610ec9565b600092836132dd95936040519687958694859363d68f602560e01b85523360048601611da1565b03926001600160a01b03165af1908115610890576000916132fc575090565b611d7d91503d806000833e6108af8183610ec9565b60009060405192808385378338925af4913d82523d6000602084013e60203d830101604052565b60009192806040519485378338925af4913d82523d6000602084013e60203d830101604052565b919290916001600160a01b0316803b156101d3576133a2600080946133bb60405197889687958694635565eb9560e11b8652606060048701526064860190610bef565b9115156024850152838203600319016044850152610bef565b03925af18015610890576133cc5750565b6101e390610e44565b634e487b7160e01b600052603260045260246000fd5b8051156133f85760200190565b6133d5565b80518210156133f85760209160051b010190565b908210156133f85761024d9160051b810190611f2a565b96959192939694909460005b86811061344657505050505050509050565b806134878a60019360051b85013561345d81610277565b6134738461346b818c6133fd565b51938c613411565b9061347f868b8b613411565b949093612a14565b01613434565b90156133f85790565b6001600160a01b039391929190848316156135d9575b6134b590611cf8565b946134e16134d46134c6838561348d565b356001600160f81b03191690565b6001600160f81b03191690565b946001600160f81b0319808716806135ba575050908061350392861693611a73565b823b156101d35761352e92600092836040518096819582946306d61fe760e41b845260048401612263565b03925af19485156108905761356a61358a936001936101e3986135a7575b505b82546001600160a01b0319166001600160a01b03909116178255565b0180546001600160a01b0319166001600160a01b03909316929092178255565b805460ff60a01b191660589290921c60ff60a01b16919091179055565b8061088a6135b492610e44565b3861354c565b92509250509491940361296a57600161358a9161356a6101e39661354e565b600192506134ac565b6001600160a01b031691821580156136a5575b6136a05760405163d60b347f60e01b8152306004820152602081602481875afa90811561089057600091613681575b501561364c576001600160f81b0319806136416134c6848661348d565b161461364c57505050565b8061365692611a73565b823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b61369a915060203d6020116108f8576108ea8183610ec9565b38613624565b505050565b50600183146135f5565b919392916001600160a01b039081841615613734575b166000818152600080516020614f8b8339815191526020526040812080546001600160a01b0319166001600160a01b0390951694909417909355803b15613730576133bb9394836040518096819582946306d61fe760e41b8452602060048501526024840191611d80565b8280fd5b600193506136c5565b906020611d7d928181520190610bef565b60407f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3919392935a8251956137ae876137a06020820193638a91b0e360e01b8552602060248401526044830190610bef565b03601f198101895288610ec9565b6000918291828587519a6137c18c610e77565b828c525193f1943d90816137f4575b6020818360009352013e81516001600160a01b0390911681528415156020820152a1565b600091506137d0565b61380d6138409194939294611cf8565b80546001600160a01b031981168255600190910180546001600160a01b0392831696919492169161264b9136919061254d565b5080546001600160a81b03191660ff60a01b179055565b6001600160a01b039081166000818152600080516020614f8b8339815191526020526040902080546001600160a01b0319811690915590911693926121f99261264b91369161254d565b909291926138d36138c1600080516020614fab8339815191525460581b90565b6001600160581b031980851691161490565b6126ef576138e3611c2583611b7a565b936139046138f084611b7a565b8054640100000000600160c01b0319169055565b6001600160f81b03198316600160f81b810361393d57506121f9929161392b91369161254d565b9060581c6001600160a01b031661374e565b600160f91b141590506103a9576101e39160081b614609565b60405161396281610e92565b600181528060005b6020808210156139855790606060209282850101520161396a565b50505090565b9061399582610f04565b6139a26040519182610ec9565b82815280926139b3601f1991610f04565b019060005b8281106139c457505050565b8060606020809385010152016139b8565b906040611d7d92600081528160208201520190610bef565b600881901b926001600160f81b031992600160f81b929091906060908516808601613a7f57505050613a26908035019060208201913590565b929093168015600014613a3e575050611d7d91614887565b03613a4c57611d7d916147ca565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b95969591929180613b2257505090613a969161471e565b93909294613aa2613956565b971680613ac7575050613ab49361476f565b613abd836133eb565b526121f9826133eb565b03613a4c57613ad593614746565b613ade846133eb565b526101e3577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7613b1d613b10846133eb565b51604051918291826139d5565b0390a1565b909650919390925003613a4c57613b4d8280613b476122f16122eb613b539787611a57565b93611a90565b91613338565b5050565b6001600160a01b03169081158015613baa575b6136a05782156133f8576001600160f81b03198135811614613b8b57505050565b826001116101d3576121f99261264b913691600019019060010161254d565b5060018214613b6a565b600080604092835136810185523683823784516014810186523360601b90528260143601925af1918151913d83523d6000602085013e60203d8401019052565b8054906000906000815582613c0857505050565b6000526020600020918201915b828110613c2157505050565b818155600101613c15565b6001600160501b03199035818116939260168110613c4957505050565b60160360031b82901b16169150565b80548210156133f85760005260206000200190600090565b805468010000000000000000811015610e5757613c9291600182018155613c58565b819291549060031b9160501c821b9160018060b01b03901b1916179055565b9092809260209483528483013701016000815290565b6001600160f01b03199035818116939260028110613ce457505050565b60020360031b82901b16169150565b90803501906020808301923560fe81118015613f4b575b613f3957600180613d1a85611d30565b0154613f20575b60001982019260005b848110613e435750613e089594613e16949093613dec9350613de59250613d85613dd6613dbd611eae613db7613db187878e613dac8e613d7d611c626122f16122eb613d77898989613411565b90611abb565b9a8b91611d30565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b613411565b90611ae9565b90613cc7565b613dc688611d30565b9060f01c61ffff19825416179055565b6001600160a01b031696613411565b8091611acc565b6040519586939092906001600160e01b03191660208501613cb1565b03601f198101845283610ec9565b803b156101d3576040516306d61fe760e41b81529160009183918290849082906121ea906004830161373d565b613e9a611c62611c626122f16122eb613d77868a8e613dac8f613e668e91611d30565b01613e94613e87613e81613e7b888888613411565b90611aad565b90613c2c565b6001600160501b03191690565b90613c70565b90613ea9613de582878b613411565b90613eca604091613e0883519485928d63ffffffff60e01b168a8501613cb1565b833b156101d3576000938492613ef492519586809481936306d61fe760e41b83526004830161373d565b03925af1918215610890578492613f0d575b5001613d2a565b8061088a613f1a92610e44565b38613f06565b613f346001613f2e86611d30565b01613bf4565b613d21565b60405163b62d956d60e01b8152600490fd5b508015613d0a565b8484613fd692613fc1979694989560405191613f6e83610ead565b613fd060009b8c92838652836020870152604086019d8e52606086019c8d918583528560808901528560a0890152606060c089015260e088019286845261010089019687529063ffffffff60e01b169052565b6001600160a01b039091169052565b52614920565b60ff80613fef613fe96134c6878661348d565b60f81c90565b16036140355761401e614009846140199561402e94611a73565b9490955163ffffffff60e01b1690565b611d30565b5460101c6001600160a01b031690565b9351929190565b60405163b32eeb6960e01b8152600490fd5b8065ffffffffffff91828160a01c16928315600114614068575b5060d01c92565b925038614061565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030147f0000000000000000000000000000000000000000000000000000000000000000461416156140fd575b671901000000000000600052601a52603a526042601820906000603a52565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f000000000000000000000000000000000000000000000000000000000000000060208201527f00000000000000000000000000000000000000000000000000000000000000006040820152466060820152306080820152206140de565b91929092614190612720565b9061419b9085611a57565b6141a491612274565b60601c60208201819052600080516020614fab8339815191525460a81c63ffffffff1680835260349560148082013582018089019791959294919360548601358601808b019490880135939092878c01358801808a013593908d0192918a0135918891908d8436906142159261254d565b80519060200120913661422990888861254d565b805190602001203661423c908b8d61254d565b8051602091820120604080517fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c5059381019384526001600160581b0319989098169088015263ffffffff9390931660608701526001600160a01b0393909316608086015260a085019390935260c084019290925260e080840192909252908252906142c861010082610ec9565b5190206142d490614070565b607489013589018d8b82013591016142eb92614b72565b9a6142f69488612a14565b6143008183614d0f565b61430991611a1b565b61431291611b4e565b61431b91614ec9565b6094810135019293830192013590565b6001600160c01b0319903581811693926008811061434857505050565b60080360031b82901b16169150565b604090611d7d939281528160208201520190612e9a565b60009493916001868161438085611d30565b016000835b6143cd575b5050505060ff806143a1613fe96134c6878961348d565b1603614035576101006143c56143be8561401e96611d7d98611a73565b369161254d565b910152611d30565b8197969754811015614566576143fe6143f66143e98385613c58565b90549060031b1c60501b90565b908160501c90565b98909761441a614414613fe96134c6858561348d565b60ff1690565b808403614535575090818161445361444761444161443b8461447098611af7565b9061432b565b60c01c90565b6001600160401b031690565b600901916144656143be848484611b08565b6101008b0152611b36565b989098975b600160f01b161561448a575b50830183614385565b99866144c7929b60018060a01b036040918983518092633894f6e760e11b8252818b868260209c8d9760049c63ffffffff60e01b168d8401614357565b0393165af1958615610890578896614516575b505084166144fc5750506144f285949392859261456e565b9a91929350614481565b51631f24c1fb60e11b81529081018c815281906020010390fd5b61452d929650803d1061302b5761301c8183610ec9565b9338806144da565b909991989083111561455357604051630760bdcf60e11b8152600490fd5b61455b6124fa565b610100880152614475565b96959661438a565b6001600160a01b03818318811615606083811b848601821b9081149186901b14171760011461459f57505050600190565b65ffffffffffff60a01b80831693906001600160d01b031984811691908316908615614601575b83811680156145fa575b8781109088180280881897146145f2575b508181119082180218921716171790565b9550386145e1565b50806145d0565b9550856145c6565b9190803501916020906020840193359061462281611d30565b9260019060018501906001825401850361470c57906000835b61469e575b5050505061468d9161468882613dec6101e397986146656001613f2e613e0898611d30565b875461467c9060101c6001600160a01b0316611c62565b94600019810191613411565b61374e565b5080546001600160b01b0319169055565b8154811015614707579083826146fd613e088c6146ef8a6146d4868e6146cc6143f66143e98c9f9e8e613c58565b969050613411565b6040519586939092906001600160e01b0319168c8501613cb1565b6001600160a01b031661374e565b500190919261463b565b614640565b60405163013dcc8d60e31b8152600490fd5b90806014116101d357813560601c92816034116101d357601483013592603401916033190190565b906000928491604051958692833738935af1913d82523d6000602084013e60203d830101604052565b9092600092819594604051968792833738935af11561479e573d82523d6000602084013e60203d830101604052565b503d6000823e3d90fd5b91908110156133f85760051b81013590605e19813603018212156101d3570190565b9190916147d68361398b565b9260005b8181106147e657505050565b806147f460019284866147a8565b80356147ff816101c2565b6148206020809360409361481585830183611f2a565b939092013590614746565b61482a858b6133fd565b5215614839575b5050016147da565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb79161487d614868858b6133fd565b51838051948594888652850152830190610bef565b0390a13880614831565b9190916148938361398b565b9260005b8181106148a357505050565b806148d960206148b660019486886147a8565b80356148c1816101c2565b6148ce6040830183611f2a565b93909201359061476f565b6148e382886133fd565b526148ee81876133fd565b5001614897565b9092608092611d7d9594835260018060a01b0316602083015260408201528160608201520190610bef565b919060608301600193600161493f614019845163ffffffff60e01b1690565b01936000936000958054965b87811061495d57505050505050505050565b8061496f6143f66143e98c9486613c58565b6001600160a01b031660a0880190815260808801959091614998906001600160f01b0319168752565b6149b26149ab613fe96134c68a8561348d565b60ff168952565b6149c0614414895160ff1690565b808403614b3a57508681816149e561444761444161443b614a399c9d614a0c98611af7565b60208c018181528c60c0614a016143be60099586018789611b08565b910152510191611b36565b959095965b51600160f11b90614a2b906001600160f01b031916611eae565b166001600160f01b03191690565b15614a46575b500161494b565b51909150614a5c906001600160a01b0316611c62565b8651614a8090614a73906001600160e01b03191681565b6001600160e01b03191690565b60e08701519091906001600160a01b031691614ac56101008901519360c08a01516040948551808095819463184dfdbb60e11b835260209a8b9760049a8b86016148f5565b03915afa938415610890578b94614b1b575b50506001600160a01b038316614b005750860180518b9392614af89161456e565b905238614a3f565b9051631f24c1fb60e11b815290810183815281906020010390fd5b614b32929450803d1061302b5761301c8183610ec9565b913880614ad7565b839196945010600014614b5957604051630760bdcf60e11b8152600490fd5b614a398b93614b68368861252a565b60c08a0152614a11565b600080516020614fab8339815191525460009493929060581b916001600160f81b03198316600160f81b8103614c355750604051637aa8f17760e11b8152936020938593909284928392614bca923060048601611da1565b039160581c6001600160a01b03165afa90811561089057600091614c16575b505b6001600160e01b0319166374eca2c160e11b01614c0457565b6040516362467c7760e11b8152600490fd5b614c2f915060203d602011611e8657611e7e8183610ec9565b38614be9565b919550929190600160f91b036103a957602091614c589160081b95843088613f53565b60405163392dffaf60e01b81529297929586949385938493614c8b93909230906001600160e01b03191660048701612c5b565b03916001600160a01b03165afa90811561089057600091614cad575b50614beb565b614cc6915060203d602011611e8657611e7e8183610ec9565b38614ca7565b15614cd357565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b6044820152606490fd5b614d1c6105c98383611a1b565b906004831015614d2b57505050565b602c8310614ebb57614d46611c626122f16122eb8685611a46565b602c8201358201602c604c820191013591604c840135840194614d80614d726134d46134c6878761348d565b6001600160f81b0319161590565b80614e2a575b94614dc761242895611c6295614dcc956101e39b956122f19a614ddc575b614db7611c626122f16122eb8a8a611b25565b916001600160a01b031690613496565b611b25565b602c86013595604c019491612274565b614e25606c8701358701614e1f602c604c830192013580614e06611c626122f16122eb8488611a57565b93614e1a856001600160a01b038a16614f2e565b611a90565b916135e2565b614da4565b5091939092956040519163ecd0596160e01b835260208380614e5460048201906002602083019252565b03816001600160a01b0389165afa928315610890576101e3986122f19761242897611c6297614dcc97614dc795600091614e9c575b50959a50959b5095509550955050614d86565b614eb5915060203d6020116108f8576108ea8183610ec9565b38614e89565b505060046101e39114614ccc565b7f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a91606091614efb82610b4483611bb3565b600160ff198254161790556040519163ffffffff60e01b1682526001600160581b031916602082015260016040820152a1565b6101e391906001600160a01b039081831615614f81575b16600052600080516020614f8b83398151915260205260406000209060018060a01b03166bffffffffffffffffffffffff60a01b825416179055565b60019250614f4556fe1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b867bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Deployed Bytecode
0x6080604052600436101561001d575b366128595761001b612828565b005b60003560e01c8063112d3a7d146101bd57806312af322c146101b85780631626ba7e146101b357806319822f7c146101ae5780631f1b92e3146101a95780633659cfe6146101a457806357b3a5f41461019f5780636e6fa0c61461019a578063721e67f41461019557806384b0196e146101905780638dd7712f1461018b57806390ef8862146101865780639198bdf5146101815780639517e29f1461017c5780639cfd7cff14610177578063a65d69d414610172578063a71763a81461016d578063adb610a314610168578063b8afe17d14610163578063c3e589781461015e578063d03c791414610159578063d691c96414610154578063e6f3d50a1461014f578063e9ae5c531461014a578063f1f7f0f9146101455763f2dc691d0361000e576119ec565b6119b4565b611888565b6116cf565b6115c0565b61150f565b611433565b611351565b61131d565b6111f1565b6111ac565b61114e565b611022565b610f1b565b610dca565b610cb6565b610c14565b610b68565b610b0b565b610a5d565b610914565b61075c565b61043c565b6103dc565b610289565b610251565b6001600160a01b038116036101d357565b600080fd5b35906101e3826101c2565b565b9181601f840112156101d3578235916001600160401b0383116101d357602083818601950101116101d357565b60606003198201126101d3576004359160243561022e816101c2565b91604435906001600160401b0382116101d35761024d916004016101e5565b9091565b346101d357602061026d61026436610212565b92919091611bec565b6040519015158152f35b6001600160581b03198116036101d357565b346101d35760803660031901126101d3576004356102a681610277565b6024356102b2816101c2565b6001600160401b03906044358281116101d3576102d39036906004016101e5565b90926064359081116101d3576102ed9036906004016101e5565b9390926001600160581b031961032d81610326610319600080516020614fab8339815191525460581b90565b6001600160581b03191690565b1615611cb6565b8616156103ca576001600160f81b03198616600160f81b81141590816103bb575b506103a9578561036061001b976129b9565b61038161036b610eea565b60018152925b6001600160a01b03166020840152565b600080516020614fab833981519152805463ffffffff60a81b1916600160a81b179055612a14565b6040516361c4e91b60e11b8152600490fd5b600160f91b141590503861034e565b604051631a0a9b9f60e21b8152600490fd5b346101d35760403660031901126101d3576024356001600160401b0381116101d35761041a61041160209236906004016101e5565b90600435611dd1565b6040516001600160e01b03199091168152f35b90816101209103126101d35790565b60603660031901126101d357600480356001600160401b0381116101d357610467903690830161042d565b60243590604435906001600160a01b03907f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03282163303610727578084926104b16020830135612d80565b6001600160f81b0319909116159590939091866106fd575b90846104d59392612f65565b956104e76104e284611b7a565b611efe565b94159485806106bb575b6106aa57602001516001600160a01b031691821690811561069957600192610526610545926000526000602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b036105f8578261059a575b5050610589576105739250805b610577575b506040519081529081906020820190565b0390f35b3490349034903490335af15038610562565b604051631a0a9b9f60e21b81528390fd5b6105f192506105ed916105cf6105c96105c36105b86105e695611bb3565b936060810190611f2a565b90611a1b565b90611b4e565b63ffffffff60e01b16600052602052604060002090565b5460ff1690565b1590565b3880610550565b82919291610666575b50610655576105c3816060610617930190611f2a565b638dd7712f60e01b916001600160e01b03199161063391611b4e565b16036106445761057392508061055d565b60405163dbbb044b60e01b81528390fd5b604051631a0a9b9f60e21b81528490fd5b61069391506105e661067a6105ed92611bb3565b6105cf6105c961068d6060880188611f2a565b90611a0a565b38610601565b604051631a0a9b9f60e21b81528990fd5b604051633ab3447f60e11b81528990fd5b50805163ffffffff1663ffffffff6106f56106ec600080516020614fab8339815191525463ffffffff9060c81c1690565b63ffffffff1690565b9116106104f1565b9350906104d59161071d600080516020614fab8339815191525460581b90565b94909192506104c9565b6040516348f5c3ed60e01b81528590fd5b6004359063ffffffff821682036101d357565b359063ffffffff821682036101d357565b60203660031901126101d357610770610738565b61079261078c600080516020614fab8339815191525460581b90565b60581c90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032831614158061090a575b156108ff5760405163ecd0596160e01b8152600480820152911690602081602481855afa908115610890576000916108d0575b50156108be5760405163d68f602560e01b8152916000838061082136343360048501611fed565b038183865af192831561089057600093610895575b506108409061310c565b803b156101d357604051635565eb9560e11b815291600091839182908490829061086d9060048301612029565b03925af180156108905761087d57005b8061088a61001b92610e44565b80610bc1565b611dc5565b6108409193506108b7903d806000833e6108af8183610ec9565b810190611f8f565b9290610836565b6040516348f5c3ed60e01b8152600490fd5b6108f2915060203d6020116108f8575b6108ea8183610ec9565b810190611f5c565b386107fa565b503d6108e0565b505061001b9061310c565b50303314156107c7565b60203660031901126101d35760043561092c816101c2565b61094861078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580610a41575b15610a365760405163ecd0596160e01b8152600480820152911690602081602481855afa90811561089057600091610a17575b50156108be5760405163d68f602560e01b815291600083806109d736343360048501611fed565b038183865af1928315610890576000936109f6575b5061084090612054565b610840919350610a10903d806000833e6108af8183610ec9565b92906109ec565b610a30915060203d6020116108f8576108ea8183610ec9565b386109b0565b505061001b90612054565b503033141561097d565b6001600160e01b03198116036101d357565b346101d35760203660031901126101d357610573610a9f600435610a8081610a4b565b600060408051610a8f81610e5c565b8281528260208201520152611cf8565b60405190610aac82610e5c565b80546001600160a01b0390811680845260019092015480821660208086019182526001600160f81b031960589390931b831660409687019081528651958652915190931692840192909252905116918101919091529081906060820190565b346101d35760403660031901126101d357602060ff610b5c600435610b2f81610277565b610b4460243591610b3f83610a4b565b611bb3565b9063ffffffff60e01b16600052602052604060002090565b54166040519015158152f35b346101d35760203660031901126101d3576020610b9e600435610b8a816101c2565b6000604051610b9881610e77565b52612992565b60405190610bab82610e77565b546001600160a01b031690819052604051908152f35b60009103126101d357565b60005b838110610bdf5750506000910152565b8181015183820152602001610bcf565b90602091610c0881518092818552858086019101610bcc565b601f01601f1916010190565b346101d35760003660031901126101d357610c63610c306131ec565b90604051928392600f60f81b8452610c5560209360e0602087015260e0860190610bef565b908482036040860152610bef565b90466060840152306080840152600060a084015282820360c0840152602060605192838152019160809160005b828110610c9f57505050500390f35b835185528695509381019392810192600101610c90565b60403660031901126101d3576004356001600160401b0381116101d357610ce190369060040161042d565b6001600160a01b03907f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032821633036108be576060906001610d3e610d316024356000526000602052604060002090565b546001600160a01b031690565b93841614159081610d9a575b610d65610d5e826060610d6c940190611f2a565b8091611a29565b9030613338565b92909115610d7d5761001b9361335f565b5091505015610d8857005b60405163f21e646b60e01b8152600490fd5b9150610d6c610d65610d5e610dc0610db8610d5e6060880188611f2a565b9034896132b6565b9492505050610d4a565b346101d35760003660031901126101d357602063ffffffff600080516020614fab8339815191525460c81c16604051908152f35b9181601f840112156101d3578235916001600160401b0383116101d3576020808501948460051b0101116101d357565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111610e5757604052565b610e2e565b606081019081106001600160401b03821117610e5757604052565b602081019081106001600160401b03821117610e5757604052565b604081019081106001600160401b03821117610e5757604052565b61012081019081106001600160401b03821117610e5757604052565b90601f801991011681019081106001600160401b03821117610e5757604052565b604051906101e382610e92565b604051906101e382610ead565b6001600160401b038111610e575760051b60200190565b60803660031901126101d3576001600160401b036004358181116101d357610f47903690600401610dfe565b906024358381116101d357366023820112156101d3578060040135610f6b81610f04565b91604091610f7c6040519485610ec9565b8084526020906024602086019160061b840101923684116101d357602401905b838210610fe45750505050506044358481116101d357610fc0903690600401610dfe565b916064359586116101d357610fdc61001b963690600401610dfe565b9590946120e9565b84823603126101d3578285918251610ffb81610e92565b6110048561074b565b815282850135611013816101c2565b83820152815201910190610f9c565b61102b36610212565b61104761078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580611144575b156111385760405163ecd0596160e01b815260048082015291169290602081602481875afa90811561089057600091611119575b50156108be5760405163d68f602560e01b815293600085806110d736343360048501611fed565b038183885af1948515610890576000956110f8575b506108409394956122a5565b610840949550611112903d806000833e6108af8183610ec9565b94936110ec565b611132915060203d6020116108f8576108ea8183610ec9565b386110b0565b50509161001b936122a5565b503033141561107c565b346101d35760003660031901126101d35761057360405161116e81610e92565b601b81527f6b65726e656c2e616476616e6365642e76302e332e302d6265746100000000006020820152604051918291602083526020830190610bef565b346101d35760003660031901126101d3576040517f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0326001600160a01b03168152602090f35b6111fa36610212565b61121661078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580611313575b156113075760405163ecd0596160e01b815260048082015291169290602081602481875afa908115610890576000916112e8575b50156108be5760405163d68f602560e01b815293600085806112a636343360048501611fed565b038183885af1948515610890576000956112c7575b50610840939495612584565b6108409495506112e1903d806000833e6108af8183610ec9565b94936112bb565b611301915060203d6020116108f8576108ea8183610ec9565b3861127f565b50509161001b93612584565b503033141561124b565b346101d35760003660031901126101d357602063ffffffff600080516020614fab8339815191525460a81c16604051908152f35b346101d35760203660031901126101d357604061138160043561137381610277565b61137b612720565b50611b7a565b602082519161138f83610e92565b5463ffffffff81169283815260018060a01b03928391019160201c168152835192835251166020820152f35b602080825282516001600160f01b03191681830152808301516001600160a01b03166040808401919091529092015160608083015280516080830181905260a090920192908101919060005b828110611415575050505090565b83516001600160501b03191685529381019392810192600101611407565b346101d3576020806003193601126101d35760043561145181610a4b565b611476604091606083805161146581610e5c565b600081526000878201520152611d30565b9080519161148383610e5c565b805460f081901b6001600160f01b031916845260101c6001600160a01b031684840152815160019182018054808352600091825286822083880197939490939092905b8282106114ed576105738888886114df818e0382610ec9565b8183015251918291826113bb565b845460501b6001600160501b03191689529788019793830193908301906114c6565b346101d35760203660031901126101d357602061026d600435612739565b9060406003198301126101d35760043591602435906001600160401b0382116101d35761024d916004016101e5565b6020808201906020835283518092526040830192602060408460051b8301019501936000915b8483106115925750505050505090565b90919293949584806115b0600193603f198682030187528a51610bef565b9801930193019194939290611582565b6115c93661152d565b916001600160a01b036115db33612992565b54169283156116bd57606090600185141593846116a6575b6115fd92936139ed565b91611611575b60405180610573848261155c565b60405161163381611625856020830161155c565b03601f198101835282610ec9565b833b156101d3576116839361166a6000809460405197889586948593635565eb9560e11b8552606060048601526064850190610bef565b6001602485015283810360031901604485015290610bef565b03925af1918215610890576105739215611603576116a090610e44565b38611603565b6115fd92506116b6363488613232565b92506115f3565b60405163710c949760e01b8152600490fd5b60603660031901126101d35760048035906116e982610277565b6001600160401b03916024358381116101d35761170990369084016101e5565b936044359081116101d35761172190369085016101e5565b9061173e61078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032831614158061187e575b1561186e57169560405163ecd0596160e01b81526020818061179c8a8201906004602083019252565b03818b5afa9081156108905760009161184f575b501561183e5760405163d68f602560e01b815293600085806117d63634338d8501611fed565b0381838c5af19485156108905760009561181f575b506117f694956127fb565b823b156101d35761086d9260009283604051809681958294635565eb9560e11b84528301612029565b6117f69550611838903d806000833e6108af8183610ec9565b946117eb565b6040516348f5c3ed60e01b81528690fd5b611868915060203d6020116108f8576108ea8183610ec9565b386117b0565b50509261001b95929194506127fb565b5030331415611773565b6118913661152d565b6118ad61078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03283161415806119aa575b1561199e5760405163ecd0596160e01b815260048082015291169190602081602481865afa9081156108905760009161197f575b50156108be5760405163d68f602560e01b8152926000848061193d36343360048501611fed565b038183875af19384156108905760009461195e575b50610840929394612810565b610840939450611978903d806000833e6108af8183610ec9565b9392611952565b611998915060203d6020116108f8576108ea8183610ec9565b38611916565b50509061001b92612810565b50303314156118e2565b346101d35760003660031901126101d3576020600080516020614fab8339815191525460581b604051906001600160581b0319168152f35b346101d35760203660031901126101d357602061026d60043561281b565b906008116101d35760040190600490565b906004116101d35790600490565b90929192836004116101d35783116101d357600401916003190190565b906018116101d35760040190601490565b906014116101d35790601490565b906020116101d35790602090565b90929192836001116101d35783116101d357600101916000190190565b90929192836014116101d35783116101d357601401916013190190565b906016116101d35790601690565b906016116101d35760020190601490565b90929192836016116101d35783116101d357601601916015190190565b906002116101d35790600290565b906009116101d35760010190600890565b90929192836009116101d35783116101d357600901916008190190565b90602c116101d35760180190601490565b909392938483116101d35784116101d3578101920390565b6001600160e01b03199035818116939260048110611b6b57505050565b60040360031b82901b16169150565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f850602052604060002090565b6001600160581b0319166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f851602052604060002090565b90929060018103611c3b57506001600160a01b0392611c359250611c25915060581b600160581b600160f81b0316600160f81b17611b7a565b5460201c6001600160a01b031690565b16151590565b60028103611c6e57506001600160a01b0392611c359250611c629150610d31908416612992565b6001600160a01b031690565b600303611cae57611c8f611c8a6105c9600193611c9d95611a1b565b611cf8565b01546001600160a01b031690565b6001600160a01b0390811691161490565b505050600090565b15611cbd57565b60405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606490fd5b63ffffffff60e01b166000527f7c341349a4360fdd5d5bc07e69f325dc6aaea3eb018b3e0ea7e53cc0bb0d6f3b602052604060002090565b63ffffffff60e01b166000527f7bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f852602052604060002090565b908160209103126101d35751611d7d81610a4b565b90565b908060209392818452848401376000828201840152601f01601f1916010190565b611d7d949260609260018060a01b0316825260208201528160408201520191611d80565b6040513d6000823e3d90fd5b91611ddb91612c05565b91906001600160f81b031980831615611edd575b6001600160a01b039081611e08611c62611c2587611b7a565b16156103ca578316600160f81b03611e8d57906020939291611e2c611e4a96612d37565b604051637aa8f17760e11b8152968795869485933360048601611da1565b039260581c165afa90811561089057600091611e64575090565b611d7d915060203d602011611e86575b611e7e8183610ec9565b810190611d68565b503d611e74565b509060081b92600160f11b611ebb611eae611ea787611d30565b5460f01b90565b6001600160f01b03191690565b16611ecb57611d7d933390612c86565b604051635b71057960e01b8152600490fd5b9150611ef8600080516020614fab8339815191525460581b90565b91611def565b90604051611f0b81610e92565b915463ffffffff81168352602090811c6001600160a01b031690830152565b903590601e19813603018212156101d357018035906001600160401b0382116101d3576020019181360383136101d357565b908160209103126101d3575180151581036101d35790565b6001600160401b038111610e5757601f01601f191660200190565b6020818303126101d3578051906001600160401b0382116101d3570181601f820112156101d3578051611fc181611f74565b92611fcf6040519485610ec9565b818452602082840101116101d357611d7d9160208085019101610bcc565b916080939160018060a01b03168352602083015260606040830152806060830152806000848401376000828201840152601f01601f1916010190565b61203d602092606083526060830190610bef565b906001838201526040818303910152600081520190565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8190556001600160a01b03167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2565b906040516120b581610e5c565b82546001600160a01b039081168252600190930154928316602082015260589290921b6001600160f81b0319166040830152565b9592949193909461210c61078c600080516020614fab8339815191525460581b90565b6001600160a01b0390337f0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da0328316141580612259575b156122495760405163ecd0596160e01b8152600480820152911695906020816024818a5afa9081156108905760009161222a575b50156108be5760405163d68f602560e01b8152966000888061219c36343360048501611fed565b0381838b5af197881561089057600098612209575b506121bd969798613428565b803b156101d357604051635565eb9560e11b81529160009183918290849082906121ea9060048301612029565b03925af18015610890576121fc575b50565b8061088a6101e392610e44565b6121bd979850612223903d806000833e6108af8183610ec9565b97966121b1565b612243915060203d6020116108f8576108ea8183610ec9565b38612175565b505091939092946101e396613428565b5030331415612141565b916020611d7d938181520191611d80565b6bffffffffffffffffffffffff19903581811693926014811061229657505050565b60140360031b82901b16169150565b9290916001840361234b576101e3935061230e6122f7611c626122f16122eb6122e4600080516020614fab8339815191525463ffffffff9060a81c1690565b9686611a57565b90612274565b60601c90565b610371612302610eea565b63ffffffff9095168552565b603480820135820160148181013595918301948482013590940190810135939201919060581b600160581b600160f81b0316600160f81b17612a14565b919092600281146000146123ad57509161239e6101e393612383611c626122f16122eb60148801358801966034890135890198611a57565b928391601482013591603401906001600160a01b03166136af565b603460148301359201906135e2565b9091906003810361242d5750612428611c626124186101e3958461241360186122f197013582016122f160388401358401996123ec6105c98787611a1b565b9061240d611c626123fd8989611a46565b6018880135976038019691612274565b91613496565b611a46565b6018860135956038019491612274565b6135e2565b9091906004810361246e57506001600160a01b031691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b600581036124ac57506001600160a01b031691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b6006036124e8576001600160a01b031691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b604051631092ef5760e11b8152600490fd5b6040519061250782610e77565b60008252565b35906020811061251b575090565b6000199060200360031b1b1690565b91906040519061253982610e77565b819360008352116101d35760206000910152565b92919261255982611f74565b916125676040519384610ec9565b8294818452818301116101d3578281602093846000960137010152565b929190600184036125ae576121f9935060581b600160581b600160f81b0316600160f81b176138a1565b600284036125c9576121f993506001600160a01b0316613857565b909190600384036125f857506121f9925080806125ec6105c96125f29486611a1b565b93611a29565b916137fd565b91926004810361267e57506121f99261264b91612624600080516020614fab8339815191525460581b90565b612630611c2582611b7a565b6001600160a01b03868116911614612651575b50369161254d565b9061374e565b61265d61267891611b7a565b8054640100000000600160c01b031916640100000000179055565b38612643565b600581036127015750600080516020614fab8339815191525460581b5b6126ae6126a88386611a65565b9061250d565b906001600160f81b03198116600160f91b146126d6575b50506121f99261264b91369161254d565b60081b6001600160e01b031916146126ef5738806126c5565b6040516313002bdd60e31b8152600490fd5b6006036124e857600080516020614fab8339815191525460581b61269b565b6040519061272d82610e92565b60006020838281520152565b61274d818060081b918160301b9160501b90565b929091600160f81b916001600160f81b0319919082168381141590816127f1575b816127e6575b816127d7575b506127cd57169081141590816127c3575b506127bc576001600160e01b0319166127b6576001600160501b0319166127b157600190565b600090565b50600090565b5050600090565b905015153861278b565b5050505050600090565b607f60f91b141590503861277a565b838114159150612774565b801515915061276e565b9161280b916101e39594936138a1565b613b57565b906121f992916139ed565b600711156127b157600190565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460408051338152346020820152a1565b6128766128716000356001600160e01b031916611cf8565b6120a8565b80516001600160a01b03908116918260008161289e57604051631cd4b64760e21b8152600490fd5b5060016060940361297c575b5060408101516001600160f81b03199081168061293257505060208101516001936128fb939290916128e4906001600160a01b0316613bb4565b9290929586939586935b516001600160a01b031690565b94851603612920575b505050501560001461291857602081519101fd5b602081519101f35b6129299361335f565b38828282612904565b9192910361296a5760208201516001936128fb93909161295c906001600160a01b03163690613311565b9290929586939586936128ee565b604051632d6a6bb760e01b8152600490fd5b61298b91935036903490613232565b91386128aa565b6001600160a01b03166000908152600080516020614f8b8339815191526020526040902090565b60207f6789ec0c85d6458d897a36a70129b101f8b4d84c6e218046c3107373dbcbae8891600080516020614fab8339815191528160581c6001600160581b0360a81b825416179055604051906001600160581b0319168152a1565b9193909294612a2f612a2584611b7a565b5463ffffffff1690565b93600080516020614fab83398151915294612a52865463ffffffff9060a81c1690565b63ffffffff809281808416911614612bc7575b50506020820180516001600160a01b0397919291612a9291891615612bbe575b5460a81c63ffffffff1690565b81612aa46106ec865163ffffffff1690565b91161490811591612b94575b50612b82576128ee612aff92612ac587611b7a565b815181546020938401516001600160c01b031990911663ffffffff9290921691909117921b640100000000600160c01b0316919091179055565b91600185841603612b71575b5050506001600160f81b03198116600160f81b8103612b55575060581c1691823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b909350600160f91b141590506103a9576101e39160081b613cf3565b612b7a926135e2565b388080612b0b565b604051633ab3447f60e11b8152600490fd5b9050612ba2612a2587611b7a565b90612bb46106ec855163ffffffff1690565b9116101538612ab0565b60018452612a85565b600080516020614fab833981519152805463ffffffff60a81b19166001939093019190911660a81b63ffffffff60a81b169190911790553881612a65565b9182358060f81c80600014612c4b5780600114612c3e57600214612c2857600080fd5b6001600160d81b03191692600501916004190190565b5092601501916014190190565b5050600160009301916000190190565b9092608092611d7d9694835260018060a01b0316602083015260408201528160608201520191611d80565b909192612ca594612c9991858585613f53565b94929391969096614047565b509065ffffffffffff8091164210918215612d2b575b5050612d1857612cf9612ccf602096612d37565b60405163392dffaf60e01b8152978896879586959193916001600160e01b03191660048701612c5b565b03916001600160a01b03165afa90811561089057600091611e64575090565b506001600160e01b031995945050505050565b16421190503880612cbb565b611d7d9060405160208101917f1547321c374afde8a591d972a084b071c594c275e36724931ff96c25f2999c838352604082015260408152612d7881610e5c565b519020614070565b90818060081b9160ff839260f01c16600214612d9857565b6001600160d81b031983169150565b9080601f830112156101d357816020611d7d9335910161254d565b9190610120838203126101d357612dd7610ef7565b92612de1816101d8565b8452602081013560208501526040810135916001600160401b03928381116101d35781612e0f918401612da7565b604086015260608201358381116101d35781612e2c918401612da7565b60608601526080820135608086015260a082013560a086015260c082013560c086015260e08201358381116101d35781612e67918401612da7565b60e086015261010092838301359081116101d357612e859201612da7565b90830152565b908160209103126101d3575190565b80516001600160a01b03168252611d7d9190612f18612ee8612ed661012060208501516020870152604085015190806040880152860190610bef565b60608401518582036060870152610bef565b6080830151608085015260a083015160a085015260c083015160c085015260e083015184820360e0860152610bef565b916101008092015191818403910152610bef565b939291612f49906040928652606060208701526060860190612e9a565b930152565b929190612f49602091604086526040860190612e9a565b929092600092612f753682612dc2565b916101009182810191612f888383611f2a565b90949093600160f81b936001600160f81b031993841685146130d1575b505050871603613032575050604051639700320360e01b815293602092859283916000918391612fd89160048401612f4e565b039260581c6001600160a01b03165af190811561089057611d7d92600092613001575b5061456e565b61302491925060203d60201161302b575b61301c8183610ec9565b810190612e8b565b9038612ffb565b503d613012565b909460081b93909291600160f01b61304f611eae611ea788611d30565b166130bf57600061307061306a60209661309a99858a61436e565b9461456e565b604051630ccab7a160e01b8152979096889586948593926001600160e01b03191660048501612f2c565b03926001600160a01b03165af190811561089057611d7d92600092613001575061456e565b6040516314b9743f60e01b8152600490fd5b909195506130ed9398506130e6929450611f2a565b9088614184565b969192909361310085899599369161254d565b90860152388080612fa5565b600080516020614fab83398151915280549163ffffffff92600a848260a81c1601908482116131d65782851691851682116131c45760c81c84161015612b8257600080516020614fab833981519152805463ffffffff60c81b191660c89290921b63ffffffff60c81b1691909117905554818160c81c1691829160a81c16106131925750565b600080516020614fab833981519152805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b60405163e60fd64760e01b8152600490fd5b634e487b7160e01b600052601160045260246000fd5b6040516131f881610e92565b600681526512d95c9b995b60d21b60208201529060405161321881610e92565b600a815269302e332e302d6265746160b01b602082015290565b60405163d68f602560e01b815233600482015260248101929092526060604483015260648201839052600092839183918290849060849083908084838501378181018301849052601f01601f191681010301926001600160a01b03165af19182156108905780926132a257505090565b611d7d92503d8091833e6108af8183610ec9565b600092836132dd95936040519687958694859363d68f602560e01b85523360048601611da1565b03926001600160a01b03165af1908115610890576000916132fc575090565b611d7d91503d806000833e6108af8183610ec9565b60009060405192808385378338925af4913d82523d6000602084013e60203d830101604052565b60009192806040519485378338925af4913d82523d6000602084013e60203d830101604052565b919290916001600160a01b0316803b156101d3576133a2600080946133bb60405197889687958694635565eb9560e11b8652606060048701526064860190610bef565b9115156024850152838203600319016044850152610bef565b03925af18015610890576133cc5750565b6101e390610e44565b634e487b7160e01b600052603260045260246000fd5b8051156133f85760200190565b6133d5565b80518210156133f85760209160051b010190565b908210156133f85761024d9160051b810190611f2a565b96959192939694909460005b86811061344657505050505050509050565b806134878a60019360051b85013561345d81610277565b6134738461346b818c6133fd565b51938c613411565b9061347f868b8b613411565b949093612a14565b01613434565b90156133f85790565b6001600160a01b039391929190848316156135d9575b6134b590611cf8565b946134e16134d46134c6838561348d565b356001600160f81b03191690565b6001600160f81b03191690565b946001600160f81b0319808716806135ba575050908061350392861693611a73565b823b156101d35761352e92600092836040518096819582946306d61fe760e41b845260048401612263565b03925af19485156108905761356a61358a936001936101e3986135a7575b505b82546001600160a01b0319166001600160a01b03909116178255565b0180546001600160a01b0319166001600160a01b03909316929092178255565b805460ff60a01b191660589290921c60ff60a01b16919091179055565b8061088a6135b492610e44565b3861354c565b92509250509491940361296a57600161358a9161356a6101e39661354e565b600192506134ac565b6001600160a01b031691821580156136a5575b6136a05760405163d60b347f60e01b8152306004820152602081602481875afa90811561089057600091613681575b501561364c576001600160f81b0319806136416134c6848661348d565b161461364c57505050565b8061365692611a73565b823b156101d3576121ea92600092836040518096819582946306d61fe760e41b845260048401612263565b61369a915060203d6020116108f8576108ea8183610ec9565b38613624565b505050565b50600183146135f5565b919392916001600160a01b039081841615613734575b166000818152600080516020614f8b8339815191526020526040812080546001600160a01b0319166001600160a01b0390951694909417909355803b15613730576133bb9394836040518096819582946306d61fe760e41b8452602060048501526024840191611d80565b8280fd5b600193506136c5565b906020611d7d928181520190610bef565b60407f2b82f87bf66300af618a9621d3f221edfab735f5bacb4e004cce1b62375396c3919392935a8251956137ae876137a06020820193638a91b0e360e01b8552602060248401526044830190610bef565b03601f198101895288610ec9565b6000918291828587519a6137c18c610e77565b828c525193f1943d90816137f4575b6020818360009352013e81516001600160a01b0390911681528415156020820152a1565b600091506137d0565b61380d6138409194939294611cf8565b80546001600160a01b031981168255600190910180546001600160a01b0392831696919492169161264b9136919061254d565b5080546001600160a81b03191660ff60a01b179055565b6001600160a01b039081166000818152600080516020614f8b8339815191526020526040902080546001600160a01b0319811690915590911693926121f99261264b91369161254d565b909291926138d36138c1600080516020614fab8339815191525460581b90565b6001600160581b031980851691161490565b6126ef576138e3611c2583611b7a565b936139046138f084611b7a565b8054640100000000600160c01b0319169055565b6001600160f81b03198316600160f81b810361393d57506121f9929161392b91369161254d565b9060581c6001600160a01b031661374e565b600160f91b141590506103a9576101e39160081b614609565b60405161396281610e92565b600181528060005b6020808210156139855790606060209282850101520161396a565b50505090565b9061399582610f04565b6139a26040519182610ec9565b82815280926139b3601f1991610f04565b019060005b8281106139c457505050565b8060606020809385010152016139b8565b906040611d7d92600081528160208201520190610bef565b600881901b926001600160f81b031992600160f81b929091906060908516808601613a7f57505050613a26908035019060208201913590565b929093168015600014613a3e575050611d7d91614887565b03613a4c57611d7d916147ca565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b95969591929180613b2257505090613a969161471e565b93909294613aa2613956565b971680613ac7575050613ab49361476f565b613abd836133eb565b526121f9826133eb565b03613a4c57613ad593614746565b613ade846133eb565b526101e3577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7613b1d613b10846133eb565b51604051918291826139d5565b0390a1565b909650919390925003613a4c57613b4d8280613b476122f16122eb613b539787611a57565b93611a90565b91613338565b5050565b6001600160a01b03169081158015613baa575b6136a05782156133f8576001600160f81b03198135811614613b8b57505050565b826001116101d3576121f99261264b913691600019019060010161254d565b5060018214613b6a565b600080604092835136810185523683823784516014810186523360601b90528260143601925af1918151913d83523d6000602085013e60203d8401019052565b8054906000906000815582613c0857505050565b6000526020600020918201915b828110613c2157505050565b818155600101613c15565b6001600160501b03199035818116939260168110613c4957505050565b60160360031b82901b16169150565b80548210156133f85760005260206000200190600090565b805468010000000000000000811015610e5757613c9291600182018155613c58565b819291549060031b9160501c821b9160018060b01b03901b1916179055565b9092809260209483528483013701016000815290565b6001600160f01b03199035818116939260028110613ce457505050565b60020360031b82901b16169150565b90803501906020808301923560fe81118015613f4b575b613f3957600180613d1a85611d30565b0154613f20575b60001982019260005b848110613e435750613e089594613e16949093613dec9350613de59250613d85613dd6613dbd611eae613db7613db187878e613dac8e613d7d611c626122f16122eb613d77898989613411565b90611abb565b9a8b91611d30565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b613411565b90611ae9565b90613cc7565b613dc688611d30565b9060f01c61ffff19825416179055565b6001600160a01b031696613411565b8091611acc565b6040519586939092906001600160e01b03191660208501613cb1565b03601f198101845283610ec9565b803b156101d3576040516306d61fe760e41b81529160009183918290849082906121ea906004830161373d565b613e9a611c62611c626122f16122eb613d77868a8e613dac8f613e668e91611d30565b01613e94613e87613e81613e7b888888613411565b90611aad565b90613c2c565b6001600160501b03191690565b90613c70565b90613ea9613de582878b613411565b90613eca604091613e0883519485928d63ffffffff60e01b168a8501613cb1565b833b156101d3576000938492613ef492519586809481936306d61fe760e41b83526004830161373d565b03925af1918215610890578492613f0d575b5001613d2a565b8061088a613f1a92610e44565b38613f06565b613f346001613f2e86611d30565b01613bf4565b613d21565b60405163b62d956d60e01b8152600490fd5b508015613d0a565b8484613fd692613fc1979694989560405191613f6e83610ead565b613fd060009b8c92838652836020870152604086019d8e52606086019c8d918583528560808901528560a0890152606060c089015260e088019286845261010089019687529063ffffffff60e01b169052565b6001600160a01b039091169052565b52614920565b60ff80613fef613fe96134c6878661348d565b60f81c90565b16036140355761401e614009846140199561402e94611a73565b9490955163ffffffff60e01b1690565b611d30565b5460101c6001600160a01b031690565b9351929190565b60405163b32eeb6960e01b8152600490fd5b8065ffffffffffff91828160a01c16928315600114614068575b5060d01c92565b925038614061565b7f87d491545ad968115eb61dd75b5e89b8060414d17379b0b248a047bab43dae6a7f00000000000000000000000094f097e1ebeb4eca3aae54cabb08905b239a7d2730147f0000000000000000000000000000000000000000000000000000000000000001461416156140fd575b671901000000000000600052601a52603a526042601820906000603a52565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f32ba20807d2fff2dbb34e0bcfa82982565bef566d4c0c633dc57b700b81c342760208201527f3d2f1e1f700693920fb7b5bfa0719e9cfaa73ef56d076f8a8a7c4dba4d61990f6040820152466060820152306080820152206140de565b91929092614190612720565b9061419b9085611a57565b6141a491612274565b60601c60208201819052600080516020614fab8339815191525460a81c63ffffffff1680835260349560148082013582018089019791959294919360548601358601808b019490880135939092878c01358801808a013593908d0192918a0135918891908d8436906142159261254d565b80519060200120913661422990888861254d565b805190602001203661423c908b8d61254d565b8051602091820120604080517fb17ab1224aca0d4255ef8161acaf2ac121b8faa32a4b2258c912cc5f8308c5059381019384526001600160581b0319989098169088015263ffffffff9390931660608701526001600160a01b0393909316608086015260a085019390935260c084019290925260e080840192909252908252906142c861010082610ec9565b5190206142d490614070565b607489013589018d8b82013591016142eb92614b72565b9a6142f69488612a14565b6143008183614d0f565b61430991611a1b565b61431291611b4e565b61431b91614ec9565b6094810135019293830192013590565b6001600160c01b0319903581811693926008811061434857505050565b60080360031b82901b16169150565b604090611d7d939281528160208201520190612e9a565b60009493916001868161438085611d30565b016000835b6143cd575b5050505060ff806143a1613fe96134c6878961348d565b1603614035576101006143c56143be8561401e96611d7d98611a73565b369161254d565b910152611d30565b8197969754811015614566576143fe6143f66143e98385613c58565b90549060031b1c60501b90565b908160501c90565b98909761441a614414613fe96134c6858561348d565b60ff1690565b808403614535575090818161445361444761444161443b8461447098611af7565b9061432b565b60c01c90565b6001600160401b031690565b600901916144656143be848484611b08565b6101008b0152611b36565b989098975b600160f01b161561448a575b50830183614385565b99866144c7929b60018060a01b036040918983518092633894f6e760e11b8252818b868260209c8d9760049c63ffffffff60e01b168d8401614357565b0393165af1958615610890578896614516575b505084166144fc5750506144f285949392859261456e565b9a91929350614481565b51631f24c1fb60e11b81529081018c815281906020010390fd5b61452d929650803d1061302b5761301c8183610ec9565b9338806144da565b909991989083111561455357604051630760bdcf60e11b8152600490fd5b61455b6124fa565b610100880152614475565b96959661438a565b6001600160a01b03818318811615606083811b848601821b9081149186901b14171760011461459f57505050600190565b65ffffffffffff60a01b80831693906001600160d01b031984811691908316908615614601575b83811680156145fa575b8781109088180280881897146145f2575b508181119082180218921716171790565b9550386145e1565b50806145d0565b9550856145c6565b9190803501916020906020840193359061462281611d30565b9260019060018501906001825401850361470c57906000835b61469e575b5050505061468d9161468882613dec6101e397986146656001613f2e613e0898611d30565b875461467c9060101c6001600160a01b0316611c62565b94600019810191613411565b61374e565b5080546001600160b01b0319169055565b8154811015614707579083826146fd613e088c6146ef8a6146d4868e6146cc6143f66143e98c9f9e8e613c58565b969050613411565b6040519586939092906001600160e01b0319168c8501613cb1565b6001600160a01b031661374e565b500190919261463b565b614640565b60405163013dcc8d60e31b8152600490fd5b90806014116101d357813560601c92816034116101d357601483013592603401916033190190565b906000928491604051958692833738935af1913d82523d6000602084013e60203d830101604052565b9092600092819594604051968792833738935af11561479e573d82523d6000602084013e60203d830101604052565b503d6000823e3d90fd5b91908110156133f85760051b81013590605e19813603018212156101d3570190565b9190916147d68361398b565b9260005b8181106147e657505050565b806147f460019284866147a8565b80356147ff816101c2565b6148206020809360409361481585830183611f2a565b939092013590614746565b61482a858b6133fd565b5215614839575b5050016147da565b7fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb79161487d614868858b6133fd565b51838051948594888652850152830190610bef565b0390a13880614831565b9190916148938361398b565b9260005b8181106148a357505050565b806148d960206148b660019486886147a8565b80356148c1816101c2565b6148ce6040830183611f2a565b93909201359061476f565b6148e382886133fd565b526148ee81876133fd565b5001614897565b9092608092611d7d9594835260018060a01b0316602083015260408201528160608201520190610bef565b919060608301600193600161493f614019845163ffffffff60e01b1690565b01936000936000958054965b87811061495d57505050505050505050565b8061496f6143f66143e98c9486613c58565b6001600160a01b031660a0880190815260808801959091614998906001600160f01b0319168752565b6149b26149ab613fe96134c68a8561348d565b60ff168952565b6149c0614414895160ff1690565b808403614b3a57508681816149e561444761444161443b614a399c9d614a0c98611af7565b60208c018181528c60c0614a016143be60099586018789611b08565b910152510191611b36565b959095965b51600160f11b90614a2b906001600160f01b031916611eae565b166001600160f01b03191690565b15614a46575b500161494b565b51909150614a5c906001600160a01b0316611c62565b8651614a8090614a73906001600160e01b03191681565b6001600160e01b03191690565b60e08701519091906001600160a01b031691614ac56101008901519360c08a01516040948551808095819463184dfdbb60e11b835260209a8b9760049a8b86016148f5565b03915afa938415610890578b94614b1b575b50506001600160a01b038316614b005750860180518b9392614af89161456e565b905238614a3f565b9051631f24c1fb60e11b815290810183815281906020010390fd5b614b32929450803d1061302b5761301c8183610ec9565b913880614ad7565b839196945010600014614b5957604051630760bdcf60e11b8152600490fd5b614a398b93614b68368861252a565b60c08a0152614a11565b600080516020614fab8339815191525460009493929060581b916001600160f81b03198316600160f81b8103614c355750604051637aa8f17760e11b8152936020938593909284928392614bca923060048601611da1565b039160581c6001600160a01b03165afa90811561089057600091614c16575b505b6001600160e01b0319166374eca2c160e11b01614c0457565b6040516362467c7760e11b8152600490fd5b614c2f915060203d602011611e8657611e7e8183610ec9565b38614be9565b919550929190600160f91b036103a957602091614c589160081b95843088613f53565b60405163392dffaf60e01b81529297929586949385938493614c8b93909230906001600160e01b03191660048701612c5b565b03916001600160a01b03165afa90811561089057600091614cad575b50614beb565b614cc6915060203d602011611e8657611e7e8183610ec9565b38614ca7565b15614cd357565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073656c6563746f724461746160601b6044820152606490fd5b614d1c6105c98383611a1b565b906004831015614d2b57505050565b602c8310614ebb57614d46611c626122f16122eb8685611a46565b602c8201358201602c604c820191013591604c840135840194614d80614d726134d46134c6878761348d565b6001600160f81b0319161590565b80614e2a575b94614dc761242895611c6295614dcc956101e39b956122f19a614ddc575b614db7611c626122f16122eb8a8a611b25565b916001600160a01b031690613496565b611b25565b602c86013595604c019491612274565b614e25606c8701358701614e1f602c604c830192013580614e06611c626122f16122eb8488611a57565b93614e1a856001600160a01b038a16614f2e565b611a90565b916135e2565b614da4565b5091939092956040519163ecd0596160e01b835260208380614e5460048201906002602083019252565b03816001600160a01b0389165afa928315610890576101e3986122f19761242897611c6297614dcc97614dc795600091614e9c575b50959a50959b5095509550955050614d86565b614eb5915060203d6020116108f8576108ea8183610ec9565b38614e89565b505060046101e39114614ccc565b7f9d17cd6d095ac90a655405ab29f30a7ee7e88ef3974c1bf7544bf591043bb71a91606091614efb82610b4483611bb3565b600160ff198254161790556040519163ffffffff60e01b1682526001600160581b031916602082015260016040820152a1565b6101e391906001600160a01b039081831615614f81575b16600052600080516020614f8b83398151915260205260406000209060018060a01b03166bffffffffffffffffffffffff60a01b825416179055565b60019250614f4556fe1bbee3173dbdc223633258c9f337a0fff8115f206d302bea0ed3eac003b68b867bcaa2ced2a71450ed5a9a1b4848e8e5206dbc3f06011e595f7f55428cc6f84f
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
-----Decoded View---------------
Arg [0] : _entrypoint (address): 0x0000000071727De22E5E9d8BAf0edAc6f37da032
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.