Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
CommonMultiECDSA
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 10000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; import {BaseAuthorizationModule} from "./BaseAuthorizationModule.sol"; import {CommonSignatureChecker} from "./CommonSignatureChecker.sol"; /** * @title MultiSigModule - EIP-4337 compatible multi sig module. Contract signatures are not covered. * @author Akash Mishra - <[email protected]> */ contract CommonMultiECDSA is BaseAuthorizationModule, CommonSignatureChecker { /** * @notice The EIP-712 type-hash for the domain separator used for verifying Safe operation signatures. */ bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); /** * @notice The EIP-712 type-hash for a SafeOp, representing the structure of a User Operation for the Safe. * {address} safe - The address of the safe on which the operation is performed. * {uint256} nonce - A unique number associated with the user operation, preventing replay attacks by ensuring each operation is unique. * {bytes} initCode - The packed encoding of a factory address and its factory-specific data for creating a new Safe account. * {bytes} callData - The bytes representing the data of the function call to be executed. * {uint256} callGasLimit - The maximum amount of gas allowed for executing the function call. * {uint256} verificationGasLimit - The maximum amount of gas allowed for the verification process. * {uint256} preVerificationGas - The amount of gas allocated for pre-verification steps before executing the main operation. * {uint256} maxFeePerGas - The maximum fee per gas that the user is willing to pay for the transaction. * {uint256} maxPriorityFeePerGas - The maximum priority fee per gas that the user is willing to pay for the transaction. * {bytes} paymasterAndData - The packed encoding of a paymaster address and its paymaster-specific data for sponsoring the user operation. * {uint48} validAfter - A timestamp representing from when the user operation is valid. * {uint48} validUntil - A timestamp representing until when the user operation is valid, or 0 to indicated "forever". * {address} entryPoint - The address of the entry point that will execute the user operation. * @dev When validating the user operation, the signature timestamps are pre-pended to the signature bytes. */ bytes32 private constant SAFE_OP_TYPEHASH = keccak256( "SafeOp(address safe,uint256 nonce,bytes initCode,bytes callData,uint256 callGasLimit,uint256 verificationGasLimit,uint256 preVerificationGas,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,bytes paymasterAndData,uint48 validAfter,uint48 validUntil,address entryPoint)" ); /** * @dev A structure used internally for manually encoding a Safe operation for when computing the EIP-712 struct hash. */ struct EncodedSafeOpStruct { bytes32 typeHash; address safe; uint256 nonce; bytes32 initCodeHash; bytes32 callDataHash; uint256 callGasLimit; uint256 verificationGasLimit; uint256 preVerificationGas; uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; bytes32 paymasterAndDataHash; uint48 validAfter; uint48 validUntil; address entryPoint; } address public immutable SUPPORTED_ENTRYPOINT; constructor(address entryPoint) { require(entryPoint != address(0), "Invalid entry point"); SUPPORTED_ENTRYPOINT = entryPoint; } /** * @notice Validates a user operation provided by the entry point. */ function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash ) external view returns (uint256 validationData) { isSmartAccount(msg.sender); // The userOp nonce is validated in the entry point (for 0.6.0+), therefore we will not check it again // validationData = _validateSignatures(userOp); // if (_validateSignatures(userOp) == VALIDATION_SUCCESS) { // return VALIDATION_SUCCESS; // } return _validateSignatures(userOp); } /** * @dev Validates a signature for a message signed by address. * @dev Also try dataHash.toEthSignedMessageHash() * @param operationDataHash hash of the data * @param operationDataPack abi.encode(operationData,validAfter, validUntil, signatures) * @return EIP1271_MAGIC_VALUE if signature is valid, 0xffffffff otherwise. */ function isValidSignature( bytes32 operationDataHash, bytes memory operationDataPack ) public view virtual override returns (bytes4) { return isValidSignatureForAddress(operationDataHash, operationDataPack, msg.sender); } /** * @dev Validates a signature for a message signed by address. * @dev Also try dataHash.toEthSignedMessageHash() * @param operationDataHash hash of the data * @param operationDataPack abi.encode(operationData,validAfter, validUntil, signatures) * @param smartAccount expected signer Smart Account address. * @return EIP1271_MAGIC_VALUE if signature is valid, 0xffffffff otherwise. */ function isValidSignatureForAddress( bytes32 operationDataHash, bytes memory operationDataPack, address smartAccount ) public view virtual returns (bytes4) { if (_validateSignatures(operationDataPack) == VALIDATION_SUCCESS) { return EIP1271_MAGIC_VALUE; } return bytes4(0xffffffff); } /** * @notice Computes the 32-byte domain separator used in EIP-712 signature verification for Safe operations. * @return The EIP-712 domain separator hash for this contract. */ function domainSeparator() public view returns (bytes32) { return keccak256( abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this) ); } /** * @notice Returns the 32-byte Safe operation hash to be signed by owners for the specified ERC-4337 user operation. * @dev The Safe operation timestamps are pre-pended to the signature bytes as `abi.encodePacked(validAfter, validUntil, signatures)`. * @param userOp The ERC-4337 user operation. * @return operationHash Operation hash. */ function getOperationHash( UserOperation calldata userOp ) external view returns (bytes32 operationHash) { (bytes memory operationData, , , ) = _getSafeOp(userOp); operationHash = keccak256(operationData); } /** * @dev Validates that the user operation is correctly signed and returns an ERC-4337 packed validation data * of `validAfter || validUntil || authorizer`: * - `authorizer`: 20-byte address, 0 for valid signature or 1 to mark signature failure (this module does not make use of signature aggregators). * - `validUntil`: 6-byte timestamp value, or zero for "infinite". The user operation is valid only up to this time. * - `validAfter`: 6-byte timestamp. The user operation is valid only after this time. * @param userOp User operation struct. * @return validationData An integer indicating the result of the validation. */ function _validateSignatures( UserOperation calldata userOp ) internal view returns (uint256 validationData) { ( bytes memory operationData, uint48 validAfter, uint48 validUntil, bytes calldata signatures ) = _getSafeOp(userOp); bool success = checkSignatures( keccak256(operationData), operationData, signatures ); // The timestamps are validated by the entry point, therefore we will not check them again if (success) validationData = _packValidationData(false, validUntil, validAfter); else validationData = _packValidationData(true, validUntil, validAfter); } /** * @dev Validates a signature for a message signed by address. * @dev Also try dataHash.toEthSignedMessageHash() * @param operationDataPack abi.encode(operationData,validAfter, validUntil, signatures) * @return validationData EIP1271_MAGIC_VALUE if signature is valid, 0xffffffff otherwise. */ function _validateSignatures( bytes memory operationDataPack ) internal view returns (uint256 validationData) { // (bytes memory operationData, uint48 validAfter, uint48 validUntil, bytes calldata signatures) = _getSafeOp(userOp); ( bytes memory operationData, uint48 validAfter, uint48 validUntil, bytes memory signatures ) = abi.decode(operationDataPack, (bytes, uint48, uint48, bytes)); bool success = checkSignatures( keccak256(operationData), operationData, signatures ); // The timestamps are validated by the entry point, therefore we will not check them again // if (success) // validationData = _packValidationData(false, validUntil, validAfter); // else validationData = _packValidationData(true, validUntil, validAfter); if (success) validationData = VALIDATION_SUCCESS; else validationData = SIG_VALIDATION_FAILED; } /** * @dev Decodes an ERC-4337 user operation into a Safe operation. * @param userOp The ERC-4337 user operation. * @return operationData Encoded EIP-712 Safe operation data bytes used for signature verification. * @return validAfter The timestamp the user operation is valid from. * @return validUntil The timestamp the user operation is valid until. * @return signatures The Safe owner signatures extracted from the user operation. */ function _getSafeOp( UserOperation calldata userOp ) internal view returns ( bytes memory operationData, uint48 validAfter, uint48 validUntil, bytes calldata signatures ) { // Extract additional Safe operation fields from the user operation signature which is encoded as: // `abi.encodePacked(validAfter, validUntil, signatures)` { bytes calldata sig = userOp.signature; validAfter = uint48(bytes6(sig[0:6])); validUntil = uint48(bytes6(sig[6:12])); bytes calldata signaturesWithModule = sig[12:]; signatures = signaturesWithModule[:signaturesWithModule.length-20]; } // It is important that **all** user operation fields are represented in the `SafeOp` data somehow, to prevent // user operations from being submitted that do not fully respect the user preferences. The only exception is // the `signature` bytes. Note that even `initCode` needs to be represented in the operation data, otherwise // it can be replaced with a more expensive initialization that would charge the user additional fees. { // In order to work around Solidity "stack too deep" errors related to too many stack variables, manually // encode the `SafeOp` fields into a memory `struct` for computing the EIP-712 struct-hash. This works // because the `EncodedSafeOpStruct` struct has no "dynamic" fields so its memory layout is identical to the // result of `abi.encode`-ing the individual fields. EncodedSafeOpStruct memory encodedSafeOp = EncodedSafeOpStruct({ typeHash: SAFE_OP_TYPEHASH, safe: userOp.sender, nonce: userOp.nonce, initCodeHash: keccak256(userOp.initCode), callDataHash: keccak256(userOp.callData), callGasLimit: userOp.callGasLimit, verificationGasLimit: userOp.verificationGasLimit, preVerificationGas: userOp.preVerificationGas, maxFeePerGas: userOp.maxFeePerGas, maxPriorityFeePerGas: userOp.maxPriorityFeePerGas, paymasterAndDataHash: keccak256(userOp.paymasterAndData), validAfter: validAfter, validUntil: validUntil, entryPoint: SUPPORTED_ENTRYPOINT }); bytes32 safeOpStructHash; // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { // Since the `encodedSafeOp` value's memory layout is identical to the result of `abi.encode`-ing the // individual `SafeOp` fields, we can pass it directly to `keccak256`. Additionally, there are 14 // 32-byte fields to hash, for a length of `14 * 32 = 448` bytes. safeOpStructHash := keccak256(encodedSafeOp, 448) } operationData = abi.encodePacked( bytes1(0x19), bytes1(0x01), domainSeparator(), safeOpStructHash ); } } function _packValidationData( bool sigFailed, uint48 validUntil, uint48 validAfter ) internal pure returns (uint256) { return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48)); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ /** * returned data from validateUserOp. * validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData` * @param aggregator - address(0) - the account validated the signature by itself. * address(1) - the account failed to validate the signature. * otherwise - this is an address of a signature aggregator that must be used to validate the signature. * @param validAfter - this UserOp is valid only after this timestamp. * @param validaUntil - this UserOp is valid only up to this timestamp. */ struct ValidationData { address aggregator; uint48 validAfter; uint48 validUntil; } //extract sigFailed, validAfter, validUntil. // also convert zero validUntil to type(uint48).max function _parseValidationData(uint validationData) pure returns (ValidationData memory data) { address aggregator = address(uint160(validationData)); uint48 validUntil = uint48(validationData >> 160); if (validUntil == 0) { validUntil = type(uint48).max; } uint48 validAfter = uint48(validationData >> (48 + 160)); return ValidationData(aggregator, validAfter, validUntil); } // intersect account and paymaster ranges. function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) { ValidationData memory accountValidationData = _parseValidationData(validationData); ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData); address aggregator = accountValidationData.aggregator; if (aggregator == address(0)) { aggregator = pmValidationData.aggregator; } uint48 validAfter = accountValidationData.validAfter; uint48 validUntil = accountValidationData.validUntil; uint48 pmValidAfter = pmValidationData.validAfter; uint48 pmValidUntil = pmValidationData.validUntil; if (validAfter < pmValidAfter) validAfter = pmValidAfter; if (validUntil > pmValidUntil) validUntil = pmValidUntil; return ValidationData(aggregator, validAfter, validUntil); } /** * helper to pack the return value for validateUserOp * @param data - the ValidationData to pack */ function _packValidationData(ValidationData memory data) pure returns (uint256) { return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48)); } /** * helper to pack the return value for validateUserOp, when not using an aggregator * @param sigFailed - true for signature failure, false for success * @param validUntil last timestamp this UserOperation is valid (or zero for infinite) * @param validAfter first timestamp this UserOperation is valid */ function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) { return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48)); } /** * keccak function over calldata. * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it. */ function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) { assembly { let mem := mload(0x40) let len := data.length calldatacopy(mem, data.offset, len) ret := keccak256(mem, len) } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ import {calldataKeccak} from "../core/Helpers.sol"; /** * User Operation struct * @param sender the sender account of this request. * @param nonce unique value the sender uses to verify it is not a replay. * @param initCode if set, the account contract will be created by this constructor/ * @param callData the method call to execute on this account. * @param callGasLimit the gas limit passed to the callData method call. * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp. * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead. * @param maxFeePerGas same as EIP-1559 gas parameter. * @param maxPriorityFeePerGas same as EIP-1559 gas parameter. * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender. * @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID. */ struct UserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; uint256 callGasLimit; uint256 verificationGasLimit; uint256 preVerificationGas; uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; bytes paymasterAndData; bytes signature; } /** * Utility functions helpful when working with UserOperation structs. */ library UserOperationLib { function getSender(UserOperation calldata userOp) internal pure returns (address) { address data; //read sender from userOp, which is first userOp member (saves 800 gas...) assembly {data := calldataload(userOp)} return address(uint160(data)); } //relayer/block builder might submit the TX with higher priorityFee, but the user should not // pay above what he signed for. function gasPrice(UserOperation calldata userOp) internal view returns (uint256) { unchecked { uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; if (maxFeePerGas == maxPriorityFeePerGas) { //legacy mode (for networks that don't support basefee opcode) return maxFeePerGas; } return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); } } function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) { address sender = getSender(userOp); uint256 nonce = userOp.nonce; bytes32 hashInitCode = calldataKeccak(userOp.initCode); bytes32 hashCallData = calldataKeccak(userOp.callData); uint256 callGasLimit = userOp.callGasLimit; uint256 verificationGasLimit = userOp.verificationGasLimit; uint256 preVerificationGas = userOp.preVerificationGas; uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); return abi.encode( sender, nonce, hashInitCode, hashCallData, callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas, hashPaymasterAndData ); } function hash(UserOperation calldata userOp) internal pure returns (bytes32) { return keccak256(pack(userOp)); } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; /* solhint-disable no-empty-blocks */ import {IAuthorizationModule} from "./interfaces/IAuthorizationModule.sol"; import {ISignatureValidator} from "./interfaces/ISignatureValidator.sol"; contract AuthorizationModulesConstants { uint256 internal constant VALIDATION_SUCCESS = 0; uint256 internal constant SIG_VALIDATION_FAILED = 1; } abstract contract BaseAuthorizationModule is IAuthorizationModule, ISignatureValidator, AuthorizationModulesConstants {}
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; import "./MultiSig/CommonOwnerManager.sol"; import "./MultiSig/SignatureDecoder.sol"; import "./MultiSig/GnosisSafeMath.sol"; contract CommonSignatureChecker is CommonOwnerManager, SignatureDecoder { using GnosisSafeMath for uint256; event SafeSetup(address indexed initiator, address[] owners, uint256 threshold); /// @dev Setup function sets initial storage of contract. /// @param _owners List of Safe owners. /// @param _threshold Number of required confirmations for a Safe transaction. function setup( address[] calldata _owners, uint256 _threshold ) external returns(address) { // setupOwners checks if the Threshold is already set, therefore preventing that this method is called twice setupOwners(_owners, _threshold); // As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules accountSupported[msg.sender] =true; emit SafeSetup(msg.sender, _owners, _threshold); return address(this); } function checkSignatures( bytes32 dataHash, bytes memory data, bytes memory signatures ) public view returns(bool) { // Load threshold to avoid multiple storage loads uint256 _threshold = smartAccountToOwners[msg.sender].threshold; // Check that a threshold is set require(_threshold > 0, "Threshold is zero"); checkNSignatures(dataHash, data, signatures, _threshold); return true; } /** * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise. * @param dataHash Hash of the data (could be either a message hash or transaction hash) * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash. * @param requiredSignatures Amount of required valid signatures. */ function checkNSignatures( bytes32 dataHash,bytes memory, bytes memory signatures, uint256 requiredSignatures ) public view { // Check that the provided signature data is not too short require(signatures.length >= requiredSignatures.mul(65), "Invalid inputs"); // There cannot be an owner with address 0. address lastOwner = address(0); address currentOwner; uint8 v; bytes32 r; bytes32 s; uint256 i; for (i = 0; i < requiredSignatures; i++) { (v, r, s) = signatureSplit(signatures, i); if (v > 30) { // If v > 30 then default va (27,28) has been adjusted for eth_sign flow // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover currentOwner = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s); } else { // Default is the ecrecover flow with the provided data hash // Use ecrecover with the messageHash for EOA signatures currentOwner = ecrecover(dataHash, v, r, s); } require(currentOwner > lastOwner && smartAccountToOwners[msg.sender].owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "Not a owner"); lastOwner = currentOwner; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; // interface for modules to verify singatures signed over userOpHash interface IAuthorizationModule { function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash ) external returns (uint256 validationData); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.8.0 <0.9.0; contract ISignatureValidatorConstants { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; } abstract contract ISignatureValidator is ISignatureValidatorConstants { /** * @dev Should return whether the signature provided is valid for the provided data * @param _dataHash Arbitrary length data signed on behalf of address(this) * @param _signature Signature byte array associated with _data * * MUST return the bytes4 magic value 0x1626ba7e when function passes. * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5) * MUST allow external calls */ function isValidSignature( bytes32 _dataHash, bytes memory _signature ) public view virtual returns (bytes4); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; /// @title OwnerManager - Manages a set of owners and a threshold to perform actions. contract CommonOwnerManager { event AddedOwner(address owner); event RemovedOwner(address owner); event ChangedThreshold(uint256 threshold); event SmartAcountAdded(address _account); address internal constant SENTINEL_OWNERS = address(0x1); struct Details { mapping(address => address) owners; uint256 threshold; uint256 ownerCount; } // mapping(address => address) internal owners; mapping(address => bool) public accountSupported; mapping(address => Details) public smartAccountToOwners; // uint256 internal ownerCount; // uint256 internal threshold; function isSmartAccount(address _account) internal view { require(accountSupported[_account], "Smart account not supported"); } /// @dev Setup function sets initial storage of contract. /// @param _owners List of Safe owners. /// @param _threshold Number of required confirmations for a Safe transaction. function setupOwners(address[] memory _owners, uint256 _threshold) internal { // Threshold can only be 0 at initialization. // Check ensures that setup function can only be called once. require(smartAccountToOwners[msg.sender].threshold == 0, "Already initialized"); // Validate that threshold is smaller than number of added owners. require(_threshold <= _owners.length, "Decrease threshold"); // There has to be at least one Safe owner. require(_threshold >= 1, "Threshold should be one atleast"); // Initializing Safe owners. address currentOwner = SENTINEL_OWNERS; for (uint256 i = 0; i < _owners.length; i++) { // Owner address cannot be null. address owner = _owners[i]; require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this) && currentOwner != owner, "Invalid owner"); // No duplicate owners allowed. require(smartAccountToOwners[msg.sender].owners[owner] == address(0), "Owner already present"); smartAccountToOwners[msg.sender].owners[currentOwner] = owner; currentOwner = owner; } smartAccountToOwners[msg.sender].owners[currentOwner] = SENTINEL_OWNERS; smartAccountToOwners[msg.sender].ownerCount = _owners.length; smartAccountToOwners[msg.sender].threshold = _threshold; } /// @dev Allows to add a new owner to the Safe and update the threshold at the same time. /// This can only be done via a Safe transaction. /// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`. /// @param owner New owner address. /// @param _threshold New threshold. function addOwnerWithThreshold(address owner, uint256 _threshold) public { isSmartAccount(msg.sender); // Owner address cannot be null, the sentinel or the Safe itself. require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this), "Invalid owner"); // No duplicate owners allowed. require(smartAccountToOwners[msg.sender].owners[owner] == address(0), "Duplicate owner"); smartAccountToOwners[msg.sender].owners[owner] = smartAccountToOwners[msg.sender].owners[SENTINEL_OWNERS]; smartAccountToOwners[msg.sender].owners[SENTINEL_OWNERS] = owner; smartAccountToOwners[msg.sender].ownerCount++; emit AddedOwner(owner); // Change threshold if threshold was changed. if (smartAccountToOwners[msg.sender].threshold != _threshold) changeThreshold(_threshold); } /// @dev Allows to remove an owner from the Safe and update the threshold at the same time. /// This can only be done via a Safe transaction. /// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`. /// @param prevOwner Owner that pointed to the owner to be removed in the linked list /// @param owner Owner address to be removed. /// @param _threshold New threshold. function removeOwner( address prevOwner, address owner, uint256 _threshold ) public { isSmartAccount(msg.sender); // Only allow to remove an owner, if threshold can still be reached. require(smartAccountToOwners[msg.sender].ownerCount - 1 >= _threshold, "Violating owner"); // Validate owner address and check that it corresponds to owner index. require(owner != address(0) && owner != SENTINEL_OWNERS, "Owner invalid"); require(smartAccountToOwners[msg.sender].owners[prevOwner] == owner, "Invalid previous owner"); smartAccountToOwners[msg.sender].owners[prevOwner] = smartAccountToOwners[msg.sender].owners[owner]; smartAccountToOwners[msg.sender].owners[owner] = address(0); smartAccountToOwners[msg.sender].ownerCount--; emit RemovedOwner(owner); // Change threshold if threshold was changed. if (smartAccountToOwners[msg.sender].threshold != _threshold) changeThreshold(_threshold); } /// @dev Allows to swap/replace an owner from the Safe with another address. /// This can only be done via a Safe transaction. /// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`. /// @param prevOwner Owner that pointed to the owner to be replaced in the linked list /// @param oldOwner Owner address to be replaced. /// @param newOwner New owner address. function swapOwner( address prevOwner, address oldOwner, address newOwner ) public { isSmartAccount(msg.sender); // Owner address cannot be null, the sentinel or the Safe itself. require(newOwner != address(0) && newOwner != SENTINEL_OWNERS && newOwner != address(this), "Invalid address"); // No duplicate owners allowed. require(smartAccountToOwners[msg.sender].owners[newOwner] == address(0), "Already a owner"); // Validate oldOwner address and check that it corresponds to owner index. require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "Invalid address"); require(smartAccountToOwners[msg.sender].owners[prevOwner] == oldOwner, "Invalid pointer address"); smartAccountToOwners[msg.sender].owners[newOwner] = smartAccountToOwners[msg.sender].owners[oldOwner]; smartAccountToOwners[msg.sender].owners[prevOwner] = newOwner; smartAccountToOwners[msg.sender].owners[oldOwner] = address(0); emit RemovedOwner(oldOwner); emit AddedOwner(newOwner); } /// @dev Allows to update the number of required confirmations by Safe owners. /// This can only be done via a Safe transaction. /// @notice Changes the threshold of the Safe to `_threshold`. /// @param _threshold New threshold. function changeThreshold(uint256 _threshold) public { isSmartAccount(msg.sender); // Validate that threshold is smaller than number of owners. require(_threshold <= smartAccountToOwners[msg.sender].ownerCount, "Threshold should be less than owners count"); // There has to be at least one Safe owner. require(_threshold >= 1, "Threshold should be atleast one"); smartAccountToOwners[msg.sender].threshold = _threshold; emit ChangedThreshold(smartAccountToOwners[msg.sender].threshold); } function getThreshold(address _account) public view returns (uint256) { return smartAccountToOwners[_account].threshold; } function isOwner(address _account, address owner) public view returns (bool) { return owner != SENTINEL_OWNERS && smartAccountToOwners[_account].owners[owner] != address(0); } /// @dev Returns array of owners. /// @return Array of Safe owners. function getOwners(address _account) public view returns (address[] memory) { address[] memory array = new address[](smartAccountToOwners[_account].ownerCount); // populate return array uint256 index = 0; address currentOwner = smartAccountToOwners[_account].owners[SENTINEL_OWNERS]; while (currentOwner != SENTINEL_OWNERS) { array[index] = currentOwner; currentOwner = smartAccountToOwners[_account].owners[currentOwner]; index++; } return array; } function addAccount(address _account) public { isSmartAccount(msg.sender); require(_account != address(0), "Zero address"); require(_account.code.length > 0, "Not a contract"); accountSupported[_account] = true; emit SmartAcountAdded(_account); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; /** * @title GnosisSafeMath * @dev Math operations with safety checks that revert on error * Renamed from SafeMath to GnosisSafeMath to avoid conflicts * TODO: remove once open zeppelin update to solc 0.5.0 */ library GnosisSafeMath { /** * @dev Multiplies two numbers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two numbers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; /// @title SignatureDecoder - Decodes signatures that a encoded as bytes contract SignatureDecoder { /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`. /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access /// @param signatures concatenated rsv signatures function signatureSplit(bytes memory signatures, uint256 pos) internal pure returns ( uint8 v, bytes32 r, bytes32 s ) { // The signature format is a compact form of: // {bytes32 r}{bytes32 s}{uint8 v} // Compact means, uint8 is not padded to 32 bytes. // solhint-disable-next-line no-inline-assembly assembly { let signaturePos := mul(0x41, pos) r := mload(add(signatures, add(signaturePos, 0x20))) s := mload(add(signatures, add(signaturePos, 0x40))) // Here we are loading the last 32 bytes, including 31 bytes // of 's'. There is no 'mload8' to do this. // // 'byte' is not working due to the Solidity parser, so lets // use the second best option, 'and' v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff) } } }
{ "optimizer": { "enabled": true, "runs": 10000000 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"entryPoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"AddedOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"threshold","type":"uint256"}],"name":"ChangedThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"RemovedOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initiator","type":"address"},{"indexed":false,"internalType":"address[]","name":"owners","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"threshold","type":"uint256"}],"name":"SafeSetup","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_account","type":"address"}],"name":"SmartAcountAdded","type":"event"},{"inputs":[],"name":"SUPPORTED_ENTRYPOINT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"addOwnerWithThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"changeThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"internalType":"uint256","name":"requiredSignatures","type":"uint256"}],"name":"checkNSignatures","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"checkSignatures","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"}],"name":"getOperationHash","outputs":[{"internalType":"bytes32","name":"operationHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getOwners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"operationDataHash","type":"bytes32"},{"internalType":"bytes","name":"operationDataPack","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"operationDataHash","type":"bytes32"},{"internalType":"bytes","name":"operationDataPack","type":"bytes"},{"internalType":"address","name":"smartAccount","type":"address"}],"name":"isValidSignatureForAddress","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"prevOwner","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"removeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_owners","type":"address[]"},{"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"setup","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"smartAccountToOwners","outputs":[{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"ownerCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"prevOwner","type":"address"},{"internalType":"address","name":"oldOwner","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"swapOwner","outputs":[],"stateMutability":"nonpayable","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":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200294a3803806200294a8339810160408190526200003491620000a1565b6001600160a01b0381166200008f5760405162461bcd60e51b815260206004820152601360248201527f496e76616c696420656e74727920706f696e7400000000000000000000000000604482015260640160405180910390fd5b6001600160a01b0316608052620000d3565b600060208284031215620000b457600080fd5b81516001600160a01b0381168114620000cc57600080fd5b9392505050565b608051612854620000f6600039600081816101830152611cf501526128546000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c8063934f3a11116100cd578063f44c339d11610081578063f8dc5dd911610066578063f8dc5dd9146103c3578063fd8b84b1146103d6578063fff35b72146103f657600080fd5b8063f44c339d14610354578063f698da251461036757600080fd5b8063cc1b5475116100b2578063cc1b5475146102ed578063e318b52b1461032e578063e89b0e1e1461034157600080fd5b8063934f3a11146102c7578063b25f3776146102da57600080fd5b80631d65ea0511610124578063694e80c311610109578063694e80c314610259578063789771681461026c5780637ddc02d4146102b457600080fd5b80631d65ea05146102135780634ab884271461024657600080fd5b80630d582f131461015657806312fb68e01461016b578063137e051e1461017e5780631626ba7e146101cf575b600080fd5b610169610164366004611f75565b610409565b005b6101696101793660046120b9565b610671565b6101a57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101e26101dd36600461212e565b610951565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016101c6565b610236610221366004612175565b60006020819052908152604090205460ff1681565b60405190151581526020016101c6565b6101a5610254366004612190565b610967565b61016961026736600461220b565b610a25565b6102a661027a366004612175565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160208190526040909120015490565b6040519081526020016101c6565b6102366102c2366004612224565b610b8d565b6102366102d5366004612257565b610beb565b6102a66102e83660046122dd565b610c7c565b6103196102fb366004612175565b60016020819052600091825260409091209081015460029091015482565b604080519283526020830191909152016101c6565b61016961033c36600461231a565b610c9e565b61016961034f366004612175565b611048565b6101e261036236600461235d565b6111cc565b6102a6604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6101696103d13660046123ab565b61122d565b6103e96103e4366004612175565b6114fc565b6040516101c691906123e7565b6102a6610404366004612441565b611636565b6104123361164a565b73ffffffffffffffffffffffffffffffffffffffff82161580159061044e575073ffffffffffffffffffffffffffffffffffffffff8216600114155b8015610470575073ffffffffffffffffffffffffffffffffffffffff82163014155b6104db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206f776e65720000000000000000000000000000000000000060448201526064015b60405180910390fd5b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86811685529252909120541615610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4475706c6963617465206f776e6572000000000000000000000000000000000060448201526064016104d2565b336000818152600160208181526040808420838552808352818520805473ffffffffffffffffffffffffffffffffffffffff8a81168089529488208054919092167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091558154169092179091559383525260029091018054916105fc836124b5565b909155505060405173ffffffffffffffffffffffffffffffffffffffff831681527f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea269060200160405180910390a13360009081526001602081905260409091200154811461066d5761066d81610a25565b5050565b61067c8160416116dc565b825110156106e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420696e7075747300000000000000000000000000000000000060448201526064016104d2565b6000808060008060005b86811015610945576041818102890160208101516040820151919092015160ff1695509093509150601e8411156107da576040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018b9052600190605c016040516020818303038152906040528051906020012060048661077a91906124ed565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156107c9573d6000803e3d6000fd5b50505060206040510351945061083a565b6040805160008152602081018083528c905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa15801561082d573d6000803e3d6000fd5b5050506020604051035194505b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156108a6575033600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff89811685529252909120541615155b80156108c9575073ffffffffffffffffffffffffffffffffffffffff8516600114155b61092f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4e6f742061206f776e657200000000000000000000000000000000000000000060448201526064016104d2565b849550808061093d906124b5565b9150506106f0565b50505050505050505050565b600061095e8383336111cc565b90505b92915050565b60006109a7848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250611711915050565b336000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f9f7ea12b584e639128b2cae69de6ca3335a28b01235291afa40ce814fdf65f3590610a1390879087908790612506565b60405180910390a250305b9392505050565b610a2e3361164a565b33600090815260016020526040902060020154811115610ad0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5468726573686f6c642073686f756c64206265206c657373207468616e206f7760448201527f6e65727320636f756e740000000000000000000000000000000000000000000060648201526084016104d2565b6001811015610b3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5468726573686f6c642073686f756c642062652061746c65617374206f6e650060448201526064016104d2565b3360009081526001602081905260409182902001829055517f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c9390610b829083815260200190565b60405180910390a150565b600073ffffffffffffffffffffffffffffffffffffffff821660011480159061095e57505073ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209385168352929052205416151590565b3360009081526001602081905260408220015480610c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5468726573686f6c64206973207a65726f00000000000000000000000000000060448201526064016104d2565b610c7185858584610671565b506001949350505050565b600080610c8883611b1d565b5050505090508080519060200120915050919050565b610ca73361164a565b73ffffffffffffffffffffffffffffffffffffffff811615801590610ce3575073ffffffffffffffffffffffffffffffffffffffff8116600114155b8015610d05575073ffffffffffffffffffffffffffffffffffffffff81163014155b610d6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c69642061646472657373000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff85811685529252909120541615610e05576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c72656164792061206f776e6572000000000000000000000000000000000060448201526064016104d2565b73ffffffffffffffffffffffffffffffffffffffff821615801590610e41575073ffffffffffffffffffffffffffffffffffffffff8216600114155b610ea7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c69642061646472657373000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8781168552925290912054811690831614610f45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420706f696e746572206164647265737300000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff868116808652918452828520805487831680885285882080549285167fffffffffffffffffffffffff0000000000000000000000000000000000000000938416179055928a1687528487208054821690931790925594829052845416909355519182527ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf910160405180910390a160405173ffffffffffffffffffffffffffffffffffffffff821681527f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea269060200160405180910390a1505050565b6110513361164a565b73ffffffffffffffffffffffffffffffffffffffff81166110ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a65726f2061646472657373000000000000000000000000000000000000000060448201526064016104d2565b60008173ffffffffffffffffffffffffffffffffffffffff163b1161114f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f74206120636f6e747261637400000000000000000000000000000000000060448201526064016104d2565b73ffffffffffffffffffffffffffffffffffffffff81166000818152602081815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f016c6c81185d9d57ee95b405e66dcd24b95197e63995a3c3fdf91d58dbf912d89101610b82565b6000806111d884611e21565b0361120457507f1626ba7e00000000000000000000000000000000000000000000000000000000610a1e565b507fffffffff000000000000000000000000000000000000000000000000000000009392505050565b6112363361164a565b33600090815260016020819052604090912060020154829161125791612567565b10156112bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f56696f6c6174696e67206f776e6572000000000000000000000000000000000060448201526064016104d2565b73ffffffffffffffffffffffffffffffffffffffff8216158015906112fb575073ffffffffffffffffffffffffffffffffffffffff8216600114155b611361576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4f776e657220696e76616c69640000000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87811685529252909120548116908316146113ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642070726576696f7573206f776e65720000000000000000000060448201526064016104d2565b33600081815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff888116865281845282862080548b831688529387208054949092167fffffffffffffffffffffffff00000000000000000000000000000000000000009485161790915580549092169091559383525260029091018054916114868361257a565b909155505060405173ffffffffffffffffffffffffffffffffffffffff831681527ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf9060200160405180910390a1336000908152600160208190526040909120015481146114f7576114f781610a25565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600160205260408120600201546060919067ffffffffffffffff81111561154157611541611f9f565b60405190808252806020026020018201604052801561156a578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff808516600090815260016020818152604080842092845291905281205492935091165b73ffffffffffffffffffffffffffffffffffffffff811660011461162d57808383815181106115d4576115d46125af565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152868216600090815260018252604080822094841682529390915291909120541681611625816124b5565b9250506115a3565b50909392505050565b60006116413361164a565b61095e83611e79565b73ffffffffffffffffffffffffffffffffffffffff811660009081526020819052604090205460ff166116d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536d617274206163636f756e74206e6f7420737570706f72746564000000000060448201526064016104d2565b50565b6000826000036116ee57506000610961565b60006116fa83856125de565b90508261170785836125f5565b1461095e57600080fd5b33600090815260016020819052604090912001541561178c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a65640000000000000000000000000060448201526064016104d2565b81518111156117f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4465637265617365207468726573686f6c64000000000000000000000000000060448201526064016104d2565b6001811015611862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5468726573686f6c642073686f756c64206265206f6e652061746c656173740060448201526064016104d2565b600160005b8351811015611aad576000848281518110611884576118846125af565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156118e2575073ffffffffffffffffffffffffffffffffffffffff8116600114155b8015611904575073ffffffffffffffffffffffffffffffffffffffff81163014155b801561193c57508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b6119a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff85811685529252909120541615611a3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f776e657220616c72656164792070726573656e74000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff9687168452909152902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169382169390931790925580611aa5816124b5565b915050611867565b5033600081815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff969096168452858252832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168317905595519290915293849052600282015590910155565b606060008036818181611b34610140890189612630565b9092509050611b4760066000838561269c565b611b50916126c6565b60d01c9550611b63600c6006838561269c565b611b6c916126c6565b60d01c9450366000611b8183600c818761269c565b909250905081600082611b95601482612567565b92611ba29392919061269c565b95509550505050506000604051806101c001604052807f84aa190356f56b8c87825f54884392a9907c23ee0f8e1ea86336b763faf021bd8152602001886000016020810190611bf19190612175565b73ffffffffffffffffffffffffffffffffffffffff16815260200188602001358152602001888060400190611c269190612630565b604051611c3492919061270e565b6040519081900390208152602001611c4f60608a018a612630565b604051611c5d92919061270e565b60405180910390208152602001886080013581526020018860a0013581526020018860c0013581526020018860e001358152602001886101000135815260200188806101200190611cae9190612630565b604051611cbc92919061270e565b6040805191829003909120825265ffffffffffff808916602084015287169082015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166060909101526101c081209091507f19000000000000000000000000000000000000000000000000000000000000007f0100000000000000000000000000000000000000000000000000000000000000611dc1604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6040517fff0000000000000000000000000000000000000000000000000000000000000093841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600080600080600085806020019051810190611e3d9190612799565b93509350935093506000611e5985805190602001208684610beb565b90508015611e6a5760009550611e6f565b600195505b5050505050919050565b600080600080366000611e8b87611b1d565b945094509450945094506000611edf86805190602001208785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610beb92505050565b90508015611efa57611ef360008587611f14565b9650611f09565b611f0660018587611f14565b96505b505050505050919050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85611f3c576000611f3f565b60015b60ff161717949350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611f7057600080fd5b919050565b60008060408385031215611f8857600080fd5b611f9183611f4c565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561201557612015611f9f565b604052919050565b600067ffffffffffffffff82111561203757612037611f9f565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261207457600080fd5b81356120876120828261201d565b611fce565b81815284602083860101111561209c57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156120cf57600080fd5b84359350602085013567ffffffffffffffff808211156120ee57600080fd5b6120fa88838901612063565b9450604087013591508082111561211057600080fd5b5061211d87828801612063565b949793965093946060013593505050565b6000806040838503121561214157600080fd5b82359150602083013567ffffffffffffffff81111561215f57600080fd5b61216b85828601612063565b9150509250929050565b60006020828403121561218757600080fd5b61095e82611f4c565b6000806000604084860312156121a557600080fd5b833567ffffffffffffffff808211156121bd57600080fd5b818601915086601f8301126121d157600080fd5b8135818111156121e057600080fd5b8760208260051b85010111156121f557600080fd5b6020928301989097509590910135949350505050565b60006020828403121561221d57600080fd5b5035919050565b6000806040838503121561223757600080fd5b61224083611f4c565b915061224e60208401611f4c565b90509250929050565b60008060006060848603121561226c57600080fd5b83359250602084013567ffffffffffffffff8082111561228b57600080fd5b61229787838801612063565b935060408601359150808211156122ad57600080fd5b506122ba86828701612063565b9150509250925092565b600061016082840312156122d757600080fd5b50919050565b6000602082840312156122ef57600080fd5b813567ffffffffffffffff81111561230657600080fd5b612312848285016122c4565b949350505050565b60008060006060848603121561232f57600080fd5b61233884611f4c565b925061234660208501611f4c565b915061235460408501611f4c565b90509250925092565b60008060006060848603121561237257600080fd5b83359250602084013567ffffffffffffffff81111561239057600080fd5b61239c86828701612063565b92505061235460408501611f4c565b6000806000606084860312156123c057600080fd5b6123c984611f4c565b92506123d760208501611f4c565b9150604084013590509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561243557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612403565b50909695505050505050565b6000806040838503121561245457600080fd5b823567ffffffffffffffff81111561246b57600080fd5b612477858286016122c4565b95602094909401359450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124e6576124e6612486565b5060010190565b60ff828116828216039081111561096157610961612486565b6040808252810183905260008460608301825b868110156125545773ffffffffffffffffffffffffffffffffffffffff61253f84611f4c565b16825260209283019290910190600101612519565b5060209390930193909352509392505050565b8181038181111561096157610961612486565b60008161258957612589612486565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808202811582820484141761096157610961612486565b60008261262b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261266557600080fd5b83018035915067ffffffffffffffff82111561268057600080fd5b60200191503681900382131561269557600080fd5b9250929050565b600080858511156126ac57600080fd5b838611156126b957600080fd5b5050820193919092039150565b7fffffffffffff000000000000000000000000000000000000000000000000000081358181169160068510156127065780818660060360031b1b83161692505b505092915050565b8183823760009101908152919050565b600082601f83011261272f57600080fd5b815161273d6120828261201d565b8181526020858184870101111561275357600080fd5b60005b83811015612771578581018201518382018301528101612756565b50600092820101919091529392505050565b805165ffffffffffff81168114611f7057600080fd5b600080600080608085870312156127af57600080fd5b845167ffffffffffffffff808211156127c757600080fd5b6127d38883890161271e565b95506127e160208801612783565b94506127ef60408801612783565b9350606087015191508082111561280557600080fd5b506128128782880161271e565b9150509295919450925056fea26469706673582212203b668abc8bac7f0eae5c009377c2ccd3ba23dcdb9c4b8a148d6951d50fe2f4ef64736f6c634300081400330000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101515760003560e01c8063934f3a11116100cd578063f44c339d11610081578063f8dc5dd911610066578063f8dc5dd9146103c3578063fd8b84b1146103d6578063fff35b72146103f657600080fd5b8063f44c339d14610354578063f698da251461036757600080fd5b8063cc1b5475116100b2578063cc1b5475146102ed578063e318b52b1461032e578063e89b0e1e1461034157600080fd5b8063934f3a11146102c7578063b25f3776146102da57600080fd5b80631d65ea0511610124578063694e80c311610109578063694e80c314610259578063789771681461026c5780637ddc02d4146102b457600080fd5b80631d65ea05146102135780634ab884271461024657600080fd5b80630d582f131461015657806312fb68e01461016b578063137e051e1461017e5780631626ba7e146101cf575b600080fd5b610169610164366004611f75565b610409565b005b6101696101793660046120b9565b610671565b6101a57f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278981565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101e26101dd36600461212e565b610951565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016101c6565b610236610221366004612175565b60006020819052908152604090205460ff1681565b60405190151581526020016101c6565b6101a5610254366004612190565b610967565b61016961026736600461220b565b610a25565b6102a661027a366004612175565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160208190526040909120015490565b6040519081526020016101c6565b6102366102c2366004612224565b610b8d565b6102366102d5366004612257565b610beb565b6102a66102e83660046122dd565b610c7c565b6103196102fb366004612175565b60016020819052600091825260409091209081015460029091015482565b604080519283526020830191909152016101c6565b61016961033c36600461231a565b610c9e565b61016961034f366004612175565b611048565b6101e261036236600461235d565b6111cc565b6102a6604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6101696103d13660046123ab565b61122d565b6103e96103e4366004612175565b6114fc565b6040516101c691906123e7565b6102a6610404366004612441565b611636565b6104123361164a565b73ffffffffffffffffffffffffffffffffffffffff82161580159061044e575073ffffffffffffffffffffffffffffffffffffffff8216600114155b8015610470575073ffffffffffffffffffffffffffffffffffffffff82163014155b6104db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206f776e65720000000000000000000000000000000000000060448201526064015b60405180910390fd5b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86811685529252909120541615610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4475706c6963617465206f776e6572000000000000000000000000000000000060448201526064016104d2565b336000818152600160208181526040808420838552808352818520805473ffffffffffffffffffffffffffffffffffffffff8a81168089529488208054919092167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091558154169092179091559383525260029091018054916105fc836124b5565b909155505060405173ffffffffffffffffffffffffffffffffffffffff831681527f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea269060200160405180910390a13360009081526001602081905260409091200154811461066d5761066d81610a25565b5050565b61067c8160416116dc565b825110156106e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c696420696e7075747300000000000000000000000000000000000060448201526064016104d2565b6000808060008060005b86811015610945576041818102890160208101516040820151919092015160ff1695509093509150601e8411156107da576040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018b9052600190605c016040516020818303038152906040528051906020012060048661077a91906124ed565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156107c9573d6000803e3d6000fd5b50505060206040510351945061083a565b6040805160008152602081018083528c905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa15801561082d573d6000803e3d6000fd5b5050506020604051035194505b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156108a6575033600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff89811685529252909120541615155b80156108c9575073ffffffffffffffffffffffffffffffffffffffff8516600114155b61092f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4e6f742061206f776e657200000000000000000000000000000000000000000060448201526064016104d2565b849550808061093d906124b5565b9150506106f0565b50505050505050505050565b600061095e8383336111cc565b90505b92915050565b60006109a7848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250611711915050565b336000818152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f9f7ea12b584e639128b2cae69de6ca3335a28b01235291afa40ce814fdf65f3590610a1390879087908790612506565b60405180910390a250305b9392505050565b610a2e3361164a565b33600090815260016020526040902060020154811115610ad0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5468726573686f6c642073686f756c64206265206c657373207468616e206f7760448201527f6e65727320636f756e740000000000000000000000000000000000000000000060648201526084016104d2565b6001811015610b3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5468726573686f6c642073686f756c642062652061746c65617374206f6e650060448201526064016104d2565b3360009081526001602081905260409182902001829055517f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c9390610b829083815260200190565b60405180910390a150565b600073ffffffffffffffffffffffffffffffffffffffff821660011480159061095e57505073ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209385168352929052205416151590565b3360009081526001602081905260408220015480610c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5468726573686f6c64206973207a65726f00000000000000000000000000000060448201526064016104d2565b610c7185858584610671565b506001949350505050565b600080610c8883611b1d565b5050505090508080519060200120915050919050565b610ca73361164a565b73ffffffffffffffffffffffffffffffffffffffff811615801590610ce3575073ffffffffffffffffffffffffffffffffffffffff8116600114155b8015610d05575073ffffffffffffffffffffffffffffffffffffffff81163014155b610d6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c69642061646472657373000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff85811685529252909120541615610e05576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c72656164792061206f776e6572000000000000000000000000000000000060448201526064016104d2565b73ffffffffffffffffffffffffffffffffffffffff821615801590610e41575073ffffffffffffffffffffffffffffffffffffffff8216600114155b610ea7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c69642061646472657373000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8781168552925290912054811690831614610f45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420706f696e746572206164647265737300000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff868116808652918452828520805487831680885285882080549285167fffffffffffffffffffffffff0000000000000000000000000000000000000000938416179055928a1687528487208054821690931790925594829052845416909355519182527ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf910160405180910390a160405173ffffffffffffffffffffffffffffffffffffffff821681527f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea269060200160405180910390a1505050565b6110513361164a565b73ffffffffffffffffffffffffffffffffffffffff81166110ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a65726f2061646472657373000000000000000000000000000000000000000060448201526064016104d2565b60008173ffffffffffffffffffffffffffffffffffffffff163b1161114f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f74206120636f6e747261637400000000000000000000000000000000000060448201526064016104d2565b73ffffffffffffffffffffffffffffffffffffffff81166000818152602081815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f016c6c81185d9d57ee95b405e66dcd24b95197e63995a3c3fdf91d58dbf912d89101610b82565b6000806111d884611e21565b0361120457507f1626ba7e00000000000000000000000000000000000000000000000000000000610a1e565b507fffffffff000000000000000000000000000000000000000000000000000000009392505050565b6112363361164a565b33600090815260016020819052604090912060020154829161125791612567565b10156112bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f56696f6c6174696e67206f776e6572000000000000000000000000000000000060448201526064016104d2565b73ffffffffffffffffffffffffffffffffffffffff8216158015906112fb575073ffffffffffffffffffffffffffffffffffffffff8216600114155b611361576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4f776e657220696e76616c69640000000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87811685529252909120548116908316146113ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642070726576696f7573206f776e65720000000000000000000060448201526064016104d2565b33600081815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff888116865281845282862080548b831688529387208054949092167fffffffffffffffffffffffff00000000000000000000000000000000000000009485161790915580549092169091559383525260029091018054916114868361257a565b909155505060405173ffffffffffffffffffffffffffffffffffffffff831681527ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf9060200160405180910390a1336000908152600160208190526040909120015481146114f7576114f781610a25565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600160205260408120600201546060919067ffffffffffffffff81111561154157611541611f9f565b60405190808252806020026020018201604052801561156a578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff808516600090815260016020818152604080842092845291905281205492935091165b73ffffffffffffffffffffffffffffffffffffffff811660011461162d57808383815181106115d4576115d46125af565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152868216600090815260018252604080822094841682529390915291909120541681611625816124b5565b9250506115a3565b50909392505050565b60006116413361164a565b61095e83611e79565b73ffffffffffffffffffffffffffffffffffffffff811660009081526020819052604090205460ff166116d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536d617274206163636f756e74206e6f7420737570706f72746564000000000060448201526064016104d2565b50565b6000826000036116ee57506000610961565b60006116fa83856125de565b90508261170785836125f5565b1461095e57600080fd5b33600090815260016020819052604090912001541561178c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a65640000000000000000000000000060448201526064016104d2565b81518111156117f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4465637265617365207468726573686f6c64000000000000000000000000000060448201526064016104d2565b6001811015611862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5468726573686f6c642073686f756c64206265206f6e652061746c656173740060448201526064016104d2565b600160005b8351811015611aad576000848281518110611884576118846125af565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156118e2575073ffffffffffffffffffffffffffffffffffffffff8116600114155b8015611904575073ffffffffffffffffffffffffffffffffffffffff81163014155b801561193c57508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b6119a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff85811685529252909120541615611a3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f776e657220616c72656164792070726573656e74000000000000000000000060448201526064016104d2565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff9687168452909152902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169382169390931790925580611aa5816124b5565b915050611867565b5033600081815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff969096168452858252832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168317905595519290915293849052600282015590910155565b606060008036818181611b34610140890189612630565b9092509050611b4760066000838561269c565b611b50916126c6565b60d01c9550611b63600c6006838561269c565b611b6c916126c6565b60d01c9450366000611b8183600c818761269c565b909250905081600082611b95601482612567565b92611ba29392919061269c565b95509550505050506000604051806101c001604052807f84aa190356f56b8c87825f54884392a9907c23ee0f8e1ea86336b763faf021bd8152602001886000016020810190611bf19190612175565b73ffffffffffffffffffffffffffffffffffffffff16815260200188602001358152602001888060400190611c269190612630565b604051611c3492919061270e565b6040519081900390208152602001611c4f60608a018a612630565b604051611c5d92919061270e565b60405180910390208152602001886080013581526020018860a0013581526020018860c0013581526020018860e001358152602001886101000135815260200188806101200190611cae9190612630565b604051611cbc92919061270e565b6040805191829003909120825265ffffffffffff808916602084015287169082015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789166060909101526101c081209091507f19000000000000000000000000000000000000000000000000000000000000007f0100000000000000000000000000000000000000000000000000000000000000611dc1604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6040517fff0000000000000000000000000000000000000000000000000000000000000093841660208201529290911660218301526022820152604281018290526062016040516020818303038152906040529650505091939590929450565b600080600080600085806020019051810190611e3d9190612799565b93509350935093506000611e5985805190602001208684610beb565b90508015611e6a5760009550611e6f565b600195505b5050505050919050565b600080600080366000611e8b87611b1d565b945094509450945094506000611edf86805190602001208785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610beb92505050565b90508015611efa57611ef360008587611f14565b9650611f09565b611f0660018587611f14565b96505b505050505050919050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85611f3c576000611f3f565b60015b60ff161717949350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611f7057600080fd5b919050565b60008060408385031215611f8857600080fd5b611f9183611f4c565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561201557612015611f9f565b604052919050565b600067ffffffffffffffff82111561203757612037611f9f565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261207457600080fd5b81356120876120828261201d565b611fce565b81815284602083860101111561209c57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156120cf57600080fd5b84359350602085013567ffffffffffffffff808211156120ee57600080fd5b6120fa88838901612063565b9450604087013591508082111561211057600080fd5b5061211d87828801612063565b949793965093946060013593505050565b6000806040838503121561214157600080fd5b82359150602083013567ffffffffffffffff81111561215f57600080fd5b61216b85828601612063565b9150509250929050565b60006020828403121561218757600080fd5b61095e82611f4c565b6000806000604084860312156121a557600080fd5b833567ffffffffffffffff808211156121bd57600080fd5b818601915086601f8301126121d157600080fd5b8135818111156121e057600080fd5b8760208260051b85010111156121f557600080fd5b6020928301989097509590910135949350505050565b60006020828403121561221d57600080fd5b5035919050565b6000806040838503121561223757600080fd5b61224083611f4c565b915061224e60208401611f4c565b90509250929050565b60008060006060848603121561226c57600080fd5b83359250602084013567ffffffffffffffff8082111561228b57600080fd5b61229787838801612063565b935060408601359150808211156122ad57600080fd5b506122ba86828701612063565b9150509250925092565b600061016082840312156122d757600080fd5b50919050565b6000602082840312156122ef57600080fd5b813567ffffffffffffffff81111561230657600080fd5b612312848285016122c4565b949350505050565b60008060006060848603121561232f57600080fd5b61233884611f4c565b925061234660208501611f4c565b915061235460408501611f4c565b90509250925092565b60008060006060848603121561237257600080fd5b83359250602084013567ffffffffffffffff81111561239057600080fd5b61239c86828701612063565b92505061235460408501611f4c565b6000806000606084860312156123c057600080fd5b6123c984611f4c565b92506123d760208501611f4c565b9150604084013590509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561243557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612403565b50909695505050505050565b6000806040838503121561245457600080fd5b823567ffffffffffffffff81111561246b57600080fd5b612477858286016122c4565b95602094909401359450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124e6576124e6612486565b5060010190565b60ff828116828216039081111561096157610961612486565b6040808252810183905260008460608301825b868110156125545773ffffffffffffffffffffffffffffffffffffffff61253f84611f4c565b16825260209283019290910190600101612519565b5060209390930193909352509392505050565b8181038181111561096157610961612486565b60008161258957612589612486565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808202811582820484141761096157610961612486565b60008261262b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261266557600080fd5b83018035915067ffffffffffffffff82111561268057600080fd5b60200191503681900382131561269557600080fd5b9250929050565b600080858511156126ac57600080fd5b838611156126b957600080fd5b5050820193919092039150565b7fffffffffffff000000000000000000000000000000000000000000000000000081358181169160068510156127065780818660060360031b1b83161692505b505092915050565b8183823760009101908152919050565b600082601f83011261272f57600080fd5b815161273d6120828261201d565b8181526020858184870101111561275357600080fd5b60005b83811015612771578581018201518382018301528101612756565b50600092820101919091529392505050565b805165ffffffffffff81168114611f7057600080fd5b600080600080608085870312156127af57600080fd5b845167ffffffffffffffff808211156127c757600080fd5b6127d38883890161271e565b95506127e160208801612783565b94506127ef60408801612783565b9350606087015191508082111561280557600080fd5b506128128782880161271e565b9150509295919450925056fea26469706673582212203b668abc8bac7f0eae5c009377c2ccd3ba23dcdb9c4b8a148d6951d50fe2f4ef64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
-----Decoded View---------------
Arg [0] : entryPoint (address): 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Loading...
Loading
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.