Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Name:
BiconomyTokenPaymaster
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 800 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; import {UserOperationLib} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {BasePaymaster} from "../BasePaymaster.sol"; import {IOracleAggregator} from "./oracles/IOracleAggregator.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@account-abstraction/contracts/core/Helpers.sol" as Helpers; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import "../utils/SafeTransferLib.sol"; import {TokenPaymasterErrors} from "./TokenPaymasterErrors.sol"; import "@openzeppelin/contracts/utils/Address.sol"; // Biconomy Token Paymaster /** * A token-based paymaster that allows user to pay gas fee in ERC20 tokens. The paymaster owner chooses which tokens to accept. * The payment manager (usually the owner) first deposits native gas into the EntryPoint. Then, for each transaction, it takes the gas fee from the user's ERC20 token balance. * The manager must convert these collected tokens back to native gas and deposit it into the EntryPoint to keep the system running. * It is an extension of VerifyingPaymaster which trusts external signer to authorize the transaction, but also with an ability to withdraw tokens. * * The validatePaymasterUserOp function does not interact with external contracts but uses an externally provided exchange rate. * Based on the exchangeRate and requiredPrefund amount, the validation method checks if the user's account has enough token balance. This is done by only looking at the referenced storage. * All Withdrawn tokens are sent to a dynamic fee receiver address. * * Optionally a safe guard deposit may be used in future versions. */ contract BiconomyTokenPaymaster is BasePaymaster, ReentrancyGuard, TokenPaymasterErrors { using ECDSA for bytes32; using Address for address; using UserOperationLib for UserOperation; /** * price source can be off-chain calculation or oracles * for oracle based it can be based on chainlink feeds or TWAP oracles * for ORACLE_BASED oracle aggregator address has to be passed in paymasterAndData */ enum ExchangeRateSource { EXTERNAL_EXCHANGE_RATE, ORACLE_BASED } // 1. use mode and based on mode treat uint256 fee sent either as priceMarkup or flatFee // 2. (no mode required) add extra value in paymasterandData so uint32 markup and uint224 flatFee both can be parsed // 3. (no mode required) without extra value treat uint256 as packed uint32uint224 and use values accordingly /*enum FeePremiumMode { PERCENTAGE, FLAT }*/ /// @notice All 'price' variable coming from outside are expected to be multiple of 1e6, and in actual calculation, /// final value is divided by PRICE_DENOMINATOR to avoid rounding up. uint32 private constant PRICE_DENOMINATOR = 1e6; // Gas used in EntryPoint._handlePostOp() method (including this#postOp() call) uint256 public UNACCOUNTED_COST = 45000; // TBD // Always rely on verifyingSigner.. address public verifyingSigner; // receiver of withdrawn fee tokens address public feeReceiver; // paymasterAndData: concat of [paymasterAddress(address), priceSource(enum 1 byte), abi.encode(validUntil, validAfter, feeToken, oracleAggregator, exchangeRate, priceMarkup): makes up 32*6 bytes, signature] // PND offset is used to indicate offsets to decode, used along with Signature offset uint256 private constant VALID_PND_OFFSET = 21; uint256 private constant SIGNATURE_OFFSET = 213; address private constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /** * Designed to enable the community to track change in storage variable UNACCOUNTED_COST which is used * to maintain gas execution cost which can't be calculated within contract*/ event EPGasOverheadChanged( uint256 indexed _oldOverheadCost, uint256 indexed _newOverheadCost, address indexed _actor ); /** * Designed to enable the community to track change in storage variable verifyingSigner which is used * to authorize any operation for this paymaster (validation stage) and provides signature*/ event VerifyingSignerChanged( address indexed _oldSigner, address indexed _newSigner, address indexed _actor ); /** * Designed to enable the community to track change in storage variable feeReceiver which is an address (self or other SCW/EOA) * responsible for collecting all the tokens being withdrawn as fees*/ event FeeReceiverChanged( address indexed _oldfeeReceiver, address indexed _newfeeReceiver, address indexed _actor ); /** * Designed to enable tracking how much fees were charged from the sender and in which ERC20 token * More information can be emitted like exchangeRate used, what was the source of exchangeRate etc*/ // priceMarkup = Multiplier value to calculate markup, 1e6 means 1x multiplier = No markup event TokenPaymasterOperation( address indexed sender, address indexed token, uint256 indexed totalCharge, address oracleAggregator, uint32 priceMarkup, bytes32 userOpHash, uint256 exchangeRate, ExchangeRateSource priceSource ); /** * Notify in case paymaster failed to withdraw tokens from sender */ event TokenPaymentDue( address indexed token, address indexed account, uint256 indexed charge ); event Received(address indexed sender, uint256 value); constructor( address _owner, IEntryPoint _entryPoint, address _verifyingSigner ) payable BasePaymaster(_owner, _entryPoint) { if (_owner == address(0)) revert OwnerCannotBeZero(); if (address(_entryPoint) == address(0)) revert EntryPointCannotBeZero(); if (_verifyingSigner == address(0)) revert VerifyingSignerCannotBeZero(); assembly ("memory-safe") { sstore(verifyingSigner.slot, _verifyingSigner) sstore(feeReceiver.slot, address()) // initialize with self (could also be _owner) } } /** * @dev Set a new verifying signer address. * Can only be called by the owner of the contract. * @param _newVerifyingSigner The new address to be set as the verifying signer. * @notice If _newVerifyingSigner is set to zero address, it will revert with an error. * After setting the new signer address, it will emit an event VerifyingSignerChanged. */ function setVerifyingSigner( address _newVerifyingSigner ) external payable onlyOwner { if (_newVerifyingSigner == address(0)) revert VerifyingSignerCannotBeZero(); address oldSigner = verifyingSigner; assembly ("memory-safe") { sstore(verifyingSigner.slot, _newVerifyingSigner) } emit VerifyingSignerChanged(oldSigner, _newVerifyingSigner, msg.sender); } // marked for removal /** * @dev Set a new fee receiver. * Can only be called by the owner of the contract. * @param _newFeeReceiver The new address to be set as the address of new fee receiver. * @notice If _newFeeReceiver is set to zero address, it will revert with an error. * After setting the new address, it will emit an event FeeReceiverChanged. */ function setFeeReceiver( address _newFeeReceiver ) external payable onlyOwner { if (_newFeeReceiver == address(0)) revert FeeReceiverCannotBeZero(); address oldFeeReceiver = feeReceiver; assembly ("memory-safe") { sstore(feeReceiver.slot, _newFeeReceiver) } emit FeeReceiverChanged(oldFeeReceiver, _newFeeReceiver, msg.sender); } /** * @dev Set a new overhead for unaccounted cost * Can only be called by the owner of the contract. * @param _newOverheadCost The new value to be set as the gas cost overhead. * @notice If _newOverheadCost is set to very high value, it will revert with an error. * After setting the new value, it will emit an event EPGasOverheadChanged. */ function setUnaccountedEPGasOverhead( uint256 _newOverheadCost ) external payable onlyOwner { // review if this could be high value in case of arbitrum if (_newOverheadCost > 200000) revert CannotBeUnrealisticValue(); uint256 oldValue = UNACCOUNTED_COST; assembly ("memory-safe") { sstore(UNACCOUNTED_COST.slot, _newOverheadCost) } emit EPGasOverheadChanged(oldValue, _newOverheadCost, msg.sender); } /** * Add a deposit in native currency for this paymaster, used for paying for transaction fees. * This is ideally done by the entity who is managing the received ERC20 gas tokens. */ function deposit() public payable virtual override nonReentrant { IEntryPoint(entryPoint).depositTo{value: msg.value}(address(this)); } /** * @dev Withdraws the specified amount of gas tokens from the paymaster's balance and transfers them to the specified address. * @param withdrawAddress The address to which the gas tokens should be transferred. * @param amount The amount of gas tokens to withdraw. */ function withdrawTo( address payable withdrawAddress, uint256 amount ) public override onlyOwner nonReentrant { if (withdrawAddress == address(0)) revert CanNotWithdrawToZeroAddress(); entryPoint.withdrawTo(withdrawAddress, amount); } /** * @dev Returns the exchange price of the token in wei. * @param _token ERC20 token address * @param _oracleAggregator oracle aggregator address */ function exchangePrice( address _token, address _oracleAggregator ) internal view virtual returns (uint256) { try IOracleAggregator(_oracleAggregator).getTokenValueOfOneNativeToken( _token ) returns (uint256 exchangeRate) { return exchangeRate; } catch { return 0; } } /** * @dev pull tokens out of paymaster in case they were sent to the paymaster at any point. * @param token the token deposit to withdraw * @param target address to send to * @param amount amount to withdraw */ function withdrawERC20( IERC20 token, address target, uint256 amount ) public payable onlyOwner nonReentrant { _withdrawERC20(token, target, amount); } /** * @dev pull tokens out of paymaster in case they were sent to the paymaster at any point. * @param token the token deposit to withdraw * @param target address to send to */ function withdrawERC20Full( IERC20 token, address target ) public payable onlyOwner nonReentrant { uint256 amount = token.balanceOf(address(this)); _withdrawERC20(token, target, amount); } /** * @dev pull multiple tokens out of paymaster in case they were sent to the paymaster at any point. * @param token the tokens deposit to withdraw * @param target address to send to * @param amount amounts to withdraw */ function withdrawMultipleERC20( IERC20[] calldata token, address target, uint256[] calldata amount ) public payable onlyOwner nonReentrant { if (token.length != amount.length) revert TokensAndAmountsLengthMismatch(); unchecked { for (uint256 i; i < token.length; ) { _withdrawERC20(token[i], target, amount[i]); ++i; } } } /** * @dev pull multiple tokens out of paymaster in case they were sent to the paymaster at any point. * @param token the tokens deposit to withdraw * @param target address to send to */ function withdrawMultipleERC20Full( IERC20[] calldata token, address target ) public payable onlyOwner nonReentrant { unchecked { for (uint256 i; i < token.length; ) { uint256 amount = token[i].balanceOf(address(this)); _withdrawERC20(token[i], target, amount); ++i; } } } /** * @dev pull native tokens out of paymaster in case they were sent to the paymaster at any point * @param dest address to send to */ function withdrawAllNative( address dest ) public payable onlyOwner nonReentrant { uint256 _balance = address(this).balance; if (_balance == 0) revert NativeTokenBalanceZero(); if (dest == address(0)) revert CanNotWithdrawToZeroAddress(); bool success; assembly ("memory-safe") { success := call(gas(), dest, _balance, 0, 0, 0, 0) } if (!success) revert NativeTokensWithdrawalFailed(); } /** * @dev This method is called by the off-chain service, to sign the request. * It is called on-chain from the validatePaymasterUserOp, to validate the signature. * @notice That this signature covers all fields of the UserOperation, except the "paymasterAndData", * which will carry the signature itself. * @return hash we're going to sign off-chain (and validate on-chain) */ function getHash( UserOperation calldata userOp, ExchangeRateSource priceSource, uint48 validUntil, uint48 validAfter, address feeToken, address oracleAggregator, uint256 exchangeRate, uint32 priceMarkup ) public view returns (bytes32) { //can't use userOp.hash(), since it contains also the paymasterAndData itself. return keccak256( abi.encode( userOp.getSender(), userOp.nonce, keccak256(userOp.initCode), keccak256(userOp.callData), userOp.callGasLimit, userOp.verificationGasLimit, userOp.preVerificationGas, userOp.maxFeePerGas, userOp.maxPriorityFeePerGas, block.chainid, address(this), priceSource, validUntil, validAfter, feeToken, oracleAggregator, exchangeRate, priceMarkup ) ); } function parsePaymasterAndData( bytes calldata paymasterAndData ) public pure returns ( ExchangeRateSource priceSource, uint48 validUntil, uint48 validAfter, address feeToken, address oracleAggregator, uint256 exchangeRate, uint32 priceMarkup, bytes calldata signature ) { // paymasterAndData.length should be at least SIGNATURE_OFFSET + 65 (checked separate) require( paymasterAndData.length >= SIGNATURE_OFFSET, "BTPM: Invalid length for paymasterAndData" ); priceSource = ExchangeRateSource( uint8( bytes1(paymasterAndData[VALID_PND_OFFSET - 1:VALID_PND_OFFSET]) ) ); ( validUntil, validAfter, feeToken, oracleAggregator, exchangeRate, priceMarkup ) = abi.decode( paymasterAndData[VALID_PND_OFFSET:SIGNATURE_OFFSET], (uint48, uint48, address, address, uint256, uint32) ); signature = paymasterAndData[SIGNATURE_OFFSET:]; } function _getRequiredPrefund( UserOperation calldata userOp ) internal view returns (uint256 requiredPrefund) { unchecked { uint256 requiredGas = userOp.callGasLimit + userOp.verificationGasLimit + userOp.preVerificationGas + UNACCOUNTED_COST; requiredPrefund = requiredGas * userOp.maxFeePerGas; } } /** * @dev Verify that an external signer signed the paymaster data of a user operation. * The paymaster data is expected to be the paymaster address, request data and a signature over the entire request parameters. * paymasterAndData: hexConcat([paymasterAddress, priceSource, abi.encode(validUntil, validAfter, feeToken, oracleAggregator, exchangeRate, priceMarkup), signature]) * @param userOp The UserOperation struct that represents the current user operation. * userOpHash The hash of the UserOperation struct. * @param requiredPreFund The required amount of pre-funding for the paymaster. * @return context A context string returned by the entry point after successful validation. * @return validationData An integer returned by the entry point after successful validation. */ function _validatePaymasterUserOp( UserOperation calldata userOp, bytes32 userOpHash, uint256 requiredPreFund ) internal view override returns (bytes memory context, uint256 validationData) { (requiredPreFund); // verificationGasLimit is dual-purposed, as gas limit for postOp. make sure it is high enough // make sure that verificationGasLimit is high enough to handle postOp require( userOp.verificationGasLimit > UNACCOUNTED_COST, "BTPM: gas too low for postOp" ); // review: in this method try to resolve stack too deep (though via-ir is good enough) ( ExchangeRateSource priceSource, uint48 validUntil, uint48 validAfter, address feeToken, address oracleAggregator, uint256 exchangeRate, uint32 priceMarkup, bytes calldata signature ) = parsePaymasterAndData(userOp.paymasterAndData); // we only "require" it here so that the revert reason on invalid signature will be of "VerifyingPaymaster", and not "ECDSA" require( signature.length == 65, "BTPM: invalid signature length in paymasterAndData" ); bytes32 _hash = getHash( userOp, priceSource, validUntil, validAfter, feeToken, oracleAggregator, exchangeRate, priceMarkup ).toEthSignedMessageHash(); context = ""; //don't revert on signature failure: return SIG_VALIDATION_FAILED if (verifyingSigner != _hash.recover(signature)) { // empty context and sigFailed true return ( context, Helpers._packValidationData(true, validUntil, validAfter) ); } address account = userOp.getSender(); // This model assumes irrespective of priceSource exchangeRate is always sent from outside // for below checks you would either need maxCost or some exchangeRate uint256 btpmRequiredPrefund = _getRequiredPrefund(userOp); uint256 tokenRequiredPreFund = (btpmRequiredPrefund * exchangeRate) / 10 ** 18; require( tokenRequiredPreFund != 0, "BTPM: calculated token charge invalid" ); require(priceMarkup <= 2e6, "BTPM: price markup percentage too high"); require(priceMarkup >= 1e6, "BTPM: price markup percentage too low"); require( IERC20(feeToken).balanceOf(account) >= ((tokenRequiredPreFund * priceMarkup) / PRICE_DENOMINATOR), "BTPM: account does not have enough token balance" ); context = abi.encode( account, feeToken, oracleAggregator, priceSource, exchangeRate, priceMarkup, userOpHash ); return ( context, Helpers._packValidationData(false, validUntil, validAfter) ); } /** * @dev Executes the paymaster's payment conditions * @param mode tells whether the op succeeded, reverted, or if the op succeeded but cause the postOp to revert * @param context payment conditions signed by the paymaster in `validatePaymasterUserOp` * @param actualGasCost amount to be paid to the entry point in wei */ function _postOp( PostOpMode mode, bytes calldata context, uint256 actualGasCost ) internal virtual override { ( address account, IERC20 feeToken, address oracleAggregator, ExchangeRateSource priceSource, uint256 exchangeRate, uint32 priceMarkup, bytes32 userOpHash ) = abi.decode( context, ( address, IERC20, address, ExchangeRateSource, uint256, uint32, bytes32 ) ); uint256 effectiveExchangeRate = exchangeRate; if ( priceSource == ExchangeRateSource.ORACLE_BASED && oracleAggregator != address(NATIVE_ADDRESS) && oracleAggregator != address(0) ) { uint256 result = exchangePrice(address(feeToken), oracleAggregator); if (result != 0) effectiveExchangeRate = result; } // We could either touch the state for BASEFEE and calculate based on maxPriorityFee passed (to be added in context along with maxFeePerGas) or just use tx.gasprice uint256 charge; // Final amount to be charged from user account { uint256 actualTokenCost = ((actualGasCost + (UNACCOUNTED_COST * tx.gasprice)) * effectiveExchangeRate) / 1e18; charge = ((actualTokenCost * priceMarkup) / PRICE_DENOMINATOR); } if (mode != PostOpMode.postOpReverted) { SafeTransferLib.safeTransferFrom( address(feeToken), account, feeReceiver, charge ); emit TokenPaymasterOperation( account, address(feeToken), charge, oracleAggregator, priceMarkup, userOpHash, effectiveExchangeRate, priceSource ); } else { // In case transferFrom failed in first handlePostOp call, attempt to charge the tokens again bytes memory _data = abi.encodeWithSelector( feeToken.transferFrom.selector, account, feeReceiver, charge ); (bool success,) = address(feeToken).call( _data ); if (!success) { // In case above transferFrom failed, pay with deposit / notify at least // Sender could be banned indefinitely or for certain period emit TokenPaymentDue(address(feeToken), account, charge); // Do nothing else here to not revert the whole bundle and harm reputation } } } function _withdrawERC20( IERC20 token, address target, uint256 amount ) private { if (target == address(0)) revert CanNotWithdrawToZeroAddress(); SafeTransferLib.safeTransfer(address(token), target, amount); } receive() external payable { emit Received(msg.sender, msg.value); } }
// 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; import "./UserOperation.sol"; /** * Aggregated Signatures validator. */ interface IAggregator { /** * validate aggregated signature. * revert if the aggregated signature does not match the given list of operations. */ function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view; /** * validate signature of a single userOp * This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps. * @param userOp the userOperation received from the user. * @return sigForUserOp the value to put into the signature field of the userOp when calling handleOps. * (usually empty, unless account and aggregator support some kind of "multisig" */ function validateUserOpSignature(UserOperation calldata userOp) external view returns (bytes memory sigForUserOp); /** * aggregate multiple signatures into a single value. * This method is called off-chain to calculate the signature to pass with handleOps() * bundler MAY use optimized custom code perform this aggregation * @param userOps array of UserOperations to collect the signatures from. * @return aggregatedSignature the aggregated signature */ function aggregateSignatures(UserOperation[] calldata userOps) external view returns (bytes memory aggregatedSignature); }
/** ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. ** Only one instance required on each chain. **/ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable avoid-low-level-calls */ /* solhint-disable no-inline-assembly */ /* solhint-disable reason-string */ import "./UserOperation.sol"; import "./IStakeManager.sol"; import "./IAggregator.sol"; import "./INonceManager.sol"; interface IEntryPoint is IStakeManager, INonceManager { /*** * An event emitted after each successful request * @param userOpHash - unique identifier for the request (hash its entire content, except signature). * @param sender - the account that generates this request. * @param paymaster - if non-null, the paymaster that pays for this request. * @param nonce - the nonce value from the request. * @param success - true if the sender transaction succeeded, false if reverted. * @param actualGasCost - actual amount paid (by account or paymaster) for this UserOperation. * @param actualGasUsed - total gas used by this UserOperation (including preVerification, creation, validation and execution). */ event UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed); /** * account "sender" was deployed. * @param userOpHash the userOp that deployed this account. UserOperationEvent will follow. * @param sender the account that is deployed * @param factory the factory used to deploy this account (in the initCode) * @param paymaster the paymaster used by this UserOp */ event AccountDeployed(bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster); /** * An event emitted if the UserOperation "callData" reverted with non-zero length * @param userOpHash the request unique identifier. * @param sender the sender of this request * @param nonce the nonce used in the request * @param revertReason - the return bytes from the (reverted) call to "callData". */ event UserOperationRevertReason(bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason); /** * an event emitted by handleOps(), before starting the execution loop. * any event emitted before this event, is part of the validation. */ event BeforeExecution(); /** * signature aggregator used by the following UserOperationEvents within this bundle. */ event SignatureAggregatorChanged(address indexed aggregator); /** * a custom revert error of handleOps, to identify the offending op. * NOTE: if simulateValidation passes successfully, there should be no reason for handleOps to fail on it. * @param opIndex - index into the array of ops to the failed one (in simulateValidation, this is always zero) * @param reason - revert reason * The string starts with a unique code "AAmn", where "m" is "1" for factory, "2" for account and "3" for paymaster issues, * so a failure can be attributed to the correct entity. * Should be caught in off-chain handleOps simulation and not happen on-chain. * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts. */ error FailedOp(uint256 opIndex, string reason); /** * error case when a signature aggregator fails to verify the aggregated signature it had created. */ error SignatureValidationFailed(address aggregator); /** * Successful result from simulateValidation. * @param returnInfo gas and time-range returned values * @param senderInfo stake information about the sender * @param factoryInfo stake information about the factory (if any) * @param paymasterInfo stake information about the paymaster (if any) */ error ValidationResult(ReturnInfo returnInfo, StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo); /** * Successful result from simulateValidation, if the account returns a signature aggregator * @param returnInfo gas and time-range returned values * @param senderInfo stake information about the sender * @param factoryInfo stake information about the factory (if any) * @param paymasterInfo stake information about the paymaster (if any) * @param aggregatorInfo signature aggregation info (if the account requires signature aggregator) * bundler MUST use it to verify the signature, or reject the UserOperation */ error ValidationResultWithAggregation(ReturnInfo returnInfo, StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo, AggregatorStakeInfo aggregatorInfo); /** * return value of getSenderAddress */ error SenderAddressResult(address sender); /** * return value of simulateHandleOp */ error ExecutionResult(uint256 preOpGas, uint256 paid, uint48 validAfter, uint48 validUntil, bool targetSuccess, bytes targetResult); //UserOps handled, per aggregator struct UserOpsPerAggregator { UserOperation[] userOps; // aggregator address IAggregator aggregator; // aggregated signature bytes signature; } /** * Execute a batch of UserOperation. * no signature aggregator is used. * if any account requires an aggregator (that is, it returned an aggregator when * performing simulateValidation), then handleAggregatedOps() must be used instead. * @param ops the operations to execute * @param beneficiary the address to receive the fees */ function handleOps(UserOperation[] calldata ops, address payable beneficiary) external; /** * Execute a batch of UserOperation with Aggregators * @param opsPerAggregator the operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts) * @param beneficiary the address to receive the fees */ function handleAggregatedOps( UserOpsPerAggregator[] calldata opsPerAggregator, address payable beneficiary ) external; /** * generate a request Id - unique identifier for this request. * the request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid. */ function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32); /** * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp. * @dev this method always revert. Successful result is ValidationResult error. other errors are failures. * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data. * @param userOp the user operation to validate. */ function simulateValidation(UserOperation calldata userOp) external; /** * gas and return values during simulation * @param preOpGas the gas used for validation (including preValidationGas) * @param prefund the required prefund for this operation * @param sigFailed validateUserOp's (or paymaster's) signature check failed * @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range) * @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range) * @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp) */ struct ReturnInfo { uint256 preOpGas; uint256 prefund; bool sigFailed; uint48 validAfter; uint48 validUntil; bytes paymasterContext; } /** * returned aggregated signature info. * the aggregator returned by the account, and its current stake. */ struct AggregatorStakeInfo { address aggregator; StakeInfo stakeInfo; } /** * Get counterfactual sender address. * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation. * this method always revert, and returns the address in SenderAddressResult error * @param initCode the constructor code to be passed into the UserOperation. */ function getSenderAddress(bytes memory initCode) external; /** * simulate full execution of a UserOperation (including both validation and target execution) * this method will always revert with "ExecutionResult". * it performs full validation of the UserOperation, but ignores signature error. * an optional target address is called after the userop succeeds, and its value is returned * (before the entire call is reverted) * Note that in order to collect the the success/failure of the target call, it must be executed * with trace enabled to track the emitted events. * @param op the UserOperation to simulate * @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult * are set to the return from that call. * @param targetCallData callData to pass to target address */ function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; interface INonceManager { /** * Return the next nonce for this sender. * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop) * But UserOp with different keys can come with arbitrary order. * * @param sender the account address * @param key the high 192 bit of the nonce * @return nonce a full nonce to pass for next UserOp with this sender. */ function getNonce(address sender, uint192 key) external view returns (uint256 nonce); /** * Manually increment the nonce of the sender. * This method is exposed just for completeness.. * Account does NOT need to call it, neither during validation, nor elsewhere, * as the EntryPoint will update the nonce regardless. * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future * UserOperations will not pay extra for the first transaction with a given key. */ function incrementNonce(uint192 key) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; import "./UserOperation.sol"; /** * the interface exposed by a paymaster contract, who agrees to pay the gas for user's operations. * a paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction. */ interface IPaymaster { enum PostOpMode { opSucceeded, // user op succeeded opReverted, // user op reverted. still has to pay for gas. postOpReverted //user op succeeded, but caused postOp to revert. Now it's a 2nd call, after user's op was deliberately reverted. } /** * payment validation: check if paymaster agrees to pay. * Must verify sender is the entryPoint. * Revert to reject this request. * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted) * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns. * @param userOp the user operation * @param userOpHash hash of the user's request data. * @param maxCost the maximum cost of this transaction (based on maximum gas and gas price from userOp) * @return context value to send to a postOp * zero length to signify postOp is not required. * @return validationData signature and time-range of this operation, encoded the same as the return value of validateUserOperation * <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 * Note that the validation code cannot use block.timestamp (or block.number) directly. */ function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) external returns (bytes memory context, uint256 validationData); /** * post-operation handler. * Must verify sender is the entryPoint * @param mode enum with the following options: * opSucceeded - user operation succeeded. * opReverted - user op reverted. still has to pay for gas. * postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert. * Now this is the 2nd call, after user's op was deliberately reverted. * @param context - the context value returned by validatePaymasterUserOp * @param actualGasCost - actual gas used so far (without this postOp call). */ function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.12; /** * manage deposits and stakes. * deposit is just a balance used to pay for UserOperations (either by a paymaster or an account) * stake is value locked for at least "unstakeDelay" by the staked entity. */ interface IStakeManager { event Deposited( address indexed account, uint256 totalDeposit ); event Withdrawn( address indexed account, address withdrawAddress, uint256 amount ); /// Emitted when stake or unstake delay are modified event StakeLocked( address indexed account, uint256 totalStaked, uint256 unstakeDelaySec ); /// Emitted once a stake is scheduled for withdrawal event StakeUnlocked( address indexed account, uint256 withdrawTime ); event StakeWithdrawn( address indexed account, address withdrawAddress, uint256 amount ); /** * @param deposit the entity's deposit * @param staked true if this entity is staked. * @param stake actual amount of ether staked for this entity. * @param unstakeDelaySec minimum delay to withdraw the stake. * @param withdrawTime - first block timestamp where 'withdrawStake' will be callable, or zero if already locked * @dev sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps) * and the rest fit into a 2nd cell. * 112 bit allows for 10^15 eth * 48 bit for full timestamp * 32 bit allows 150 years for unstake delay */ struct DepositInfo { uint112 deposit; bool staked; uint112 stake; uint32 unstakeDelaySec; uint48 withdrawTime; } //API struct used by getStakeInfo and simulateValidation struct StakeInfo { uint256 stake; uint256 unstakeDelaySec; } /// @return info - full deposit information of given account function getDepositInfo(address account) external view returns (DepositInfo memory info); /// @return the deposit (for gas payment) of the account function balanceOf(address account) external view returns (uint256); /** * add to the deposit of the given account */ function depositTo(address account) external payable; /** * add to the account's stake - amount and delay * any pending unstake is first cancelled. * @param _unstakeDelaySec the new lock duration before the deposit can be withdrawn. */ function addStake(uint32 _unstakeDelaySec) external payable; /** * attempt to unlock the stake. * the value can be withdrawn (using withdrawStake) after the unstake delay. */ function unlockStake() external; /** * withdraw from the (unlocked) stake. * must first call unlockStake and wait for the unstakeDelay to pass * @param withdrawAddress the address to send withdrawn value. */ function withdrawStake(address payable withdrawAddress) external; /** * withdraw from the deposit. * @param withdrawAddress the address to send withdrawn value. * @param withdrawAmount the amount to withdraw. */ function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external; }
// SPDX-License-Identifier: 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 // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; /* solhint-disable reason-string */ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol"; import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; import "@account-abstraction/contracts/core/Helpers.sol"; /** * @notice Could have Ownable2Step * Helper class for creating a paymaster. * provides helper methods for staking. * validates that the postOp is called only by the entryPoint */ abstract contract BasePaymaster is IPaymaster, Ownable { IEntryPoint public immutable entryPoint; constructor(address _owner, IEntryPoint _entryPoint) { entryPoint = _entryPoint; _transferOwnership(_owner); } /// @inheritdoc IPaymaster function validatePaymasterUserOp( UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost ) external override returns (bytes memory context, uint256 validationData) { _requireFromEntryPoint(); return _validatePaymasterUserOp(userOp, userOpHash, maxCost); } /// @inheritdoc IPaymaster function postOp( PostOpMode mode, bytes calldata context, uint256 actualGasCost ) external override { _requireFromEntryPoint(); _postOp(mode, context, actualGasCost); } /** * add a deposit for this paymaster, used for paying for transaction fees */ function deposit() external payable virtual; /** * withdraw value from the deposit * @param withdrawAddress target to send to * @param amount to withdraw */ function withdrawTo( address payable withdrawAddress, uint256 amount ) external virtual; /** * add stake for this paymaster. * This method can also carry eth value to add to the current stake. * @param unstakeDelaySec - the unstake delay for this paymaster. Can only be increased. */ function addStake(uint32 unstakeDelaySec) external payable onlyOwner { entryPoint.addStake{value: msg.value}(unstakeDelaySec); } /** * unlock the stake, in order to withdraw it. * The paymaster can't serve requests once unlocked, until it calls addStake again */ function unlockStake() external onlyOwner { entryPoint.unlockStake(); } /** * withdraw the entire paymaster's stake. * stake must be unlocked first (and then wait for the unstakeDelay to be over) * @param withdrawAddress the address to send withdrawn value. */ function withdrawStake(address payable withdrawAddress) external onlyOwner { entryPoint.withdrawStake(withdrawAddress); } /** * return current paymaster's deposit on the entryPoint. */ function getDeposit() public view returns (uint256) { return entryPoint.balanceOf(address(this)); } /// validate the call is made from a valid entrypoint function _requireFromEntryPoint() internal virtual { require(msg.sender == address(entryPoint), "Sender not EntryPoint"); } function _validatePaymasterUserOp( UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost ) internal virtual returns (bytes memory context, uint256 validationData); /** * post-operation handler. * (verified to be called only through the entryPoint) * @dev if subclass returns a non-empty context from validatePaymasterUserOp, it must also implement this method. * @param mode enum with the following options: * opSucceeded - user operation succeeded. * opReverted - user op reverted. still has to pay for gas. * postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert. * Now this is the 2nd call, after user's op was deliberately reverted. * @param context - the context value returned by validatePaymasterUserOp * @param actualGasCost - actual gas used so far (without this postOp call). */ function _postOp( PostOpMode mode, bytes calldata context, uint256 actualGasCost ) internal virtual { (mode, context, actualGasCost); // unused params // subclass must override this method if validatePaymasterUserOp returns a context revert("must override"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IOracleAggregator { function getTokenValueOfOneNativeToken( address _token ) external view returns (uint256 exchangeRate); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.17; contract TokenPaymasterErrors { /** * @notice Throws when the Entrypoint address provided is address(0) */ error EntryPointCannotBeZero(); /** * @notice Throws when the owner address provided is address(0) */ error OwnerCannotBeZero(); /** * @notice Throws when the verifiying signer address provided is address(0) */ error VerifyingSignerCannotBeZero(); /** * @notice Throws when the 0 has been provided as deposit */ error DepositCanNotBeZero(); /** * @notice Throws when trying to withdraw to address(0) */ error CanNotWithdrawToZeroAddress(); /** * @notice Throws when trying to withdraw more than balance available * @param amountRequired required balance * @param currentBalance available balance */ /*error InsufficientTokenBalance( uint256 amountRequired, uint256 currentBalance );*/ /** * @notice Throws when signature provided has invalid length * @param sigLength length oif the signature provided */ // error InvalidPaymasterSignatureLength(uint256 sigLength); /** * @notice Throws when the fee receiver address provided is address(0) */ error FeeReceiverCannotBeZero(); error TokensAndAmountsLengthMismatch(); error NativeTokenBalanceZero(); error NativeTokensWithdrawalFailed(); error CannotBeUnrealisticValue(); error DEXRouterCannotBeZero(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH /// that disallows any storage writes. uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. /// Multiply by a small constant (e.g. 2), if needed. uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000; /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom( address token, address from, address to, uint256 amount ) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x0c, 0x23b872dd000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x00, 0x20) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferAllFrom( address token, address from, address to ) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. // Store the function selector of `balanceOf(address)`. mstore(0x0c, 0x70a08231000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x00, 0x20) } // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) // The `amount` argument is already written to the memory word at 0x6c. amount := mload(0x60) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x00, 0x20) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `transfer(address,uint256)`. mstore(0x00, 0xa9059cbb000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x00, 0x20) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll( address token, address to ) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x00, 0x20) } mstore(0x14, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x34. amount := mload(0x34) // Store the function selector of `transfer(address,uint256)`. mstore(0x00, 0xa9059cbb000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x00, 0x20) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`. mstore(0x00, 0x095ea7b3000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x00, 0x20) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf( address token, address account ) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. // Store the function selector of `balanceOf(address)`. mstore(0x00, 0x70a08231000000000000000000000000) amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } }
{ "optimizer": { "enabled": true, "runs": 800 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"contract IEntryPoint","name":"_entryPoint","type":"address"},{"internalType":"address","name":"_verifyingSigner","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"CanNotWithdrawToZeroAddress","type":"error"},{"inputs":[],"name":"CannotBeUnrealisticValue","type":"error"},{"inputs":[],"name":"DEXRouterCannotBeZero","type":"error"},{"inputs":[],"name":"DepositCanNotBeZero","type":"error"},{"inputs":[],"name":"EntryPointCannotBeZero","type":"error"},{"inputs":[],"name":"FeeReceiverCannotBeZero","type":"error"},{"inputs":[],"name":"NativeTokenBalanceZero","type":"error"},{"inputs":[],"name":"NativeTokensWithdrawalFailed","type":"error"},{"inputs":[],"name":"OwnerCannotBeZero","type":"error"},{"inputs":[],"name":"TokensAndAmountsLengthMismatch","type":"error"},{"inputs":[],"name":"VerifyingSignerCannotBeZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_oldOverheadCost","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_newOverheadCost","type":"uint256"},{"indexed":true,"internalType":"address","name":"_actor","type":"address"}],"name":"EPGasOverheadChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldfeeReceiver","type":"address"},{"indexed":true,"internalType":"address","name":"_newfeeReceiver","type":"address"},{"indexed":true,"internalType":"address","name":"_actor","type":"address"}],"name":"FeeReceiverChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"totalCharge","type":"uint256"},{"indexed":false,"internalType":"address","name":"oracleAggregator","type":"address"},{"indexed":false,"internalType":"uint32","name":"priceMarkup","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"indexed":false,"internalType":"enum BiconomyTokenPaymaster.ExchangeRateSource","name":"priceSource","type":"uint8"}],"name":"TokenPaymasterOperation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"charge","type":"uint256"}],"name":"TokenPaymentDue","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldSigner","type":"address"},{"indexed":true,"internalType":"address","name":"_newSigner","type":"address"},{"indexed":true,"internalType":"address","name":"_actor","type":"address"}],"name":"VerifyingSignerChanged","type":"event"},{"inputs":[],"name":"UNACCOUNTED_COST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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"},{"internalType":"enum BiconomyTokenPaymaster.ExchangeRateSource","name":"priceSource","type":"uint8"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint48","name":"validAfter","type":"uint48"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"oracleAggregator","type":"address"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"uint32","name":"priceMarkup","type":"uint32"}],"name":"getHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"paymasterAndData","type":"bytes"}],"name":"parsePaymasterAndData","outputs":[{"internalType":"enum BiconomyTokenPaymaster.ExchangeRateSource","name":"priceSource","type":"uint8"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint48","name":"validAfter","type":"uint48"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"oracleAggregator","type":"address"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"uint32","name":"priceMarkup","type":"uint32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum IPaymaster.PostOpMode","name":"mode","type":"uint8"},{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"uint256","name":"actualGasCost","type":"uint256"}],"name":"postOp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newFeeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newOverheadCost","type":"uint256"}],"name":"setUnaccountedEPGasOverhead","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVerifyingSigner","type":"address"}],"name":"setVerifyingSigner","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlockStake","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"},{"internalType":"uint256","name":"maxCost","type":"uint256"}],"name":"validatePaymasterUserOp","outputs":[{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifyingSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dest","type":"address"}],"name":"withdrawAllNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"target","type":"address"}],"name":"withdrawERC20Full","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"token","type":"address[]"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256[]","name":"amount","type":"uint256[]"}],"name":"withdrawMultipleERC20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"token","type":"address[]"},{"internalType":"address","name":"target","type":"address"}],"name":"withdrawMultipleERC20Full","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
601f62001f7838819003918201601f191660a09081019290916001600160401b038411838510176200013657816060928492604096875283398101031262000131576200004c816200014c565b6020820151916001600160a01b03918284169190828503620001315762000076868593016200014c565b94620000823362000161565b608052620000908162000161565b6001805561afc860025516156200012057156200010f57811615620000fe576003553060045551611dcf9081620001a982396080518181816104d7015281816106680152818161070f015281816107980152818161082e01528181610f960152818161103601526112280152f35b8151638fc6a93160e01b8152600490fd5b825163091748f960e21b8152600490fd5b8351639b15e16f60e01b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200013157565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe604060808152600480361015610048575b50361561001c57600080fd5b513481527f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460203392a2005b600090813560e01c80630396cb6014611005578063205c287814610f5457806323d9ac9b14610f2c57806344004cc114610ef35780635deef2aa14610e43578063617d057a14610d8c578063715018a614610d2557806378b1da2314610c255780638da5cb5b14610bff57806394d4ad6014610b45578063a9a2340914610852578063b0d691fe1461080e578063b3f00674146107e6578063bb9fe6bf14610773578063c23a5cea146106e0578063c399ec8814610634578063c6e7a95714610611578063d0db6f751461055a578063d0e30db0146104b7578063d9f66db11461043a578063deeb3874146103d6578063efdcd97414610368578063f2fde38b1461027d578063f465c77e146101dd5763f5cba98c146101685750610010565b8260203660031901126101d95761017d6110a5565b9161018661117a565b6001600160a01b03908184169283156101cc575050600354169160035533917fe1f62c0e6d7bb6d470828565415bf2e87dbfea50e52d2d753788b529bd0c6d628480a480f35b51638fc6a93160e01b8152fd5b8280fd5b5082346101d9576060916003199083823601126102755780359167ffffffffffffffff831161027957610160908336030112610275576102299161021f61121e565b60243591016115e8565b8291925194859383855280518094860152815b84811061025e5750508383018501526020830152601f01601f19168101030190f35b60208282018101518983018901528896500161023c565b8480fd5b8580fd5b508290346101d95760203660031901126101d9576102996110a5565b906102a261117a565b6001600160a01b038092169283156102ff5750506000548273ffffffffffffffffffffffffffffffffffffffff19821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b508260203660031901126101d95761037e6110a5565b61038661117a565b6001600160a01b038082169283156103c75750835416925533917fff179728e4df4b0421c7de2106b1968d0604e1670493f8da3f907f2d020bb6d58480a480f35b5163193ba87b60e31b81528490fd5b50829060203660031901126101d9578035916103f061117a565b62030d40831161042d575050600254908060025533917f303a4cca6d7dba1a29764b1c0aabac67516608dd37f88e064abc64c24b9c27438480a480f35b51637dabea7560e11b8152fd5b508260203660031901126101d9576104506110a5565b61045861117a565b610460611295565b479081156104a8576001600160a01b03811615610499578480809381935af11561048c57826001805580f35b5163cdf0648960e01b8152fd5b5050516392bc9df360e01b8152fd5b50505163d17e42bf60e01b8152fd5b50819282600319360112610556576104cd611295565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b15610551578390602483518095819363b760faf960e01b8352309083015234905af19081156105485750610531575b506001805580f35b61053a906111d2565b610545578038610529565b80fd5b513d84823e3d90fd5b505050fd5b5050fd5b508290346101d957600319906101003683011261060d5780359167ffffffffffffffff83116102755761016090833603011261060d5760243593600285101561054557506044359065ffffffffffff8083168303610608576064359081168103610608576084356001600160a01b039182821682036106085760a43592831683036106085760e4359463ffffffff86168603610608576020986106019760c43596016113ab565b9051908152f35b600080fd5b8380fd5b8284346106305781600319360112610630576020906002549051908152f35b5080fd5b5091346106305781600319360112610630578051926370a0823160e01b845230908401526020836024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9182156106d557916106a1575b6020925051908152f35b90506020823d82116106cd575b816106bb602093836111fc565b81010312610608576020915190610697565b3d91506106ae565b9051903d90823e3d90fd5b50819234610556576020366003190112610556576106fc6110a5565b61070461117a565b6001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016803b15610279578592836024928651978895869463611d2e7560e11b865216908401525af190811561054857506107635750f35b61076c906111d2565b6105455780f35b5081923461055657826003193601126105565761078e61117a565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691823b1561055157815163bb9fe6bf60e01b81529284918491829084905af190811561054857506107635750f35b50919034610545578060031936011261054557506001600160a01b0360209254169051908152f35b828434610630578160031936011261063057602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b508290346101d95760608060031936011261060d5781359260038410156102755767ffffffffffffffff602435818111610b41576108939036908601611116565b909360e085604435936108a461121e565b81010312610b3d576108b5856110bb565b936020956108c48782016110bb565b6108cf8383016110bb565b9784830135966002881015610b39576108ea60a08501611094565b926001600160a01b039081808c169c169260808701359960018c1480610b1b575b80610b12575b610af2575b6109236002543a906115bf565b8101809111610add57620f424061095763ffffffff670de0b6b3a764000061094d8f6002966115bf565b04991680996115bf565b049f14610a09575081169b5416988551998d885286526bffffffffffffffffffffffff1990871b16602c526f23b872dd000000000000000000000000600c52818d808d5a91601c91606493f18d516001143d151716156109fe578c8652888552885287015260c00135908501528301527f7c405b9cef9e824a5cf31a09e7b8810d01d9db34ee384388f33b438608807e1a9160a0916109fa906080830190611144565ba480f35b508b637939f4248152fd5b98509598509550509650505081879697541692845196868801946323b872dd60e01b86528960248a015260448901528960648901526064885260a088019188831090831117610ac857508452945194169387918291829182885af1923d15610ac0573d610a81610a7882611358565b945194856111fc565b83523d92013e5b15610a94575b50505080f35b7f41614445ea2ab6d87c504bdfc83cb5cb840e7219aa772383baff1ab0dd2a31138480a4818080610a8e565b505050610a88565b604190634e487b7160e01b6000525260246000fd5b5050634e487b7160e01b8f5260118d5260248ffd5b610afe85858516611cb9565b80610b0a575b50610916565b9a5038610b04565b50841515610911565b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85141561090b565b8c80fd5b8780fd5b8680fd5b508290346101d95760203660031901126101d957803567ffffffffffffffff811161060d5792610b89610b8363ffffffff93610ba096369101611116565b906114c6565b98979996909a91958295949395519c8d809c611144565b65ffffffffffff80921660208c015216908901526001600160a01b03809216606089015216608087015260a08601521660c0840152816101008060e0860152840152816101209485850137828201840152601f01601f19168101030190f35b8284346106305781600319360112610630576001600160a01b0360209254169051908152f35b508290816003193601126101d957803567ffffffffffffffff811161060d57610c5190369083016110e5565b610c5c9391936110cf565b93610c6561117a565b610c6d611295565b855b828110610c7e57866001805580f35b6001600160a01b03610c99610c948386866112eb565b611311565b1690845180926370a0823160e01b8252308883015281602460209586935afa928315610d1b578993610ce8575b5050610ce260019288610cdd610c948589896112eb565b611d2e565b01610c6f565b90809350813d8311610d14575b610cff81836111fc565b8101031261060857610ce26001925192610cc6565b503d610cf5565b86513d8b823e3d90fd5b8234610545578060031936011261054557610d3e61117a565b60006001600160a01b03815473ffffffffffffffffffffffffffffffffffffffff1981168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b508260603660031901126101d95767ffffffffffffffff823581811161027557610db990369085016110e5565b610dc49491946110cf565b92604435908111610b4157610ddc90369084016110e5565b929094610de761117a565b610def611295565b838303610e36575050855b818110610e0957866001805580f35b80610e30610e1d610c94600194868b6112eb565b86610e2984888b6112eb565b3591611d2e565b01610dfa565b51630483384360e11b8152fd5b5082806003193601126101d957610e586110a5565b610e606110cf565b90610e6961117a565b610e71611295565b8251936370a0823160e01b855230908501526020846024816001600160a01b0385165afa928315610eea57508492610eb5575b610eae9350611d2e565b6001805580f35b91506020833d8211610ee2575b81610ecf602093836111fc565b8101031261060857610eae925191610ea4565b3d9150610ec2565b513d86823e3d90fd5b82606036600319011261054557610eae610f0b6110a5565b610f136110cf565b610f1b61117a565b610f23611295565b60443591611d2e565b8284346106305781600319360112610630576020906001600160a01b03600354169051908152f35b509134610630578060031936011261063057610f6e6110a5565b90610f7761117a565b610f7f611295565b6001600160a01b03809216918215610ff5579383947f00000000000000000000000000000000000000000000000000000000000000001692833b156102755760448592838551968794859363040b850f60e31b855284015260243560248401525af1908115610548575061053157506001805580f35b81516392bc9df360e01b81528590fd5b508260203660031901126101d95782823563ffffffff81168091036106305761102c61117a565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693843b156101d95760249084519586938492621cb65b60e51b845283015234905af19081156105485750611088575080f35b611091906111d2565b80f35b359063ffffffff8216820361060857565b600435906001600160a01b038216820361060857565b35906001600160a01b038216820361060857565b602435906001600160a01b038216820361060857565b9181601f840112156106085782359167ffffffffffffffff8311610608576020808501948460051b01011161060857565b9181601f840112156106085782359167ffffffffffffffff8311610608576020838186019501011161060857565b9060028210156111515752565b634e487b7160e01b600052602160045260246000fd5b359065ffffffffffff8216820361060857565b6001600160a01b0360005416330361118e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b67ffffffffffffffff81116111e657604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176111e657604052565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361125057565b60405162461bcd60e51b815260206004820152601560248201527f53656e646572206e6f7420456e747279506f696e7400000000000000000000006044820152606490fd5b6002600154146112a6576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b91908110156112fb5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160a01b03811681036106085790565b903590601e1981360301821215610608570180359067ffffffffffffffff82116106085760200191813603831361060857565b67ffffffffffffffff81116111e657601f01601f191660200190565b92919261138082611358565b9161138e60405193846111fc565b829481845281830111610608578281602093846000960137010152565b929694919095936113c96113c26040860186611325565b3691611374565b60208151910120916113e16113c26060870187611325565b602081519101209861146a604051998a97602089019c8d9760606001600160a01b039b8c9a8b863516905260208501356040820152015260808d0152608081013560a08d015260a081013560c08d015260c081013560e08d0152610100908c8260e083013591015201356101208c0152466101408c0152306101608c01526101808b0190611144565b65ffffffffffff8092166101a08a0152166101c0880152166101e08601521661020084015261022083015263ffffffff6102409116818301528152610260810181811067ffffffffffffffff8211176111e65760405251902090565b909160d58310611554578260151161060857601482013560f81c600281101561115157928060d511610608576114fe60158401611167565b9161150b60358501611167565b91611518605586016110bb565b91611525607587016110bb565b9161153260b58801611094565b9160d56095890135946001600160a01b038091169616969798019160d4190190565b60405162461bcd60e51b815260206004820152602960248201527f4254504d3a20496e76616c6964206c656e67746820666f72207061796d61737460448201527f6572416e644461746100000000000000000000000000000000000000000000006064820152608490fd5b818102929181159184041417156115d257565b634e487b7160e01b600052601160045260246000fd5b919060a08301356002549384821115611aa95761160c610b83610120830183611325565b916041839e99949592989c979e03611a3e57896116538f878f8a7f19457468657265756d205369676e6564204d6573736167653a0a3332000000009f9388928b89966113ab565b9b60409a8b519560209e8f88019e8f52603c880152603c8752606087019067ffffffffffffffff9e8f898410908411176111e657828f5288519020976080018f8111838210176111e6578e5260009c8d83526001600160a01b0398899182600354169336906116c192611374565b6116ca91611bf2565b6116d390611aee565b16036119ef575087670de0b6b3a76400009261170792888635169560e081013592608060c0830135920135010101026115bf565b049182156119855763ffffffff1696621e8480881161191b57620f424088106118b1578a516370a0823160e01b815260048101839052908516928d82602481875afa9182156118a7579089918c9361186d575b50620f424091611769916115bf565b04116118035789519b8c01528a89015216606089015261178d906080890190611144565b60a087015260c086015260e085015260e08452610100840192848410908411176117ef5750917fffffffffffff00000000000000000000000000000000000000000000000000009165ffffffffffff60a01b93529460d01b169160a01b161790565b634e487b7160e01b81526041600452602490fd5b895162461bcd60e51b8152600481018d9052603060248201527f4254504d3a206163636f756e7420646f6573206e6f74206861766520656e6f7560448201527f676820746f6b656e2062616c616e6365000000000000000000000000000000006064820152608490fd5b8f809294508193503d83116118a0575b61188781836111fc565b8101031261189c5751908890620f424061175a565b8a80fd5b503d61187d565b8c513d8d823e3d90fd5b8a5162461bcd60e51b8152600481018e9052602560248201527f4254504d3a207072696365206d61726b75702070657263656e7461676520746f60448201527f6f206c6f770000000000000000000000000000000000000000000000000000006064820152608490fd5b8a5162461bcd60e51b8152600481018e9052602660248201527f4254504d3a207072696365206d61726b75702070657263656e7461676520746f60448201527f6f206869676800000000000000000000000000000000000000000000000000006064820152608490fd5b8a5162461bcd60e51b8152600481018e9052602560248201527f4254504d3a2063616c63756c6174656420746f6b656e2063686172676520696e60448201527f76616c69640000000000000000000000000000000000000000000000000000006064820152608490fd5b9a5050505050505050505050600194935065ffffffffffff60a01b92507fffffffffffff000000000000000000000000000000000000000000000000000091509560d01b169160a01b16171790565b60405162461bcd60e51b815260206004820152603260248201527f4254504d3a20696e76616c6964207369676e6174757265206c656e677468206960448201527f6e207061796d6173746572416e644461746100000000000000000000000000006064820152608490fd5b60405162461bcd60e51b815260206004820152601c60248201527f4254504d3a2067617320746f6f206c6f7720666f7220706f73744f70000000006044820152606490fd5b60058110156111515780611aff5750565b60018103611b4c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b60028103611b995760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b600314611ba257565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b906041815114600014611c2057611c1c916020820151906060604084015193015160001a90611c2a565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311611cad5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa15611ca05781516001600160a01b03811615611c9a579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b604051633f81538960e11b81526001600160a01b0391821660048201529160209183916024918391165afa60009181611cfb575b50611cf85750600090565b90565b90916020823d8211611d26575b81611d15602093836111fc565b810103126105455750519038611ced565b3d9150611d08565b6001600160a01b039283831615611d8757602092601452603452604460106000809581946fa9059cbb0000000000000000000000008352165af13d156001835114171615611d7b57603452565b806390b8ec1860209252fd5b6040516392bc9df360e01b8152600490fdfea2646970667358221220f43cb9b4e4ecf507f85d6ed4b4e47cd86481fb10afeb19bb1d410ff6b94548c864736f6c634300081100330000000000000000000000003e01030db6d99649d419ed13c49706ab23b1dee90000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27890000000000000000000000003e01030db6d99649d419ed13c49706ab23b1dee9
Deployed Bytecode
0x604060808152600480361015610048575b50361561001c57600080fd5b513481527f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587460203392a2005b600090813560e01c80630396cb6014611005578063205c287814610f5457806323d9ac9b14610f2c57806344004cc114610ef35780635deef2aa14610e43578063617d057a14610d8c578063715018a614610d2557806378b1da2314610c255780638da5cb5b14610bff57806394d4ad6014610b45578063a9a2340914610852578063b0d691fe1461080e578063b3f00674146107e6578063bb9fe6bf14610773578063c23a5cea146106e0578063c399ec8814610634578063c6e7a95714610611578063d0db6f751461055a578063d0e30db0146104b7578063d9f66db11461043a578063deeb3874146103d6578063efdcd97414610368578063f2fde38b1461027d578063f465c77e146101dd5763f5cba98c146101685750610010565b8260203660031901126101d95761017d6110a5565b9161018661117a565b6001600160a01b03908184169283156101cc575050600354169160035533917fe1f62c0e6d7bb6d470828565415bf2e87dbfea50e52d2d753788b529bd0c6d628480a480f35b51638fc6a93160e01b8152fd5b8280fd5b5082346101d9576060916003199083823601126102755780359167ffffffffffffffff831161027957610160908336030112610275576102299161021f61121e565b60243591016115e8565b8291925194859383855280518094860152815b84811061025e5750508383018501526020830152601f01601f19168101030190f35b60208282018101518983018901528896500161023c565b8480fd5b8580fd5b508290346101d95760203660031901126101d9576102996110a5565b906102a261117a565b6001600160a01b038092169283156102ff5750506000548273ffffffffffffffffffffffffffffffffffffffff19821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b508260203660031901126101d95761037e6110a5565b61038661117a565b6001600160a01b038082169283156103c75750835416925533917fff179728e4df4b0421c7de2106b1968d0604e1670493f8da3f907f2d020bb6d58480a480f35b5163193ba87b60e31b81528490fd5b50829060203660031901126101d9578035916103f061117a565b62030d40831161042d575050600254908060025533917f303a4cca6d7dba1a29764b1c0aabac67516608dd37f88e064abc64c24b9c27438480a480f35b51637dabea7560e11b8152fd5b508260203660031901126101d9576104506110a5565b61045861117a565b610460611295565b479081156104a8576001600160a01b03811615610499578480809381935af11561048c57826001805580f35b5163cdf0648960e01b8152fd5b5050516392bc9df360e01b8152fd5b50505163d17e42bf60e01b8152fd5b50819282600319360112610556576104cd611295565b6001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891691823b15610551578390602483518095819363b760faf960e01b8352309083015234905af19081156105485750610531575b506001805580f35b61053a906111d2565b610545578038610529565b80fd5b513d84823e3d90fd5b505050fd5b5050fd5b508290346101d957600319906101003683011261060d5780359167ffffffffffffffff83116102755761016090833603011261060d5760243593600285101561054557506044359065ffffffffffff8083168303610608576064359081168103610608576084356001600160a01b039182821682036106085760a43592831683036106085760e4359463ffffffff86168603610608576020986106019760c43596016113ab565b9051908152f35b600080fd5b8380fd5b8284346106305781600319360112610630576020906002549051908152f35b5080fd5b5091346106305781600319360112610630578051926370a0823160e01b845230908401526020836024816001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789165afa9182156106d557916106a1575b6020925051908152f35b90506020823d82116106cd575b816106bb602093836111fc565b81010312610608576020915190610697565b3d91506106ae565b9051903d90823e3d90fd5b50819234610556576020366003190112610556576106fc6110a5565b61070461117a565b6001600160a01b03807f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278916803b15610279578592836024928651978895869463611d2e7560e11b865216908401525af190811561054857506107635750f35b61076c906111d2565b6105455780f35b5081923461055657826003193601126105565761078e61117a565b6001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891691823b1561055157815163bb9fe6bf60e01b81529284918491829084905af190811561054857506107635750f35b50919034610545578060031936011261054557506001600160a01b0360209254169051908152f35b828434610630578160031936011261063057602090516001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789168152f35b508290346101d95760608060031936011261060d5781359260038410156102755767ffffffffffffffff602435818111610b41576108939036908601611116565b909360e085604435936108a461121e565b81010312610b3d576108b5856110bb565b936020956108c48782016110bb565b6108cf8383016110bb565b9784830135966002881015610b39576108ea60a08501611094565b926001600160a01b039081808c169c169260808701359960018c1480610b1b575b80610b12575b610af2575b6109236002543a906115bf565b8101809111610add57620f424061095763ffffffff670de0b6b3a764000061094d8f6002966115bf565b04991680996115bf565b049f14610a09575081169b5416988551998d885286526bffffffffffffffffffffffff1990871b16602c526f23b872dd000000000000000000000000600c52818d808d5a91601c91606493f18d516001143d151716156109fe578c8652888552885287015260c00135908501528301527f7c405b9cef9e824a5cf31a09e7b8810d01d9db34ee384388f33b438608807e1a9160a0916109fa906080830190611144565ba480f35b508b637939f4248152fd5b98509598509550509650505081879697541692845196868801946323b872dd60e01b86528960248a015260448901528960648901526064885260a088019188831090831117610ac857508452945194169387918291829182885af1923d15610ac0573d610a81610a7882611358565b945194856111fc565b83523d92013e5b15610a94575b50505080f35b7f41614445ea2ab6d87c504bdfc83cb5cb840e7219aa772383baff1ab0dd2a31138480a4818080610a8e565b505050610a88565b604190634e487b7160e01b6000525260246000fd5b5050634e487b7160e01b8f5260118d5260248ffd5b610afe85858516611cb9565b80610b0a575b50610916565b9a5038610b04565b50841515610911565b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85141561090b565b8c80fd5b8780fd5b8680fd5b508290346101d95760203660031901126101d957803567ffffffffffffffff811161060d5792610b89610b8363ffffffff93610ba096369101611116565b906114c6565b98979996909a91958295949395519c8d809c611144565b65ffffffffffff80921660208c015216908901526001600160a01b03809216606089015216608087015260a08601521660c0840152816101008060e0860152840152816101209485850137828201840152601f01601f19168101030190f35b8284346106305781600319360112610630576001600160a01b0360209254169051908152f35b508290816003193601126101d957803567ffffffffffffffff811161060d57610c5190369083016110e5565b610c5c9391936110cf565b93610c6561117a565b610c6d611295565b855b828110610c7e57866001805580f35b6001600160a01b03610c99610c948386866112eb565b611311565b1690845180926370a0823160e01b8252308883015281602460209586935afa928315610d1b578993610ce8575b5050610ce260019288610cdd610c948589896112eb565b611d2e565b01610c6f565b90809350813d8311610d14575b610cff81836111fc565b8101031261060857610ce26001925192610cc6565b503d610cf5565b86513d8b823e3d90fd5b8234610545578060031936011261054557610d3e61117a565b60006001600160a01b03815473ffffffffffffffffffffffffffffffffffffffff1981168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b508260603660031901126101d95767ffffffffffffffff823581811161027557610db990369085016110e5565b610dc49491946110cf565b92604435908111610b4157610ddc90369084016110e5565b929094610de761117a565b610def611295565b838303610e36575050855b818110610e0957866001805580f35b80610e30610e1d610c94600194868b6112eb565b86610e2984888b6112eb565b3591611d2e565b01610dfa565b51630483384360e11b8152fd5b5082806003193601126101d957610e586110a5565b610e606110cf565b90610e6961117a565b610e71611295565b8251936370a0823160e01b855230908501526020846024816001600160a01b0385165afa928315610eea57508492610eb5575b610eae9350611d2e565b6001805580f35b91506020833d8211610ee2575b81610ecf602093836111fc565b8101031261060857610eae925191610ea4565b3d9150610ec2565b513d86823e3d90fd5b82606036600319011261054557610eae610f0b6110a5565b610f136110cf565b610f1b61117a565b610f23611295565b60443591611d2e565b8284346106305781600319360112610630576020906001600160a01b03600354169051908152f35b509134610630578060031936011261063057610f6e6110a5565b90610f7761117a565b610f7f611295565b6001600160a01b03809216918215610ff5579383947f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891692833b156102755760448592838551968794859363040b850f60e31b855284015260243560248401525af1908115610548575061053157506001805580f35b81516392bc9df360e01b81528590fd5b508260203660031901126101d95782823563ffffffff81168091036106305761102c61117a565b6001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27891693843b156101d95760249084519586938492621cb65b60e51b845283015234905af19081156105485750611088575080f35b611091906111d2565b80f35b359063ffffffff8216820361060857565b600435906001600160a01b038216820361060857565b35906001600160a01b038216820361060857565b602435906001600160a01b038216820361060857565b9181601f840112156106085782359167ffffffffffffffff8311610608576020808501948460051b01011161060857565b9181601f840112156106085782359167ffffffffffffffff8311610608576020838186019501011161060857565b9060028210156111515752565b634e487b7160e01b600052602160045260246000fd5b359065ffffffffffff8216820361060857565b6001600160a01b0360005416330361118e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b67ffffffffffffffff81116111e657604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176111e657604052565b6001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d278916330361125057565b60405162461bcd60e51b815260206004820152601560248201527f53656e646572206e6f7420456e747279506f696e7400000000000000000000006044820152606490fd5b6002600154146112a6576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b91908110156112fb5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160a01b03811681036106085790565b903590601e1981360301821215610608570180359067ffffffffffffffff82116106085760200191813603831361060857565b67ffffffffffffffff81116111e657601f01601f191660200190565b92919261138082611358565b9161138e60405193846111fc565b829481845281830111610608578281602093846000960137010152565b929694919095936113c96113c26040860186611325565b3691611374565b60208151910120916113e16113c26060870187611325565b602081519101209861146a604051998a97602089019c8d9760606001600160a01b039b8c9a8b863516905260208501356040820152015260808d0152608081013560a08d015260a081013560c08d015260c081013560e08d0152610100908c8260e083013591015201356101208c0152466101408c0152306101608c01526101808b0190611144565b65ffffffffffff8092166101a08a0152166101c0880152166101e08601521661020084015261022083015263ffffffff6102409116818301528152610260810181811067ffffffffffffffff8211176111e65760405251902090565b909160d58310611554578260151161060857601482013560f81c600281101561115157928060d511610608576114fe60158401611167565b9161150b60358501611167565b91611518605586016110bb565b91611525607587016110bb565b9161153260b58801611094565b9160d56095890135946001600160a01b038091169616969798019160d4190190565b60405162461bcd60e51b815260206004820152602960248201527f4254504d3a20496e76616c6964206c656e67746820666f72207061796d61737460448201527f6572416e644461746100000000000000000000000000000000000000000000006064820152608490fd5b818102929181159184041417156115d257565b634e487b7160e01b600052601160045260246000fd5b919060a08301356002549384821115611aa95761160c610b83610120830183611325565b916041839e99949592989c979e03611a3e57896116538f878f8a7f19457468657265756d205369676e6564204d6573736167653a0a3332000000009f9388928b89966113ab565b9b60409a8b519560209e8f88019e8f52603c880152603c8752606087019067ffffffffffffffff9e8f898410908411176111e657828f5288519020976080018f8111838210176111e6578e5260009c8d83526001600160a01b0398899182600354169336906116c192611374565b6116ca91611bf2565b6116d390611aee565b16036119ef575087670de0b6b3a76400009261170792888635169560e081013592608060c0830135920135010101026115bf565b049182156119855763ffffffff1696621e8480881161191b57620f424088106118b1578a516370a0823160e01b815260048101839052908516928d82602481875afa9182156118a7579089918c9361186d575b50620f424091611769916115bf565b04116118035789519b8c01528a89015216606089015261178d906080890190611144565b60a087015260c086015260e085015260e08452610100840192848410908411176117ef5750917fffffffffffff00000000000000000000000000000000000000000000000000009165ffffffffffff60a01b93529460d01b169160a01b161790565b634e487b7160e01b81526041600452602490fd5b895162461bcd60e51b8152600481018d9052603060248201527f4254504d3a206163636f756e7420646f6573206e6f74206861766520656e6f7560448201527f676820746f6b656e2062616c616e6365000000000000000000000000000000006064820152608490fd5b8f809294508193503d83116118a0575b61188781836111fc565b8101031261189c5751908890620f424061175a565b8a80fd5b503d61187d565b8c513d8d823e3d90fd5b8a5162461bcd60e51b8152600481018e9052602560248201527f4254504d3a207072696365206d61726b75702070657263656e7461676520746f60448201527f6f206c6f770000000000000000000000000000000000000000000000000000006064820152608490fd5b8a5162461bcd60e51b8152600481018e9052602660248201527f4254504d3a207072696365206d61726b75702070657263656e7461676520746f60448201527f6f206869676800000000000000000000000000000000000000000000000000006064820152608490fd5b8a5162461bcd60e51b8152600481018e9052602560248201527f4254504d3a2063616c63756c6174656420746f6b656e2063686172676520696e60448201527f76616c69640000000000000000000000000000000000000000000000000000006064820152608490fd5b9a5050505050505050505050600194935065ffffffffffff60a01b92507fffffffffffff000000000000000000000000000000000000000000000000000091509560d01b169160a01b16171790565b60405162461bcd60e51b815260206004820152603260248201527f4254504d3a20696e76616c6964207369676e6174757265206c656e677468206960448201527f6e207061796d6173746572416e644461746100000000000000000000000000006064820152608490fd5b60405162461bcd60e51b815260206004820152601c60248201527f4254504d3a2067617320746f6f206c6f7720666f7220706f73744f70000000006044820152606490fd5b60058110156111515780611aff5750565b60018103611b4c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b60028103611b995760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b600314611ba257565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b906041815114600014611c2057611c1c916020820151906060604084015193015160001a90611c2a565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311611cad5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa15611ca05781516001600160a01b03811615611c9a579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b604051633f81538960e11b81526001600160a01b0391821660048201529160209183916024918391165afa60009181611cfb575b50611cf85750600090565b90565b90916020823d8211611d26575b81611d15602093836111fc565b810103126105455750519038611ced565b3d9150611d08565b6001600160a01b039283831615611d8757602092601452603452604460106000809581946fa9059cbb0000000000000000000000008352165af13d156001835114171615611d7b57603452565b806390b8ec1860209252fd5b6040516392bc9df360e01b8152600490fdfea2646970667358221220f43cb9b4e4ecf507f85d6ed4b4e47cd86481fb10afeb19bb1d410ff6b94548c864736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003e01030db6d99649d419ed13c49706ab23b1dee90000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27890000000000000000000000003e01030db6d99649d419ed13c49706ab23b1dee9
-----Decoded View---------------
Arg [0] : _owner (address): 0x3E01030dB6d99649d419eD13c49706AB23B1deE9
Arg [1] : _entryPoint (address): 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
Arg [2] : _verifyingSigner (address): 0x3E01030dB6d99649d419eD13c49706AB23B1deE9
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000003e01030db6d99649d419ed13c49706ab23b1dee9
Arg [1] : 0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Arg [2] : 0000000000000000000000003e01030db6d99649d419ed13c49706ab23b1dee9
Loading...
Loading
[ Download: CSV Export ]
[ 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.