More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 648,132 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Metacall | 70648585 | 37 secs ago | IN | 0 POL | 0.01708692 | ||||
Metacall | 70648584 | 39 secs ago | IN | 0 POL | 0.01498975 | ||||
Metacall | 70648583 | 41 secs ago | IN | 0 POL | 0.02020659 | ||||
Metacall | 70648582 | 43 secs ago | IN | 0 POL | 0.01500575 | ||||
Metacall | 70648582 | 43 secs ago | IN | 0 POL | 0.01133915 | ||||
Metacall | 70648582 | 43 secs ago | IN | 0 POL | 0.0385618 | ||||
Metacall | 70648582 | 43 secs ago | IN | 0 POL | 0.03222064 | ||||
Metacall | 70648582 | 43 secs ago | IN | 0 POL | 0.10164088 | ||||
Metacall | 70648582 | 43 secs ago | IN | 0 POL | 0.07610114 | ||||
Metacall | 70648580 | 47 secs ago | IN | 0 POL | 0.01784628 | ||||
Metacall | 70648555 | 1 min ago | IN | 0 POL | 0.03450284 | ||||
Withdraw | 70648487 | 4 mins ago | IN | 0 POL | 0.00107764 | ||||
Metacall | 70648408 | 6 mins ago | IN | 0 POL | 0.03137535 | ||||
Unbond | 70648404 | 7 mins ago | IN | 0 POL | 0.0013535 | ||||
Metacall | 70648379 | 7 mins ago | IN | 0 POL | 0.03802291 | ||||
Metacall | 70648356 | 8 mins ago | IN | 0 POL | 0.0125395 | ||||
Metacall | 70648356 | 8 mins ago | IN | 0 POL | 0.01262235 | ||||
Metacall | 70648356 | 8 mins ago | IN | 0 POL | 0.02379858 | ||||
Metacall | 70648352 | 8 mins ago | IN | 0 POL | 0.0254374 | ||||
Metacall | 70648322 | 9 mins ago | IN | 0 POL | 0.02583273 | ||||
Withdraw | 70648318 | 10 mins ago | IN | 0 POL | 0.00107764 | ||||
Metacall | 70648274 | 11 mins ago | IN | 0 POL | 0.0263459 | ||||
Metacall | 70648274 | 11 mins ago | IN | 0 POL | 0.031091 | ||||
Metacall | 70648262 | 12 mins ago | IN | 0 POL | 0.01044384 | ||||
Metacall | 70648261 | 12 mins ago | IN | 0 POL | 0.00729794 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
70648585 | 37 secs ago | 0.03085268 POL | ||||
70648580 | 47 secs ago | 0.03129097 POL | ||||
70648555 | 1 min ago | 0.05555224 POL | ||||
70648487 | 4 mins ago | 0.32123078 POL | ||||
70648322 | 9 mins ago | 0.04265715 POL | ||||
70648318 | 10 mins ago | 0.44469399 POL | ||||
70648274 | 11 mins ago | 0.04975212 POL | ||||
70648274 | 11 mins ago | 0.05991784 POL | ||||
70648249 | 12 mins ago | 0.05125271 POL | ||||
70648205 | 14 mins ago | 0.05721141 POL | ||||
70648095 | 17 mins ago | 0.05788286 POL | ||||
70648091 | 18 mins ago | 0.03535197 POL | ||||
70648053 | 19 mins ago | 0.06746149 POL | ||||
70648032 | 20 mins ago | 0.03105051 POL | ||||
70647985 | 21 mins ago | 0.05052889 POL | ||||
70647985 | 21 mins ago | 0.07369295 POL | ||||
70647973 | 22 mins ago | 0.04438845 POL | ||||
70647970 | 22 mins ago | 0.03781394 POL | ||||
70647935 | 23 mins ago | 0.02687026 POL | ||||
70647932 | 23 mins ago | 0.23308004 POL | ||||
70647926 | 23 mins ago | 0.04215249 POL | ||||
70647924 | 24 mins ago | 0.02659976 POL | ||||
70647852 | 26 mins ago | 0.20576437 POL | ||||
70647850 | 26 mins ago | 0.05109111 POL | ||||
70647845 | 26 mins ago | 0.04615602 POL |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
Atlas
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 50 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { LibSort } from "solady/utils/LibSort.sol"; import { Escrow } from "./Escrow.sol"; import { Factory } from "./Factory.sol"; import "../types/SolverOperation.sol"; import "../types/UserOperation.sol"; import "../types/LockTypes.sol"; import "../types/ConfigTypes.sol"; import "../types/DAppOperation.sol"; import "../types/ValidCalls.sol"; import { CallBits } from "../libraries/CallBits.sol"; import { SafetyBits } from "../libraries/SafetyBits.sol"; import { IL2GasCalculator } from "../interfaces/IL2GasCalculator.sol"; import { IDAppControl } from "../interfaces/IDAppControl.sol"; /// @title Atlas V1.1 /// @author FastLane Labs /// @notice The Execution Abstraction protocol. contract Atlas is Escrow, Factory { using CallBits for uint32; using SafetyBits for Context; constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator, address factoryLib ) Escrow( escrowDuration, atlasSurchargeRate, bundlerSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator ) Factory(factoryLib) { } /// @notice metacall is the entrypoint function for the Atlas transactions. /// @dev Any ETH sent as msg.value with a metacall should be considered a potential subsidy for the winning solver's /// gas repayment. /// @param userOp The UserOperation struct containing the user's transaction data. /// @param solverOps The SolverOperation array containing the solvers' transaction data. /// @param dAppOp The DAppOperation struct containing the DApp's transaction data. /// @param gasRefundBeneficiary The address to receive the gas refund. /// @return auctionWon A boolean indicating whether there was a successful, winning solver. function metacall( UserOperation calldata userOp, // set by user SolverOperation[] calldata solverOps, // supplied by ops relay DAppOperation calldata dAppOp, // supplied by front end via atlas SDK address gasRefundBeneficiary // address(0) = msg.sender ) external payable returns (bool auctionWon) { uint256 _gasMarker = L2_GAS_CALCULATOR == address(0) ? gasleft() + _BASE_TRANSACTION_GAS_USED + (msg.data.length * _CALLDATA_LENGTH_PREMIUM_HALVED) : gasleft() + IL2GasCalculator(L2_GAS_CALCULATOR).initialGasUsed(msg.data.length); bool _isSimulation = msg.sender == SIMULATOR; address _bundler = _isSimulation ? dAppOp.bundler : msg.sender; (address _executionEnvironment, DAppConfig memory _dConfig) = _getOrCreateExecutionEnvironment(userOp); { ValidCallsResult _validCallsResult = VERIFICATION.validateCalls(_dConfig, userOp, solverOps, dAppOp, msg.value, _bundler, _isSimulation); if (_validCallsResult != ValidCallsResult.Valid) { if (_isSimulation) revert VerificationSimFail(_validCallsResult); // Gracefully return for results that need nonces to be stored and prevent replay attacks if (uint8(_validCallsResult) >= _GRACEFUL_RETURN_THRESHOLD && !_dConfig.callConfig.allowsReuseUserOps()) { return false; } // Revert for all other results revert ValidCalls(_validCallsResult); } } // Initialize the environment lock and accounting values _setEnvironmentLock(_dConfig, _executionEnvironment); _initializeAccountingValues(_gasMarker); // userOpHash has already been calculated and verified in validateCalls at this point, so rather // than re-calculate it, we can simply take it from the dAppOp here. It's worth noting that this will // be either a TRUSTED or DEFAULT hash, depending on the allowsTrustedOpHash setting. try this.execute(_dConfig, userOp, solverOps, _executionEnvironment, _bundler, dAppOp.userOpHash, _isSimulation) returns (Context memory ctx) { // Gas Refund to sender only if execution is successful (uint256 _ethPaidToBundler, uint256 _netGasSurcharge) = _settle(ctx, _dConfig.solverGasLimit, gasRefundBeneficiary); auctionWon = ctx.solverSuccessful; emit MetacallResult( msg.sender, userOp.from, auctionWon, ctx.paymentsSuccessful, _ethPaidToBundler, _netGasSurcharge ); } catch (bytes memory revertData) { // Bubble up some specific errors _handleErrors(revertData, _dConfig.callConfig); // Set lock to FullyLocked to prevent any reentrancy possibility _setLockPhase(uint8(ExecutionPhase.FullyLocked)); // Refund the msg.value to sender if it errored // WARNING: If msg.sender is a disposable address such as a session key, make sure to remove ETH from it // before disposal if (msg.value != 0) SafeTransferLib.safeTransferETH(msg.sender, msg.value); // Emit event indicating the metacall failed in `execute()` emit MetacallResult(msg.sender, userOp.from, false, false, 0, 0); } // The environment lock is explicitly released here to allow multiple metacalls in a single transaction. _releaseLock(); } /// @notice execute is called above, in a try-catch block in metacall. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param userOp UserOperation struct of the current metacall tx. /// @param solverOps SolverOperation array of the current metacall tx. /// @param executionEnvironment Address of the execution environment contract of the current metacall tx. /// @param bundler Address of the bundler of the current metacall tx. /// @param userOpHash Hash of the userOp struct of the current metacall tx. /// @return ctx Context struct containing relevant context information for the Atlas auction. function execute( DAppConfig memory dConfig, UserOperation calldata userOp, SolverOperation[] calldata solverOps, address executionEnvironment, address bundler, bytes32 userOpHash, bool isSimulation ) external payable returns (Context memory ctx) { // This is a self.call made externally so that it can be used with try/catch if (msg.sender != address(this)) revert InvalidAccess(); // Build the context object ctx = _buildContext(executionEnvironment, userOpHash, bundler, uint8(solverOps.length), isSimulation); bytes memory _returnData; // PreOps Call if (dConfig.callConfig.needsPreOpsCall()) { _returnData = _executePreOpsCall(ctx, dConfig, userOp); } // UserOp Call _returnData = _executeUserOperation(ctx, dConfig, userOp, _returnData); // SolverOps Calls uint256 _winningBidAmount = dConfig.callConfig.exPostBids() ? _bidFindingIteration(ctx, dConfig, userOp, solverOps, _returnData) : _bidKnownIteration(ctx, dConfig, userOp, solverOps, _returnData); // AllocateValue Call if (ctx.solverSuccessful) { _allocateValue(ctx, dConfig, _winningBidAmount, _returnData); } // PostOp Call if (dConfig.callConfig.needsPostOpsCall()) { _executePostOpsCall(ctx, ctx.solverSuccessful, _returnData); } } /// @notice Called above in `execute` if the DAppConfig requires ex post bids. Sorts solverOps by bid amount and /// executes them in descending order until a successful winner is found. /// @param ctx Context struct containing the current state of the escrow lock. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param userOp UserOperation struct of the current metacall tx. /// @param solverOps SolverOperation array of the current metacall tx. /// @param returnData Return data from the preOps and userOp calls. /// @return The winning bid amount or 0 when no solverOps. function _bidFindingIteration( Context memory ctx, DAppConfig memory dConfig, UserOperation calldata userOp, SolverOperation[] calldata solverOps, bytes memory returnData ) internal returns (uint256) { uint256 solverOpsLength = solverOps.length; // computed once for efficiency // Return early if no solverOps (e.g. in simUserOperation) if (solverOpsLength == 0) { if (ctx.isSimulation) revert SolverSimFail(0); if (dConfig.callConfig.needsFulfillment()) revert UserNotFulfilled(); return 0; } ctx.bidFind = true; uint256[] memory _bidsAndIndices = new uint256[](solverOpsLength); uint256 _bidAmountFound; uint256 _bidsAndIndicesLastIndex = solverOpsLength - 1; // Start from the last index uint256 _gasWaterMark = gasleft(); // First, get all bid amounts. Bids of zero are ignored by only storing non-zero bids in the array, from right // to left. If there are any zero bids they will end up on the left as uint(0) values - in their sorted // position. This reduces operations needed later when sorting the array in ascending order. // Each non-zero bid amount is packed with its original solverOps array index, to fit into a uint256 value. The // order of bidAmount and index is important - with bidAmount using the most significant bits, and considering // we do not store zero bids in the array, the index values within the uint256 should not impact the sorting. // |<------------------------- uint256 (256 bits) ------------------------->| // | | // |<------------------ uint240 ----------------->|<-------- uint16 ------->| // | | | // | bidAmount | index | // | | | // |<------------------ 240 bits ---------------->|<------- 16 bits ------->| for (uint256 i; i < solverOpsLength; ++i) { _bidAmountFound = _getBidAmount(ctx, dConfig, userOp, solverOps[i], returnData); // skip zero and overflow bid's if (_bidAmountFound != 0 && _bidAmountFound <= type(uint240).max) { // Non-zero bids are packed with their original solverOps index. // The array is filled with non-zero bids from the right. _bidsAndIndices[_bidsAndIndicesLastIndex] = uint256(_bidAmountFound << _BITS_FOR_INDEX | uint16(i)); unchecked { --_bidsAndIndicesLastIndex; } } } // Reinitialize _bidsAndIndicesLastIndex to iterate through the sorted array in descending order _bidsAndIndicesLastIndex = solverOpsLength - 1; // Then, sorts the uint256 array in-place, in ascending order. LibSort.insertionSort(_bidsAndIndices); ctx.bidFind = false; // Write off the gas cost involved in on-chain bid-finding execution of all solverOps, as these costs should be // paid by the bundler. _writeOffBidFindGasCost(_gasWaterMark - gasleft()); // Finally, iterate through sorted bidsAndIndices array in descending order of bidAmount. for (uint256 i = _bidsAndIndicesLastIndex;; /* breaks when 0 */ --i) { // Isolate the bidAmount from the packed uint256 value _bidAmountFound = _bidsAndIndices[i] >> _BITS_FOR_INDEX; // If we reach the zero bids on the left of array, break as all valid bids already checked. if (_bidAmountFound == 0) break; // NOTE: We reuse the ctx.solverIndex variable to store the count of solver ops that have been executed. // This count is useful in `_settle()` when we may penalize the bundler for overestimating gas limit of the // metacall tx. ctx.solverIndex = uint8(_bidsAndIndicesLastIndex - i); // Isolate the original solverOps index from the packed uint256 value uint256 _solverIndex = uint8(_bidsAndIndices[i] & _FIRST_16_BITS_TRUE_MASK); // Execute the solver operation. If solver won, allocate value and return. Otherwise continue looping. _bidAmountFound = _executeSolverOperation( ctx, dConfig, userOp, solverOps[_solverIndex], _bidAmountFound, true, returnData ); if (ctx.solverSuccessful) { return _bidAmountFound; } if (i == 0) break; // break to prevent underflow in next loop } if (ctx.isSimulation) revert SolverSimFail(uint256(ctx.solverOutcome)); if (dConfig.callConfig.needsFulfillment()) revert UserNotFulfilled(); return 0; } /// @notice Called above in `execute` as an alternative to `_bidFindingIteration`, if solverOps have already been /// reliably sorted. Executes solverOps in order until a successful winner is found. /// @param ctx Context struct containing the current state of the escrow lock. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param userOp UserOperation struct of the current metacall tx. /// @param solverOps SolverOperation array of the current metacall tx. /// @param returnData Return data from the preOps and userOp calls. /// @return The winning bid amount or 0 when no solverOps. function _bidKnownIteration( Context memory ctx, DAppConfig memory dConfig, UserOperation calldata userOp, SolverOperation[] calldata solverOps, bytes memory returnData ) internal returns (uint256) { uint256 _bidAmount; uint8 i = uint8(solverOps.length); for (; ctx.solverIndex < i; ctx.solverIndex++) { SolverOperation calldata solverOp = solverOps[ctx.solverIndex]; _bidAmount = _executeSolverOperation(ctx, dConfig, userOp, solverOp, solverOp.bidAmount, false, returnData); if (ctx.solverSuccessful) { return _bidAmount; } } if (ctx.isSimulation) revert SolverSimFail(uint256(ctx.solverOutcome)); if (dConfig.callConfig.needsFulfillment()) revert UserNotFulfilled(); return 0; } /// @notice Called at the end of `metacall` to bubble up specific error info in a revert. /// @param revertData Revert data from a failure during the execution of the metacall. /// @param callConfig The CallConfig of the current metacall tx. function _handleErrors(bytes memory revertData, uint32 callConfig) internal view { bytes4 _errorSwitch = bytes4(revertData); if (msg.sender == SIMULATOR) { if (_errorSwitch == SolverSimFail.selector) { // Expects revertData in form [bytes4, uint256] uint256 _solverOutcomeResult; assembly { let dataLocation := add(revertData, 0x20) _solverOutcomeResult := mload(add(dataLocation, sub(mload(revertData), 32))) } revert SolverSimFail(_solverOutcomeResult); } else if ( _errorSwitch == PreOpsSimFail.selector || _errorSwitch == UserOpSimFail.selector || _errorSwitch == AllocateValueSimFail.selector || _errorSwitch == PostOpsSimFail.selector ) { assembly { mstore(0, _errorSwitch) revert(0, 4) } } } // NOTE: If error was UserNotFulfilled, we revert and bubble up the error. // For any other error, we only bubble up the revert if allowReuseUserOps = true. This is to prevent storing the // nonce as used so the userOp can be reused. Otherwise, the whole metacall doesn't revert but the inner // execute() does so, no operation changes are persisted. if (_errorSwitch == UserNotFulfilled.selector || callConfig.allowsReuseUserOps()) { assembly { mstore(0, _errorSwitch) revert(0, 4) } } } /// @notice Returns whether or not the execution environment address matches what's expected from the set of inputs. /// @param environment ExecutionEnvironment address /// @param user User address /// @param control DAppControl contract address /// @param callConfig CallConfig of the current metacall tx. /// @return A bool indicating whether the execution environment address is the same address that the factory would /// deploy an Execution Environment to, given the user, control, and callConfig params. function _verifyUserControlExecutionEnv( address environment, address user, address control, uint32 callConfig ) internal override returns (bool) { return environment == _getExecutionEnvironmentCustom(user, control, callConfig); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @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) /// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol) /// /// @dev Note: /// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection. /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @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(); /// @dev The Permit2 operation has failed. error Permit2Failed(); /// @dev The Permit2 amount must be less than `2**160 - 1`. error Permit2AmountOverflow(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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. uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000; /// @dev The unique EIP-712 domain domain separator for the DAI token contract. bytes32 internal constant DAI_DOMAIN_SEPARATOR = 0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7; /// @dev The address for the WETH9 contract on Ethereum mainnet. address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; /// @dev The canonical Permit2 address. /// [Github](https://github.com/Uniswap/permit2) /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3) address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. // // The regular variants: // - Forwards all remaining gas to the target. // - Reverts if the target reverts. // - Reverts if the current contract has insufficient balance. // // The force variants: // - Forwards with an optional gas stipend // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases). // - If the target reverts, or if the gas stipend is exhausted, // creates a temporary contract to force send the ETH via `SELFDESTRUCT`. // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758. // - Reverts if the current contract has insufficient balance. // // The try variants: // - Forwards with a mandatory gas stipend. // - Instead of reverting, returns whether the transfer succeeded. /// @dev Sends `amount` (in wei) ETH to `to`. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Sends all the ETH in the current contract to `to`. function safeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // Transfer all the ETH and check if it succeeded or not. if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`. function forceSafeTransferAllETH(address to, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // forgefmt: disable-next-item if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00) } } /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`. function trySafeTransferAllETH(address to, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// /// The `from` account must have at least `amount` approved for the current contract to manage. function trySafeTransferFrom(address token, address from, address to, uint256 amount) internal returns (bool success) { /// @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. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. success := and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 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 their entire balance 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. mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`. // Read the balance, reverting upon failure. 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) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`. amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } 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. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @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. // Read the balance, reverting upon failure. 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) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @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. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(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. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @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. mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`. amount := mul( // The arguments of `mul` are evaluated from right to left. 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) ) ) } } /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// If the initial attempt fails, try to use Permit2 to transfer the token. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for the current contract to manage. function safeTransferFrom2(address token, address from, address to, uint256 amount) internal { if (!trySafeTransferFrom(token, from, to, amount)) { permit2TransferFrom(token, from, to, amount); } } /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2. /// Reverts upon failure. function permit2TransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(add(m, 0x74), shr(96, shl(96, token))) mstore(add(m, 0x54), amount) mstore(add(m, 0x34), to) mstore(add(m, 0x20), shl(96, from)) // `transferFrom(address,address,uint160,address)`. mstore(m, 0x36c78516000000000000000000000000) let p := PERMIT2 let exists := eq(chainid(), 1) if iszero(exists) { exists := iszero(iszero(extcodesize(p))) } if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) { mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`. revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04) } } } /// @dev Permit a user to spend a given amount of /// another user's tokens via native EIP-2612 permit if possible, falling /// back to Permit2 if native permit fails or is not implemented on the token. function permit2( address token, address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { bool success; /// @solidity memory-safe-assembly assembly { for {} shl(96, xor(token, WETH9)) {} { mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`. if iszero( and( // The arguments of `and` are evaluated from right to left. lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word. // Gas stipend to limit gas burn for tokens that don't refund gas when // an non-existing function is called. 5K should be enough for a SLOAD. staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20) ) ) { break } // After here, we can be sure that token is a contract. let m := mload(0x40) mstore(add(m, 0x34), spender) mstore(add(m, 0x20), shl(96, owner)) mstore(add(m, 0x74), deadline) if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) { mstore(0x14, owner) mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`. mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20)) mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`. // `nonces` is already at `add(m, 0x54)`. // `1` is already stored at `add(m, 0x94)`. mstore(add(m, 0xb4), and(0xff, v)) mstore(add(m, 0xd4), r) mstore(add(m, 0xf4), s) success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00) break } mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`. mstore(add(m, 0x54), amount) mstore(add(m, 0x94), and(0xff, v)) mstore(add(m, 0xb4), r) mstore(add(m, 0xd4), s) success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00) break } } if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s); } /// @dev Simple permit on the Permit2 contract. function simplePermit2( address token, address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(m, 0x927da105) // `allowance(address,address,address)`. { let addressMask := shr(96, not(0)) mstore(add(m, 0x20), and(addressMask, owner)) mstore(add(m, 0x40), and(addressMask, token)) mstore(add(m, 0x60), and(addressMask, spender)) mstore(add(m, 0xc0), and(addressMask, spender)) } let p := mul(PERMIT2, iszero(shr(160, amount))) if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`. staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60) ) ) { mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`. revert(add(0x18, shl(2, iszero(p))), 0x04) } mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant). // `owner` is already `add(m, 0x20)`. // `token` is already at `add(m, 0x40)`. mstore(add(m, 0x60), amount) mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`. // `nonce` is already at `add(m, 0xa0)`. // `spender` is already at `add(m, 0xc0)`. mstore(add(m, 0xe0), deadline) mstore(add(m, 0x100), 0x100) // `signature` offset. mstore(add(m, 0x120), 0x41) // `signature` length. mstore(add(m, 0x140), r) mstore(add(m, 0x160), s) mstore(add(m, 0x180), shl(248, v)) if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) { mstore(0x00, 0x6b836e6b) // `Permit2Failed()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Optimized sorts and operations for sorted arrays. /// @author Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibSort.sol) library LibSort { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSERTION SORT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // - Faster on small arrays (32 or lesser elements). // - Faster on almost sorted arrays. // - Smaller bytecode. // - May be suitable for view functions intended for off-chain querying. /// @dev Sorts the array in-place with insertion sort. function insertionSort(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let n := mload(a) // Length of `a`. mstore(a, 0) // For insertion sort's inner loop to terminate. let h := add(a, shl(5, n)) // High slot. let w := not(0x1f) for { let i := add(a, 0x20) } 1 {} { i := add(i, 0x20) if gt(i, h) { break } let k := mload(i) // Key. let j := add(i, w) // The slot before the current slot. let v := mload(j) // The value of `j`. if iszero(gt(v, k)) { continue } for {} 1 {} { mstore(add(j, 0x20), v) j := add(j, w) // `sub(j, 0x20)`. v := mload(j) if iszero(gt(v, k)) { break } } mstore(add(j, 0x20), k) } mstore(a, n) // Restore the length of `a`. } } /// @dev Sorts the array in-place with insertion sort. function insertionSort(int256[] memory a) internal pure { _flipSign(a); insertionSort(_toUints(a)); _flipSign(a); } /// @dev Sorts the array in-place with insertion sort. function insertionSort(address[] memory a) internal pure { insertionSort(_toUints(a)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTRO-QUICKSORT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // - Faster on larger arrays (more than 32 elements). // - Robust performance. // - Larger bytecode. /// @dev Sorts the array in-place with intro-quicksort. function sort(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { function swap(a_, b_) -> _a, _b { _b := a_ _a := b_ } function mswap(i_, j_) { let t_ := mload(i_) mstore(i_, mload(j_)) mstore(j_, t_) } function sortInner(w_, l_, h_) { // Do insertion sort if `h_ - l_ <= 0x20 * 12`. // Threshold is fine-tuned via trial and error. if iszero(gt(sub(h_, l_), 0x180)) { // Hardcode sort the first 2 elements. let i_ := add(l_, 0x20) if iszero(lt(mload(l_), mload(i_))) { mswap(i_, l_) } for {} 1 {} { i_ := add(i_, 0x20) if gt(i_, h_) { break } let k_ := mload(i_) // Key. let j_ := add(i_, w_) // The slot before the current slot. let v_ := mload(j_) // The value of `j_`. if iszero(gt(v_, k_)) { continue } for {} 1 {} { mstore(add(j_, 0x20), v_) j_ := add(j_, w_) v_ := mload(j_) if iszero(gt(v_, k_)) { break } } mstore(add(j_, 0x20), k_) } leave } // Pivot slot is the average of `l_` and `h_`. let p_ := add(shl(5, shr(6, add(l_, h_))), and(31, l_)) // Median of 3 with sorting. { let e0_ := mload(l_) let e1_ := mload(p_) if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) } let e2_ := mload(h_) if iszero(lt(e1_, e2_)) { e1_, e2_ := swap(e1_, e2_) if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) } } mstore(h_, e2_) mstore(p_, e1_) mstore(l_, e0_) } // Hoare's partition. { // The value of the pivot slot. let x_ := mload(p_) p_ := h_ for { let i_ := l_ } 1 {} { for {} 1 {} { i_ := add(0x20, i_) if iszero(gt(x_, mload(i_))) { break } } let j_ := p_ for {} 1 {} { j_ := add(w_, j_) if iszero(lt(x_, mload(j_))) { break } } p_ := j_ if iszero(lt(i_, p_)) { break } mswap(i_, p_) } } if iszero(eq(add(p_, 0x20), h_)) { sortInner(w_, add(p_, 0x20), h_) } if iszero(eq(p_, l_)) { sortInner(w_, l_, p_) } } for { let n := mload(a) } iszero(lt(n, 2)) {} { let w := not(0x1f) // `-0x20`. let l := add(a, 0x20) // Low slot. let h := add(a, shl(5, n)) // High slot. let j := h // While `mload(j - 0x20) <= mload(j): j -= 0x20`. for {} iszero(gt(mload(add(w, j)), mload(j))) {} { j := add(w, j) } // If the array is already sorted, break. if iszero(gt(j, l)) { break } // While `mload(j - 0x20) >= mload(j): j -= 0x20`. for { j := h } iszero(lt(mload(add(w, j)), mload(j))) {} { j := add(w, j) } // If the array is reversed sorted. if iszero(gt(j, l)) { for {} 1 {} { let t := mload(l) mstore(l, mload(h)) mstore(h, t) h := add(w, h) l := add(l, 0x20) if iszero(lt(l, h)) { break } } break } mstore(a, 0) // For insertion sort's inner loop to terminate. sortInner(w, l, h) mstore(a, n) // Restore the length of `a`. break } } } /// @dev Sorts the array in-place with intro-quicksort. function sort(int256[] memory a) internal pure { _flipSign(a); sort(_toUints(a)); _flipSign(a); } /// @dev Sorts the array in-place with intro-quicksort. function sort(address[] memory a) internal pure { sort(_toUints(a)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER USEFUL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, the `uniquifySorted` methods will not revert if the // array is not sorted -- it will simply remove consecutive duplicate elements. /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { // If the length of `a` is greater than 1. if iszero(lt(mload(a), 2)) { let x := add(a, 0x20) let y := add(a, 0x40) let end := add(a, shl(5, add(mload(a), 1))) for {} 1 {} { if iszero(eq(mload(x), mload(y))) { x := add(x, 0x20) mstore(x, mload(y)) } y := add(y, 0x20) if eq(y, end) { break } } mstore(a, shr(5, sub(x, a))) } } } /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(int256[] memory a) internal pure { uniquifySorted(_toUints(a)); } /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(address[] memory a) internal pure { uniquifySorted(_toUints(a)); } /// @dev Returns whether `a` contains `needle`, and the index of `needle`. /// `index` precedence: equal to > nearest before > nearest after. function searchSorted(uint256[] memory a, uint256 needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(a, needle, 0); } /// @dev Returns whether `a` contains `needle`, and the index of `needle`. /// `index` precedence: equal to > nearest before > nearest after. function searchSorted(int256[] memory a, int256 needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255); } /// @dev Returns whether `a` contains `needle`, and the index of `needle`. /// `index` precedence: equal to > nearest before > nearest after. function searchSorted(address[] memory a, address needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(_toUints(a), uint256(uint160(needle)), 0); } /// @dev Reverses the array in-place. function reverse(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { if iszero(lt(mload(a), 2)) { let s := 0x20 let w := not(0x1f) let h := add(a, shl(5, mload(a))) for { a := add(a, s) } 1 {} { let t := mload(a) mstore(a, mload(h)) mstore(h, t) h := add(h, w) a := add(a, s) if iszero(lt(a, h)) { break } } } } } /// @dev Reverses the array in-place. function reverse(int256[] memory a) internal pure { reverse(_toUints(a)); } /// @dev Reverses the array in-place. function reverse(address[] memory a) internal pure { reverse(_toUints(a)); } /// @dev Returns a copy of the array. function copy(uint256[] memory a) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let end := add(add(result, 0x20), shl(5, mload(a))) let o := result for { let d := sub(a, result) } 1 {} { mstore(o, mload(add(o, d))) o := add(0x20, o) if eq(o, end) { break } } mstore(0x40, o) } } /// @dev Returns a copy of the array. function copy(int256[] memory a) internal pure returns (int256[] memory result) { result = _toInts(copy(_toUints(a))); } /// @dev Returns a copy of the array. function copy(address[] memory a) internal pure returns (address[] memory result) { result = _toAddresses(copy(_toUints(a))); } /// @dev Returns whether the array is sorted in ascending order. function isSorted(uint256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := iszero(gt(p, mload(a))) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is sorted in ascending order. function isSorted(int256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := iszero(sgt(p, mload(a))) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is sorted in ascending order. function isSorted(address[] memory a) internal pure returns (bool result) { result = isSorted(_toUints(a)); } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := lt(p, mload(a)) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := slt(p, mload(a)) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) { result = isSortedAndUniquified(_toUints(a)); } /// @dev Returns the sorted set difference of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _difference(a, b, 0); } /// @dev Returns the sorted set difference between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set difference between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_difference(_toUints(a), _toUints(b), 0)); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _intersection(a, b, 0); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0)); } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _union(a, b, 0); } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set union between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_union(_toUints(a), _toUints(b), 0)); } /// @dev Cleans the upper 96 bits of the addresses. /// In case `a` is produced via assembly and might have dirty upper bits. function clean(address[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let addressMask := shr(96, not(0)) for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} { a := add(a, 0x20) mstore(a, and(mload(a), addressMask)) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Reinterpret cast to an uint256 array. function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Reinterpret cast to an uint256 array. function _toUints(address[] memory a) private pure returns (uint256[] memory casted) { /// @solidity memory-safe-assembly assembly { // As any address written to memory will have the upper 96 bits // of the word zeroized (as per Solidity spec), we can directly // compare these addresses as if they are whole uint256 words. casted := a } } /// @dev Reinterpret cast to an int array. function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Reinterpret cast to an address array. function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Converts an array of signed integers to unsigned /// integers suitable for sorting or vice versa. function _flipSign(int256[] memory a) private pure { /// @solidity memory-safe-assembly assembly { let w := shl(255, 1) for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} { a := add(a, 0x20) mstore(a, add(mload(a), w)) } } } /// @dev Returns whether `a` contains `needle`, and the index of `needle`. /// `index` precedence: equal to > nearest before > nearest after. function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed) private pure returns (bool found, uint256 index) { /// @solidity memory-safe-assembly assembly { let w := not(0) let l := 1 let h := mload(a) let t := 0 for { needle := add(signed, needle) } 1 {} { index := shr(1, add(l, h)) t := add(signed, mload(add(a, shl(5, index)))) if or(gt(l, h), eq(t, needle)) { break } // Decide whether to search the left or right half. if iszero(gt(needle, t)) { h := add(index, w) continue } l := add(index, 1) } // `index` will be zero in the case of an empty array, // or when the value is less than the smallest value in the array. found := eq(t, needle) t := iszero(iszero(index)) index := mul(add(index, w), t) found := and(found, t) } } /// @dev Returns the sorted set difference of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _difference(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { b := add(b, s) continue } k := add(k, s) mstore(k, u) a := add(a, s) } for {} iszero(gt(a, aEnd)) {} { k := add(k, s) mstore(k, mload(a)) a := add(a, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { k := add(k, s) mstore(k, u) a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { b := add(b, s) continue } a := add(a, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _union(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { k := add(k, s) mstore(k, u) a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { k := add(k, s) mstore(k, v) b := add(b, s) continue } k := add(k, s) mstore(k, u) a := add(a, s) } for {} iszero(gt(a, aEnd)) {} { k := add(k, s) mstore(k, mload(a)) a := add(a, s) } for {} iszero(gt(b, bEnd)) {} { k := add(k, s) mstore(k, mload(b)) b := add(b, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { AtlETH } from "./AtlETH.sol"; import { IExecutionEnvironment } from "../interfaces/IExecutionEnvironment.sol"; import { IAtlas } from "../interfaces/IAtlas.sol"; import { ISolverContract } from "../interfaces/ISolverContract.sol"; import { IAtlasVerification } from "../interfaces/IAtlasVerification.sol"; import { IDAppControl } from "../interfaces/IDAppControl.sol"; import { SafeCall } from "../libraries/SafeCall/SafeCall.sol"; import { EscrowBits } from "../libraries/EscrowBits.sol"; import { CallBits } from "../libraries/CallBits.sol"; import { SafetyBits } from "../libraries/SafetyBits.sol"; import { AccountingMath } from "../libraries/AccountingMath.sol"; import { DAppConfig } from "../types/ConfigTypes.sol"; import "../types/SolverOperation.sol"; import "../types/UserOperation.sol"; import "../types/EscrowTypes.sol"; import "../types/LockTypes.sol"; /// @title Escrow /// @author FastLane Labs /// @notice This Escrow component of Atlas handles execution of stages by calling corresponding functions on the /// Execution Environment contract. abstract contract Escrow is AtlETH { using EscrowBits for uint256; using CallBits for uint32; using SafetyBits for Context; using SafeCall for address; constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator ) AtlETH( escrowDuration, atlasSurchargeRate, bundlerSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator ) { if (escrowDuration == 0) revert InvalidEscrowDuration(); } /// @notice Executes the preOps logic defined in the Execution Environment. /// @param ctx Metacall context data from the Context struct. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param userOp UserOperation struct of the current metacall tx. /// @return preOpsData The data returned by the preOps call, if successful. function _executePreOpsCall( Context memory ctx, DAppConfig memory dConfig, UserOperation calldata userOp ) internal withLockPhase(ExecutionPhase.PreOps) returns (bytes memory) { (bool _success, bytes memory _data) = ctx.executionEnvironment.call( abi.encodePacked( abi.encodeCall(IExecutionEnvironment.preOpsWrapper, userOp), ctx.setAndPack(ExecutionPhase.PreOps) ) ); if (_success) { if (dConfig.callConfig.needsPreOpsReturnData()) { return abi.decode(_data, (bytes)); } else { return new bytes(0); } } if (ctx.isSimulation) revert PreOpsSimFail(); revert PreOpsFail(); } /// @notice Executes the user operation logic defined in the Execution Environment. /// @param ctx Metacall context data from the Context struct. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param userOp UserOperation struct containing the user's transaction data. /// @param returnData Data returned from previous call phases. /// @return userData Data returned from executing the UserOperation, if the call was successful. function _executeUserOperation( Context memory ctx, DAppConfig memory dConfig, UserOperation calldata userOp, bytes memory returnData ) internal withLockPhase(ExecutionPhase.UserOperation) returns (bytes memory) { bool _success; bytes memory _data; // Calculate gas limit ceiling, including gas to return gracefully even if userOp call is OOG. uint256 _gasLimit = gasleft() * 63 / 64 - _GRACEFUL_RETURN_GAS_OFFSET; // Use the smaller of userOp.gas and the gas limit ceiling _gasLimit = userOp.gas < _gasLimit ? userOp.gas : _gasLimit; if (!_borrow(userOp.value)) { revert InsufficientEscrow(); } (_success, _data) = ctx.executionEnvironment.call{ value: userOp.value, gas: _gasLimit }( abi.encodePacked( abi.encodeCall(IExecutionEnvironment.userWrapper, userOp), ctx.setAndPack(ExecutionPhase.UserOperation) ) ); if (_success) { // Handle formatting of returnData if (dConfig.callConfig.needsUserReturnData()) { return abi.decode(_data, (bytes)); } else { return returnData; } } // revert for failed if (ctx.isSimulation) revert UserOpSimFail(); revert UserOpFail(); } /// @notice Checks if the trusted operation hash matches and sets the appropriate error bit if it doesn't. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param prevalidated Boolean flag indicating whether the SolverOperation has been prevalidated to skip certain /// checks. /// @param userOp UserOperation struct containing the user's transaction data relevant to this SolverOperation. /// @param solverOp SolverOperation struct containing the solver's bid and execution data. /// @param result The current result bitmask that tracks the status of various checks and validations. /// @return The updated result bitmask with the AltOpHashMismatch bit set if the operation hash does not match. function _checkTrustedOpHash( DAppConfig memory dConfig, bool prevalidated, UserOperation calldata userOp, SolverOperation calldata solverOp, uint256 result ) internal returns (uint256) { if (dConfig.callConfig.allowsTrustedOpHash() && !prevalidated && !_handleAltOpHash(userOp, solverOp)) { result |= 1 << uint256(SolverOutcome.AltOpHashMismatch); } return result; } /// @notice Attempts to execute a SolverOperation and determine if it wins the auction. /// @param ctx Context struct containing the current state of the escrow lock. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param userOp UserOperation struct containing the user's transaction data relevant to this SolverOperation. /// @param solverOp SolverOperation struct containing the solver's bid and execution data. /// @param bidAmount The amount of bid submitted by the solver for this operation. /// @param prevalidated Boolean flag indicating whether the SolverOperation has been prevalidated to skip certain /// @param returnData Data returned from UserOp execution, used as input if necessary. /// @return bidAmount The determined bid amount for the SolverOperation if all validations pass and the operation is /// executed successfully; otherwise, returns 0. function _executeSolverOperation( Context memory ctx, DAppConfig memory dConfig, UserOperation calldata userOp, SolverOperation calldata solverOp, uint256 bidAmount, bool prevalidated, bytes memory returnData ) internal returns (uint256) { // Set the gas baseline uint256 _gasWaterMark = gasleft(); uint256 _result; if (!prevalidated) { _result = VERIFICATION.verifySolverOp( solverOp, ctx.userOpHash, userOp.maxFeePerGas, ctx.bundler, dConfig.callConfig.allowsTrustedOpHash() ); _result = _checkSolverBidToken(solverOp.bidToken, dConfig.bidToken, _result); } // Verify the transaction. if (_result.canExecute()) { uint256 _gasLimit; // Verify gasLimit again (_result, _gasLimit) = _validateSolverOpGasAndValue(dConfig, solverOp, _gasWaterMark, _result); _result |= _validateSolverOpDeadline(solverOp, dConfig); // Check for trusted operation hash _result = _checkTrustedOpHash(dConfig, prevalidated, userOp, solverOp, _result); // If there are no errors, attempt to execute if (_result.canExecute()) { SolverTracker memory _solverTracker; // Execute the solver call (_result, _solverTracker) = _solverOpWrapper(ctx, solverOp, bidAmount, _gasLimit, returnData); if (_result.executionSuccessful()) { // First successful solver call that paid what it bid emit SolverTxResult( solverOp.solver, solverOp.from, dConfig.to, solverOp.bidToken, bidAmount, true, true, _result ); ctx.solverSuccessful = true; ctx.solverOutcome = uint24(_result); return _solverTracker.bidAmount; } } } // If we reach this point, the solver call did not execute successfully. ctx.solverOutcome = uint24(_result); // Account for failed SolverOperation gas costs _handleSolverAccounting(solverOp, _gasWaterMark, _result, !prevalidated); emit SolverTxResult( solverOp.solver, solverOp.from, dConfig.to, solverOp.bidToken, bidAmount, _result.executedWithError(), false, _result ); return 0; } /// @notice Allocates the winning bid amount after a successful SolverOperation execution. /// @dev This function handles the allocation of the bid amount to the appropriate recipients as defined in the /// DApp's configuration. It calls the allocateValue function in the Execution Environment, which is responsible for /// distributing the bid amount. Note that balance discrepancies leading to payment failures are typically due to /// issues in the DAppControl contract, not the execution environment itself. /// @param ctx Context struct containing the current state of the escrow lock. /// @param dConfig Configuration data for the DApp involved, containing execution parameters and settings. /// @param bidAmount The winning solver's bid amount, to be allocated. /// @param returnData Data returned from the execution of the UserOperation, which may influence how the bid amount /// is allocated. function _allocateValue( Context memory ctx, DAppConfig memory dConfig, uint256 bidAmount, bytes memory returnData ) internal withLockPhase(ExecutionPhase.AllocateValue) { (bool _success, bytes memory _returnData) = ctx.executionEnvironment.call( abi.encodePacked( abi.encodeCall(IExecutionEnvironment.allocateValue, (dConfig.bidToken, bidAmount, returnData)), ctx.setAndPack(ExecutionPhase.AllocateValue) ) ); // If the call from Atlas to EE succeeded, decode the return data to check if the allocateValue delegatecall // from EE to DAppControl succeeded. if (_success) _success = abi.decode(_returnData, (bool)); // Revert if allocateValue failed at any point, unless the call config allows allocate value failure. if (!_success && !dConfig.callConfig.allowAllocateValueFailure()) { if (ctx.isSimulation) revert AllocateValueSimFail(); revert AllocateValueFail(); } // paymentsSuccessful is part of the data forwarded to the postOps hook, dApps can easily check the value by // calling _paymentsSuccessful() ctx.paymentsSuccessful = _success; } /// @notice Executes post-operation logic after SolverOperation, depending on the outcome of the auction. /// @dev Calls the postOpsWrapper function in the Execution Environment, which handles any necessary cleanup or /// finalization logic after the winning SolverOperation. /// @param ctx Context struct containing the current state of the escrow lock. /// @param solved Boolean indicating whether a SolverOperation was successful and won the auction. /// @param returnData Data returned from execution of the UserOp call, which may be required for the postOps logic. function _executePostOpsCall( Context memory ctx, bool solved, bytes memory returnData ) internal withLockPhase(ExecutionPhase.PostOps) { (bool _success,) = ctx.executionEnvironment.call( abi.encodePacked( abi.encodeCall(IExecutionEnvironment.postOpsWrapper, (solved, returnData)), ctx.setAndPack(ExecutionPhase.PostOps) ) ); if (!_success) { if (ctx.isSimulation) revert PostOpsSimFail(); revert PostOpsFail(); } } /// @notice Validates a SolverOperation's gas requirements against the escrow state. /// @dev Performs a series of checks to ensure that a SolverOperation can be executed within the defined parameters /// and limits. This includes verifying that the operation is within the gas limit and that the solver has /// sufficient balance in escrow to cover the gas costs. /// @param dConfig DApp configuration data, including solver gas limits and operation parameters. /// @param solverOp The SolverOperation being validated. /// @param gasWaterMark The initial gas measurement before validation begins, used to ensure enough gas remains for /// validation logic. /// @param result The current result bitmap, which will be updated with the outcome of the gas validation checks. /// @return result Updated result flags after performing the validation checks, including any new errors /// encountered. /// @return gasLimit The calculated gas limit for the SolverOperation, considering the operation's gas usage and /// the protocol's gas buffers. function _validateSolverOpGasAndValue( DAppConfig memory dConfig, SolverOperation calldata solverOp, uint256 gasWaterMark, uint256 result ) internal view returns (uint256, uint256 gasLimit) { if (gasWaterMark < _VALIDATION_GAS_LIMIT + dConfig.solverGasLimit) { // Make sure to leave enough gas for dApp validation calls result |= 1 << uint256(SolverOutcome.UserOutOfGas); return (result, gasLimit); // gasLimit = 0 } gasLimit = AccountingMath.solverGasLimitScaledDown(solverOp.gas, dConfig.solverGasLimit) + _FASTLANE_GAS_BUFFER; uint256 _gasCost = (tx.gasprice * gasLimit) + _getCalldataCost(solverOp.data.length); // Verify that we can lend the solver their tx value if (solverOp.value > address(this).balance) { result |= 1 << uint256(SolverOutcome.CallValueTooHigh); return (result, gasLimit); } // subtract out the gas buffer since the solver's metaTx won't use it gasLimit -= _FASTLANE_GAS_BUFFER; uint256 _solverBalance = S_accessData[solverOp.from].bonded; // see if solver's escrow can afford tx gascost if (_gasCost > _solverBalance) { // charge solver for calldata so that we can avoid vampire attacks from solver onto user result |= 1 << uint256(SolverOutcome.InsufficientEscrow); } return (result, gasLimit); } /// @notice Validates a SolverOperation's deadline against the current block. /// @param solverOp The SolverOperation being validated. /// @param dConfig DApp configuration data, including solver gas limits and operation parameters. /// @return result Updated result flags after performing the validation checks, including any new errors function _validateSolverOpDeadline( SolverOperation calldata solverOp, DAppConfig memory dConfig ) internal view returns (uint256 result) { if (solverOp.deadline != 0 && block.number > solverOp.deadline) { result |= ( 1 << uint256( dConfig.callConfig.allowsTrustedOpHash() ? uint256(SolverOutcome.DeadlinePassedAlt) : uint256(SolverOutcome.DeadlinePassed) ) ); return result; } uint256 lastAccessedBlock = S_accessData[solverOp.from].lastAccessedBlock; if (lastAccessedBlock >= block.number) { result |= 1 << uint256(SolverOutcome.PerBlockLimit); } } /// @notice Determines the bid amount for a SolverOperation based on verification and validation results. /// @dev This function assesses whether a SolverOperation meets the criteria for execution by verifying it against /// the Atlas protocol's rules and the current Context lock state. It checks for valid execution based on the /// SolverOperation's specifics, like gas usage and deadlines. The function aims to protect against malicious /// bundlers by ensuring solvers are not unfairly charged for on-chain bid finding gas usage. If the operation /// passes verification and validation, and if it's eligible for bid amount determination, the function /// attempts to execute and determine the bid amount. /// @param ctx The Context struct containing the current state of the escrow lock. /// @param dConfig The DApp configuration data, including parameters relevant to solver bid validation. /// @param userOp The UserOperation associated with this SolverOperation, providing context for the bid amount /// determination. /// @param solverOp The SolverOperation being assessed, containing the solver's bid amount. /// @param returnData Data returned from the execution of the UserOp call. /// @return bidAmount The determined bid amount for the SolverOperation if all validations pass and the operation is /// executed successfully; otherwise, returns 0. function _getBidAmount( Context memory ctx, DAppConfig memory dConfig, UserOperation calldata userOp, SolverOperation calldata solverOp, bytes memory returnData ) internal returns (uint256 bidAmount) { // NOTE: To prevent a malicious bundler from aggressively collecting storage refunds, // solvers should not be on the hook for any 'on chain bid finding' gas usage. uint256 _gasWaterMark = gasleft(); uint256 _gasLimit; uint256 _result = VERIFICATION.verifySolverOp( solverOp, ctx.userOpHash, userOp.maxFeePerGas, ctx.bundler, dConfig.callConfig.allowsTrustedOpHash() ); _result = _checkSolverBidToken(solverOp.bidToken, dConfig.bidToken, _result); (_result, _gasLimit) = _validateSolverOpGasAndValue(dConfig, solverOp, _gasWaterMark, _result); _result |= _validateSolverOpDeadline(solverOp, dConfig); // Verify the transaction. if (!_result.canExecute()) return 0; if (dConfig.callConfig.allowsTrustedOpHash()) { if (!_handleAltOpHash(userOp, solverOp)) { return (0); } } (bool _success, bytes memory _data) = address(this).call{ gas: _gasLimit }( abi.encodeCall(this.solverCall, (ctx, solverOp, solverOp.bidAmount, returnData)) ); // The `solverCall()` above should always revert as key.bidFind is always true when it's called in the context // of this function. Therefore `success` should always be false below, and the revert should be unreachable. if (_success) { revert Unreachable(); } if (bytes4(_data) == BidFindSuccessful.selector) { // Get the uint256 from the memory array assembly { let dataLocation := add(_data, 0x20) bidAmount := mload(add(dataLocation, sub(mload(_data), 32))) } return bidAmount; } return 0; } /// @notice Validates UserOp hashes provided by the SolverOperation, using the alternative set of hashed parameters. /// @param userOp The UserOperation struct, providing the baseline parameters for comparison. /// @param solverOp The SolverOperation struct being validated against the UserOperation. /// @return A boolean value indicating whether the SolverOperation passed the alternative hash check, with `true` /// meaning it is considered valid function _handleAltOpHash( UserOperation calldata userOp, SolverOperation calldata solverOp ) internal returns (bool) { // These failures should be attributed to bundler maliciousness if (userOp.control != solverOp.control) { return false; } if (!(userOp.deadline == 0 || solverOp.deadline == 0 || solverOp.deadline == userOp.deadline)) { return false; } bytes32 _hashId = keccak256(abi.encodePacked(solverOp.userOpHash, solverOp.from, solverOp.deadline)); if (S_solverOpHashes[_hashId]) { return false; } S_solverOpHashes[_hashId] = true; return true; } /// @notice Checks if the solver's bid token matches the dApp's bid token. /// @param solverBidToken The solver's bid token address. /// @param dConfigBidToken The dApp's bid token address. /// @param result The current result bitmap, which will be updated with the outcome of the bid token check. /// @return The updated result bitmap, with the SolverOutcome.InvalidBidToken flag set if the bid token check fails. function _checkSolverBidToken( address solverBidToken, address dConfigBidToken, uint256 result ) internal pure returns (uint256) { if (solverBidToken != dConfigBidToken) { return result | 1 << uint256(SolverOutcome.InvalidBidToken); } return result; } /// @notice Wraps the execution of a SolverOperation and handles potential errors. /// @param ctx The current lock data. /// @param solverOp The SolverOperation struct containing the operation's execution data. /// @param bidAmount The bid amount associated with the SolverOperation. /// @param gasLimit The gas limit for executing the SolverOperation, calculated based on the operation's /// requirements and protocol buffers. /// @param returnData Data returned from the execution of the associated UserOperation, which may be required /// for the SolverOperation's logic. /// @return result SolverOutcome enum value encoded as a uint256 bitmap, representing the result of the /// SolverOperation /// @return solverTracker Tracking data for the solver's bid function _solverOpWrapper( Context memory ctx, SolverOperation calldata solverOp, uint256 bidAmount, uint256 gasLimit, bytes memory returnData ) internal returns (uint256 result, SolverTracker memory solverTracker) { // Calls the solverCall function, just below this function, which will handle calling solverPreTryCatch and // solverPostTryCatch via the ExecutionEnvironment, and in between those two hooks, the actual solver call // directly from Atlas to the solver contract (not via the ExecutionEnvironment). (bool _success, bytes memory _data) = address(this).call{ gas: gasLimit }(abi.encodeCall(this.solverCall, (ctx, solverOp, bidAmount, returnData))); if (_success) { // If solverCall() was successful, intentionally leave uint256 result unset as 0 indicates success. solverTracker = abi.decode(_data, (SolverTracker)); } else { // If solverCall() failed, catch the error and encode the failure case in the result uint accordingly. bytes4 _errorSwitch = bytes4(_data); if (_errorSwitch == AlteredControl.selector) { result = 1 << uint256(SolverOutcome.AlteredControl); } else if (_errorSwitch == InsufficientEscrow.selector) { result = 1 << uint256(SolverOutcome.InsufficientEscrow); } else if (_errorSwitch == PreSolverFailed.selector) { result = 1 << uint256(SolverOutcome.PreSolverFailed); } else if (_errorSwitch == SolverOpReverted.selector) { result = 1 << uint256(SolverOutcome.SolverOpReverted); } else if (_errorSwitch == PostSolverFailed.selector) { result = 1 << uint256(SolverOutcome.PostSolverFailed); } else if (_errorSwitch == BidNotPaid.selector) { result = 1 << uint256(SolverOutcome.BidNotPaid); } else if (_errorSwitch == InvalidSolver.selector) { result = 1 << uint256(SolverOutcome.InvalidSolver); } else if (_errorSwitch == BalanceNotReconciled.selector) { result = 1 << uint256(SolverOutcome.BalanceNotReconciled); } else if (_errorSwitch == CallbackNotCalled.selector) { result = 1 << uint256(SolverOutcome.CallbackNotCalled); } else if (_errorSwitch == InvalidEntry.selector) { // DAppControl is attacking solver contract - treat as AlteredControl result = 1 << uint256(SolverOutcome.AlteredControl); } else { result = 1 << uint256(SolverOutcome.EVMError); } } } /// @notice Executes the SolverOperation logic, including preSolver and postSolver hooks via the Execution /// Environment, as well as the actual solver call directly from Atlas to the solver contract. /// @param ctx The Context struct containing lock data and the Execution Environment address. /// @param solverOp The SolverOperation to be executed. /// @param bidAmount The bid amount associated with the SolverOperation. /// @param returnData Data returned from previous call phases. /// @return solverTracker Additional data for handling the solver's bid in different scenarios. function solverCall( Context memory ctx, SolverOperation calldata solverOp, uint256 bidAmount, bytes calldata returnData ) external payable returns (SolverTracker memory solverTracker) { if (msg.sender != address(this)) revert InvalidEntry(); bytes memory _data; bool _success; // Set the solver lock and solver address at the beginning to ensure reliability t_solverLock = uint256(uint160(solverOp.from)); t_solverTo = solverOp.solver; // ------------------------------------- // // Pre-Solver Call // // ------------------------------------- // _setLockPhase(uint8(ExecutionPhase.PreSolver)); (_success, _data) = ctx.executionEnvironment.call( abi.encodePacked( abi.encodeCall(IExecutionEnvironment.solverPreTryCatch, (bidAmount, solverOp, returnData)), ctx.setAndPack(ExecutionPhase.PreSolver) ) ); // If ExecutionEnvironment.solverPreTryCatch() failed, bubble up the error if (!_success) { assembly { revert(add(_data, 32), mload(_data)) } } // Update solverTracker with returned data solverTracker = abi.decode(_data, (SolverTracker)); // ------------------------------------- // // Solver Call // // ------------------------------------- // _setLockPhase(uint8(ExecutionPhase.SolverOperation)); // Make sure there's enough value in Atlas for the Solver if (!_borrow(solverOp.value)) revert InsufficientEscrow(); // Optimism's SafeCall lib allows us to limit how much returndata gets copied to memory, to prevent OOG attacks. _success = solverOp.solver.safeCall( gasleft(), solverOp.value, abi.encodeCall( ISolverContract.atlasSolverCall, ( solverOp.from, ctx.executionEnvironment, solverOp.bidToken, bidAmount, solverOp.data, // Only pass the returnData (either from userOp or preOps) if the dApp requires it _activeCallConfig().forwardReturnData() ? returnData : new bytes(0) ) ) ); if (!_success) revert SolverOpReverted(); // ------------------------------------- // // Post-Solver Call // // ------------------------------------- // _setLockPhase(uint8(ExecutionPhase.PostSolver)); (_success, _data) = ctx.executionEnvironment.call( abi.encodePacked( abi.encodeCall(IExecutionEnvironment.solverPostTryCatch, (solverOp, returnData, solverTracker)), ctx.setAndPack(ExecutionPhase.PostSolver) ) ); // If ExecutionEnvironment.solverPostTryCatch() failed, bubble up the error if (!_success) { assembly { revert(add(_data, 32), mload(_data)) } } // Update solverTracker with returned data solverTracker = abi.decode(_data, (SolverTracker)); // ------------------------------------- // // Final Checks // // ------------------------------------- // // Verify that the solver repaid their borrowed solverOp.value by calling `reconcile()`. If `reconcile()` did // not fully repay the borrowed amount, the `postSolverCall` might have covered the outstanding debt via // `contribute()`. This final check ensures that the solver has fulfilled their repayment obligations before // proceeding. (, bool _calledback, bool _fulfilled) = _solverLockData(); if (!_calledback) revert CallbackNotCalled(); if (!_fulfilled && !_isBalanceReconciled()) revert BalanceNotReconciled(); // Check if this is an on-chain, ex post bid search by verifying the `ctx.bidFind` flag. // If the flag is set, revert with `BidFindSuccessful` and include the solver's bid amount in `solverTracker`. // This indicates that the bid search process has completed successfully. if (ctx.bidFind) revert BidFindSuccessful(solverTracker.bidAmount); } receive() external payable { } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { FactoryLib } from "./FactoryLib.sol"; import { IDAppControl } from "../interfaces/IDAppControl.sol"; import { DAppConfig } from "../types/ConfigTypes.sol"; import { UserOperation } from "../types/UserOperation.sol"; import { AtlasErrors } from "../types/AtlasErrors.sol"; abstract contract Factory { address public immutable FACTORY_LIB; bytes32 internal immutable _FACTORY_BASE_SALT; constructor(address factoryLib) { FACTORY_LIB = factoryLib; _FACTORY_BASE_SALT = keccak256(abi.encodePacked(block.chainid, address(this))); } /// @notice Creates a new Execution Environment for the caller, given a DAppControl contract address. /// @param user The address of the user for whom the execution environment is being created. /// @param control The address of the DAppControl contract for which the execution environment is being created. /// @return executionEnvironment The address of the newly created Execution Environment instance. function createExecutionEnvironment( address user, address control ) external returns (address executionEnvironment) { if (msg.sender != user && msg.sender != control) revert AtlasErrors.Unauthorized(); uint32 _callConfig = IDAppControl(control).CALL_CONFIG(); executionEnvironment = _getOrCreateExecutionEnvironment({ user: user, control: control, callConfig: _callConfig }); } /// @notice Retrieves the address and configuration of an existing execution environment for a given user and DApp /// control contract. /// @param user The address of the user for whom the execution environment is being queried. /// @param control The address of the DAppControl contract associated with the execution environment. /// @return executionEnvironment The address of the queried execution environment. /// @return callConfig The call configuration used by the execution environment, retrieved from the DAppControl /// contract. /// @return exists A boolean indicating whether the execution environment already exists (true) or not (false). function getExecutionEnvironment( address user, address control ) external returns (address executionEnvironment, uint32 callConfig, bool exists) { callConfig = IDAppControl(control).CALL_CONFIG(); executionEnvironment = _getExecutionEnvironmentCustom(user, control, callConfig); exists = executionEnvironment.code.length != 0; } /// @notice Gets an existing execution environment or creates a new one if it does not exist for the specified user /// operation. /// @param userOp The user operation containing details about the user and the DAppControl contract. /// @return executionEnvironment The address of the execution environment that was found or created. /// @return dConfig The DAppConfig for the execution environment, specifying how operations should be handled. function _getOrCreateExecutionEnvironment(UserOperation calldata userOp) internal returns (address executionEnvironment, DAppConfig memory dConfig) { dConfig = IDAppControl(userOp.control).getDAppConfig(userOp); executionEnvironment = _getOrCreateExecutionEnvironment({ user: userOp.from, control: userOp.control, callConfig: dConfig.callConfig }); } /// @notice Deploys a new execution environment or retrieves the address of an existing one based on the DApp /// control, user, and configuration. /// @dev Uses the `create2` opcode for deterministic deployment, allowing the calculation of the execution /// environment's address before deployment. The deployment uses a combination of the DAppControl address, user /// address, call configuration, and a unique salt to ensure the uniqueness and predictability of the environment's /// address. /// @param user The address of the user for whom the execution environment is being set. /// @param control The address of the DAppControl contract providing the operational context. /// @param callConfig CallConfig settings of the DAppControl contract. /// @return executionEnvironment The address of the newly created or already existing execution environment. function _getOrCreateExecutionEnvironment( address user, address control, uint32 callConfig ) internal returns (address executionEnvironment) { bytes32 _salt = _computeSalt(user, control, callConfig); bytes memory returnData = _delegatecallFactoryLib( abi.encodeCall(FactoryLib.getOrCreateExecutionEnvironment, (user, control, callConfig, _salt)) ); return abi.decode(returnData, (address)); } /// @notice Generates the address of a user's execution environment affected by deprecated callConfig changes in the /// DAppControl. /// @dev Calculates the deterministic address of the execution environment based on the user, control, /// callConfig, and controlCodeHash, ensuring consistency across changes in callConfig. /// @param user The address of the user for whom the execution environment's address is being generated. /// @param control The address of the DAppControl contract associated with the execution environment. /// @param callConfig The configuration flags defining the behavior of the execution environment. /// @return executionEnvironment The address of the user's execution environment. function _getExecutionEnvironmentCustom( address user, address control, uint32 callConfig ) internal returns (address executionEnvironment) { bytes32 _salt = _computeSalt(user, control, callConfig); bytes memory returnData = _delegatecallFactoryLib( abi.encodeCall(FactoryLib.getExecutionEnvironmentCustom, (user, control, callConfig, _salt)) ); return abi.decode(returnData, (address)); } function _computeSalt(address user, address control, uint32 callConfig) internal view returns (bytes32) { return keccak256(abi.encodePacked(_FACTORY_BASE_SALT, user, control, callConfig)); } function _delegatecallFactoryLib(bytes memory data) internal returns (bytes memory) { (bool _success, bytes memory _result) = FACTORY_LIB.delegatecall(data); if (!_success) { assembly { revert(add(_result, 32), mload(_result)) } } return _result; } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; bytes32 constant SOLVER_TYPEHASH = keccak256( "SolverOperation(address from,address to,uint256 value,uint256 gas,uint256 maxFeePerGas,uint256 deadline,address solver,address control,bytes32 userOpHash,address bidToken,uint256 bidAmount,bytes data)" ); // NOTE: The calldata length of this SolverOperation struct is 608 bytes when the `data` field is excluded. This value // is stored in the `_SOLVER_OP_BASE_CALLDATA` constant in AtlasConstants.sol and must be kept up-to-date with any // changes to this struct. struct SolverOperation { address from; // Solver address address to; // Atlas address uint256 value; // Amount of ETH required for the solver operation (used in `value` field of the solver call) uint256 gas; // Gas limit for the solver operation uint256 maxFeePerGas; // maxFeePerGas solver is willing to pay. This goes to validator, not dApp or user uint256 deadline; // block.number deadline for the solver operation address solver; // Nested "to" address (used in `to` field of the solver call) address control; // DAppControl address bytes32 userOpHash; // hash of User's Operation, for verification of user's tx (if not matched, solver wont be // charged for gas) address bidToken; // address(0) for ETH uint256 bidAmount; // Amount of bidToken that the solver bids bytes data; // Solver op calldata (used in `data` field of the solver call) bytes signature; // Solver operation signature signed by SolverOperation.from }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; // Default UserOperation typehash bytes32 constant USER_TYPEHASH_DEFAULT = keccak256( "UserOperation(address from,address to,uint256 value,uint256 gas,uint256 maxFeePerGas,uint256 nonce,uint256 deadline,address dapp,address control,uint32 callConfig,address sessionKey,bytes data)" ); // Trusted UserOperation typehash // NOTE: This is explicitly for the 'trustedOpHash' configuration option meant so that solvers can submit // SolverOperations // prior to seeing the UserOperation or its hash. In this scenario, the Solvers should trust the signer of the // UserOperation. bytes32 constant USER_TYPEHASH_TRUSTED = keccak256( "UserOperation(address from,address to,address dapp,address control,uint32 callConfig,address sessionKey)" ); struct UserOperation { address from; // User address address to; // Atlas address uint256 value; // Amount of ETH required for the user operation (used in `value` field of the user call) uint256 gas; // Gas limit for the user operation uint256 maxFeePerGas; // Max fee per gas for the user operation uint256 nonce; // Atlas nonce of the user operation available in the AtlasVerification contract uint256 deadline; // block.number deadline for the user operation address dapp; // Nested "to" for user's call (used in `to` field of the user call) address control; // Address of the DAppControl contract uint32 callConfig; // Call configuration expected by user, refer to // `src/contracts/types/ConfigTypes.sol:CallConfig` address sessionKey; // Address of the temporary session key which is used to sign the DappOperation bytes data; // User operation calldata (used in `data` field of the user call) bytes signature; // User operation signature signed by UserOperation.from }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; struct Context { bytes32 userOpHash; // not packed address executionEnvironment; // not packed uint24 solverOutcome; uint8 solverIndex; uint8 solverCount; uint8 callDepth; uint8 phase; bool solverSuccessful; bool paymentsSuccessful; bool bidFind; bool isSimulation; address bundler; } enum ExecutionPhase { Uninitialized, PreOps, UserOperation, PreSolver, SolverOperation, PostSolver, AllocateValue, PostOps, FullyLocked }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; struct DAppConfig { address to; // Address of the DAppControl contract uint32 callConfig; // Configuration address bidToken; // address(0) for ETH uint32 solverGasLimit; // Max gas limit for solverOps } struct CallConfig { // userNoncesSequential: The userOp nonce must be the next sequential nonce for that user’s address in Atlas’ // nonce system. If false, the userOp nonces are allowed to be non-sequential (unordered), as long as they are // unique. bool userNoncesSequential; // dappNoncesSequential: The dappOp nonce must be the next sequential nonce for that dApp signer’s address in // Atlas’ nonce system. If false, the dappOp nonce is not checked, as the dAppOp is tied to its userOp's nonce via // the callChainHash. bool dappNoncesSequential; // requirePreOps: The preOps hook is executed before the userOp is executed. If false, the preOps hook is skipped. // the dapp control should check the validity of the user operation (whether its dapps can support userOp.dapp and // userOp.data) in the preOps hook. bool requirePreOps; // trackPreOpsReturnData: The return data from the preOps hook is passed to the next call phase. If false preOps // return data is discarded. If both trackPreOpsReturnData and trackUserReturnData are true, they are concatenated. bool trackPreOpsReturnData; // trackUserReturnData: The return data from the userOp call is passed to the next call phase. If false userOp // return data is discarded. If both trackPreOpsReturnData and trackUserReturnData are true, they are concatenated. bool trackUserReturnData; // delegateUser: The userOp call is made using delegatecall from the Execution Environment. If false, userOp is // called using call. bool delegateUser; // requirePreSolver: The preSolver hook is executed before the solverOp is executed. If false, the preSolver hook is // skipped. bool requirePreSolver; // requirePostSolver: The postSolver hook is executed after the solverOp is executed. If false, the postSolver hook // is skipped. bool requirePostSolver; // requirePostOps: The postOps hook is executed as the last step of the metacall. If false, the postOps hook is // skipped. bool requirePostOps; // zeroSolvers: Allow the metacall to proceed even if there are no solverOps. The solverOps do not necessarily need // to be successful, but at least 1 must exist. bool zeroSolvers; // reuseUserOp: If true, the metacall will revert if unsuccessful so as not to store nonce data, so the userOp can // be reused. bool reuseUserOp; // userAuctioneer: The user is allowed to be the auctioneer (the signer of the dAppOp). More than one auctioneer // option can be set to true for the same DAppControl. bool userAuctioneer; // solverAuctioneer: The solver is allowed to be the auctioneer (the signer of the dAppOp). If the solver is the // auctioneer then their solverOp must be the only one. More than one auctioneer option can be set to true for the // same DAppControl. bool solverAuctioneer; // unknownAuctioneer: Anyone is allowed to be the auctioneer - dAppOp.from must be the signer of the dAppOp, but the // usual signatory[] checks are skipped. More than one auctioneer option can be set to true for the same // DAppControl. bool unknownAuctioneer; // verifyCallChainHash: Check that the dAppOp callChainHash matches the actual callChainHash as calculated in // AtlasVerification. bool verifyCallChainHash; // forwardReturnData: The return data from previous steps is included as calldata in the call from the Execution // Environment to the solver contract. If false, return data is not passed to the solver contract. bool forwardReturnData; // requireFulfillment: If true, a winning solver must be found, otherwise the metacall will fail. bool requireFulfillment; // trustedOpHash: If true, the userOpHash excludes some userOp inputs such as `value`, `gas`, `maxFeePerGas`, // `nonce`, `deadline`, and `data`, implying solvers trust changes made to these parts of the userOp after signing // their associated solverOps. bool trustedOpHash; // invertBidValue: If true, the solver with the lowest successful bid wins. bool invertBidValue; // exPostBids: Bids are found on-chain using `_getBidAmount` in Atlas, and solverOp.bidAmount is used as the max // bid. If solverOp.bidAmount is 0, then there is no max bid limit for that solver. bool exPostBids; // allowAllocateValueFailure: If true, the metacall will proceed even if the value allocation fails. If false, the // metacall will revert if the value allocation fails. bool allowAllocateValueFailure; } enum CallConfigIndex { UserNoncesSequential, DAppNoncesSequential, RequirePreOps, TrackPreOpsReturnData, TrackUserReturnData, DelegateUser, RequirePreSolver, RequirePostSolver, RequirePostOpsCall, ZeroSolvers, ReuseUserOp, UserAuctioneer, SolverAuctioneer, UnknownAuctioneer, // Default = DAppAuctioneer VerifyCallChainHash, ForwardReturnData, RequireFulfillment, TrustedOpHash, InvertBidValue, ExPostBids, AllowAllocateValueFailure }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; bytes32 constant DAPP_TYPEHASH = keccak256( "DAppOperation(address from,address to,uint256 nonce,uint256 deadline,address control,address bundler,bytes32 userOpHash,bytes32 callChainHash)" ); struct DAppOperation { address from; // signer of the DAppOperation address to; // Atlas address uint256 nonce; // Atlas nonce of the DAppOperation available in the AtlasVerification contract uint256 deadline; // block.number deadline for the DAppOperation address control; // DAppControl address address bundler; // Signer of the atlas tx (msg.sender) bytes32 userOpHash; // keccak256 of userOp.to, userOp.data bytes32 callChainHash; // keccak256 of the solvers' txs bytes signature; // DAppOperation signed by DAppOperation.from }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /// @title ValidCallsResult /// @notice Enum for ValidCallsResult /// @dev A single ValidCallsResult is returned by `validateCalls` in AtlasVerification enum ValidCallsResult { Valid, // Results below this line will cause metacall to revert UserFromInvalid, UserSignatureInvalid, DAppSignatureInvalid, UserNonceInvalid, InvalidDAppNonce, UnknownAuctioneerNotAllowed, InvalidAuctioneer, InvalidBundler, // Results above this line will cause metacall to revert InvertBidValueCannotBeExPostBids, // Threshold value (included in the revert range), any new reverting values should // be included above this line // Results below this line will cause metacall to gracefully return GasPriceHigherThanMax, TxValueLowerThanCallValue, TooManySolverOps, UserDeadlineReached, DAppDeadlineReached, ExecutionEnvEmpty, NoSolverOp, InvalidSequence, OpHashMismatch, DeadlineMismatch, InvalidControl, InvalidSolverGasLimit, InvalidCallConfig, CallConfigMismatch, DAppToInvalid, UserToInvalid, ControlMismatch, InvalidCallChainHash, DAppNotEnabled, BothUserAndDAppNoncesCannotBeSequential }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { IDAppControl } from "../interfaces/IDAppControl.sol"; import "../types/ConfigTypes.sol"; library CallBits { uint32 internal constant _ONE = uint32(1); function buildCallConfig(address control) internal view returns (uint32 callConfig) { callConfig = IDAppControl(control).CALL_CONFIG(); } function encodeCallConfig(CallConfig memory callConfig) internal pure returns (uint32 encodedCallConfig) { if (callConfig.userNoncesSequential) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.UserNoncesSequential); } if (callConfig.dappNoncesSequential) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.DAppNoncesSequential); } if (callConfig.requirePreOps) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePreOps); } if (callConfig.trackPreOpsReturnData) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.TrackPreOpsReturnData); } if (callConfig.trackUserReturnData) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.TrackUserReturnData); } if (callConfig.delegateUser) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.DelegateUser); } if (callConfig.requirePreSolver) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePreSolver); } if (callConfig.requirePostSolver) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePostSolver); } if (callConfig.requirePostOps) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequirePostOpsCall); } if (callConfig.zeroSolvers) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ZeroSolvers); } if (callConfig.reuseUserOp) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ReuseUserOp); } if (callConfig.userAuctioneer) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.UserAuctioneer); } if (callConfig.solverAuctioneer) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.SolverAuctioneer); } if (callConfig.unknownAuctioneer) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.UnknownAuctioneer); } if (callConfig.verifyCallChainHash) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.VerifyCallChainHash); } if (callConfig.forwardReturnData) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ForwardReturnData); } if (callConfig.requireFulfillment) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.RequireFulfillment); } if (callConfig.trustedOpHash) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.TrustedOpHash); } if (callConfig.invertBidValue) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.InvertBidValue); } if (callConfig.exPostBids) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.ExPostBids); } if (callConfig.allowAllocateValueFailure) { encodedCallConfig ^= _ONE << uint32(CallConfigIndex.AllowAllocateValueFailure); } } function decodeCallConfig(uint32 encodedCallConfig) internal pure returns (CallConfig memory callConfig) { callConfig = CallConfig({ userNoncesSequential: needsSequentialUserNonces(encodedCallConfig), dappNoncesSequential: needsSequentialDAppNonces(encodedCallConfig), requirePreOps: needsPreOpsCall(encodedCallConfig), trackPreOpsReturnData: needsPreOpsReturnData(encodedCallConfig), trackUserReturnData: needsUserReturnData(encodedCallConfig), delegateUser: needsDelegateUser(encodedCallConfig), requirePreSolver: needsPreSolverCall(encodedCallConfig), requirePostSolver: needsPostSolverCall(encodedCallConfig), requirePostOps: needsPostOpsCall(encodedCallConfig), zeroSolvers: allowsZeroSolvers(encodedCallConfig), reuseUserOp: allowsReuseUserOps(encodedCallConfig), userAuctioneer: allowsUserAuctioneer(encodedCallConfig), solverAuctioneer: allowsSolverAuctioneer(encodedCallConfig), unknownAuctioneer: allowsUnknownAuctioneer(encodedCallConfig), verifyCallChainHash: verifyCallChainHash(encodedCallConfig), forwardReturnData: forwardReturnData(encodedCallConfig), requireFulfillment: needsFulfillment(encodedCallConfig), trustedOpHash: allowsTrustedOpHash(encodedCallConfig), invertBidValue: invertsBidValue(encodedCallConfig), exPostBids: exPostBids(encodedCallConfig), allowAllocateValueFailure: allowAllocateValueFailure(encodedCallConfig) }); } function needsSequentialUserNonces(uint32 callConfig) internal pure returns (bool sequential) { sequential = callConfig & (1 << uint32(CallConfigIndex.UserNoncesSequential)) != 0; } function needsSequentialDAppNonces(uint32 callConfig) internal pure returns (bool sequential) { sequential = callConfig & (1 << uint32(CallConfigIndex.DAppNoncesSequential)) != 0; } function needsPreOpsCall(uint32 callConfig) internal pure returns (bool needsPreOps) { needsPreOps = callConfig & (1 << uint32(CallConfigIndex.RequirePreOps)) != 0; } function needsPreOpsReturnData(uint32 callConfig) internal pure returns (bool needsReturnData) { needsReturnData = callConfig & (1 << uint32(CallConfigIndex.TrackPreOpsReturnData)) != 0; } function needsUserReturnData(uint32 callConfig) internal pure returns (bool needsReturnData) { needsReturnData = callConfig & (1 << uint32(CallConfigIndex.TrackUserReturnData)) != 0; } function needsDelegateUser(uint32 callConfig) internal pure returns (bool delegateUser) { delegateUser = callConfig & (1 << uint32(CallConfigIndex.DelegateUser)) != 0; } function needsPreSolverCall(uint32 callConfig) internal pure returns (bool needsPreSolver) { needsPreSolver = callConfig & (1 << uint32(CallConfigIndex.RequirePreSolver)) != 0; } function needsPostSolverCall(uint32 callConfig) internal pure returns (bool needsPostSolver) { needsPostSolver = callConfig & (1 << uint32(CallConfigIndex.RequirePostSolver)) != 0; } function needsPostOpsCall(uint32 callConfig) internal pure returns (bool needsPostOps) { needsPostOps = callConfig & (1 << uint32(CallConfigIndex.RequirePostOpsCall)) != 0; } function allowsZeroSolvers(uint32 callConfig) internal pure returns (bool zeroSolvers) { zeroSolvers = callConfig & (1 << uint32(CallConfigIndex.ZeroSolvers)) != 0; } function allowsReuseUserOps(uint32 callConfig) internal pure returns (bool reuseUserOp) { reuseUserOp = callConfig & (1 << uint32(CallConfigIndex.ReuseUserOp)) != 0; } function allowsUserAuctioneer(uint32 callConfig) internal pure returns (bool userAuctioneer) { userAuctioneer = callConfig & (1 << uint32(CallConfigIndex.UserAuctioneer)) != 0; } function allowsSolverAuctioneer(uint32 callConfig) internal pure returns (bool userAuctioneer) { userAuctioneer = callConfig & (1 << uint32(CallConfigIndex.SolverAuctioneer)) != 0; } function allowsUnknownAuctioneer(uint32 callConfig) internal pure returns (bool unknownAuctioneer) { unknownAuctioneer = callConfig & (1 << uint32(CallConfigIndex.UnknownAuctioneer)) != 0; } function verifyCallChainHash(uint32 callConfig) internal pure returns (bool verify) { verify = callConfig & (1 << uint32(CallConfigIndex.VerifyCallChainHash)) != 0; } function forwardReturnData(uint32 callConfig) internal pure returns (bool) { return callConfig & (1 << uint32(CallConfigIndex.ForwardReturnData)) != 0; } function needsFulfillment(uint32 callConfig) internal pure returns (bool) { return callConfig & (1 << uint32(CallConfigIndex.RequireFulfillment)) != 0; } function allowsTrustedOpHash(uint32 callConfig) internal pure returns (bool) { return callConfig & (1 << uint32(CallConfigIndex.TrustedOpHash)) != 0; } function invertsBidValue(uint32 callConfig) internal pure returns (bool) { return callConfig & (1 << uint32(CallConfigIndex.InvertBidValue)) != 0; } function exPostBids(uint32 callConfig) internal pure returns (bool) { return callConfig & (1 << uint32(CallConfigIndex.ExPostBids)) != 0; } function allowAllocateValueFailure(uint32 callConfig) internal pure returns (bool) { return callConfig & (1 << uint32(CallConfigIndex.AllowAllocateValueFailure)) != 0; } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/LockTypes.sol"; // NOTE: No user transfers allowed during AllocateValue uint8 constant SAFE_USER_TRANSFER = uint8( 1 << (uint8(ExecutionPhase.PreOps)) | 1 << (uint8(ExecutionPhase.UserOperation)) | 1 << (uint8(ExecutionPhase.PreSolver)) | 1 << (uint8(ExecutionPhase.PostSolver)) | 1 << (uint8(ExecutionPhase.PostOps)) ); // NOTE: No Dapp transfers allowed during UserOperation uint8 constant SAFE_DAPP_TRANSFER = uint8( 1 << (uint8(ExecutionPhase.PreOps)) | 1 << (uint8(ExecutionPhase.PreSolver)) | 1 << (uint8(ExecutionPhase.PostSolver)) | 1 << (uint8(ExecutionPhase.AllocateValue)) | 1 << (uint8(ExecutionPhase.PostOps)) ); library SafetyBits { function setAndPack(Context memory self, ExecutionPhase phase) internal pure returns (bytes memory packedCtx) { self.phase = uint8(phase); packedCtx = abi.encodePacked( self.bundler, self.solverSuccessful, self.paymentsSuccessful, self.solverIndex, self.solverCount, uint8(phase), self.solverOutcome, self.bidFind, self.isSimulation, uint8(1) // callDepth ); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; interface IL2GasCalculator { /// @notice Calculate the cost of calldata in ETH on a L2 with a different fee structure than mainnet function getCalldataCost(uint256 calldataLength) external view returns (uint256 calldataCost); /// @notice Gets the cost of initial gas used for a transaction with a different calldata fee than mainnet function initialGasUsed(uint256 calldataLength) external view returns (uint256 gasUsed); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/UserOperation.sol"; import "../types/SolverOperation.sol"; import "../types/ConfigTypes.sol"; interface IDAppControl { function preOpsCall(UserOperation calldata userOp) external payable returns (bytes memory); function preSolverCall(SolverOperation calldata solverOp, bytes calldata returnData) external payable; function postSolverCall(SolverOperation calldata solverOp, bytes calldata returnData) external payable; function postOpsCall(bool solved, bytes calldata data) external payable; function allocateValueCall(address bidToken, uint256 bidAmount, bytes calldata data) external; function getDAppConfig(UserOperation calldata userOp) external view returns (DAppConfig memory dConfig); function getCallConfig() external view returns (CallConfig memory callConfig); function getBidFormat(UserOperation calldata userOp) external view returns (address bidToken); function getBidValue(SolverOperation calldata solverOp) external view returns (uint256); function getDAppSignatory() external view returns (address governanceAddress); function requireSequentialUserNonces() external view returns (bool isSequential); function requireSequentialDAppNonces() external view returns (bool isSequential); function preOpsDelegated() external view returns (bool delegated); function userDelegated() external view returns (bool delegated); function allocatingDelegated() external view returns (bool delegated); function verificationDelegated() external view returns (bool delegated); function CALL_CONFIG() external view returns (uint32); function transferGovernance(address newGovernance) external; function acceptGovernance() external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; import { Permit69 } from "./Permit69.sol"; import "../types/EscrowTypes.sol"; /// @author FastLane Labs /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract AtlETH is Permit69 { constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator ) Permit69( escrowDuration, atlasSurchargeRate, bundlerSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator ) { } /*////////////////////////////////////////////////////////////// ATLETH //////////////////////////////////////////////////////////////*/ /// @notice Returns the unbonded AtlETH balance of the specified account. /// @param account The address for which to query the unbonded AtlETH balance. /// @return The unbonded AtlETH balance of the specified account. function balanceOf(address account) external view returns (uint256) { return uint256(s_balanceOf[account].balance); } /// @notice Returns the bonded AtlETH balance of the specified account. /// @param account The address for which to query the bonded AtlETH balance. /// @return The bonded AtlETH balance of the specified account. function balanceOfBonded(address account) external view returns (uint256) { return uint256(S_accessData[account].bonded); } /// @notice Returns the unbonding AtlETH balance of the specified account. /// @param account The address for which to query the unbonding AtlETH balance. /// @return The unbonding AtlETH balance of the specified account. function balanceOfUnbonding(address account) external view returns (uint256) { return uint256(s_balanceOf[account].unbonding); } /// @notice Returns the last active block of the specified account in the escrow contract. /// @param account The address for which to query the last active block. /// @return The last active block of the specified account in the escrow contract. function accountLastActiveBlock(address account) external view returns (uint256) { return uint256(S_accessData[account].lastAccessedBlock); } /// @notice Returns the block number at which the unbonding process of the specified account will be completed. /// @param account The address for which to query the completion block of unbonding. /// @return The block number at which the unbonding process of the specified account will be completed. function unbondingCompleteBlock(address account) external view returns (uint256) { uint256 _lastAccessedBlock = uint256(S_accessData[account].lastAccessedBlock); if (_lastAccessedBlock == 0) return 0; return _lastAccessedBlock + ESCROW_DURATION; } /// @notice Deposits ETH to receive atlETH tokens in return. /// @dev Mints atlETH tokens to the caller in exchange for the deposited ETH. function deposit() external payable { _mint(msg.sender, msg.value); } /// @notice Redeems atlETH tokens for ETH. /// @dev Burns the specified amount of atlETH tokens from the caller's balance and transfers the equivalent amount /// of ETH to the caller. /// @param amount The amount of atlETH tokens to redeem for ETH. function withdraw(uint256 amount) external { _checkIfUnlocked(); _burn(msg.sender, amount); SafeTransferLib.safeTransferETH(msg.sender, amount); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Mints new atlETH tokens and assigns them to the specified account. /// @param to The address to which the newly minted atlETH tokens will be assigned. /// @param amount The amount of atlETH tokens to mint and assign to the specified account. function _mint(address to, uint256 amount) internal { S_totalSupply += amount; s_balanceOf[to].balance += SafeCast.toUint112(amount); emit Mint(to, amount); } /// @notice Burns atlETH tokens from the specified account. /// @param from The address from which the atlETH tokens will be burned. /// @param amount The amount of atlETH tokens to burn from the specified account. function _burn(address from, uint256 amount) internal { _deduct(from, amount); S_totalSupply -= amount; emit Burn(from, amount); } /// @notice Deducts atlETH tokens from the specified account. /// @dev This function deducts the specified amount of atlETH tokens from the balance of the specified account. /// If the deduction results in a negative balance, it handles the shortfall differently depending on whether the /// account has passed the unbonding lock period. If the account has passed the lock period, the shortfall is /// considered as unbonding, and the total supply is adjusted accordingly. Otherwise, if the account is still within /// the lock period, the function reverts due to insufficient balance for deduction. /// @param account The address from which to deduct atlETH tokens. /// @param amount The amount of atlETH tokens to deduct from the specified account. function _deduct(address account, uint256 amount) internal { uint112 _amt = SafeCast.toUint112(amount); EscrowAccountBalance storage s_aData = s_balanceOf[account]; uint112 _balance = s_aData.balance; if (_amt <= _balance) { s_aData.balance = _balance - _amt; } else if (block.number > S_accessData[account].lastAccessedBlock + ESCROW_DURATION) { uint112 _shortfall = _amt - _balance; s_aData.balance = 0; s_aData.unbonding -= _shortfall; // underflow here to revert if insufficient balance uint256 _shortfall256 = uint256(_shortfall); S_totalSupply += _shortfall256; // add the released supply back to atleth. S_bondedTotalSupply -= _shortfall256; // subtract the unbonded, freed amount } else { // Reverts because amount > account's balance revert InsufficientBalanceForDeduction(uint256(_balance), amount); } } /*////////////////////////////////////////////////////////////// EXTERNAL BOND/UNBOND LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Puts a "hold" on a solver's AtlETH, enabling it to be used in Atlas transactions. /// @dev This function locks the specified amount of AtlETH tokens for the sender, making them bonded. /// Bonded AtlETH tokens must first be unbonded before they can be transferred or withdrawn. /// @param amount The amount of AtlETH tokens to bond. function bond(uint256 amount) external { _bond(msg.sender, amount); } /// @notice Deposits the caller's ETH and mints AtlETH, then bonds a specified amount of that AtlETH. /// @param amountToBond The amount of AtlETH tokens to bond after the deposit. function depositAndBond(uint256 amountToBond) external payable { _mint(msg.sender, msg.value); _bond(msg.sender, amountToBond); } /// @notice Starts the unbonding wait time for the specified amount of AtlETH tokens. /// @dev This function initiates the unbonding process for the specified amount of AtlETH tokens /// held by the sender. Unbonding AtlETH tokens can still be used by solvers while the unbonding /// process is ongoing, but adjustments may be made at withdrawal to ensure solvency. /// @param amount The amount of AtlETH tokens to unbond. function unbond(uint256 amount) external { _checkIfUnlocked(); _unbond(msg.sender, amount); } /// @notice Redeems the specified amount of AtlETH tokens for withdrawal. /// @param amount The amount of AtlETH tokens to redeem for withdrawal. function redeem(uint256 amount) external { _checkIfUnlocked(); _redeem(msg.sender, amount); } /*////////////////////////////////////////////////////////////// INTERNAL BOND/UNBOND LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Puts a hold on a solver's AtlETH tokens, enabling them to be used in Atlas transactions. /// @dev This internal function puts a hold on a solver's AtlETH tokens, enabling them to be used /// in Atlas transactions. The specified amount of AtlETH tokens is deducted from the owner's balance /// and added to the bonded balance. The total supply and bonded total supply are updated accordingly. /// @param owner The address of the account to put a hold on AtlETH tokens for. /// @param amount The amount of AtlETH tokens to put a hold on. function _bond(address owner, uint256 amount) internal { uint112 _amt = SafeCast.toUint112(amount); s_balanceOf[owner].balance -= _amt; S_totalSupply -= amount; S_accessData[owner].bonded += _amt; S_bondedTotalSupply += amount; emit Bond(owner, amount); } /// @notice Starts the unbonding wait time for a specified amount of AtlETH tokens. /// @dev This internal function starts the unbonding wait time for a specified amount of AtlETH tokens. /// The specified amount of AtlETH tokens is deducted from the owner's bonded balance and added to the /// unbonding balance. The last accessed block for the owner is updated to the current block number. /// @param owner The address of the account to start the unbonding wait time for. /// @param amount The amount of AtlETH tokens to start the unbonding wait time for. function _unbond(address owner, uint256 amount) internal { uint112 _amt = SafeCast.toUint112(amount); // totalSupply and totalBondedSupply are unaffected; continue to count the // unbonding amount as bonded total supply since it is still inaccessible // for atomic xfer. EscrowAccountAccessData storage s_aData = S_accessData[owner]; s_aData.bonded -= _amt; s_aData.lastAccessedBlock = uint32(block.number); s_balanceOf[owner].unbonding += _amt; emit Unbond(owner, amount, block.number + ESCROW_DURATION + 1); } /// @notice Redeems the specified amount of AtlETH tokens for withdrawal. /// @dev This function allows the owner to redeem a specified amount of AtlETH tokens /// for withdrawal. If the unbonding process is active for the specified account, the /// function will revert. Otherwise, the specified amount of AtlETH tokens will be added /// back to the account's balance, and the total supply will be updated accordingly. /// @param owner The address of the account redeeming AtlETH tokens for withdrawal. /// @param amount The amount of AtlETH tokens to redeem for withdrawal. function _redeem(address owner, uint256 amount) internal { if (block.number <= uint256(S_accessData[owner].lastAccessedBlock) + ESCROW_DURATION) { revert EscrowLockActive(); } uint112 _amt = SafeCast.toUint112(amount); EscrowAccountBalance storage s_bData = s_balanceOf[owner]; s_bData.unbonding -= _amt; S_bondedTotalSupply -= amount; s_bData.balance += _amt; S_totalSupply += amount; emit Redeem(owner, amount); } /// @notice Allows the current surcharge recipient to withdraw the accumulated surcharge. NOTE: If the only ETH in /// Atlas is the surcharge, be mindful that withdrawing this ETH may limit solvers' liquidity to flashloan ETH from /// Atlas in their solverOps. /// @dev This function can only be called by the current surcharge recipient. /// It transfers the accumulated surcharge amount to the surcharge recipient's address. function withdrawSurcharge() external { _onlySurchargeRecipient(); uint256 _paymentAmount = S_cumulativeSurcharge; S_cumulativeSurcharge = 0; // Clear before transfer to prevent reentrancy SafeTransferLib.safeTransferETH(msg.sender, _paymentAmount); emit SurchargeWithdrawn(msg.sender, _paymentAmount); } /// @notice Starts the transfer of the surcharge recipient designation to a new address. /// @dev This function can only be called by the current surcharge recipient. /// It sets the `pendingSurchargeRecipient` to the specified `newRecipient` address, /// allowing the new recipient to claim the surcharge recipient designation by calling `becomeSurchargeRecipient`. /// If the caller is not the current surcharge recipient, it reverts with an `InvalidAccess` error. /// @param newRecipient The address of the new surcharge recipient. function transferSurchargeRecipient(address newRecipient) external { _onlySurchargeRecipient(); address _surchargeRecipient = S_surchargeRecipient; S_pendingSurchargeRecipient = newRecipient; emit SurchargeRecipientTransferStarted(_surchargeRecipient, newRecipient); } /// @notice Finalizes the transfer of the surcharge recipient designation to a new address. /// @dev This function can only be called by the pending surcharge recipient, /// and it completes the transfer of the surcharge recipient designation to the address /// stored in `pendingSurchargeRecipient`. /// If the caller is not the pending surcharge recipient, it reverts with an `InvalidAccess` error. function becomeSurchargeRecipient() external { if (msg.sender != S_pendingSurchargeRecipient) { revert InvalidAccess(); } S_surchargeRecipient = msg.sender; S_pendingSurchargeRecipient = address(0); emit SurchargeRecipientTransferred(msg.sender); } function _checkIfUnlocked() internal view { if (!_isUnlocked()) revert InvalidLockState(); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/SolverOperation.sol"; import "../types/UserOperation.sol"; import "../types/ConfigTypes.sol"; import "../types/EscrowTypes.sol"; interface IExecutionEnvironment { function preOpsWrapper(UserOperation calldata userOp) external returns (bytes memory preOpsData); function userWrapper(UserOperation calldata userOp) external payable returns (bytes memory userReturnData); function postOpsWrapper(bool solved, bytes calldata returnData) external; function solverPreTryCatch( uint256 bidAmount, SolverOperation calldata solverOp, bytes calldata returnData ) external returns (SolverTracker memory solverTracker); function solverPostTryCatch( SolverOperation calldata solverOp, bytes calldata returnData, SolverTracker memory solverTracker ) external returns (SolverTracker memory); function allocateValue( address bidToken, uint256 bidAmount, bytes memory returnData ) external returns (bool allocateValueSucceeded); function getUser() external pure returns (address user); function getControl() external pure returns (address control); function getConfig() external pure returns (uint32 config); function getEscrow() external view returns (address escrow); function withdrawERC20(address token, uint256 amount) external; function withdrawEther(uint256 amount) external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/SolverOperation.sol"; import "../types/UserOperation.sol"; import "../types/DAppOperation.sol"; import "../types/LockTypes.sol"; interface IAtlas { // Atlas.sol function metacall( UserOperation calldata userOp, SolverOperation[] calldata solverOps, DAppOperation calldata dAppOp, address gasRefundBeneficiary ) external payable returns (bool auctionWon); // Factory.sol function createExecutionEnvironment( address user, address control ) external returns (address executionEnvironment); function getExecutionEnvironment( address user, address control ) external view returns (address executionEnvironment, uint32 callConfig, bool exists); // AtlETH.sol function balanceOf(address account) external view returns (uint256); function balanceOfBonded(address account) external view returns (uint256); function balanceOfUnbonding(address account) external view returns (uint256); function accountLastActiveBlock(address account) external view returns (uint256); function unbondingCompleteBlock(address account) external view returns (uint256); function deposit() external payable; function withdraw(uint256 amount) external; function bond(uint256 amount) external; function depositAndBond(uint256 amountToBond) external payable; function unbond(uint256 amount) external; function redeem(uint256 amount) external; function withdrawSurcharge() external; function transferSurchargeRecipient(address newRecipient) external; function becomeSurchargeRecipient() external; function setSurchargeRates(uint128 newAtlasRate, uint128 newBundlerRate) external; // Permit69.sol function transferUserERC20( address token, address destination, uint256 amount, address user, address control ) external; function transferDAppERC20( address token, address destination, uint256 amount, address user, address control ) external; // GasAccounting.sol function contribute() external payable; function borrow(uint256 amount) external payable; function shortfall() external view returns (uint256); function reconcile(uint256 maxApprovedGasSpend) external payable returns (uint256 owed); // SafetyLocks.sol function isUnlocked() external view returns (bool); // Storage.sol function VERIFICATION() external view returns (address); function SIMULATOR() external view returns (address); function L2_GAS_CALCULATOR() external view returns (address); function ESCROW_DURATION() external view returns (uint256); function solverLockData() external view returns (address currentSolver, bool calledBack, bool fulfilled); function totalSupply() external view returns (uint256); function bondedTotalSupply() external view returns (uint256); function accessData(address account) external view returns ( uint112 bonded, uint32 lastAccessedBlock, uint24 auctionWins, uint24 auctionFails, uint64 totalGasValueUsed ); function solverOpHashes(bytes32 opHash) external view returns (bool); function lock() external view returns (address activeEnvironment, uint32 callConfig, uint8 phase); function solverLock() external view returns (uint256); function cumulativeSurcharge() external view returns (uint256); function surchargeRecipient() external view returns (address); function pendingSurchargeRecipient() external view returns (address); function atlasSurchargeRate() external view returns (uint256); function bundlerSurchargeRate() external view returns (uint256); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/SolverOperation.sol"; interface ISolverContract { function atlasSolverCall( address solverOpFrom, address executionEnvironment, address bidToken, uint256 bidAmount, bytes calldata solverOpData, bytes calldata extraReturnData ) external payable; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/UserOperation.sol"; import "../types/ConfigTypes.sol"; import "../types/DAppOperation.sol"; import "../types/SolverOperation.sol"; import "../types/EscrowTypes.sol"; import "../types/ValidCalls.sol"; interface IAtlasVerification { // AtlasVerification.sol function validateCalls( DAppConfig calldata dConfig, UserOperation calldata userOp, SolverOperation[] calldata solverOps, DAppOperation calldata dAppOp, uint256 msgValue, address msgSender, bool isSimulation ) external returns (ValidCallsResult); function verifySolverOp( SolverOperation calldata solverOp, bytes32 userOpHash, uint256 userMaxFeePerGas, address bundler, bool allowsTrustedOpHash ) external view returns (uint256 result); function verifyCallConfig(uint32 callConfig) external view returns (ValidCallsResult); function getUserOperationHash(UserOperation calldata userOp) external view returns (bytes32 hash); function getUserOperationPayload(UserOperation calldata userOp) external view returns (bytes32 payload); function getSolverPayload(SolverOperation calldata solverOp) external view returns (bytes32 payload); function getDAppOperationPayload(DAppOperation calldata dAppOp) external view returns (bytes32 payload); function getDomainSeparator() external view returns (bytes32 domainSeparator); // NonceManager.sol function getUserNextNonce(address user, bool sequential) external view returns (uint256 nextNonce); function getUserNextNonSeqNonceAfter(address user, uint256 refNonce) external view returns (uint256); function getDAppNextNonce(address dApp) external view returns (uint256 nextNonce); function userSequentialNonceTrackers(address account) external view returns (uint256 lastUsedSeqNonce); function dAppSequentialNonceTrackers(address account) external view returns (uint256 lastUsedSeqNonce); function userNonSequentialNonceTrackers( address account, uint248 wordIndex ) external view returns (uint256 bitmap); // DAppIntegration.sol function initializeGovernance(address control) external; function addSignatory(address control, address signatory) external; function removeSignatory(address control, address signatory) external; function changeDAppGovernance(address oldGovernance, address newGovernance) external; function disableDApp(address control) external; function getGovFromControl(address control) external view returns (address); function isDAppSignatory(address control, address signatory) external view returns (bool); function signatories(bytes32 key) external view returns (bool); function dAppSignatories(address control) external view returns (address[] memory); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @title SafeCall /// @author FastLane Labs /// @author Modified from Optimism's SafeCall lib /// (https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/libraries/SafeCall.sol) /// @notice Perform low level safe calls library SafeCall { /// @notice Perform a low level call without copying any returndata /// @param _target Address to call /// @param _gas Amount of gas to pass to the call /// @param _value Amount of value to pass to the call /// @param _calldata Calldata to pass to the call function safeCall(address _target, uint256 _gas, uint256 _value, bytes memory _calldata) internal returns (bool) { bool _success; assembly { _success := call( _gas, // gas _target, // recipient _value, // ether value add(_calldata, 32), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) } return _success; } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/EscrowTypes.sol"; library EscrowBits { // Bundler's Fault - solver doesn't owe any gas refund. SolverOp isn't executed uint256 internal constant _NO_REFUND = ( 1 << uint256(SolverOutcome.InvalidSignature) // <- detected by verification | 1 << uint256(SolverOutcome.InvalidUserHash) // <- detected by verification | 1 << uint256(SolverOutcome.DeadlinePassedAlt) // <- detected by escrow | 1 << uint256(SolverOutcome.GasPriceBelowUsersAlt) // <- detected by verification | 1 << uint256(SolverOutcome.InvalidTo) // <- detected by verification | 1 << uint256(SolverOutcome.UserOutOfGas) // <- detected by escrow | 1 << uint256(SolverOutcome.AlteredControl) // <- detected by EE | 1 << uint256(SolverOutcome.AltOpHashMismatch) ); // <- detected by escrow // Solver's Fault - solver *does* owe gas refund, SolverOp isn't executed uint256 internal constant _PARTIAL_REFUND = ( 1 << uint256(SolverOutcome.DeadlinePassed) // <- detected by escrow | 1 << uint256(SolverOutcome.GasPriceOverCap) // <- detected by verification | 1 << uint256(SolverOutcome.InvalidSolver) // <- detected by verification | 1 << uint256(SolverOutcome.InvalidBidToken) // <- detected by escrow | 1 << uint256(SolverOutcome.PerBlockLimit) // <- detected by escrow | 1 << uint256(SolverOutcome.InsufficientEscrow) // <- detected by escrow | 1 << uint256(SolverOutcome.GasPriceBelowUsers) // <- detected by verification | 1 << uint256(SolverOutcome.CallValueTooHigh) // <- detected by escrow | 1 << uint256(SolverOutcome.PreSolverFailed) ); // <- detected by EE // Solver's Fault - solver *does* owe gas refund, SolverOp *was* executed uint256 internal constant _FULL_REFUND = ( 1 << uint256(SolverOutcome.SolverOpReverted) // <- detected by Escrow | 1 << uint256(SolverOutcome.PostSolverFailed) // <- detected by EE | 1 << uint256(SolverOutcome.BidNotPaid) // <- detected by EE | 1 << uint256(SolverOutcome.InvertedBidExceedsCeiling) // <- detected by EE | 1 << uint256(SolverOutcome.BalanceNotReconciled) // <- detected by Escrow | 1 << uint256(SolverOutcome.CallbackNotCalled) // <- detected by Escrow | 1 << uint256(SolverOutcome.EVMError) ); // <- default if err by EE function canExecute(uint256 result) internal pure returns (bool) { return (result == 0); } // NOTE: PartialRefunds mean that the tx isn't executed but solver is still liable // for some gas costs. function partialRefund(uint256 result) internal pure returns (bool) { return ((result & _PARTIAL_REFUND) != 0); } function executionSuccessful(uint256 result) internal pure returns (bool) { return (result == 0); } function executedWithError(uint256 result) internal pure returns (bool) { return (result & _FULL_REFUND) != 0; } function bundlersFault(uint256 result) internal pure returns (bool) { // Only update solver escrow if failure is not due to bundler's fault // returns true if bundler blamed and no solver refund required return (result & _NO_REFUND != 0); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; library AccountingMath { uint256 internal constant _MAX_BUNDLER_REFUND_RATE = 8_000_000; // out of 10_000_000 = 80% uint256 internal constant _SOLVER_GAS_LIMIT_BUFFER_PERCENTAGE = 500_000; // out of 10_000_000 = 5% uint256 internal constant _SCALE = 10_000_000; // 10_000_000 / 10_000_000 = 100% uint256 internal constant _FIXED_GAS_OFFSET = 120_000; function withSurcharge(uint256 amount, uint256 surchargeRate) internal pure returns (uint256 adjustedAmount) { adjustedAmount = amount * (_SCALE + surchargeRate) / _SCALE; } function withoutSurcharge(uint256 amount, uint256 surchargeRate) internal pure returns (uint256 unadjustedAmount) { unadjustedAmount = amount * _SCALE / (_SCALE + surchargeRate); } function withSurcharges( uint256 amount, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate ) internal pure returns (uint256 adjustedAmount) { adjustedAmount = amount * (_SCALE + atlasSurchargeRate + bundlerSurchargeRate) / _SCALE; } // gets the Atlas surcharge from an unadjusted amount function getSurcharge( uint256 unadjustedAmount, uint256 surchargeRate ) internal pure returns (uint256 surchargeAmount) { surchargeAmount = unadjustedAmount * surchargeRate / _SCALE; } function getPortionFromTotalSurcharge( uint256 totalSurcharge, uint256 targetSurchargeRate, uint256 totalSurchargeRate ) internal pure returns (uint256 surchargePortion) { surchargePortion = totalSurcharge * targetSurchargeRate / totalSurchargeRate; } // NOTE: This max should only be applied when there are no winning solvers. // Set to 80% of the metacall gas cost, because the remaining 20% can be collected through storage refunds. function maxBundlerRefund(uint256 metacallGasCost) internal pure returns (uint256 maxRefund) { maxRefund = metacallGasCost * _MAX_BUNDLER_REFUND_RATE / _SCALE; } function solverGasLimitScaledDown( uint256 solverOpGasLimit, uint256 dConfigGasLimit ) internal pure returns (uint256 gasLimit) { gasLimit = (solverOpGasLimit < dConfigGasLimit ? solverOpGasLimit : dConfigGasLimit) * _SCALE / (_SCALE + _SOLVER_GAS_LIMIT_BUFFER_PERCENTAGE); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; // bonded = total - unbonding struct EscrowAccountBalance { uint112 balance; uint112 unbonding; } struct EscrowAccountAccessData { uint112 bonded; uint32 lastAccessedBlock; uint24 auctionWins; uint24 auctionFails; uint64 totalGasValueUsed; // The cumulative ETH value spent on gas in metacalls. Measured in gwei. } // Additional struct to avoid Stack Too Deep while tracking variables related to the solver call. struct SolverTracker { uint256 bidAmount; uint256 floor; uint256 ceiling; bool etherIsBidToken; bool invertsBidValue; } /// @title SolverOutcome /// @notice Enum for SolverOutcome /// @dev Multiple SolverOutcomes can be used to represent the outcome of a solver call /// @dev Typical usage looks like solverOutcome = (1 << SolverOutcome.InvalidSignature) | (1 << /// SolverOutcome.InvalidUserHash) to indicate SolverOutcome.InvalidSignature and SolverOutcome.InvalidUserHash enum SolverOutcome { // No Refund (relay error or hostile user) InvalidSignature, InvalidUserHash, DeadlinePassedAlt, GasPriceBelowUsersAlt, InvalidTo, UserOutOfGas, AlteredControl, AltOpHashMismatch, // Partial Refund but no execution DeadlinePassed, GasPriceOverCap, InvalidSolver, InvalidBidToken, PerBlockLimit, // solvers can only send one tx per block // if they sent two we wouldn't be able to flag builder censorship InsufficientEscrow, GasPriceBelowUsers, CallValueTooHigh, PreSolverFailed, // execution, with Full Refund SolverOpReverted, PostSolverFailed, BidNotPaid, InvertedBidExceedsCeiling, BalanceNotReconciled, CallbackNotCalled, EVMError }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { Mimic } from "../common/Mimic.sol"; import { AtlasEvents } from "../types/AtlasEvents.sol"; // NOTE: Do not call these functions directly. This contract should only ever be delegatecalled by the Atlas contract. contract FactoryLib { address public immutable EXECUTION_ENV_TEMPLATE; /// @notice Initializes a new Factory contract instance by setting the immutable salt for deterministic deployment /// of Execution Environments and storing the execution template address. /// @dev The Execution Environment Template must be separately deployed using the same calculated salt. /// @param executionTemplate Address of the pre-deployed execution template contract for creating Execution /// Environment instances. constructor(address executionTemplate) { EXECUTION_ENV_TEMPLATE = executionTemplate; } /// @notice Deploys a new execution environment or retrieves the address of an existing one based on the DApp /// control, user, and configuration. /// @dev Uses the `create2` opcode for deterministic deployment, allowing the calculation of the execution /// environment's address before deployment. The deployment uses a combination of the DAppControl address, user /// address, call configuration, and a unique salt to ensure the uniqueness and predictability of the environment's /// address. /// @param user The address of the user for whom the execution environment is being set. /// @param control The address of the DAppControl contract providing the operational context. /// @param callConfig CallConfig settings of the DAppControl contract. /// @return executionEnvironment The address of the newly created or already existing execution environment. function getOrCreateExecutionEnvironment( address user, address control, uint32 callConfig, bytes32 salt ) public payable returns (address executionEnvironment) { bytes memory _creationCode = _getMimicCreationCode({ user: user, control: control, callConfig: callConfig }); executionEnvironment = address( uint160( uint256( keccak256( abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(abi.encodePacked(_creationCode))) ) ) ) ); if (executionEnvironment.code.length == 0) { assembly { executionEnvironment := create2(0, add(_creationCode, 32), mload(_creationCode), salt) } emit AtlasEvents.ExecutionEnvironmentCreated(user, executionEnvironment); } } /// @notice Generates the address of a user's execution environment affected by deprecated callConfig changes in the /// DAppControl. /// @dev Calculates the deterministic address of the execution environment based on the user, control, /// callConfig, and controlCodeHash, ensuring consistency across changes in callConfig. /// @param user The address of the user for whom the execution environment's address is being generated. /// @param control The address of the DAppControl contract associated with the execution environment. /// @param callConfig The configuration flags defining the behavior of the execution environment. /// @return executionEnvironment The address of the user's execution environment. function getExecutionEnvironmentCustom( address user, address control, uint32 callConfig, bytes32 salt ) public view returns (address executionEnvironment) { bytes memory _creationCode = _getMimicCreationCode({ user: user, control: control, callConfig: callConfig }); executionEnvironment = address( uint160( uint256( keccak256( abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(abi.encodePacked(_creationCode))) ) ) ) ); } /// @notice Generates the creation code for the execution environment contract. /// @param control The address of the DAppControl contract associated with the execution environment. /// @param callConfig The configuration flags defining the behavior of the execution environment. /// @param user The address of the user for whom the execution environment is being created, contributing to the /// uniqueness of the creation code. /// @return creationCode The bytecode representing the creation code of the execution environment contract. function _getMimicCreationCode( address user, address control, uint32 callConfig ) internal view returns (bytes memory creationCode) { address _executionLib = EXECUTION_ENV_TEMPLATE; // NOTE: Changing compiler settings or solidity versions can break this. creationCode = type(Mimic).creationCode; assembly { // Insert the ExecutionEnvironment "Lib" address, into the AAAA placeholder in the creation code. mstore( add(creationCode, 79), or( and(mload(add(creationCode, 79)), not(shl(96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))), shl(96, _executionLib) ) ) // Insert the user address into the BBBB placeholder in the creation code. mstore( add(creationCode, 111), or( and(mload(add(creationCode, 111)), not(shl(96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))), shl(96, user) ) ) // Insert the control address into the CCCC placeholder in the creation code. mstore( add(creationCode, 132), or( and(mload(add(creationCode, 132)), not(shl(96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))), shl(96, control) ) ) // Insert the callConfig into the 2222 placeholder in the creation code. mstore( add(creationCode, 153), or(and(mload(add(creationCode, 153)), not(shl(224, 0xFFFFFFFF))), shl(224, callConfig)) ) } } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "./ValidCalls.sol"; contract AtlasErrors { // Simulator error SimulatorBalanceTooLow(); error Unauthorized(); error Unreachable(); error NoAuctionWinner(); error InvalidEntryFunction(); error SimulationPassed(); error UserSimulationFailed(); error UserSimulationSucceeded(); error UserUnexpectedSuccess(); error UserNotFulfilled(); error BidFindSuccessful(uint256 bidAmount); error UnexpectedNonRevert(); error InvalidSolver(); error BidNotPaid(); error InvertedBidExceedsCeiling(); error BalanceNotReconciled(); error SolverOpReverted(); error AlteredControl(); error InvalidEntry(); error CallbackNotCalled(); error PreSolverFailed(); error PostSolverFailed(); error InsufficientEscrow(); error VerificationSimFail(ValidCallsResult); error PreOpsSimFail(); error UserOpSimFail(); error SolverSimFail(uint256 solverOutcomeResult); // uint param is result returned in `verifySolverOp` error AllocateValueSimFail(); error PostOpsSimFail(); error ValidCalls(ValidCallsResult); // Execution Environment error InvalidUser(); error InvalidTo(); error InvalidCodeHash(); error PreOpsDelegatecallFail(); error UserOpValueExceedsBalance(); error UserWrapperDelegatecallFail(); error UserWrapperCallFail(); error PostOpsDelegatecallFail(); error PostOpsDelegatecallReturnedFalse(); error AllocateValueDelegatecallFail(); error NotEnvironmentOwner(); error ExecutionEnvironmentBalanceTooLow(); // Atlas error PreOpsFail(); error UserOpFail(); // error SolverFail(); // Only sim version of err is used error AllocateValueFail(); error PostOpsFail(); error InvalidAccess(); // Escrow error UncoveredResult(); error InvalidEscrowDuration(); // AtlETH error EscrowLockActive(); error InsufficientBalanceForDeduction(uint256 balance, uint256 requested); // DAppIntegration error OnlyGovernance(); error SignatoryActive(); error InvalidCaller(); error InvalidDAppControl(); error DAppNotEnabled(); error AtlasLockActive(); error InvalidSignatory(); // Permit69 error InvalidEnvironment(); error EnvironmentMismatch(); error InvalidLockState(); // GasAccounting error LedgerFinalized(uint8 id); error LedgerBalancing(uint8 id); error MissingFunds(uint8 id); error InsufficientFunds(); error NoUnfilledRequests(); error SolverMustReconcile(); error DoubleReconcile(); error InvalidExecutionEnvironment(address correctEnvironment); error InvalidSolverFrom(address solverFrom); error InsufficientSolverBalance(uint256 actual, uint256 msgValue, uint256 holds, uint256 needed); error InsufficientAtlETHBalance(uint256 actual, uint256 needed); error InsufficientTotalBalance(uint256 shortfall); error UnbalancedAccounting(); // SafetyLocks error NotInitialized(); error AlreadyInitialized(); // Storage error SurchargeRateTooHigh(); // AtlasVerification error NoUnusedNonceInBitmap(); // DAppControl error BothUserAndDAppNoncesCannotBeSequential(); error BothPreOpsAndUserReturnDataCannotBeTracked(); error InvalidControl(); error NoDelegatecall(); error MustBeDelegatecalled(); error OnlyAtlas(); error WrongPhase(); error WrongDepth(); error InsufficientLocalFunds(); error NotImplemented(); error InvertBidValueCannotBeExPostBids(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import { GasAccounting } from "./GasAccounting.sol"; import { SAFE_USER_TRANSFER, SAFE_DAPP_TRANSFER } from "../libraries/SafetyBits.sol"; import "../types/LockTypes.sol"; import "../types/EscrowTypes.sol"; // NOTE: Permit69 only works inside of the Atlas environment - specifically // inside of the custom ExecutionEnvironments that each user deploys when // interacting with Atlas in a manner controlled by the DeFi dApp. // The name comes from the reciprocal nature of the token transfers. Both // the user and the DAppControl can transfer tokens from the User // and the DAppControl contracts... but only if they each have granted // token approval to the Atlas main contract, and only during specific phases // of the Atlas execution process. /// @title Permit69 /// @author FastLane Labs /// @notice Permit69 manages ERC20 approvals and transfers between Atlas and Execution Environment contracts during /// metacall transactions. abstract contract Permit69 is GasAccounting { constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator ) GasAccounting( escrowDuration, atlasSurchargeRate, bundlerSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator ) { } /// @notice Verifies that the caller is an authorized Execution Environment contract. /// @dev This function is called internally to ensure that the caller is a legitimate Execution Environment contract /// controlled by the current DAppControl contract. It helps prevent unauthorized access and ensures that /// token transfers are performed within the context of Atlas's controlled environment. The implementation of this /// function can be found in Atlas.sol /// @param environment ExecutionEnvironment address /// @param user The address of the user invoking the function. /// @param control The address of the current DAppControl contract. /// @param callConfig The CallConfig of the DAppControl contract of the current transaction. function _verifyUserControlExecutionEnv( address environment, address user, address control, uint32 callConfig ) internal virtual returns (bool) { } /// @notice Transfers ERC20 tokens from a user to a destination address, only callable by the expected Execution /// Environment. /// @param token The address of the ERC20 token contract. /// @param destination The address to which the tokens will be transferred. /// @param amount The amount of tokens to transfer. /// @param user The address of the user invoking the function. /// @param control The address of the current DAppControl contract. function transferUserERC20( address token, address destination, uint256 amount, address user, address control ) external { // Validate that the transfer is legitimate _validateTransfer({ user: user, control: control, safeExecutionPhaseSet: SAFE_USER_TRANSFER }); // Transfer token SafeTransferLib.safeTransferFrom(token, user, destination, amount); } /// @notice Transfers ERC20 tokens from the DAppControl contract to a destination address, only callable by the /// expected Execution Environment. /// @param token The address of the ERC20 token contract. /// @param destination The address to which the tokens will be transferred. /// @param amount The amount of tokens to transfer. /// @param user The address of the user invoking the function. /// @param control The address of the current DAppControl contract. function transferDAppERC20( address token, address destination, uint256 amount, address user, address control ) external { // Validate that the transfer is legitimate _validateTransfer({ user: user, control: control, safeExecutionPhaseSet: SAFE_DAPP_TRANSFER }); // Transfer token SafeTransferLib.safeTransferFrom(token, control, destination, amount); } /// @notice Verifies whether the lock state allows execution in the specified safe execution phase. /// @param user The address of the user invoking the function. /// @param control The address of the current DAppControl contract. /// @param safeExecutionPhaseSet The set of safe execution phases. function _validateTransfer(address user, address control, uint8 safeExecutionPhaseSet) internal { (address _activeEnv, uint32 _callConfig, uint8 _currentPhase) = _lock(); // Verify that the ExecutionEnvironment's context is correct. if (_activeEnv != msg.sender) { revert InvalidEnvironment(); } // Verify that the given user and control are the owners of this ExecutionEnvironment if (!_verifyUserControlExecutionEnv(msg.sender, user, control, _callConfig)) { revert EnvironmentMismatch(); } // Verify that the current phase allows for transfers if (1 << _currentPhase & safeExecutionPhaseSet == 0) { revert InvalidLockState(); } } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; contract Mimic { /* 0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa is standin for the ExecutionEnvironment, which is a de facto library 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB is standin for the userOp.from address 0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC is standin for the dApp control address 0x2222 is standin for the call configuration These values are adjusted by the factory to match the appropriate values for the intended user/control/config. This happens during contract creation. creationCode = type(Mimic).creationCode; assembly { mstore(add(creationCode, 85), add( shl(96, executionLib), 0x73ffffffffffffffffffffff )) mstore(add(creationCode, 131), add( shl(96, user), 0x73ffffffffffffffffffffff )) mstore(add(creationCode, 152), add( shl(96, control), add( add( shl(88, 0x61), shl(72, callConfig) ), 0x7f0000000000000000 ) )) } */ receive() external payable { } fallback(bytes calldata) external payable returns (bytes memory) { (bool success, bytes memory output) = address(0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa).delegatecall( abi.encodePacked( msg.data, address(0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB), address(0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC), uint32(0x22222222) ) ); if (!success) { assembly { revert(add(output, 32), mload(output)) } } return output; } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; contract AtlasEvents { // Metacall event MetacallResult( address indexed bundler, address indexed user, bool solverSuccessful, bool disbursementSuccessful, uint256 ethPaidToBundler, uint256 netGasSurcharge ); // AtlETH event Bond(address indexed owner, uint256 amount); event Unbond(address indexed owner, uint256 amount, uint256 earliestAvailable); event Redeem(address indexed owner, uint256 amount); event Mint(address indexed to, uint256 amount); event Burn(address indexed from, uint256 amount); // Escrow events event SolverTxResult( address indexed solverTo, address indexed solverFrom, address indexed dAppControl, address bidToken, uint256 bidAmount, bool executed, bool success, uint256 result ); // Factory events event ExecutionEnvironmentCreated(address indexed user, address indexed executionEnvironment); // Surcharge events event SurchargeWithdrawn(address indexed to, uint256 amount); event SurchargeRecipientTransferStarted(address indexed currentRecipient, address indexed newRecipient); event SurchargeRecipientTransferred(address indexed newRecipient); // DAppControl events event GovernanceTransferStarted(address indexed previousGovernance, address indexed newGovernance); event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance); // DAppIntegration events event NewDAppSignatory( address indexed control, address indexed governance, address indexed signatory, uint32 callConfig ); event RemovedDAppSignatory( address indexed control, address indexed governance, address indexed signatory, uint32 callConfig ); event DAppGovernanceChanged( address indexed control, address indexed oldGovernance, address indexed newGovernance, uint32 callConfig ); event DAppDisabled(address indexed control, address indexed governance, uint32 callConfig); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; import { SafetyLocks } from "./SafetyLocks.sol"; import { EscrowBits } from "../libraries/EscrowBits.sol"; import { AccountingMath } from "../libraries/AccountingMath.sol"; import { SolverOperation } from "../types/SolverOperation.sol"; import { DAppConfig } from "../types/ConfigTypes.sol"; import { IL2GasCalculator } from "../interfaces/IL2GasCalculator.sol"; import "../types/EscrowTypes.sol"; import "../types/LockTypes.sol"; /// @title GasAccounting /// @author FastLane Labs /// @notice GasAccounting manages the accounting of gas surcharges and escrow balances for the Atlas protocol. abstract contract GasAccounting is SafetyLocks { using EscrowBits for uint256; using AccountingMath for uint256; constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator ) SafetyLocks( escrowDuration, atlasSurchargeRate, bundlerSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator ) { } /// @notice Sets the initial accounting values for the metacall transaction. /// @param gasMarker The gas marker used to calculate the initial accounting values. function _initializeAccountingValues(uint256 gasMarker) internal { uint256 _rawClaims = (FIXED_GAS_OFFSET + gasMarker) * tx.gasprice; (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates(); // Set any withdraws or deposits t_claims = _rawClaims.withSurcharge(_bundlerSurchargeRate); // Atlas surcharge is based on the raw claims value. t_fees = _rawClaims.getSurcharge(_atlasSurchargeRate); t_deposits = msg.value; // Explicitly set other transient vars to 0 in case multiple metacalls in single tx. t_writeoffs = 0; t_withdrawals = 0; t_solverSurcharge = 0; t_solverLock = 0; t_solverTo = address(0); // The Lock slot is cleared at the end of the metacall, so no need to zero again here. } /// @notice Contributes ETH to the contract, increasing the deposits if a non-zero value is sent. function contribute() external payable { address _activeEnv = _activeEnvironment(); if (_activeEnv != msg.sender) revert InvalidExecutionEnvironment(_activeEnv); _contribute(); } /// @notice Borrows ETH from the contract, transferring the specified amount to the caller if available. /// @dev Borrowing is only available until the end of the SolverOperation phase, for solver protection. /// @param amount The amount of ETH to borrow. function borrow(uint256 amount) external payable { if (amount == 0) return; // borrow() can only be called by the Execution Environment (by delegatecalling a DAppControl hook), and only // during or before the SolverOperation phase. (address _activeEnv,, uint8 _currentPhase) = _lock(); if (_activeEnv != msg.sender) revert InvalidExecutionEnvironment(_activeEnv); if (_currentPhase > uint8(ExecutionPhase.SolverOperation)) revert WrongPhase(); // borrow() will revert if called after solver calls reconcile() (, bool _calledBack,) = _solverLockData(); if (_calledBack) revert WrongPhase(); if (_borrow(amount)) { SafeTransferLib.safeTransferETH(msg.sender, amount); } else { revert InsufficientAtlETHBalance(address(this).balance, amount); } } /// @notice Calculates the current shortfall currently owed by the winning solver. /// @dev The shortfall is calculated `(claims + withdrawals + fees - writeoffs) - deposits`. If this value is less /// than zero, shortfall returns 0 as there is no shortfall because the solver is in surplus. /// @return uint256 The current shortfall amount, or 0 if there is no shortfall. function shortfall() external view returns (uint256) { uint256 _currentDeficit = _deficit(); uint256 _deposits = t_deposits; return (_currentDeficit > _deposits) ? (_currentDeficit - _deposits) : 0; } function _deficit() internal view returns (uint256) { // _deficit() is compared against t_deposits which includes: // + msg.value deposited // + gas cost + A + B (prev solver fault fails) // _deficit() is therefore composed of: // + withdrawals = msg.value borrowed // + claims = gas cost + B (full tx) // + fees = A (full tx) // - writeoffs = gas cost + A + B (prev bundler fault fails) // Such that `deficit() - t_deposits` = // + msg.value still owed // + gas cost + A + B (full tx) // - gas cost + A + B (prev solver fault fails) // - gas cost + A + B (prev bundler fault fails) // == only what the current solver owes if they win return t_withdrawals + t_claims + t_fees - t_writeoffs; } /// @notice Allows a solver to settle any outstanding ETH owed, either to repay gas used by their solverOp or to /// repay any ETH borrowed from Atlas. This debt can be paid either by sending ETH when calling this function /// (msg.value) or by approving Atlas to use a certain amount of the solver's bonded AtlETH. /// @param maxApprovedGasSpend The maximum amount of the solver's bonded AtlETH that Atlas can deduct to cover the /// solver's debt. /// @return owed The amount owed, if any, by the solver after reconciliation. /// @dev The solver can call this function multiple times until the owed amount is zero. /// @dev Note: `reconcile()` must be called by the solver to avoid a `CallbackNotCalled` error in `solverCall()`. function reconcile(uint256 maxApprovedGasSpend) external payable returns (uint256 owed) { // NOTE: maxApprovedGasSpend is the amount of the solver's atlETH that the solver is allowing // to be used to cover what they owe. Assuming they're successful, a value up to this amount // will be subtracted from the solver's bonded AtlETH during _settle(). // NOTE: After reconcile is called for the first time by the solver, neither the claims nor withdrawals values // can be increased. // NOTE: While anyone can call this function, it can only be called in the SolverOperation phase. Because Atlas // calls directly to the solver contract in this phase, the solver should be careful to not call malicious // contracts which may call reconcile() on their behalf, with an excessive maxApprovedGasSpend. if (_phase() != uint8(ExecutionPhase.SolverOperation)) revert WrongPhase(); if (msg.sender != t_solverTo) revert InvalidAccess(); (address _currentSolver, bool _calledBack, bool _fulfilled) = _solverLockData(); uint256 _bondedBalance = uint256(S_accessData[_currentSolver].bonded); // Solver can only approve up to their bonded balance, not more if (maxApprovedGasSpend > _bondedBalance) maxApprovedGasSpend = _bondedBalance; uint256 _deductions = _deficit(); uint256 _additions = t_deposits + msg.value; // Add msg.value to solver's deposits // NOTE: Surplus deposits are credited back to the Solver during settlement. // NOTE: This function is called inside the solver try/catch and will be undone if solver fails. if (msg.value > 0) t_deposits = _additions; // CASE: Callback verified but insufficient balance if (_deductions > _additions + maxApprovedGasSpend) { if (!_calledBack) { // Setting the solverLock here does not make the solver liable for the submitted maxApprovedGasSpend, // but it does treat any msg.value as a deposit and allows for either the solver to call back with a // higher maxApprovedGasSpend or to have their deficit covered by a contribute during the postSolverOp // hook. t_solverLock = (uint256(uint160(_currentSolver)) | _SOLVER_CALLED_BACK_MASK); } return _deductions - _additions; } // CASE: Callback verified and solver duty fulfilled if (!_fulfilled) { t_solverLock = (uint256(uint160(_currentSolver)) | _SOLVER_CALLED_BACK_MASK | _SOLVER_FULFILLED_MASK); } return 0; } /// @notice Internal function to handle ETH contribution, increasing deposits if a non-zero value is sent. function _contribute() internal { if (msg.value != 0) t_deposits += msg.value; } /// @notice Borrows ETH from the contract, transferring the specified amount to the caller if available. /// @dev Borrowing should never be allowed after the SolverOperation phase, for solver safety. This is enforced in /// the external `borrow` function, and the only other time this internal `_borrow` function is called is in /// `_solverOpInner` which happens at the beginning of the SolverOperation phase. /// @param amount The amount of ETH to borrow. /// @return valid A boolean indicating whether the borrowing operation was successful. function _borrow(uint256 amount) internal returns (bool valid) { if (amount == 0) return true; if (address(this).balance < amount) return false; t_withdrawals += amount; return true; } /// @notice Takes AtlETH from the owner's bonded balance and, if necessary, from the owner's unbonding balance to /// increase transient solver deposits. /// @param owner The address of the owner from whom AtlETH is taken. /// @param amount The amount of AtlETH to be taken. /// @param gasValueUsed The ETH value of gas used in the SolverOperation. /// @param solverWon A boolean indicating whether the solver won the bid. /// @return deficit The amount of AtlETH that was not repaid, if any. function _assign( address owner, uint256 amount, uint256 gasValueUsed, bool solverWon ) internal returns (uint256 deficit) { uint112 _amt = SafeCast.toUint112(amount); EscrowAccountAccessData memory _aData = S_accessData[owner]; if (_amt > _aData.bonded) { // The bonded balance does not cover the amount owed. Check if there is enough unbonding balance to // make up for the missing difference. If not, there is a deficit. Atlas does not consider drawing from // the regular AtlETH balance (not bonded nor unbonding) to cover the remaining deficit because it is // not meant to be used within an Atlas transaction, and must remain independent. EscrowAccountBalance memory _bData = s_balanceOf[owner]; uint256 _total = uint256(_bData.unbonding) + uint256(_aData.bonded); if (_amt > _total) { // The unbonding balance is insufficient to cover the remaining amount owed. There is a deficit. Set // both bonded and unbonding balances to 0 and adjust the "amount" variable to reflect the amount // that was actually deducted. deficit = amount - _total; s_balanceOf[owner].unbonding = 0; _aData.bonded = 0; t_writeoffs += deficit; amount -= deficit; // Set amount equal to total to accurately track the changing bondedTotalSupply } else { // The unbonding balance is sufficient to cover the remaining amount owed. Draw everything from the // bonded balance, and adjust the unbonding balance accordingly. s_balanceOf[owner].unbonding = SafeCast.toUint112(_total - _amt); _aData.bonded = 0; } } else { // The bonded balance is sufficient to cover the amount owed. _aData.bonded -= _amt; } // Update analytics (auctionWins, auctionFails, totalGasValueUsed) and lastAccessedBlock _updateAnalytics(_aData, solverWon && deficit == 0, gasValueUsed); _aData.lastAccessedBlock = uint32(block.number); // Persist changes in the _aData memory struct back to storage S_accessData[owner] = _aData; S_bondedTotalSupply -= amount; t_deposits += amount; } /// @notice Increases the owner's bonded balance by the specified amount. /// @param owner The address of the owner whose bonded balance will be increased. /// @param amount The amount by which to increase the owner's bonded balance. /// @param gasValueUsed The ETH value of gas used in the SolverOperation. function _credit(address owner, uint256 amount, uint256 gasValueUsed) internal { EscrowAccountAccessData memory _aData = S_accessData[owner]; _aData.lastAccessedBlock = uint32(block.number); _aData.bonded += SafeCast.toUint112(amount); S_bondedTotalSupply += amount; // Update analytics (auctionWins, auctionFails, totalGasValueUsed) _updateAnalytics(_aData, true, gasValueUsed); // Persist changes in the _aData memory struct back to storage S_accessData[owner] = _aData; t_withdrawals += amount; } /// @notice Accounts for the gas cost of a failed SolverOperation, either by increasing writeoffs (if the bundler is /// blamed for the failure) or by assigning the gas cost to the solver's bonded AtlETH balance (if the solver is /// blamed for the failure). /// @param solverOp The current SolverOperation for which to account. /// @param gasWaterMark The `gasleft()` watermark taken at the start of executing the SolverOperation. /// @param result The result bitmap of the SolverOperation execution. /// @param includeCalldata Whether to include calldata cost in the gas calculation. function _handleSolverAccounting( SolverOperation calldata solverOp, uint256 gasWaterMark, uint256 result, bool includeCalldata ) internal { uint256 _gasUsed = (gasWaterMark + _SOLVER_BASE_GAS_USED - gasleft()) * tx.gasprice; (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates(); if (includeCalldata) { _gasUsed += _getCalldataCost(solverOp.data.length); } // Calculate what the solver owes // NOTE: This will cause an error if you are simulating with a gasPrice of 0 if (result.bundlersFault()) { // CASE: Solver is not responsible for the failure of their operation, so we blame the bundler // and reduce the total amount refunded to the bundler t_writeoffs += _gasUsed.withSurcharges(_atlasSurchargeRate, _bundlerSurchargeRate); } else { // CASE: Solver failed, so we calculate what they owe. uint256 _gasUsedWithSurcharges = _gasUsed.withSurcharges(_atlasSurchargeRate, _bundlerSurchargeRate); uint256 _surchargesOnly = _gasUsedWithSurcharges - _gasUsed; // In `_assign()`, the failing solver's bonded AtlETH balance is reduced by `_gasUsedWithSurcharges`. Any // deficit from that operation is added to `writeoffs` and returned as `_assignDeficit` below. The portion // that can be covered by the solver's AtlETH is added to `deposits`, to account that it has been paid. uint256 _assignDeficit = _assign(solverOp.from, _gasUsedWithSurcharges, _gasUsedWithSurcharges, false); // We track the surcharges (in excess of deficit - so the actual AtlETH that can be collected) separately, // so that in the event of no successful solvers, any `_assign()`ed surcharges can be attributed to an // increase in Atlas' cumulative surcharge. if (_surchargesOnly > _assignDeficit) { t_solverSurcharge += (_surchargesOnly - _assignDeficit); } } } function _writeOffBidFindGasCost(uint256 gasUsed) internal { (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates(); t_writeoffs += gasUsed.withSurcharges(_atlasSurchargeRate, _bundlerSurchargeRate); } /// @param ctx Context struct containing relevant context information for the Atlas auction. /// @param solverGasLimit The maximum gas limit for a solver, as set in the DAppConfig /// @return adjustedWithdrawals Withdrawals of the current metacall, adjusted by adding the Atlas gas surcharge. /// @return adjustedClaims Claims of the current metacall, adjusted by subtracting the unused gas scaled to include /// bundler surcharge. /// @return adjustedWriteoffs Writeoffs of the current metacall, adjusted by adding the bundler gas overage penalty /// if applicable. /// @return netAtlasGasSurcharge The net gas surcharge of the metacall, taken by Atlas. /// @dev This function is called internally to adjust the accounting for fees based on the gas usage. /// Note: The behavior of this function depends on whether `_bidFindingIteration()` or `_bidKnownIteration()` is /// used, as they both use a different order of execution. function _adjustAccountingForFees( Context memory ctx, uint256 solverGasLimit ) internal returns ( uint256 adjustedWithdrawals, uint256 adjustedClaims, uint256 adjustedWriteoffs, uint256 netAtlasGasSurcharge ) { uint256 _surcharge = S_cumulativeSurcharge; adjustedWithdrawals = t_withdrawals; adjustedClaims = t_claims; adjustedWriteoffs = t_writeoffs; uint256 _fees = t_fees; (uint256 _atlasSurchargeRate, uint256 _bundlerSurchargeRate) = _surchargeRates(); uint256 _gasLeft = gasleft(); // Hold this constant for the calculations // Estimate the unspent, remaining gas that the Solver will not be liable for. uint256 _gasRemainder = _gasLeft * tx.gasprice; adjustedClaims -= _gasRemainder.withSurcharge(_bundlerSurchargeRate); if (ctx.solverSuccessful) { // If a solver was successful, calc the full Atlas gas surcharge on the gas cost of the entire metacall, and // add it to withdrawals so that the cost is assigned to winning solver by the end of _settle(). This will // be offset by any gas surcharge paid by failed solvers, which would have been added to deposits or // writeoffs in _handleSolverAccounting(). As such, the winning solver does not pay for surcharge on the gas // used by other solvers. netAtlasGasSurcharge = _fees - _gasRemainder.getSurcharge(_atlasSurchargeRate); adjustedWithdrawals += netAtlasGasSurcharge; S_cumulativeSurcharge = _surcharge + netAtlasGasSurcharge; } else { // If no successful solvers, only collect partial surcharges from solver's fault failures (if any) uint256 _solverSurcharge = t_solverSurcharge; if (_solverSurcharge > 0) { netAtlasGasSurcharge = _solverSurcharge.getPortionFromTotalSurcharge({ targetSurchargeRate: _atlasSurchargeRate, totalSurchargeRate: _atlasSurchargeRate + _bundlerSurchargeRate }); // When no winning solvers, bundler max refund is 80% of metacall gas cost. The remaining 20% can be // collected through storage refunds. Any excess bundler surcharge is instead taken as Atlas surcharge. uint256 _bundlerSurcharge = _solverSurcharge - netAtlasGasSurcharge; uint256 _maxBundlerRefund = adjustedClaims.withoutSurcharge(_bundlerSurchargeRate).maxBundlerRefund(); if (_bundlerSurcharge > _maxBundlerRefund) { netAtlasGasSurcharge += _bundlerSurcharge - _maxBundlerRefund; } adjustedWithdrawals += netAtlasGasSurcharge; S_cumulativeSurcharge = _surcharge + netAtlasGasSurcharge; } return (adjustedWithdrawals, adjustedClaims, adjustedWriteoffs, netAtlasGasSurcharge); } // Calculate whether or not the bundler used an excessive amount of gas and, if so, reduce their // gas rebate. By reducing the claims, solvers end up paying less in total. if (ctx.solverCount > 0) { // Calculate the unadjusted bundler gas surcharge uint256 _grossBundlerGasSurcharge = adjustedClaims.withoutSurcharge(_bundlerSurchargeRate); // Calculate an estimate for how much gas should be remaining // NOTE: There is a free buffer of one SolverOperation because solverIndex starts at 0. uint256 _upperGasRemainingEstimate = (solverGasLimit * (ctx.solverCount - ctx.solverIndex)) + _BUNDLER_GAS_PENALTY_BUFFER; // Increase the writeoffs value if the bundler set too high of a gas parameter and forced solvers to // maintain higher escrow balances. if (_gasLeft > _upperGasRemainingEstimate) { // Penalize the bundler's gas uint256 _bundlerGasOveragePenalty = _grossBundlerGasSurcharge - (_grossBundlerGasSurcharge * _upperGasRemainingEstimate / _gasLeft); adjustedWriteoffs += _bundlerGasOveragePenalty; } } } /// @notice Settle makes the final adjustments to accounting variables based on gas used in the metacall. AtlETH is /// either taken (via _assign) or given (via _credit) to the winning solver, the bundler is sent the appropriate /// refund for gas spent, and Atlas' gas surcharge is updated. /// @param ctx Context struct containing relevant context information for the Atlas auction. /// @param solverGasLimit The dApp's maximum gas limit for a solver, as set in the DAppConfig. /// @param gasRefundBeneficiary The address to receive the gas refund. /// @return claimsPaidToBundler The amount of ETH paid to the bundler in this function. /// @return netAtlasGasSurcharge The net gas surcharge of the metacall, taken by Atlas. function _settle( Context memory ctx, uint256 solverGasLimit, address gasRefundBeneficiary ) internal returns (uint256 claimsPaidToBundler, uint256 netAtlasGasSurcharge) { // NOTE: If there is no winning solver but the dApp config allows unfulfilled 'successes', the bundler // is treated as the solver. // If a solver won, their address is still in the _solverLock (address _winningSolver,,) = _solverLockData(); if (gasRefundBeneficiary == address(0)) gasRefundBeneficiary = ctx.bundler; // Load what we can from storage so that it shows up in the gasleft() calc uint256 _claims; uint256 _writeoffs; uint256 _withdrawals; uint256 _deposits = t_deposits; // load here, not used in adjustment function below (_withdrawals, _claims, _writeoffs, netAtlasGasSurcharge) = _adjustAccountingForFees(ctx, solverGasLimit); uint256 _amountSolverPays; uint256 _amountSolverReceives; uint256 _adjustedClaims = _claims - _writeoffs; // Calculate the balances that should be debited or credited to the solver and the bundler if (_deposits < _withdrawals) { _amountSolverPays = _withdrawals - _deposits; } else { _amountSolverReceives = _deposits - _withdrawals; } // Only force solver to pay gas claims if they aren't also the bundler // NOTE: If the auction isn't won, _winningSolver will be address(0). if (ctx.solverSuccessful && _winningSolver != ctx.bundler) { _amountSolverPays += _adjustedClaims; claimsPaidToBundler = _adjustedClaims; } else if (_winningSolver == ctx.bundler) { claimsPaidToBundler = 0; } else { // this else block is only executed if there is no successful solver claimsPaidToBundler = 0; _winningSolver = gasRefundBeneficiary; } if (_amountSolverPays > _amountSolverReceives) { if (!ctx.solverSuccessful) { revert InsufficientTotalBalance(_amountSolverPays - _amountSolverReceives); } uint256 _currentDeficit = _assign(_winningSolver, _amountSolverPays - _amountSolverReceives, _adjustedClaims, true); if (_currentDeficit > claimsPaidToBundler) { revert InsufficientTotalBalance(_currentDeficit - claimsPaidToBundler); } claimsPaidToBundler -= _currentDeficit; } else { _credit(_winningSolver, _amountSolverReceives - _amountSolverPays, _adjustedClaims); } // Set lock to FullyLocked to prevent any reentrancy possibility _setLockPhase(uint8(ExecutionPhase.FullyLocked)); if (claimsPaidToBundler != 0) SafeTransferLib.safeTransferETH(gasRefundBeneficiary, claimsPaidToBundler); return (claimsPaidToBundler, netAtlasGasSurcharge); } /// @notice Updates auctionWins, auctionFails, and totalGasUsed values of a solver's EscrowAccountAccessData. /// @dev This function is only ever called in the context of bidFind = false so no risk of doublecounting changes. /// @param aData The Solver's EscrowAccountAccessData struct to update. /// @param auctionWon A boolean indicating whether the solver's solverOp won the auction. /// @param gasValueUsed The ETH value of gas used by the solverOp. Should be calculated as gasUsed * tx.gasprice. function _updateAnalytics( EscrowAccountAccessData memory aData, bool auctionWon, uint256 gasValueUsed ) internal pure { if (auctionWon) { unchecked { ++aData.auctionWins; } } else { unchecked { ++aData.auctionFails; } } // Track total ETH value of gas spent by solver in metacalls. Measured in gwei (1e9 digits truncated). aData.totalGasValueUsed += SafeCast.toUint64(gasValueUsed / _GAS_VALUE_DECIMALS_TO_DROP); } /// @notice Calculates the gas cost of the calldata used to execute a SolverOperation. /// @param calldataLength The length of the `data` field in the SolverOperation. /// @return calldataCost The gas cost of the calldata used to execute the SolverOperation. function _getCalldataCost(uint256 calldataLength) internal view returns (uint256 calldataCost) { if (L2_GAS_CALCULATOR == address(0)) { // Default to using mainnet gas calculations // _SOLVER_OP_BASE_CALLDATA = SolverOperation calldata length excluding solverOp.data calldataCost = (calldataLength + _SOLVER_OP_BASE_CALLDATA) * _CALLDATA_LENGTH_PREMIUM_HALVED * tx.gasprice; } else { calldataCost = IL2GasCalculator(L2_GAS_CALCULATOR).getCalldataCost(calldataLength + _SOLVER_OP_BASE_CALLDATA); } } /// @notice Checks if the current balance is reconciled. /// @dev Compares the deposits with the sum of claims, withdrawals, fees, and write-offs to ensure the balance is /// correct. /// @return True if the balance is reconciled, false otherwise. function _isBalanceReconciled() internal view returns (bool) { return t_deposits >= _deficit(); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import { Storage } from "./Storage.sol"; import { CallBits } from "../libraries/CallBits.sol"; import "../types/SolverOperation.sol"; import "../types/UserOperation.sol"; import "../types/ConfigTypes.sol"; import "../types/EscrowTypes.sol"; import "../types/LockTypes.sol"; /// @title SafetyLocks /// @author FastLane Labs /// @notice SafetyLocks manages the locking and unlocking of the Atlas environment during the execution of a metacall /// transaction. abstract contract SafetyLocks is Storage { using CallBits for uint32; constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator ) Storage( escrowDuration, atlasSurchargeRate, bundlerSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator ) { } /// @notice Sets the Atlas lock to the specified execution environment. /// @param dConfig The DAppConfig of the current DAppControl contract. /// @param executionEnvironment The address of the execution environment to set the lock to. function _setEnvironmentLock(DAppConfig memory dConfig, address executionEnvironment) internal { if (!_isUnlocked()) revert AlreadyInitialized(); // Initialize the Lock _setLock({ activeEnvironment: executionEnvironment, callConfig: dConfig.callConfig, phase: uint8(ExecutionPhase.PreOps) }); } modifier withLockPhase(ExecutionPhase executionPhase) { _setLockPhase(uint8(executionPhase)); _; } /// @notice Builds an Context struct with the specified parameters, called at the start of /// `_preOpsUserExecutionIteration`. /// @param executionEnvironment The address of the current Execution Environment. /// @param userOpHash The UserOperation hash. /// @param bundler The address of the bundler. /// @param solverOpCount The count of SolverOperations. /// @param isSimulation Boolean indicating whether the call is a simulation or not. /// @return An Context struct initialized with the provided parameters. function _buildContext( address executionEnvironment, bytes32 userOpHash, address bundler, uint8 solverOpCount, bool isSimulation ) internal pure returns (Context memory) { return Context({ executionEnvironment: executionEnvironment, userOpHash: userOpHash, bundler: bundler, solverSuccessful: false, paymentsSuccessful: false, solverIndex: 0, solverCount: solverOpCount, phase: uint8(ExecutionPhase.PreOps), solverOutcome: 0, bidFind: false, isSimulation: isSimulation, callDepth: 0 }); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "../types/EscrowTypes.sol"; import "../types/LockTypes.sol"; import "../libraries/AccountingMath.sol"; import { AtlasEvents } from "../types/AtlasEvents.sol"; import { AtlasErrors } from "../types/AtlasErrors.sol"; import { AtlasConstants } from "../types/AtlasConstants.sol"; import { IAtlasVerification } from "../interfaces/IAtlasVerification.sol"; /// @title Storage /// @author FastLane Labs /// @notice Storage manages all storage variables and constants for the Atlas smart contract. contract Storage is AtlasEvents, AtlasErrors, AtlasConstants { IAtlasVerification public immutable VERIFICATION; address public immutable SIMULATOR; address public immutable L2_GAS_CALCULATOR; uint256 public immutable ESCROW_DURATION; // AtlETH public constants // These constants double as interface functions for the ERC20 standard, hence the lowercase naming convention. string public constant name = "Atlas ETH"; string public constant symbol = "atlETH"; uint8 public constant decimals = 18; // Gas Accounting public constants uint256 public constant SCALE = AccountingMath._SCALE; uint256 public constant FIXED_GAS_OFFSET = AccountingMath._FIXED_GAS_OFFSET; // Transient storage slots uint256 internal transient t_lock; // contains activeAddress, callConfig, and phase uint256 internal transient t_solverLock; address internal transient t_solverTo; // current solverOp.solver contract address // solverSurcharge = total surcharge collected from failed solverOps due to solver fault. uint256 internal transient t_solverSurcharge; uint256 internal transient t_claims; uint256 internal transient t_fees; uint256 internal transient t_writeoffs; uint256 internal transient t_withdrawals; uint256 internal transient t_deposits; // AtlETH storage uint256 internal S_totalSupply; uint256 internal S_bondedTotalSupply; // Surcharge-related storage uint256 internal S_surchargeRates; // left 128 bits: Atlas rate, right 128 bits: Bundler rate uint256 internal S_cumulativeSurcharge; // Cumulative gas surcharges collected address internal S_surchargeRecipient; // Fastlane surcharge recipient address internal S_pendingSurchargeRecipient; // For 2-step transfer process mapping(address => EscrowAccountBalance) internal s_balanceOf; // public balanceOf will return a uint256 mapping(address => EscrowAccountAccessData) internal S_accessData; mapping(bytes32 => bool) internal S_solverOpHashes; // NOTE: Only used for when allowTrustedOpHash is enabled constructor( uint256 escrowDuration, uint256 atlasSurchargeRate, uint256 bundlerSurchargeRate, address verification, address simulator, address initialSurchargeRecipient, address l2GasCalculator ) payable { VERIFICATION = IAtlasVerification(verification); SIMULATOR = simulator; L2_GAS_CALCULATOR = l2GasCalculator; ESCROW_DURATION = escrowDuration; // Check Atlas and Bundler gas surcharges fit in 128 bits each if(atlasSurchargeRate > type(uint128).max || bundlerSurchargeRate > type(uint128).max) { revert SurchargeRateTooHigh(); } S_surchargeRates = atlasSurchargeRate << 128 | bundlerSurchargeRate; S_cumulativeSurcharge = msg.value; S_surchargeRecipient = initialSurchargeRecipient; emit SurchargeRecipientTransferred(initialSurchargeRecipient); } // ---------------------------------------------------- // // Storage Setters // // ---------------------------------------------------- // function setSurchargeRates(uint256 newAtlasRate, uint256 newBundlerRate) external { _onlySurchargeRecipient(); // Check Atlas and Bundler gas surcharges fit in 128 bits each if(newAtlasRate > type(uint128).max || newBundlerRate > type(uint128).max) { revert SurchargeRateTooHigh(); } S_surchargeRates = newAtlasRate << 128 | newBundlerRate; } function _onlySurchargeRecipient() internal view { if (msg.sender != S_surchargeRecipient) { revert InvalidAccess(); } } // ---------------------------------------------------- // // Storage Getters // // ---------------------------------------------------- // function totalSupply() external view returns (uint256) { return S_totalSupply; } function bondedTotalSupply() external view returns (uint256) { return S_bondedTotalSupply; } function accessData(address account) external view returns ( uint112 bonded, uint32 lastAccessedBlock, uint24 auctionWins, uint24 auctionFails, uint64 totalGasValueUsed ) { EscrowAccountAccessData memory _aData = S_accessData[account]; bonded = _aData.bonded; lastAccessedBlock = _aData.lastAccessedBlock; auctionWins = _aData.auctionWins; auctionFails = _aData.auctionFails; totalGasValueUsed = _aData.totalGasValueUsed; } function solverOpHashes(bytes32 opHash) external view returns (bool) { return S_solverOpHashes[opHash]; } function cumulativeSurcharge() external view returns (uint256) { return S_cumulativeSurcharge; } function surchargeRecipient() external view returns (address) { return S_surchargeRecipient; } function pendingSurchargeRecipient() external view returns (address) { return S_pendingSurchargeRecipient; } function atlasSurchargeRate() external view returns (uint256) { // Includes only the left 128 bits to isolate the Atlas rate return S_surchargeRates >> 128; } function bundlerSurchargeRate() external view returns (uint256) { // Includes only the right 128 bits to isolate the bundler rate return S_surchargeRates & ((1 << 128) - 1); } // ---------------------------------------------------- // // Storage Internal Getters // // ---------------------------------------------------- // function _surchargeRates() internal view returns (uint256 atlasRate, uint256 bundlerRate) { uint256 _bothRates = S_surchargeRates; atlasRate = _bothRates >> 128; bundlerRate = _bothRates & ((1 << 128) - 1); } // ---------------------------------------------------- // // Transient External Getters // // ---------------------------------------------------- // function lock() external view returns (address activeEnvironment, uint32 callConfig, uint8 phase) { return _lock(); } /// @notice Returns the current lock state of Atlas. /// @return Boolean indicating whether Atlas is in a locked state or not. function isUnlocked() external view returns (bool) { return _isUnlocked(); } /// @notice Returns information about the current state of the solver lock. /// @return currentSolver Address of the current solver. /// @return calledBack Boolean indicating whether the solver has called back via `reconcile`. /// @return fulfilled Boolean indicating whether the solver's outstanding debt has been repaid via `reconcile`. function solverLockData() external view returns (address currentSolver, bool calledBack, bool fulfilled) { return _solverLockData(); } // ---------------------------------------------------- // // Transient Internal Getters // // ---------------------------------------------------- // function _lock() internal view returns (address activeEnvironment, uint32 callConfig, uint8 phase) { uint256 _lockData = t_lock; activeEnvironment = address(uint160(_lockData >> 40)); callConfig = uint32(_lockData >> 8); phase = uint8(_lockData); } function _activeEnvironment() internal view returns (address) { // right shift 40 bits to remove the callConfig and phase, only activeEnvironment remains return address(uint160(t_lock >> 40)); } function _activeCallConfig() internal view returns (uint32) { // right shift 8 bits to remove the phase, cast to uint32 to remove the activeEnvironment return uint32(t_lock >> 8); } function _phase() internal view returns (uint8) { // right-most 8 bits of Lock are the phase return uint8(t_lock); } /// @notice Returns information about the current state of the solver lock. /// @return currentSolver Address of the current solver. /// @return calledBack Boolean indicating whether the solver has called back via `reconcile`. /// @return fulfilled Boolean indicating whether the solver's outstanding debt has been repaid via `reconcile`. function _solverLockData() internal view returns (address currentSolver, bool calledBack, bool fulfilled) { uint256 _solverLock = t_solverLock; currentSolver = address(uint160(_solverLock)); calledBack = _solverLock & _SOLVER_CALLED_BACK_MASK != 0; fulfilled = _solverLock & _SOLVER_FULFILLED_MASK != 0; } function _isUnlocked() internal view returns (bool) { return t_lock == _UNLOCKED; } // ---------------------------------------------------- // // Transient Setters // // ---------------------------------------------------- // function _setLock(address activeEnvironment, uint32 callConfig, uint8 phase) internal { // Pack the lock slot from the right: // [ 56 bits ][ 160 bits ][ 32 bits ][ 8 bits ] // [ unused bits ][ activeEnvironment ][ callConfig ][ phase ] t_lock = uint256(uint160(activeEnvironment)) << 40 | uint256(callConfig) << 8 | uint256(phase); } function _releaseLock() internal { t_lock = _UNLOCKED; } // Sets the Lock phase without changing the activeEnvironment or callConfig. function _setLockPhase(uint8 newPhase) internal { t_lock = (t_lock & _LOCK_PHASE_MASK) | uint256(newPhase); } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import "./ValidCalls.sol"; // NOTE: Internal constants that are defined but not used in the logic of a smart contract, will NOT be included in the // bytecode of the smart contract when compiled. However, public constants will be included in every inheriting contract // as they are part of the ABI. As such, only internal constants are defined in this shared contract. contract AtlasConstants { // ------------------------------------------------------- // // ATLAS CONSTANTS // // ------------------------------------------------------- // // Atlas constants uint256 internal constant _GAS_VALUE_DECIMALS_TO_DROP = 1e9; // measured in gwei uint256 internal constant _UNLOCKED = 0; // Atlas constants used in `_bidFindingIteration()` uint256 internal constant _BITS_FOR_INDEX = 16; uint256 internal constant _FIRST_16_BITS_TRUE_MASK = uint256(0xFFFF); // Escrow constants uint256 internal constant _VALIDATION_GAS_LIMIT = 500_000; uint256 internal constant _FASTLANE_GAS_BUFFER = 125_000; // integer amount uint256 internal constant _GRACEFUL_RETURN_GAS_OFFSET = 40_000; // Gas Accounting constants uint256 internal constant _CALLDATA_LENGTH_PREMIUM_HALVED = 8; // Half of the upper gas cost per byte of calldata // (16 gas). Multiplied by msg.data.length. Equivalent to `msg.data.length / 2 * 16` because 2 hex chars per // byte. uint256 internal constant _BASE_TRANSACTION_GAS_USED = 21_000; uint256 internal constant _SOLVER_OP_BASE_CALLDATA = 608; // SolverOperation calldata length excluding solverOp.data uint256 internal constant _SOLVER_BASE_GAS_USED = 5000; // Base gas charged to solver in `_handleSolverAccounting()` uint256 internal constant _BUNDLER_GAS_PENALTY_BUFFER = 500_000; // First 160 bits of _solverLock are the address of the current solver. // The 161st bit represents whether the solver has called back via `reconcile`. // The 162nd bit represents whether the solver's outstanding debt has been repaid via `reconcile`. uint256 internal constant _SOLVER_CALLED_BACK_MASK = 1 << 161; uint256 internal constant _SOLVER_FULFILLED_MASK = 1 << 162; // Used to set Lock phase without changing the activeEnvironment or callConfig. uint256 internal constant _LOCK_PHASE_MASK = uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00); // ValidCalls error threshold before which the metacall reverts, and after which it returns gracefully to store // nonces as used. uint8 internal constant _GRACEFUL_RETURN_THRESHOLD = uint8(ValidCallsResult.InvertBidValueCannotBeExPostBids) + 1; // ------------------------------------------------------- // // ATLAS VERIFICATION CONSTANTS // // ------------------------------------------------------- // uint8 internal constant _MAX_SOLVERS = type(uint8).max - 1; }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/" ], "optimizer": { "enabled": true, "runs": 50 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"escrowDuration","type":"uint256"},{"internalType":"uint256","name":"atlasSurchargeRate","type":"uint256"},{"internalType":"uint256","name":"bundlerSurchargeRate","type":"uint256"},{"internalType":"address","name":"verification","type":"address"},{"internalType":"address","name":"simulator","type":"address"},{"internalType":"address","name":"initialSurchargeRecipient","type":"address"},{"internalType":"address","name":"l2GasCalculator","type":"address"},{"internalType":"address","name":"factoryLib","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllocateValueDelegatecallFail","type":"error"},{"inputs":[],"name":"AllocateValueFail","type":"error"},{"inputs":[],"name":"AllocateValueSimFail","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlteredControl","type":"error"},{"inputs":[],"name":"AtlasLockActive","type":"error"},{"inputs":[],"name":"BalanceNotReconciled","type":"error"},{"inputs":[{"internalType":"uint256","name":"bidAmount","type":"uint256"}],"name":"BidFindSuccessful","type":"error"},{"inputs":[],"name":"BidNotPaid","type":"error"},{"inputs":[],"name":"BothPreOpsAndUserReturnDataCannotBeTracked","type":"error"},{"inputs":[],"name":"BothUserAndDAppNoncesCannotBeSequential","type":"error"},{"inputs":[],"name":"CallbackNotCalled","type":"error"},{"inputs":[],"name":"DAppNotEnabled","type":"error"},{"inputs":[],"name":"DoubleReconcile","type":"error"},{"inputs":[],"name":"EnvironmentMismatch","type":"error"},{"inputs":[],"name":"EscrowLockActive","type":"error"},{"inputs":[],"name":"ExecutionEnvironmentBalanceTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientAtlETHBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalanceForDeduction","type":"error"},{"inputs":[],"name":"InsufficientEscrow","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InsufficientLocalFunds","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"msgValue","type":"uint256"},{"internalType":"uint256","name":"holds","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientSolverBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"shortfall","type":"uint256"}],"name":"InsufficientTotalBalance","type":"error"},{"inputs":[],"name":"InvalidAccess","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidCodeHash","type":"error"},{"inputs":[],"name":"InvalidControl","type":"error"},{"inputs":[],"name":"InvalidDAppControl","type":"error"},{"inputs":[],"name":"InvalidEntry","type":"error"},{"inputs":[],"name":"InvalidEntryFunction","type":"error"},{"inputs":[],"name":"InvalidEnvironment","type":"error"},{"inputs":[],"name":"InvalidEscrowDuration","type":"error"},{"inputs":[{"internalType":"address","name":"correctEnvironment","type":"address"}],"name":"InvalidExecutionEnvironment","type":"error"},{"inputs":[],"name":"InvalidLockState","type":"error"},{"inputs":[],"name":"InvalidSignatory","type":"error"},{"inputs":[],"name":"InvalidSolver","type":"error"},{"inputs":[{"internalType":"address","name":"solverFrom","type":"address"}],"name":"InvalidSolverFrom","type":"error"},{"inputs":[],"name":"InvalidTo","type":"error"},{"inputs":[],"name":"InvalidUser","type":"error"},{"inputs":[],"name":"InvertBidValueCannotBeExPostBids","type":"error"},{"inputs":[],"name":"InvertedBidExceedsCeiling","type":"error"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"LedgerBalancing","type":"error"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"LedgerFinalized","type":"error"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"MissingFunds","type":"error"},{"inputs":[],"name":"MustBeDelegatecalled","type":"error"},{"inputs":[],"name":"NoAuctionWinner","type":"error"},{"inputs":[],"name":"NoDelegatecall","type":"error"},{"inputs":[],"name":"NoUnfilledRequests","type":"error"},{"inputs":[],"name":"NoUnusedNonceInBitmap","type":"error"},{"inputs":[],"name":"NotEnvironmentOwner","type":"error"},{"inputs":[],"name":"NotImplemented","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"OnlyAtlas","type":"error"},{"inputs":[],"name":"OnlyGovernance","type":"error"},{"inputs":[],"name":"PostOpsDelegatecallFail","type":"error"},{"inputs":[],"name":"PostOpsDelegatecallReturnedFalse","type":"error"},{"inputs":[],"name":"PostOpsFail","type":"error"},{"inputs":[],"name":"PostOpsSimFail","type":"error"},{"inputs":[],"name":"PostSolverFailed","type":"error"},{"inputs":[],"name":"PreOpsDelegatecallFail","type":"error"},{"inputs":[],"name":"PreOpsFail","type":"error"},{"inputs":[],"name":"PreOpsSimFail","type":"error"},{"inputs":[],"name":"PreSolverFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"SignatoryActive","type":"error"},{"inputs":[],"name":"SimulationPassed","type":"error"},{"inputs":[],"name":"SimulatorBalanceTooLow","type":"error"},{"inputs":[],"name":"SolverMustReconcile","type":"error"},{"inputs":[],"name":"SolverOpReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"solverOutcomeResult","type":"uint256"}],"name":"SolverSimFail","type":"error"},{"inputs":[],"name":"SurchargeRateTooHigh","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnbalancedAccounting","type":"error"},{"inputs":[],"name":"UncoveredResult","type":"error"},{"inputs":[],"name":"UnexpectedNonRevert","type":"error"},{"inputs":[],"name":"Unreachable","type":"error"},{"inputs":[],"name":"UserNotFulfilled","type":"error"},{"inputs":[],"name":"UserOpFail","type":"error"},{"inputs":[],"name":"UserOpSimFail","type":"error"},{"inputs":[],"name":"UserOpValueExceedsBalance","type":"error"},{"inputs":[],"name":"UserSimulationFailed","type":"error"},{"inputs":[],"name":"UserSimulationSucceeded","type":"error"},{"inputs":[],"name":"UserUnexpectedSuccess","type":"error"},{"inputs":[],"name":"UserWrapperCallFail","type":"error"},{"inputs":[],"name":"UserWrapperDelegatecallFail","type":"error"},{"inputs":[{"internalType":"enum ValidCallsResult","name":"","type":"uint8"}],"name":"ValidCalls","type":"error"},{"inputs":[{"internalType":"enum ValidCallsResult","name":"","type":"uint8"}],"name":"VerificationSimFail","type":"error"},{"inputs":[],"name":"WrongDepth","type":"error"},{"inputs":[],"name":"WrongPhase","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Bond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"governance","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"DAppDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"oldGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"DAppGovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"executionEnvironment","type":"address"}],"name":"ExecutionEnvironmentCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bundler","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"solverSuccessful","type":"bool"},{"indexed":false,"internalType":"bool","name":"disbursementSuccessful","type":"bool"},{"indexed":false,"internalType":"uint256","name":"ethPaidToBundler","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"netGasSurcharge","type":"uint256"}],"name":"MetacallResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"governance","type":"address"},{"indexed":true,"internalType":"address","name":"signatory","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"NewDAppSignatory","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"control","type":"address"},{"indexed":true,"internalType":"address","name":"governance","type":"address"},{"indexed":true,"internalType":"address","name":"signatory","type":"address"},{"indexed":false,"internalType":"uint32","name":"callConfig","type":"uint32"}],"name":"RemovedDAppSignatory","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"solverTo","type":"address"},{"indexed":true,"internalType":"address","name":"solverFrom","type":"address"},{"indexed":true,"internalType":"address","name":"dAppControl","type":"address"},{"indexed":false,"internalType":"address","name":"bidToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"executed","type":"bool"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"result","type":"uint256"}],"name":"SolverTxResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currentRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"SurchargeRecipientTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"SurchargeRecipientTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SurchargeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"earliestAvailable","type":"uint256"}],"name":"Unbond","type":"event"},{"inputs":[],"name":"ESCROW_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY_LIB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FIXED_GAS_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2_GAS_CALCULATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIMULATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFICATION","outputs":[{"internalType":"contract IAtlasVerification","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accessData","outputs":[{"internalType":"uint112","name":"bonded","type":"uint112"},{"internalType":"uint32","name":"lastAccessedBlock","type":"uint32"},{"internalType":"uint24","name":"auctionWins","type":"uint24"},{"internalType":"uint24","name":"auctionFails","type":"uint24"},{"internalType":"uint64","name":"totalGasValueUsed","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountLastActiveBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"atlasSurchargeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfBonded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfUnbonding","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"becomeSurchargeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"bond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bondedTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"bundlerSurchargeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contribute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"createExecutionEnvironment","outputs":[{"internalType":"address","name":"executionEnvironment","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cumulativeSurcharge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToBond","type":"uint256"}],"name":"depositAndBond","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint32","name":"solverGasLimit","type":"uint32"}],"internalType":"struct DAppConfig","name":"dConfig","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"dapp","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"address","name":"sessionKey","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SolverOperation[]","name":"solverOps","type":"tuple[]"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"address","name":"bundler","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bool","name":"isSimulation","type":"bool"}],"name":"execute","outputs":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"uint24","name":"solverOutcome","type":"uint24"},{"internalType":"uint8","name":"solverIndex","type":"uint8"},{"internalType":"uint8","name":"solverCount","type":"uint8"},{"internalType":"uint8","name":"callDepth","type":"uint8"},{"internalType":"uint8","name":"phase","type":"uint8"},{"internalType":"bool","name":"solverSuccessful","type":"bool"},{"internalType":"bool","name":"paymentsSuccessful","type":"bool"},{"internalType":"bool","name":"bidFind","type":"bool"},{"internalType":"bool","name":"isSimulation","type":"bool"},{"internalType":"address","name":"bundler","type":"address"}],"internalType":"struct Context","name":"ctx","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"getExecutionEnvironment","outputs":[{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock","outputs":[{"internalType":"address","name":"activeEnvironment","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"uint8","name":"phase","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"dapp","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"uint32","name":"callConfig","type":"uint32"},{"internalType":"address","name":"sessionKey","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SolverOperation[]","name":"solverOps","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"control","type":"address"},{"internalType":"address","name":"bundler","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"callChainHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct DAppOperation","name":"dAppOp","type":"tuple"},{"internalType":"address","name":"gasRefundBeneficiary","type":"address"}],"name":"metacall","outputs":[{"internalType":"bool","name":"auctionWon","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingSurchargeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxApprovedGasSpend","type":"uint256"}],"name":"reconcile","outputs":[{"internalType":"uint256","name":"owed","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAtlasRate","type":"uint256"},{"internalType":"uint256","name":"newBundlerRate","type":"uint256"}],"name":"setSurchargeRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shortfall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"uint24","name":"solverOutcome","type":"uint24"},{"internalType":"uint8","name":"solverIndex","type":"uint8"},{"internalType":"uint8","name":"solverCount","type":"uint8"},{"internalType":"uint8","name":"callDepth","type":"uint8"},{"internalType":"uint8","name":"phase","type":"uint8"},{"internalType":"bool","name":"solverSuccessful","type":"bool"},{"internalType":"bool","name":"paymentsSuccessful","type":"bool"},{"internalType":"bool","name":"bidFind","type":"bool"},{"internalType":"bool","name":"isSimulation","type":"bool"},{"internalType":"address","name":"bundler","type":"address"}],"internalType":"struct Context","name":"ctx","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"address","name":"control","type":"address"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"bidToken","type":"address"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SolverOperation","name":"solverOp","type":"tuple"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"solverCall","outputs":[{"components":[{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"uint256","name":"floor","type":"uint256"},{"internalType":"uint256","name":"ceiling","type":"uint256"},{"internalType":"bool","name":"etherIsBidToken","type":"bool"},{"internalType":"bool","name":"invertsBidValue","type":"bool"}],"internalType":"struct SolverTracker","name":"solverTracker","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"solverLockData","outputs":[{"internalType":"address","name":"currentSolver","type":"address"},{"internalType":"bool","name":"calledBack","type":"bool"},{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"opHash","type":"bytes32"}],"name":"solverOpHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"surchargeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"transferDAppERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"transferSurchargeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"control","type":"address"}],"name":"transferUserERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unbond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unbondingCompleteBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawSurcharge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
610140604052348015610010575f5ffd5b5060405161600138038061600183398101604081905261002f916101cc565b6001600160a01b0380861660805280851660a052821660c05260e0889052808888888888888886868686868686868686868686868686868686868686868686868686868686868686866001600160801b0386118061009357506001600160801b0385115b156100b1576040516359b9784760e01b815260040160405180910390fd5b608086901b851760025534600355600480546001600160a01b0319166001600160a01b0384169081179091556040517f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde43985905f90a25050505050505050505050505050505050505050505050505050505050505050505050865f036101485760405163b4ff4a4d60e01b815260040160405180910390fd5b5050506001600160a01b0385166101005250506040516101869250469150309060200191825260601b6001600160601b031916602082015260340190565b60408051601f198184030181529190528051602090910120610120525061024a975050505050505050565b80516001600160a01b03811681146101c7575f5ffd5b919050565b5f5f5f5f5f5f5f5f610100898b0312156101e4575f5ffd5b885160208a015160408b01519199509750955061020360608a016101b1565b945061021160808a016101b1565b935061021f60a08a016101b1565b925061022d60c08a016101b1565b915061023b60e08a016101b1565b90509295985092959890939650565b60805160a05160c05160e0516101005161012051615d0e6102f35f395f6139bb01525f818161055a0152613a3801525f818161080301528181611041015281816120ea01528181612fcc01526138ac01525f818161042f015281816109ff01528181610a41015281816147d8015261483101525f818161062b01528181610af20152611be901525f81816105f801528181610b4301528181613ada0152613d7e0152615d0e5ff3fe608060405260043610610251575f3560e01c80638380edb711610137578063c41d54da116100af578063c41d54da146108da578063c5471d9e146108ee578063c5ebeaec14610902578063d0e30db014610915578063d1c23acf1461091d578063d7bb99ba1461093a578063db006a7514610942578063eced552614610961578063f05f88e014610977578063f68b84f71461098a578063f83d08ba1461099d578063fc61c541146109de575f5ffd5b80638380edb714610727578063890c28541461073b5780638ebf091f1461074f57806395d89b4114610763578063966a1f9a146107945780639940686e146107b4578063a0531b02146107d3578063a6efccf9146107f2578063a98efd6714610825578063aa7d2dc81461083c578063aebaa5f714610877578063b2c5c510146108bb575f5ffd5b80635cd6ef67116101ca5780635cd6ef671461041e5780635e8edccc1461045e57806367f7c8e0146105495780636ef5ac7a1461057c57806370a08231146105aa578063791ae748146105e757806379b797651461061a57806379efd1841461064d5780637c20857a1461066d5780637c3c3160146106ae5780637e29c684146106cb578063825ad607146106ea575f5ffd5b806219f2741461025c57806306fdde03146102855780630baf1745146102c657806318160ddd146102e957806319b1faef146102fc578063234b7ede1461031057806327de9e32146103315780632e1a7d4d14610350578063313ce5671461036f5780634511290614610395578063522bc026146103e05780635270182c146103ff575f5ffd5b3661025857005b5f5ffd5b348015610267575f5ffd5b506102726201d4c081565b6040519081526020015b60405180910390f35b348015610290575f5ffd5b506102b960405180604001604052806009815260200168082e8d8c2e6408aa8960bb1b81525081565b60405161027c9190614983565b6102d96102d4366004614a12565b6109fb565b604051901515815260200161027c565b3480156102f4575f5ffd5b505f54610272565b348015610307575f5ffd5b50610272610e8a565b34801561031b575f5ffd5b5061032f61032a366004614abc565b610eb7565b005b34801561033c575f5ffd5b5061032f61034b366004614b12565b610f02565b34801561035b575f5ffd5b5061032f61036a366004614b12565b610f17565b34801561037a575f5ffd5b50610383601281565b60405160ff909116815260200161027c565b3480156103a0575f5ffd5b506103b46103af366004614b29565b610f33565b604080516001600160a01b03909416845263ffffffff909216602084015215159082015260600161027c565b3480156103eb575f5ffd5b5061032f6103fa366004614b6d565b610fbb565b34801561040a575f5ffd5b50610272610419366004614b8d565b611008565b348015610429575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b60405161027c9190614ba8565b348015610469575f5ffd5b50610501610478366004614b8d565b6001600160a01b03165f90815260076020908152604091829020825160a08101845290546001600160701b038116808352600160701b820463ffffffff16938301849052600160901b820462ffffff908116958401869052600160a81b83041660608401819052600160c01b9092046001600160401b0316608090930183905294929392909190565b604080516001600160701b03909616865263ffffffff909416602086015262ffffff928316938501939093521660608301526001600160401b0316608082015260a00161027c565b348015610554575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b348015610587575f5ffd5b506102d9610596366004614b12565b5f9081526008602052604090205460ff1690565b3480156105b5575f5ffd5b506102726105c4366004614b8d565b6001600160a01b03165f908152600660205260409020546001600160701b031690565b3480156105f2575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b348015610625575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b61066061065b366004614c7f565b61106d565b60405161027c9190614e74565b348015610678575f5ffd5b50610272610687366004614b8d565b6001600160a01b03165f90815260076020526040902054600160701b900463ffffffff1690565b3480156106b9575f5ffd5b506005546001600160a01b0316610451565b3480156106d6575f5ffd5b506104516106e5366004614b29565b611160565b3480156106f5575f5ffd5b50610272610704366004614b8d565b6001600160a01b03165f908152600760205260409020546001600160701b031690565b348015610732575f5ffd5b505f5c156102d9565b348015610746575f5ffd5b50600154610272565b34801561075a575f5ffd5b5061032f61121b565b34801561076e575f5ffd5b506102b9604051806040016040528060068152602001650c2e8d88aa8960d31b81525081565b6107a76107a2366004614ef4565b61128f565b60405161027c9190615084565b3480156107bf575f5ffd5b5061032f6107ce366004614b12565b6116d4565b3480156107de575f5ffd5b5061032f6107ed366004614b8d565b6116de565b3480156107fd575f5ffd5b506102727f000000000000000000000000000000000000000000000000000000000000000081565b348015610830575f5ffd5b5060025460801c610272565b348015610847575f5ffd5b5061085061173c565b604080516001600160a01b039094168452911515602084015215159082015260600161027c565b348015610882575f5ffd5b50610272610891366004614b8d565b6001600160a01b03165f90815260066020526040902054600160701b90046001600160701b031690565b3480156108c6575f5ffd5b5061032f6108d5366004614abc565b611752565b3480156108e5575f5ffd5b5061032f611770565b3480156108f9575f5ffd5b50600354610272565b61032f610910366004614b12565b6117c2565b61032f611895565b348015610928575f5ffd5b506002546001600160801b0316610272565b61032f6118a1565b34801561094d575f5ffd5b5061032f61095c366004614b12565b6118d9565b34801561096c575f5ffd5b506102726298968081565b61032f610985366004614b12565b6118eb565b610272610998366004614b12565b6118f5565b3480156109a8575f5ffd5b506109b1611a17565b604080516001600160a01b03909416845263ffffffff909216602084015260ff169082015260600161027c565b3480156109e9575f5ffd5b506004546001600160a01b0316610451565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610ac2576040516336d2da6b60e21b81523660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063db4b69ac90602401602060405180830381865afa158015610a8e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab29190615092565b5a610abd91906150bd565b610ae5565b610acd6008366150d0565b6152085a610adb91906150bd565b610ae591906150bd565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145f81610b1f5733610b2f565b610b2f60c0870160a08801614b8d565b90505f5f610b3c8b611a2d565b915091505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ab0a4b96838e8e8e8e348b8d6040518963ffffffff1660e01b8152600401610b9b9897969594939291906153d7565b6020604051808303815f875af1158015610bb7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdb91906154ed565b90505f81601d811115610bf057610bf061550b565b14610c8f578415610c1f5780604051634e47c97160e01b8152600401610c16919061551f565b60405180910390fd5b610c2b60096001615545565b60ff1681601d811115610c4057610c4061550b565b60ff1610158015610c615750610c5f826020015163ffffffff16611b00565b155b15610c74575f9650505050505050610e81565b80604051631eb2e74960e01b8152600401610c16919061551f565b50610c9a8183611b20565b610ca385611b55565b306001600160a01b03166379efd184828d8d8d87898f60c001358c6040518963ffffffff1660e01b8152600401610ce198979695949392919061555e565b610180604051808303815f875af1925050508015610d1c575060408051601f3d908101601f19168201909252610d19918101906155f3565b60015b610de0573d808015610d49576040519150601f19603f3d011682016040523d82523d5f602084013e610d4e565b606091505b50610d5d818360200151611bd3565b610d676008611cf5565b3415610d7757610d773334611d08565b610d8460208d018d614b8d565b604080515f80825260208201819052818301819052606082015290516001600160a01b03929092169133917fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff063919081900360800190a350610e73565b5f5f610df783856060015163ffffffff168c611d21565b60e08501519a509092509050610e1060208f018f614b8d565b610100840151604080518c1515815291151560208301528101849052606081018390526001600160a01b03919091169033907fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff0639060800160405180910390a35050505b610e7b611eb6565b50505050505b95945050505050565b5f5f610e94611ebd565b905060085c808211610ea6575f610eb0565b610eb081836156dc565b9250505090565b610eef828260806020600860025b60ff166001901b60016008811115610edf57610edf61550b565b60ff166001901b17171717611ee6565b610efb85838686611f7a565b5050505050565b610f0a611fc9565b610f143382611fe9565b50565b610f1f611fc9565b610f29338261213e565b610f143382611d08565b5f5f5f836001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9691906156ef565b9150610fa38585846121a0565b95919450506001600160a01b0385163b151592509050565b610fc3612219565b6001600160801b03821180610fde57506001600160801b0381115b15610ffc576040516359b9784760e01b815260040160405180910390fd5b60809190911b17600255565b6001600160a01b0381165f90815260076020526040812054600160701b900463ffffffff1680820361103c57505f92915050565b6110667f0000000000000000000000000000000000000000000000000000000000000000826150bd565b9392505050565b6110756148c4565b33301461109557604051633006171960e21b815260040160405180910390fd5b6110a28584868986612244565b905060606110b98a6020015163ffffffff166122be565b156110cc576110c9828b8b6122c6565b90505b6110d8828b8b8461242e565b90505f6110ee8b6020015163ffffffff16612602565b61110557611100838c8c8c8c8761260a565b611113565b611113838c8c8c8c87612705565b90508260e001511561112b5761112b838c83856129d1565b61113e8b6020015163ffffffff16612b37565b1561115257611152838460e0015184612b3f565b505098975050505050505050565b5f336001600160a01b038416148015906111835750336001600160a01b03831614155b156111a0576040516282b42960e81b815260040160405180910390fd5b5f826001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111dd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061120191906156ef565b905061120e848483612c50565b949350505050565b905090565b6005546001600160a01b0316331461124657604051633006171960e21b815260040160405180910390fd5b60048054336001600160a01b031991821681179092556005805490911690556040517f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde43985905f90a2565b611297614927565b3330146112b75760405163887efaa560e01b815260040160405180910390fd5b60605f6112c76020880188614b8d565b6001600160a01b03168060015d506112e560e0880160c08901614b8d565b6002805c6001600160a01b0319166001600160a01b03831617905d5061130b6003611cf5565b87602001516001600160a01b031686888787604051602401611330949392919061570a565b60408051601f198184030181529190526020810180516001600160e01b03166001626c60f760e01b03191790526113688a6003612ca9565b60405160200161137992919061574c565b60408051601f198184030181529082905261139391615760565b5f604051808303815f865af19150503d805f81146113cc576040519150601f19603f3d011682016040523d82523d5f602084013e6113d1565b606091505b5092509050806113e357815160208301fd5b818060200190518101906113f7919061576b565b92506114036004611cf5565b6114108760400135612d33565b61142d57604051631217157160e31b815260040160405180910390fd5b61152a5a604089013561144360208b018b614b8d565b60208c015161145a6101408d016101208e01614b8d565b8b6114696101608f018f6157e7565b61147c5f5c60081c63ffffffff16612d70565b61149357604080515f8152602081019091526114c9565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050505b6040516024016114df9796959493929190615829565b60408051601f198184030181529190526020810180516001600160e01b0316630120c0d360e11b17905261151960e08c0160c08d01614b8d565b6001600160a01b0316929190612d78565b90508061154a57604051630357b89960e61b815260040160405180910390fd5b6115546005611cf5565b87602001516001600160a01b0316878686866040516024016115799493929190615884565b60408051601f198184030181529190526020810180516001600160e01b0316634667020160e11b1790526115ae8a6005612ca9565b6040516020016115bf92919061574c565b60408051601f19818403018152908290526115d991615760565b5f604051808303815f865af19150503d805f8114611612576040519150601f19603f3d011682016040523d82523d5f602084013e611617565b606091505b50925090508061162957815160208301fd5b8180602001905181019061163d919061576b565b92505f5f611649612d90565b92509250508161166c57604051638ac3609160e01b815260040160405180910390fd5b8015801561167f575061167d612daa565b155b1561169d57604051631d75534f60e01b815260040160405180910390fd5b896101200151156116c757845160405163304680d760e01b81526004810191909152602401610c16565b5050505095945050505050565b610f143382612dbd565b6116e6612219565b600454600580546001600160a01b0319166001600160a01b0384811691821790925560405191909216919082907ffc722bcd56a71612cd14b287fbf50545429e6c9e8de86ea7c3febdecd34882fd905f90a35050565b5f5f5f611747612d90565b925092509250909192565b61176482826080604060206003610ec5565b610efb85828686611f7a565b611778612219565b600380545f90915561178a3382611d08565b60405181815233907f87fa2ce024d3bdae31517696c13905fc0882bc1b4f4508060eb29358056de22b9060200160405180910390a250565b805f036117cc5750565b5f5c602881901c906001600160a01b03821633146117ff57816040516346ba7eb160e11b8152600401610c169190614ba8565b600460ff82161115611824576040516338961af360e21b815260040160405180910390fd5b5f61182d612d90565b509150508015611850576040516338961af360e21b815260040160405180910390fd5b61185984612d33565b1561186d576118683385611d08565b61188f565b60405163029d54f560e21b815247600482015260248101859052604401610c16565b50505050565b61189f3334612ee2565b565b5f5c60281c336001600160a01b038216146118d157806040516346ba7eb160e11b8152600401610c169190614ba8565b610f14612f90565b6118e1611fc9565b610f143382612fae565b6116d43334612ee2565b5f6004815c60ff161461191b576040516338961af360e21b815260040160405180910390fd5b336001600160a01b0360025c161461194657604051633006171960e21b815260040160405180910390fd5b5f5f5f611951612d90565b6001600160a01b0383165f9081526007602052604090205492955090935091506001600160701b031680861115611986578095505b5f61198f611ebd565b90505f61199e3460085c6150bd565b905034156119ad57808060085d505b6119b788826150bd565b8211156119ef57846119d9576001600160a01b038616600160a11b178060015d505b6119e381836156dc565b98975050505050505050565b83611a0a57600360a11b6001600160a01b038716178060015d505b505f979650505050505050565b5f8080805c602881901c90600881901c90611747565b604080516080810182525f8082526020820181905291810182905260608101829052611a6161012084016101008501614b8d565b6001600160a01b03166344912b6e846040518263ffffffff1660e01b8152600401611a8c91906158b9565b608060405180830381865afa158015611aa7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb91906158cb565b9050611af9611add6020850185614b8d565b611aef61012086016101008701614b8d565b8360200151612c50565b9150915091565b5f600a5b63ffffffff166001901b8263ffffffff16165f14159050919050565b5f5c15611b3f5760405162dc149f60e41b815260040160405180910390fd5b6020820151611b519082906001613130565b5050565b5f3a611b64836201d4c06150bd565b611b6e91906150d0565b90505f5f611b7a61315c565b9092509050611b898382613173565b8060045d50611b988383613196565b8060055d50348060085d505f8060065d505f8060075d505f8060035d505f8060015d505f6002805c6001600160a01b031916905d5050505050565b5f611bdd83615932565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163303611cba57631b63f4db60e01b6001600160e01b0319821601611c4857825183015160405163e49c0b2560e01b815260048101829052602401610c16565b6001600160e01b03198116635933e62b60e11b1480611c7757506001600160e01b0319811663bdc56ad160e01b145b80611c9257506001600160e01b0319811663a695d44360e01b145b80611cad57506001600160e01b03198116635fd307e960e11b145b15611cba57805f5260045ffd5b6001600160e01b03198116634011dcb760e11b1480611ce35750611ce38263ffffffff16611b00565b15611cf057805f5260045ffd5b505050565b8060ff1660ff195f5c16175f81905d5050565b5f385f3884865af1611b515763b12d13eb5f526004601cfd5b5f5f5f611d2c612d90565b50909150506001600160a01b038416611d485785610160015193505b5f808060085c611d588a8a6131a5565b9850909550935091505f8080611d6e86886156dc565b905084841015611d8957611d8284866156dc565b9250611d96565b611d9385856156dc565b91505b8c60e001518015611dbe57508c61016001516001600160a01b0316886001600160a01b031614155b15611dd757611dcd81846150bd565b9250809950611e04565b8c61016001516001600160a01b0316886001600160a01b031603611dfd575f9950611e04565b5f99508a97505b81831115611e78578c60e00151611e3b57611e1f82846156dc565b6040516306de921b60e51b8152600401610c1691815260200190565b5f611e5289611e4a85876156dc565b84600161334d565b90508a811115611e6657611e1f8b826156dc565b611e70818c6156dc565b9a5050611e8c565b611e8c88611e8685856156dc565b8361363a565b611e966008611cf5565b8915611ea657611ea68b8b611d08565b5050505050505050935093915050565b5f80805d50565b5f60065c60055c611ed260045c60075c6150bd565b611edc91906150bd565b61121691906156dc565b5f5c602881901c90600881901c90336001600160a01b03841614611f1d57604051631e6d8cfb60e21b815260040160405180910390fd5b611f29338787856137c8565b611f46576040516343fcae1b60e01b815260040160405180910390fd5b8360ff168160ff166001901b165f03611f7257604051630106530b60e21b815260040160405180910390fd5b505050505050565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716611fbc57637939f4245f526004601cfd5b5f60605260405250505050565b5f5c1561189f57604051630106530b60e21b815260040160405180910390fd5b5f611ff3826137f2565b6001600160a01b0384165f908152600760205260408120805492935091839183916120289084906001600160701b0316615970565b82546101009290920a6001600160701b03818102199093169183160217909155825463ffffffff60701b1916600160701b4363ffffffff1681029190911784556001600160a01b0387165f90815260066020526040902080548694509092600e926120989286929190041661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550836001600160a01b03167f7659747cd8571f1071eea946fdc648adcf181cad916f32a05f82c3a525976048847f00000000000000000000000000000000000000000000000000000000000000004361211491906150bd565b61211f9060016150bd565b604080519283526020830191909152015b60405180910390a250505050565b6121488282613829565b805f5f82825461215891906156dc565b90915550506040518181526001600160a01b038316907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5906020015b60405180910390a25050565b5f5f6121ad8585856139b5565b90505f6121f9868686856040516024016121ca94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b031663d447616160e01b179052613a32565b90508080602001905181019061220f91906159dd565b9695505050505050565b6004546001600160a01b0316331461189f57604051633006171960e21b815260040160405180910390fd5b61224c6148c4565b5060408051610180810182529485526001600160a01b0395861660208601525f9085018190526060850181905260ff92909216608085015260a08401829052600160c085015260e084018290526101008401829052610120840191909152151561014083015290911661016082015290565b5f6002611b04565b606060016122d381611cf5565b5f5f86602001516001600160a01b0316856040516024016122f491906158b9565b60408051601f198184030181529190526020810180516001600160e01b0316630e75dff560e21b179052612329896001612ca9565b60405160200161233a92919061574c565b60408051601f198184030181529082905261235491615760565b5f604051808303815f865af19150503d805f811461238d576040519150601f19603f3d011682016040523d82523d5f602084013e612392565b606091505b509150915081156123e9576123b0866020015163ffffffff16613abd565b156123d257808060200190518101906123c991906159f8565b93505050612426565b5050604080515f8152602081019091529150612426565b8661014001511561240d57604051635933e62b60e11b815260040160405180910390fd5b604051635b47d49f60e11b815260040160405180910390fd5b509392505050565b6060600261243b81611cf5565b5f60605f619c4060405a61245090603f6150d0565b61245a9190615a8a565b61246491906156dc565b905080876060013510612477578061247d565b86606001355b905061248c8760400135612d33565b6124a957604051631217157160e31b815260040160405180910390fd5b88602001516001600160a01b031687604001358290896040516024016124cf91906158b9565b60408051601f198184030181529190526020810180516001600160e01b031663a395822560e01b1790526125048d6002612ca9565b60405160200161251592919061574c565b60408051601f198184030181529082905261252f91615760565b5f60405180830381858888f193505050503d805f811461256a576040519150601f19603f3d011682016040523d82523d5f602084013e61256f565b606091505b50909350915082156125bc5761258e886020015163ffffffff16613ac5565b156125b157818060200190518101906125a791906159f8565b94505050506125f9565b8594505050506125f9565b886101400151156125e05760405163bdc56ad160e01b815260040160405180910390fd5b604051639f885ee560e01b815260040160405180910390fd5b50949350505050565b5f6013611b04565b5f80835b8060ff16896060015160ff161015612695573686868b6060015160ff1681811061263a5761263a615aa9565b905060200281019061264c9190615abd565b90506126628a8a8a848561014001355f8b613acd565b92508960e00151156126795782935050505061220f565b506060890180519061268a82615adc565b60ff1690525061260e565b886101400151156126c657886040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6126d9886020015163ffffffff16613d6d565b156126f757604051634011dcb760e11b815260040160405180910390fd5b505f98975050505050505050565b5f8280820361276e57876101400151156127345760405163e49c0b2560e01b81525f6004820152602401610c16565b612747876020015163ffffffff16613d6d565b1561276557604051634011dcb760e11b815260040160405180910390fd5b5f91505061220f565b60016101208901525f816001600160401b0381111561278f5761278f614bbc565b6040519080825280602002602001820160405280156127b8578160200160208202803683370190505b5090505f806127c86001856156dc565b90505f5a90505f5b8581101561285c576128088d8d8d8d8d868181106127f0576127f0615aa9565b90506020028101906128029190615abd565b8c613d75565b9350831580159061282057506001600160f01b038411155b15612854578061ffff16601085901b1785848151811061284257612842615aa9565b60209081029190910101525f19909201915b6001016127d0565b506128686001866156dc565b915061287384613fc1565b5f6101208d015261288d5a61288890836156dc565b614016565b815b60108582815181106128a3576128a3615aa9565b6020026020010151901c9350835f031561295d576128c181846156dc565b60ff1660608e015284515f9061ffff908790849081106128e3576128e3615aa9565b60200260200101511660ff1690506129248e8e8e8e8e8681811061290957612909615aa9565b905060200281019061291b9190615abd565b8960018f613acd565b94508d60e001511561293f578497505050505050505061220f565b815f0361294c575061295d565b5061295681615afa565b905061288f565b508b61014001511561298f578b6040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6129a28b6020015163ffffffff16613d6d565b156129c057604051634011dcb760e11b815260040160405180910390fd5b505f9b9a5050505050505050505050565b60066129dc81611cf5565b5f5f86602001516001600160a01b031686604001518686604051602401612a0593929190615b0f565b60408051601f198184030181529190526020810180516001600160e01b0316630b65dadf60e11b179052612a3a896006612ca9565b604051602001612a4b92919061574c565b60408051601f1981840301815290829052612a6591615760565b5f604051808303815f865af19150503d805f8114612a9e576040519150601f19603f3d011682016040523d82523d5f602084013e612aa3565b606091505b50915091508115612ac55780806020019051810190612ac29190615b35565b91505b81158015612ae35750612ae1866020015163ffffffff1661404a565b155b15612b245786610140015115612b0c5760405163a695d44360e01b815260040160405180910390fd5b60405162d14f5160e11b815260040160405180910390fd5b5015156101009095019490945250505050565b5f6008611b04565b6007612b4a81611cf5565b5f84602001516001600160a01b03168484604051602401612b6c929190615b50565b60408051601f198184030181529190526020810180516001600160e01b031663b1d5b5a360e01b179052612ba1876007612ca9565b604051602001612bb292919061574c565b60408051601f1981840301815290829052612bcc91615760565b5f604051808303815f865af19150503d805f8114612c05576040519150601f19603f3d011682016040523d82523d5f602084013e612c0a565b606091505b5050905080610efb5784610140015115612c3757604051635fd307e960e11b815260040160405180910390fd5b6040516333c0622b60e11b815260040160405180910390fd5b5f5f612c5d8585856139b5565b90505f6121f986868685604051602401612c7a94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b0316630cfce7b160e11b179052613a32565b6060816008811115612cbd57612cbd61550b565b60ff1660c084015261016083015160e084015161010085015160608601516080870151866008811115612cf257612cf261550b565b6040808a01516101208b01516101408c01519251612d1c9998979695949390600190602001615b7b565b604051602081830303815290604052905092915050565b5f815f03612d4357506001919050565b81471015612d5257505f919050565b8160075f612d6183835c6150bd565b92505081905d50600192915050565b5f600f611b04565b5f5f5f5f845160208601878a8af19695505050505050565b60015c90600160a11b8216151590600160a21b8316151590565b5f612db3611ebd565b60085c1015905090565b5f612dc7826137f2565b6001600160a01b0384165f90815260066020526040812080549293508392909190612dfc9084906001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550815f5f828254612e3091906156dc565b90915550506001600160a01b0383165f9081526007602052604081208054839290612e659084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508160015f828254612e9a91906150bd565b90915550506040518281526001600160a01b038416907f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d9060200160405180910390a2505050565b805f5f828254612ef291906150bd565b90915550612f019050816137f2565b6001600160a01b0383165f9081526006602052604081208054909190612f319084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161219491815260200190565b341561189f573460085f612fa583835c6150bd565b92505081905d50565b6001600160a01b0382165f90815260076020526040902054612ffe907f000000000000000000000000000000000000000000000000000000000000000090600160701b900463ffffffff166150bd565b431161301d5760405163078e135760e51b815260040160405180910390fd5b5f613027826137f2565b6001600160a01b0384165f90815260066020526040902080549192509082908290600e90613066908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508260015f82825461309b91906156dc565b90915550508054829082905f906130bc9084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550825f5f8282546130f091906150bd565b90915550506040518381526001600160a01b038516907f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a690602001612130565b600160281b600160c81b03602884901b1664ffffffff00600884901b161760ff821617805f5d50505050565b600254608081901c916001600160801b0390911690565b5f6298968061318283826150bd565b61318c90856150d0565b6110669190615a8a565b5f6298968061318c83856150d0565b60035460075c9060045c9060065c905f9060055c82806131c361315c565b915091505f5a90505f6131d63a836150d0565b90506131e28184613173565b6131ec908a6156dc565b98508b60e001511561322c576132028185613196565b61320c90866156dc565b9650613218878b6150bd565b995061322487876150bd565b6003556132b6565b60035c80156132aa5761324b8561324386826150bd565b839190614052565b97505f61325889836156dc565b90505f61326d6132688d88614068565b614083565b90508082111561328e5761328181836156dc565b61328b908b6150bd565b99505b6132988a8e6150bd565b9c506132a48a8a6150bd565b60035550505b50505050505050613344565b60808c015160ff161561333d575f6132ce8a85614068565b90505f6207a1208e606001518f608001516132e99190615c1c565b6132f69060ff168f6150d0565b61330091906150bd565b90508084111561333a575f8461331683856150d0565b6133209190615a8a565b61332a90846156dc565b9050613336818c6150bd565b9a50505b50505b5050505050505b92959194509250565b5f5f613358856137f2565b6001600160a01b0387165f90815260076020908152604091829020825160a08101845290546001600160701b0380821680845263ffffffff600160701b8404169484019490945262ffffff600160901b8304811695840195909552600160a81b820490941660608301526001600160401b03600160c01b909104166080820152929350908316111561350f576001600160a01b0387165f9081526006602090815260408083208151808301909252546001600160701b038082168352600160701b9091048116928201839052845191939261343692909116906150bd565b905080846001600160701b031611156134a95761345381896156dc565b6001600160a01b038a165f90815260066020819052604082208054600160701b600160e01b031916905581865291965086919061349183835c6150bd565b92505081905d506134a285896156dc565b9750613508565b6134c46134bf6001600160701b038616836156dc565b6137f2565b6001600160a01b038a165f90815260066020526040812080546001600160701b0393909316600160701b02600160701b600160e01b03199093169290921790915583525b505061352d565b81815f018181516135209190615970565b6001600160701b03169052505b6135428185801561353c575084155b876140a5565b63ffffffff43811660208084019182526001600160a01b038a165f9081526007909152604080822085518154945192870151606088015160808901516001600160401b0316600160c01b026001600160c01b0362ffffff928316600160a81b0262ffffff60a81b1993909416600160901b029290921665ffffffffffff60901b1996909916600160701b026001600160901b03199098166001600160701b03909416939093179690961793909316959095179190911792909216929092179055600180548892906136149084906156dc565b9091555086905060085f61362983835c6150bd565b92505081905d505050949350505050565b6001600160a01b0383165f90815260076020908152604091829020825160a08101845290546001600160701b0381168252600160901b810462ffffff90811694830194909452600160a81b81049093166060820152600160c01b9092046001600160401b0316608083015263ffffffff4316908201526136b9836137f2565b815182906136c890839061598f565b6001600160701b0316905250600180548491905f906136e89084906150bd565b909155506136fa9050816001846140a5565b6001600160a01b0384165f908152600760208181526040808420855181549387015192870151606088015160808901516001600160701b039093166001600160901b031990961695909517600160701b63ffffffff909516949094029390931765ffffffffffff60901b1916600160901b62ffffff9485160262ffffff60a81b191617600160a81b9390941692909202929092176001600160c01b0316600160c01b6001600160401b039092169190910217905584916137bb83835c6150bd565b92505081905d5050505050565b5f6137d48484846121a0565b6001600160a01b0316856001600160a01b0316149050949350505050565b5f6001600160701b03821115613825576040516306dfcc6560e41b81526070600482015260248101839052604401610c16565b5090565b5f613833826137f2565b6001600160a01b0384165f9081526006602052604090208054919250906001600160701b03908116908316811061388e5761386e8382615970565b82546001600160701b0319166001600160701b0391909116178255610efb565b6001600160a01b0385165f908152600760205260409020546138de907f000000000000000000000000000000000000000000000000000000000000000090600160701b900463ffffffff166150bd565b43111561398a575f6138f08285615970565b83546001600160701b03191680855590915081908490600e90613924908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505f816001600160701b03169050805f5f82825461396591906150bd565b925050819055508060015f82825461397d91906156dc565b90915550610efb92505050565b6040516307d2457d60e21b81526001600160701b038216600482015260248101859052604401610c16565b604080517f0000000000000000000000000000000000000000000000000000000000000000602080830191909152606095861b6001600160601b0319908116838501529490951b909316605484015260e09190911b6001600160e01b03191660688301528051604c818403018152606c9092019052805191012090565b60605f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031684604051613a6e9190615760565b5f60405180830381855af49150503d805f8114613aa6576040519150601f19603f3d011682016040523d82523d5f602084013e613aab565b606091505b50915091508161106657805160208201fd5b5f6003611b04565b5f6004611b04565b5f5f5a90505f84613bae577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639f7e72b6888c5f01518b608001358e6101600151613b2a8f6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613b4a959493929190615c35565b602060405180830381865afa158015613b65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b899190615092565b9050613bab613ba061014089016101208a01614b8d565b8a6040015183614111565b90505b80613cb3575f613bc08a89858561413d565b9092509050613bcf888b614246565b82179150613be08a878b8b866142d8565b915081613cb157613bef614927565b613bfc8c8a8a858a61431a565b909350905082613caf578a516001600160a01b0316613c1e60208b018b614b8d565b6001600160a01b0316613c3760e08c0160c08d01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613c736101408e016101208f01614b8d565b8c6001808a604051613c89959493929190615c76565b60405180910390a4600160e08d015262ffffff90921660408c015250519150613d629050565b505b505b62ffffff811660408b0152613ccb8783838815614550565b88516001600160a01b0316613ce36020890189614b8d565b6001600160a01b0316613cfc60e08a0160c08b01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613d386101408c016101208d01614b8d565b8a62fe0000871615155f88604051613d54959493929190615c76565b60405180910390a45f925050505b979650505050505050565b5f6010611b04565b5f5f5a90505f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639f7e72b6878b5f01518a608001358d6101600151613dce8e6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613dee959493929190615c35565b602060405180830381865afa158015613e09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e2d9190615092565b9050613e4f613e4461014088016101208901614b8d565b896040015183614111565b9050613e5d8887858461413d565b92509050613e6b8689614246565b178015613e7d575f9350505050610e81565b613e90886020015163ffffffff16614109565b15613eae57613e9f8787614640565b613eae575f9350505050610e81565b5f5f306001600160a01b031684306001600160a01b031663966a1f9a8e8c8d61014001358d604051602401613ee69493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b939093179092529051613f1e9250615760565b5f604051808303815f8787f1925050503d805f8114613f58576040519150601f19603f3d011682016040523d82523d5f602084013e613f5d565b606091505b50915091508115613f815760405163039f249b60e61b815260040160405180910390fd5b63304680d760e01b613f9282615932565b6001600160e01b03191603613fb157805101519450610e819350505050565b505f9a9950505050505050505050565b80515f82528060051b8201601f19602084015b60200182811161400f5780518282018051828111613ff457505050613fd4565b5b602082015283018051828111613ff5575060200152613fd4565b5050509052565b5f5f61402061315c565b9092509050614030838383614756565b60065f61403e83835c6150bd565b92505081905d50505050565b5f6014611b04565b5f8161405e84866150d0565b61120e9190615a8a565b5f61407682629896806150bd565b61318c62989680856150d0565b5f62989680614095627a1200846150d0565b61409f9190615a8a565b92915050565b81156140c05760408301805160010162ffffff1690526140d1565b60608301805160010162ffffff1690525b6140e76140e2633b9aca0083615a8a565b61477a565b836080018181516140f89190615ce2565b6001600160401b0316905250505050565b5f6011611b04565b5f826001600160a01b0316846001600160a01b03161461413657506108008117611066565b5092915050565b5f5f856060015163ffffffff166207a12061415891906150bd565b84101561416e576020929092179182915061423d565b6201e84861418a8660600135886060015163ffffffff166147af565b61419491906150bd565b90505f6141af6141a86101608801886157e7565b90506147d5565b6141b9833a6150d0565b6141c391906150bd565b905047866040013511156141e25750618000929092179182915061423d565b6141ef6201e848836156dc565b91505f60078161420260208a018a614b8d565b6001600160a01b0316815260208101919091526040015f20546001600160701b03169050808211156142375761200094909417935b84935050505b94509492505050565b5f60a08301351580159061425d57508260a0013543115b1561428d57614275826020015163ffffffff16614109565b614280576008614283565b60025b6001901b1761409f565b5f60078161429e6020870187614b8d565b6001600160a01b0316815260208101919091526040015f2054600160701b900463ffffffff16905043811061413657506110001792915050565b5f6142ec866020015163ffffffff16614109565b80156142f6575084155b801561430957506143078484614640565b155b156125f95750608017949350505050565b5f614323614927565b5f5f306001600160a01b031686306001600160a01b031663966a1f9a8c8c8c8b6040516024016143569493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b93909317909252905161438e9250615760565b5f604051808303815f8787f1925050503d805f81146143c8576040519150601f19603f3d011682016040523d82523d5f602084013e6143cd565b606091505b509150915081156143f357808060200190518101906143ec919061576b565b9250614544565b5f6143fd82615932565b90506353068ee960e11b6001600160e01b03198216016144255760065b6001901b9450614542565b630de8ea8f60e31b6001600160e01b031982160161444457600d61441a565b6317f387a160e21b6001600160e01b031982160161446357601061441a565b62a8476760e61b6001600160e01b031982160161448157601161441a565b633277ac1760e21b6001600160e01b03198216016144a057601261441a565b6305bb473560e21b6001600160e01b03198216016144bf57601361441a565b6350dbf98960e01b6001600160e01b03198216016144de57600a61441a565b63e28aacb160e01b6001600160e01b03198216016144fd57601561441a565b63753c9f6f60e01b6001600160e01b031982160161451c57601661441a565b637781055b60e01b6001600160e01b031982160161453b57600661441a565b6280000094505b505b50509550959350505050565b5f3a5a61455f611388876150bd565b61456991906156dc565b61457391906150d0565b90505f5f61457f61315c565b9150915083156145a75761459a6141a86101608901896157e7565b6145a490846150bd565b92505b60ff8516156145d5576145bb838383614756565b60065f6145c983835c6150bd565b92505081905d50614637565b5f6145e1848484614756565b90505f6145ee85836156dc565b90505f61460961460160208c018c614b8d565b84855f61334d565b9050808211156146335761461d81836156dc565b60035f61462b83835c6150bd565b92505081905d505b5050505b50505050505050565b5f614652610100830160e08401614b8d565b6001600160a01b031661466d61012085016101008601614b8d565b6001600160a01b03161461468257505f61409f565b60c08301351580614695575060a0820135155b806146a757508260c001358260a00135145b6146b257505f61409f565b5f6101008301356146c66020850185614b8d565b8460a001356040516020016146fb9392919092835260609190911b6001600160601b0319166020830152603482015260540190565b60408051601f1981840301815291815281516020928301205f818152600890935291205490915060ff1615614733575f91505061409f565b5f908152600860205260409020805460ff19166001908117909155905092915050565b5f629896808261476685836150bd565b61477091906150bd565b61405e90866150d0565b5f6001600160401b0382111561382557604080516306dfcc6560e41b8152600481019190915260248101839052604401610c16565b5f6147c06207a120629896806150bd565b629896808385106131825761318c90846150d0565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614827573a6008614813610260856150bd565b61481d91906150d0565b61409f91906150d0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016632c652d89614862610260856150bd565b6040518263ffffffff1660e01b815260040161488091815260200190565b602060405180830381865afa15801561489b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061409f9190615092565b919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518060a001604052805f81526020015f81526020015f81526020015f151581526020015f151581525090565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6110666020830184614955565b5f6101a082840312156149a6575f5ffd5b50919050565b5f5f83601f8401126149bc575f5ffd5b5081356001600160401b038111156149d2575f5ffd5b6020830191508360208260051b85010111156149ec575f5ffd5b9250929050565b6001600160a01b0381168114610f14575f5ffd5b80356148bf816149f3565b5f5f5f5f5f60808688031215614a26575f5ffd5b85356001600160401b03811115614a3b575f5ffd5b614a4788828901614995565b95505060208601356001600160401b03811115614a62575f5ffd5b614a6e888289016149ac565b90955093505060408601356001600160401b03811115614a8c575f5ffd5b86016101208189031215614a9e575f5ffd5b91506060860135614aae816149f3565b809150509295509295909350565b5f5f5f5f5f60a08688031215614ad0575f5ffd5b8535614adb816149f3565b94506020860135614aeb816149f3565b9350604086013592506060860135614b02816149f3565b91506080860135614aae816149f3565b5f60208284031215614b22575f5ffd5b5035919050565b5f5f60408385031215614b3a575f5ffd5b8235614b45816149f3565b91506020830135614b55816149f3565b809150509250929050565b6001600160a01b03169052565b5f5f60408385031215614b7e575f5ffd5b50508035926020909101359150565b5f60208284031215614b9d575f5ffd5b8135611066816149f3565b6001600160a01b0391909116815260200190565b634e487b7160e01b5f52604160045260245ffd5b604051608081016001600160401b0381118282101715614bf257614bf2614bbc565b60405290565b60405161018081016001600160401b0381118282101715614bf257614bf2614bbc565b604051601f8201601f191681016001600160401b0381118282101715614c4357614c43614bbc565b604052919050565b63ffffffff81168114610f14575f5ffd5b80356148bf81614c4b565b8015158114610f14575f5ffd5b80356148bf81614c67565b5f5f5f5f5f5f5f5f888a03610140811215614c98575f5ffd5b6080811215614ca5575f5ffd5b50614cae614bd0565b8935614cb9816149f3565b815260208a0135614cc981614c4b565b602082015260408a0135614cdc816149f3565b604082015260608a0135614cef81614c4b565b6060820152975060808901356001600160401b03811115614d0e575f5ffd5b614d1a8b828c01614995565b97505060a08901356001600160401b03811115614d35575f5ffd5b614d418b828c016149ac565b9097509550614d54905060c08a01614a07565b9350614d6260e08a01614a07565b92506101008901359150614d796101208a01614c74565b90509295985092959890939650565b805182526020810151614d9e6020840182614b60565b506040810151614db5604084018262ffffff169052565b506060810151614dca606084018260ff169052565b506080810151614ddf608084018260ff169052565b5060a0810151614df460a084018260ff169052565b5060c0810151614e0960c084018260ff169052565b5060e0810151614e1d60e084018215159052565b50610100810151614e3361010084018215159052565b50610120810151614e4961012084018215159052565b50610140810151614e5f61014084018215159052565b50610160810151611cf0610160840182614b60565b610180810161409f8284614d88565b62ffffff81168114610f14575f5ffd5b80356148bf81614e83565b60ff81168114610f14575f5ffd5b80356148bf81614e9e565b5f5f83601f840112614ec7575f5ffd5b5081356001600160401b03811115614edd575f5ffd5b6020830191508360208285010111156149ec575f5ffd5b5f5f5f5f5f8587036101e0811215614f0a575f5ffd5b610180811215614f18575f5ffd5b50614f21614bf8565b86358152614f3160208801614a07565b6020820152614f4260408801614e93565b6040820152614f5360608801614eac565b6060820152614f6460808801614eac565b6080820152614f7560a08801614eac565b60a0820152614f8660c08801614eac565b60c0820152614f9760e08801614c74565b60e0820152614fa96101008801614c74565b610100820152614fbc6101208801614c74565b610120820152614fcf6101408801614c74565b610140820152614fe26101608801614a07565b61016082015294506101808601356001600160401b03811115615003575f5ffd5b61500f88828901614995565b9450506101a086013592506101c08601356001600160401b03811115615033575f5ffd5b61503f88828901614eb7565b969995985093965092949392505050565b8051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b60a0810161409f8284615050565b5f602082840312156150a2575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561409f5761409f6150a9565b808202811582820484141761409f5761409f6150a9565b60018060a01b03815116825263ffffffff602082015116602083015260018060a01b03604082015116604083015263ffffffff60608201511660608301525050565b5f5f8335601e1984360301811261513e575f5ffd5b83016020810192503590506001600160401b0381111561515c575f5ffd5b8036038213156149ec575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6151a48261519f83614a07565b614b60565b5f6151b160208301614a07565b6151be6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015260c080830135908401526151fd60e08301614a07565b61520a60e0850182614b60565b506152186101008301614a07565b615226610100850182614b60565b506152346101208301614c5c565b63ffffffff1661012084015261524d6101408301614a07565b61525b610140850182614b60565b5061526a610160830183615129565b6101a06101608601526152826101a08601828461516a565b915050615293610180840184615129565b85830361018087015261220f83828461516a565b6152b48261519f83614a07565b5f6152c160208301614a07565b6152ce6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015261530360c08301614a07565b61531060c0850182614b60565b5061531d60e08301614a07565b61532a60e0850182614b60565b5061010082810135908401526153436101208301614a07565b615351610120850182614b60565b50610140828101359084015261526a610160830183615129565b5f8383855260208501945060208460051b820101835f5b868110156153cb57838303601f1901885281353687900361019e190181126153a8575f5ffd5b6153b4848883016152a7565b6020998a0199909450929092019150600101615382565b50909695505050505050565b6153e1818a6150e7565b61014060808201525f6153f861014083018a615192565b82810360a084015261540b81898b61536b565b905082810360c08401526154228161519f89614a07565b61542e60208801614a07565b61543b6020830182614b60565b50604087810135908201526060808801359082015261545c60808801614a07565b6154696080830182614b60565b5061547660a08801614a07565b61548360a0830182614b60565b5060c0878101359082015260e080880135908201526154a6610100880188615129565b6101206101008401526154be6101208401828461516a565b93505050508460e08301526154d7610100830185614b60565b8215156101208301529998505050505050505050565b5f602082840312156154fd575f5ffd5b8151601e8110611066575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b60208101601e831061553f57634e487b7160e01b5f52602160045260245ffd5b91905290565b60ff818116838216019081111561409f5761409f6150a9565b615568818a6150e7565b61014060808201525f61557f61014083018a615192565b82810360a084015261559281898b61536b565b6001600160a01b0397881660c08501529590961660e08301525061010081019290925215156101209091015295945050505050565b80516148bf816149f3565b80516148bf81614e83565b80516148bf81614e9e565b80516148bf81614c67565b5f610180828403128015615605575f5ffd5b5061560e614bf8565b8251815261561e602084016155c7565b602082015261562f604084016155d2565b6040820152615640606084016155dd565b6060820152615651608084016155dd565b608082015261566260a084016155dd565b60a082015261567360c084016155dd565b60c082015261568460e084016155e8565b60e082015261569661010084016155e8565b6101008201526156a961012084016155e8565b6101208201526156bc61014084016155e8565b6101408201526156cf61016084016155c7565b6101608201529392505050565b8181038181111561409f5761409f6150a9565b5f602082840312156156ff575f5ffd5b815161106681614c4b565b848152606060208201525f61572260608301866152a7565b8281036040840152613d6281858761516a565b5f81518060208401855e5f93019283525090919050565b5f61120e61575a8386615735565b84615735565b5f6110668284615735565b5f60a082840312801561577c575f5ffd5b5060405160a081016001600160401b038111828210171561579f5761579f614bbc565b60409081528351825260208085015190830152838101519082015260608301516157c881614c67565b606082015260808301516157db81614c67565b60808201529392505050565b5f5f8335601e198436030181126157fc575f5ffd5b8301803591506001600160401b03821115615815575f5ffd5b6020019150368190038213156149ec575f5ffd5b6001600160a01b0388811682528781166020830152861660408201526060810185905260c0608082018190525f90615864908301858761516a565b82810360a08401526158768185614955565b9a9950505050505050505050565b60e081525f61589660e08301876152a7565b82810360208401526158a981868861516a565b915050610e816040830184615050565b602081525f6110666020830184615192565b5f60808284031280156158dc575f5ffd5b506158e5614bd0565b82516158f0816149f3565b8152602083015161590081614c4b565b60208201526040830151615913816149f3565b6040820152606083015161592681614c4b565b60608201529392505050565b805160208201516001600160e01b0319811691906004821015615969576001600160e01b0319600483900360031b81901b82161692505b5050919050565b6001600160701b03828116828216039081111561409f5761409f6150a9565b6001600160701b03818116838216019081111561409f5761409f6150a9565b6001600160a01b03948516815292909316602083015263ffffffff166040820152606081019190915260800190565b5f602082840312156159ed575f5ffd5b8151611066816149f3565b5f60208284031215615a08575f5ffd5b81516001600160401b03811115615a1d575f5ffd5b8201601f81018413615a2d575f5ffd5b80516001600160401b03811115615a4657615a46614bbc565b615a59601f8201601f1916602001614c1b565b818152856020838501011115615a6d575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f82615aa457634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b5f823561019e19833603018112615ad2575f5ffd5b9190910192915050565b5f60ff821660ff8103615af157615af16150a9565b60010192915050565b5f81615b0857615b086150a9565b505f190190565b60018060a01b0384168152826020820152606060408201525f610e816060830184614955565b5f60208284031215615b45575f5ffd5b815161106681614c67565b8215158152604060208201525f61120e6040830184614955565b60f81b6001600160f81b0319169052565b60608b901b6001600160601b031916815289151560f890811b6014830152891515811b601583015288901b6001600160f81b0319166016820152615bc26017820188615b6a565b615bcf6018820187615b6a565b615be8601982018660e81b6001600160e81b0319169052565b83151560f81b601c82015282151560f81b601d820152615c0b601e820183615b6a565b601f019a9950505050505050505050565b60ff828116828216039081111561409f5761409f6150a9565b60a081525f615c4760a08301886152a7565b60208301969096525060408101939093526001600160a01b039190911660608301521515608090910152919050565b6001600160a01b039590951685526020850193909352901515604084015215156060830152608082015260a00190565b615cb08186614d88565b6101e06101808201525f615cc86101e08301866152a7565b846101a08401528281036101c0840152613d628185614955565b6001600160401b03818116838216019081111561409f5761409f6150a956fea164736f6c634300081c000a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e9000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a4740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf
Deployed Bytecode
0x608060405260043610610251575f3560e01c80638380edb711610137578063c41d54da116100af578063c41d54da146108da578063c5471d9e146108ee578063c5ebeaec14610902578063d0e30db014610915578063d1c23acf1461091d578063d7bb99ba1461093a578063db006a7514610942578063eced552614610961578063f05f88e014610977578063f68b84f71461098a578063f83d08ba1461099d578063fc61c541146109de575f5ffd5b80638380edb714610727578063890c28541461073b5780638ebf091f1461074f57806395d89b4114610763578063966a1f9a146107945780639940686e146107b4578063a0531b02146107d3578063a6efccf9146107f2578063a98efd6714610825578063aa7d2dc81461083c578063aebaa5f714610877578063b2c5c510146108bb575f5ffd5b80635cd6ef67116101ca5780635cd6ef671461041e5780635e8edccc1461045e57806367f7c8e0146105495780636ef5ac7a1461057c57806370a08231146105aa578063791ae748146105e757806379b797651461061a57806379efd1841461064d5780637c20857a1461066d5780637c3c3160146106ae5780637e29c684146106cb578063825ad607146106ea575f5ffd5b806219f2741461025c57806306fdde03146102855780630baf1745146102c657806318160ddd146102e957806319b1faef146102fc578063234b7ede1461031057806327de9e32146103315780632e1a7d4d14610350578063313ce5671461036f5780634511290614610395578063522bc026146103e05780635270182c146103ff575f5ffd5b3661025857005b5f5ffd5b348015610267575f5ffd5b506102726201d4c081565b6040519081526020015b60405180910390f35b348015610290575f5ffd5b506102b960405180604001604052806009815260200168082e8d8c2e6408aa8960bb1b81525081565b60405161027c9190614983565b6102d96102d4366004614a12565b6109fb565b604051901515815260200161027c565b3480156102f4575f5ffd5b505f54610272565b348015610307575f5ffd5b50610272610e8a565b34801561031b575f5ffd5b5061032f61032a366004614abc565b610eb7565b005b34801561033c575f5ffd5b5061032f61034b366004614b12565b610f02565b34801561035b575f5ffd5b5061032f61036a366004614b12565b610f17565b34801561037a575f5ffd5b50610383601281565b60405160ff909116815260200161027c565b3480156103a0575f5ffd5b506103b46103af366004614b29565b610f33565b604080516001600160a01b03909416845263ffffffff909216602084015215159082015260600161027c565b3480156103eb575f5ffd5b5061032f6103fa366004614b6d565b610fbb565b34801561040a575f5ffd5b50610272610419366004614b8d565b611008565b348015610429575f5ffd5b506104517f000000000000000000000000000000000000000000000000000000000000000081565b60405161027c9190614ba8565b348015610469575f5ffd5b50610501610478366004614b8d565b6001600160a01b03165f90815260076020908152604091829020825160a08101845290546001600160701b038116808352600160701b820463ffffffff16938301849052600160901b820462ffffff908116958401869052600160a81b83041660608401819052600160c01b9092046001600160401b0316608090930183905294929392909190565b604080516001600160701b03909616865263ffffffff909416602086015262ffffff928316938501939093521660608301526001600160401b0316608082015260a00161027c565b348015610554575f5ffd5b506104517f000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf81565b348015610587575f5ffd5b506102d9610596366004614b12565b5f9081526008602052604090205460ff1690565b3480156105b5575f5ffd5b506102726105c4366004614b8d565b6001600160a01b03165f908152600660205260409020546001600160701b031690565b3480156105f2575f5ffd5b506104517f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e981565b348015610625575f5ffd5b506104517f000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b81565b61066061065b366004614c7f565b61106d565b60405161027c9190614e74565b348015610678575f5ffd5b50610272610687366004614b8d565b6001600160a01b03165f90815260076020526040902054600160701b900463ffffffff1690565b3480156106b9575f5ffd5b506005546001600160a01b0316610451565b3480156106d6575f5ffd5b506104516106e5366004614b29565b611160565b3480156106f5575f5ffd5b50610272610704366004614b8d565b6001600160a01b03165f908152600760205260409020546001600160701b031690565b348015610732575f5ffd5b505f5c156102d9565b348015610746575f5ffd5b50600154610272565b34801561075a575f5ffd5b5061032f61121b565b34801561076e575f5ffd5b506102b9604051806040016040528060068152602001650c2e8d88aa8960d31b81525081565b6107a76107a2366004614ef4565b61128f565b60405161027c9190615084565b3480156107bf575f5ffd5b5061032f6107ce366004614b12565b6116d4565b3480156107de575f5ffd5b5061032f6107ed366004614b8d565b6116de565b3480156107fd575f5ffd5b506102727f000000000000000000000000000000000000000000000000000000000000004081565b348015610830575f5ffd5b5060025460801c610272565b348015610847575f5ffd5b5061085061173c565b604080516001600160a01b039094168452911515602084015215159082015260600161027c565b348015610882575f5ffd5b50610272610891366004614b8d565b6001600160a01b03165f90815260066020526040902054600160701b90046001600160701b031690565b3480156108c6575f5ffd5b5061032f6108d5366004614abc565b611752565b3480156108e5575f5ffd5b5061032f611770565b3480156108f9575f5ffd5b50600354610272565b61032f610910366004614b12565b6117c2565b61032f611895565b348015610928575f5ffd5b506002546001600160801b0316610272565b61032f6118a1565b34801561094d575f5ffd5b5061032f61095c366004614b12565b6118d9565b34801561096c575f5ffd5b506102726298968081565b61032f610985366004614b12565b6118eb565b610272610998366004614b12565b6118f5565b3480156109a8575f5ffd5b506109b1611a17565b604080516001600160a01b03909416845263ffffffff909216602084015260ff169082015260600161027c565b3480156109e9575f5ffd5b506004546001600160a01b0316610451565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610ac2576040516336d2da6b60e21b81523660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063db4b69ac90602401602060405180830381865afa158015610a8e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab29190615092565b5a610abd91906150bd565b610ae5565b610acd6008366150d0565b6152085a610adb91906150bd565b610ae591906150bd565b9050336001600160a01b037f000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b16145f81610b1f5733610b2f565b610b2f60c0870160a08801614b8d565b90505f5f610b3c8b611a2d565b915091505f7f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e96001600160a01b031663ab0a4b96838e8e8e8e348b8d6040518963ffffffff1660e01b8152600401610b9b9897969594939291906153d7565b6020604051808303815f875af1158015610bb7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdb91906154ed565b90505f81601d811115610bf057610bf061550b565b14610c8f578415610c1f5780604051634e47c97160e01b8152600401610c16919061551f565b60405180910390fd5b610c2b60096001615545565b60ff1681601d811115610c4057610c4061550b565b60ff1610158015610c615750610c5f826020015163ffffffff16611b00565b155b15610c74575f9650505050505050610e81565b80604051631eb2e74960e01b8152600401610c16919061551f565b50610c9a8183611b20565b610ca385611b55565b306001600160a01b03166379efd184828d8d8d87898f60c001358c6040518963ffffffff1660e01b8152600401610ce198979695949392919061555e565b610180604051808303815f875af1925050508015610d1c575060408051601f3d908101601f19168201909252610d19918101906155f3565b60015b610de0573d808015610d49576040519150601f19603f3d011682016040523d82523d5f602084013e610d4e565b606091505b50610d5d818360200151611bd3565b610d676008611cf5565b3415610d7757610d773334611d08565b610d8460208d018d614b8d565b604080515f80825260208201819052818301819052606082015290516001600160a01b03929092169133917fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff063919081900360800190a350610e73565b5f5f610df783856060015163ffffffff168c611d21565b60e08501519a509092509050610e1060208f018f614b8d565b610100840151604080518c1515815291151560208301528101849052606081018390526001600160a01b03919091169033907fde0b67c553d23d5f8bb4c6305ceb7112ee27f974197bee8c02502a7e36cff0639060800160405180910390a35050505b610e7b611eb6565b50505050505b95945050505050565b5f5f610e94611ebd565b905060085c808211610ea6575f610eb0565b610eb081836156dc565b9250505090565b610eef828260806020600860025b60ff166001901b60016008811115610edf57610edf61550b565b60ff166001901b17171717611ee6565b610efb85838686611f7a565b5050505050565b610f0a611fc9565b610f143382611fe9565b50565b610f1f611fc9565b610f29338261213e565b610f143382611d08565b5f5f5f836001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9691906156ef565b9150610fa38585846121a0565b95919450506001600160a01b0385163b151592509050565b610fc3612219565b6001600160801b03821180610fde57506001600160801b0381115b15610ffc576040516359b9784760e01b815260040160405180910390fd5b60809190911b17600255565b6001600160a01b0381165f90815260076020526040812054600160701b900463ffffffff1680820361103c57505f92915050565b6110667f0000000000000000000000000000000000000000000000000000000000000040826150bd565b9392505050565b6110756148c4565b33301461109557604051633006171960e21b815260040160405180910390fd5b6110a28584868986612244565b905060606110b98a6020015163ffffffff166122be565b156110cc576110c9828b8b6122c6565b90505b6110d8828b8b8461242e565b90505f6110ee8b6020015163ffffffff16612602565b61110557611100838c8c8c8c8761260a565b611113565b611113838c8c8c8c87612705565b90508260e001511561112b5761112b838c83856129d1565b61113e8b6020015163ffffffff16612b37565b1561115257611152838460e0015184612b3f565b505098975050505050505050565b5f336001600160a01b038416148015906111835750336001600160a01b03831614155b156111a0576040516282b42960e81b815260040160405180910390fd5b5f826001600160a01b0316638d2129786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111dd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061120191906156ef565b905061120e848483612c50565b949350505050565b905090565b6005546001600160a01b0316331461124657604051633006171960e21b815260040160405180910390fd5b60048054336001600160a01b031991821681179092556005805490911690556040517f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde43985905f90a2565b611297614927565b3330146112b75760405163887efaa560e01b815260040160405180910390fd5b60605f6112c76020880188614b8d565b6001600160a01b03168060015d506112e560e0880160c08901614b8d565b6002805c6001600160a01b0319166001600160a01b03831617905d5061130b6003611cf5565b87602001516001600160a01b031686888787604051602401611330949392919061570a565b60408051601f198184030181529190526020810180516001600160e01b03166001626c60f760e01b03191790526113688a6003612ca9565b60405160200161137992919061574c565b60408051601f198184030181529082905261139391615760565b5f604051808303815f865af19150503d805f81146113cc576040519150601f19603f3d011682016040523d82523d5f602084013e6113d1565b606091505b5092509050806113e357815160208301fd5b818060200190518101906113f7919061576b565b92506114036004611cf5565b6114108760400135612d33565b61142d57604051631217157160e31b815260040160405180910390fd5b61152a5a604089013561144360208b018b614b8d565b60208c015161145a6101408d016101208e01614b8d565b8b6114696101608f018f6157e7565b61147c5f5c60081c63ffffffff16612d70565b61149357604080515f8152602081019091526114c9565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050505b6040516024016114df9796959493929190615829565b60408051601f198184030181529190526020810180516001600160e01b0316630120c0d360e11b17905261151960e08c0160c08d01614b8d565b6001600160a01b0316929190612d78565b90508061154a57604051630357b89960e61b815260040160405180910390fd5b6115546005611cf5565b87602001516001600160a01b0316878686866040516024016115799493929190615884565b60408051601f198184030181529190526020810180516001600160e01b0316634667020160e11b1790526115ae8a6005612ca9565b6040516020016115bf92919061574c565b60408051601f19818403018152908290526115d991615760565b5f604051808303815f865af19150503d805f8114611612576040519150601f19603f3d011682016040523d82523d5f602084013e611617565b606091505b50925090508061162957815160208301fd5b8180602001905181019061163d919061576b565b92505f5f611649612d90565b92509250508161166c57604051638ac3609160e01b815260040160405180910390fd5b8015801561167f575061167d612daa565b155b1561169d57604051631d75534f60e01b815260040160405180910390fd5b896101200151156116c757845160405163304680d760e01b81526004810191909152602401610c16565b5050505095945050505050565b610f143382612dbd565b6116e6612219565b600454600580546001600160a01b0319166001600160a01b0384811691821790925560405191909216919082907ffc722bcd56a71612cd14b287fbf50545429e6c9e8de86ea7c3febdecd34882fd905f90a35050565b5f5f5f611747612d90565b925092509250909192565b61176482826080604060206003610ec5565b610efb85828686611f7a565b611778612219565b600380545f90915561178a3382611d08565b60405181815233907f87fa2ce024d3bdae31517696c13905fc0882bc1b4f4508060eb29358056de22b9060200160405180910390a250565b805f036117cc5750565b5f5c602881901c906001600160a01b03821633146117ff57816040516346ba7eb160e11b8152600401610c169190614ba8565b600460ff82161115611824576040516338961af360e21b815260040160405180910390fd5b5f61182d612d90565b509150508015611850576040516338961af360e21b815260040160405180910390fd5b61185984612d33565b1561186d576118683385611d08565b61188f565b60405163029d54f560e21b815247600482015260248101859052604401610c16565b50505050565b61189f3334612ee2565b565b5f5c60281c336001600160a01b038216146118d157806040516346ba7eb160e11b8152600401610c169190614ba8565b610f14612f90565b6118e1611fc9565b610f143382612fae565b6116d43334612ee2565b5f6004815c60ff161461191b576040516338961af360e21b815260040160405180910390fd5b336001600160a01b0360025c161461194657604051633006171960e21b815260040160405180910390fd5b5f5f5f611951612d90565b6001600160a01b0383165f9081526007602052604090205492955090935091506001600160701b031680861115611986578095505b5f61198f611ebd565b90505f61199e3460085c6150bd565b905034156119ad57808060085d505b6119b788826150bd565b8211156119ef57846119d9576001600160a01b038616600160a11b178060015d505b6119e381836156dc565b98975050505050505050565b83611a0a57600360a11b6001600160a01b038716178060015d505b505f979650505050505050565b5f8080805c602881901c90600881901c90611747565b604080516080810182525f8082526020820181905291810182905260608101829052611a6161012084016101008501614b8d565b6001600160a01b03166344912b6e846040518263ffffffff1660e01b8152600401611a8c91906158b9565b608060405180830381865afa158015611aa7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb91906158cb565b9050611af9611add6020850185614b8d565b611aef61012086016101008701614b8d565b8360200151612c50565b9150915091565b5f600a5b63ffffffff166001901b8263ffffffff16165f14159050919050565b5f5c15611b3f5760405162dc149f60e41b815260040160405180910390fd5b6020820151611b519082906001613130565b5050565b5f3a611b64836201d4c06150bd565b611b6e91906150d0565b90505f5f611b7a61315c565b9092509050611b898382613173565b8060045d50611b988383613196565b8060055d50348060085d505f8060065d505f8060075d505f8060035d505f8060015d505f6002805c6001600160a01b031916905d5050505050565b5f611bdd83615932565b90506001600160a01b037f000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b163303611cba57631b63f4db60e01b6001600160e01b0319821601611c4857825183015160405163e49c0b2560e01b815260048101829052602401610c16565b6001600160e01b03198116635933e62b60e11b1480611c7757506001600160e01b0319811663bdc56ad160e01b145b80611c9257506001600160e01b0319811663a695d44360e01b145b80611cad57506001600160e01b03198116635fd307e960e11b145b15611cba57805f5260045ffd5b6001600160e01b03198116634011dcb760e11b1480611ce35750611ce38263ffffffff16611b00565b15611cf057805f5260045ffd5b505050565b8060ff1660ff195f5c16175f81905d5050565b5f385f3884865af1611b515763b12d13eb5f526004601cfd5b5f5f5f611d2c612d90565b50909150506001600160a01b038416611d485785610160015193505b5f808060085c611d588a8a6131a5565b9850909550935091505f8080611d6e86886156dc565b905084841015611d8957611d8284866156dc565b9250611d96565b611d9385856156dc565b91505b8c60e001518015611dbe57508c61016001516001600160a01b0316886001600160a01b031614155b15611dd757611dcd81846150bd565b9250809950611e04565b8c61016001516001600160a01b0316886001600160a01b031603611dfd575f9950611e04565b5f99508a97505b81831115611e78578c60e00151611e3b57611e1f82846156dc565b6040516306de921b60e51b8152600401610c1691815260200190565b5f611e5289611e4a85876156dc565b84600161334d565b90508a811115611e6657611e1f8b826156dc565b611e70818c6156dc565b9a5050611e8c565b611e8c88611e8685856156dc565b8361363a565b611e966008611cf5565b8915611ea657611ea68b8b611d08565b5050505050505050935093915050565b5f80805d50565b5f60065c60055c611ed260045c60075c6150bd565b611edc91906150bd565b61121691906156dc565b5f5c602881901c90600881901c90336001600160a01b03841614611f1d57604051631e6d8cfb60e21b815260040160405180910390fd5b611f29338787856137c8565b611f46576040516343fcae1b60e01b815260040160405180910390fd5b8360ff168160ff166001901b165f03611f7257604051630106530b60e21b815260040160405180910390fd5b505050505050565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716611fbc57637939f4245f526004601cfd5b5f60605260405250505050565b5f5c1561189f57604051630106530b60e21b815260040160405180910390fd5b5f611ff3826137f2565b6001600160a01b0384165f908152600760205260408120805492935091839183916120289084906001600160701b0316615970565b82546101009290920a6001600160701b03818102199093169183160217909155825463ffffffff60701b1916600160701b4363ffffffff1681029190911784556001600160a01b0387165f90815260066020526040902080548694509092600e926120989286929190041661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550836001600160a01b03167f7659747cd8571f1071eea946fdc648adcf181cad916f32a05f82c3a525976048847f00000000000000000000000000000000000000000000000000000000000000404361211491906150bd565b61211f9060016150bd565b604080519283526020830191909152015b60405180910390a250505050565b6121488282613829565b805f5f82825461215891906156dc565b90915550506040518181526001600160a01b038316907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5906020015b60405180910390a25050565b5f5f6121ad8585856139b5565b90505f6121f9868686856040516024016121ca94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b031663d447616160e01b179052613a32565b90508080602001905181019061220f91906159dd565b9695505050505050565b6004546001600160a01b0316331461189f57604051633006171960e21b815260040160405180910390fd5b61224c6148c4565b5060408051610180810182529485526001600160a01b0395861660208601525f9085018190526060850181905260ff92909216608085015260a08401829052600160c085015260e084018290526101008401829052610120840191909152151561014083015290911661016082015290565b5f6002611b04565b606060016122d381611cf5565b5f5f86602001516001600160a01b0316856040516024016122f491906158b9565b60408051601f198184030181529190526020810180516001600160e01b0316630e75dff560e21b179052612329896001612ca9565b60405160200161233a92919061574c565b60408051601f198184030181529082905261235491615760565b5f604051808303815f865af19150503d805f811461238d576040519150601f19603f3d011682016040523d82523d5f602084013e612392565b606091505b509150915081156123e9576123b0866020015163ffffffff16613abd565b156123d257808060200190518101906123c991906159f8565b93505050612426565b5050604080515f8152602081019091529150612426565b8661014001511561240d57604051635933e62b60e11b815260040160405180910390fd5b604051635b47d49f60e11b815260040160405180910390fd5b509392505050565b6060600261243b81611cf5565b5f60605f619c4060405a61245090603f6150d0565b61245a9190615a8a565b61246491906156dc565b905080876060013510612477578061247d565b86606001355b905061248c8760400135612d33565b6124a957604051631217157160e31b815260040160405180910390fd5b88602001516001600160a01b031687604001358290896040516024016124cf91906158b9565b60408051601f198184030181529190526020810180516001600160e01b031663a395822560e01b1790526125048d6002612ca9565b60405160200161251592919061574c565b60408051601f198184030181529082905261252f91615760565b5f60405180830381858888f193505050503d805f811461256a576040519150601f19603f3d011682016040523d82523d5f602084013e61256f565b606091505b50909350915082156125bc5761258e886020015163ffffffff16613ac5565b156125b157818060200190518101906125a791906159f8565b94505050506125f9565b8594505050506125f9565b886101400151156125e05760405163bdc56ad160e01b815260040160405180910390fd5b604051639f885ee560e01b815260040160405180910390fd5b50949350505050565b5f6013611b04565b5f80835b8060ff16896060015160ff161015612695573686868b6060015160ff1681811061263a5761263a615aa9565b905060200281019061264c9190615abd565b90506126628a8a8a848561014001355f8b613acd565b92508960e00151156126795782935050505061220f565b506060890180519061268a82615adc565b60ff1690525061260e565b886101400151156126c657886040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6126d9886020015163ffffffff16613d6d565b156126f757604051634011dcb760e11b815260040160405180910390fd5b505f98975050505050505050565b5f8280820361276e57876101400151156127345760405163e49c0b2560e01b81525f6004820152602401610c16565b612747876020015163ffffffff16613d6d565b1561276557604051634011dcb760e11b815260040160405180910390fd5b5f91505061220f565b60016101208901525f816001600160401b0381111561278f5761278f614bbc565b6040519080825280602002602001820160405280156127b8578160200160208202803683370190505b5090505f806127c86001856156dc565b90505f5a90505f5b8581101561285c576128088d8d8d8d8d868181106127f0576127f0615aa9565b90506020028101906128029190615abd565b8c613d75565b9350831580159061282057506001600160f01b038411155b15612854578061ffff16601085901b1785848151811061284257612842615aa9565b60209081029190910101525f19909201915b6001016127d0565b506128686001866156dc565b915061287384613fc1565b5f6101208d015261288d5a61288890836156dc565b614016565b815b60108582815181106128a3576128a3615aa9565b6020026020010151901c9350835f031561295d576128c181846156dc565b60ff1660608e015284515f9061ffff908790849081106128e3576128e3615aa9565b60200260200101511660ff1690506129248e8e8e8e8e8681811061290957612909615aa9565b905060200281019061291b9190615abd565b8960018f613acd565b94508d60e001511561293f578497505050505050505061220f565b815f0361294c575061295d565b5061295681615afa565b905061288f565b508b61014001511561298f578b6040015162ffffff1660405163e49c0b2560e01b8152600401610c1691815260200190565b6129a28b6020015163ffffffff16613d6d565b156129c057604051634011dcb760e11b815260040160405180910390fd5b505f9b9a5050505050505050505050565b60066129dc81611cf5565b5f5f86602001516001600160a01b031686604001518686604051602401612a0593929190615b0f565b60408051601f198184030181529190526020810180516001600160e01b0316630b65dadf60e11b179052612a3a896006612ca9565b604051602001612a4b92919061574c565b60408051601f1981840301815290829052612a6591615760565b5f604051808303815f865af19150503d805f8114612a9e576040519150601f19603f3d011682016040523d82523d5f602084013e612aa3565b606091505b50915091508115612ac55780806020019051810190612ac29190615b35565b91505b81158015612ae35750612ae1866020015163ffffffff1661404a565b155b15612b245786610140015115612b0c5760405163a695d44360e01b815260040160405180910390fd5b60405162d14f5160e11b815260040160405180910390fd5b5015156101009095019490945250505050565b5f6008611b04565b6007612b4a81611cf5565b5f84602001516001600160a01b03168484604051602401612b6c929190615b50565b60408051601f198184030181529190526020810180516001600160e01b031663b1d5b5a360e01b179052612ba1876007612ca9565b604051602001612bb292919061574c565b60408051601f1981840301815290829052612bcc91615760565b5f604051808303815f865af19150503d805f8114612c05576040519150601f19603f3d011682016040523d82523d5f602084013e612c0a565b606091505b5050905080610efb5784610140015115612c3757604051635fd307e960e11b815260040160405180910390fd5b6040516333c0622b60e11b815260040160405180910390fd5b5f5f612c5d8585856139b5565b90505f6121f986868685604051602401612c7a94939291906159ae565b60408051601f198184030181529190526020810180516001600160e01b0316630cfce7b160e11b179052613a32565b6060816008811115612cbd57612cbd61550b565b60ff1660c084015261016083015160e084015161010085015160608601516080870151866008811115612cf257612cf261550b565b6040808a01516101208b01516101408c01519251612d1c9998979695949390600190602001615b7b565b604051602081830303815290604052905092915050565b5f815f03612d4357506001919050565b81471015612d5257505f919050565b8160075f612d6183835c6150bd565b92505081905d50600192915050565b5f600f611b04565b5f5f5f5f845160208601878a8af19695505050505050565b60015c90600160a11b8216151590600160a21b8316151590565b5f612db3611ebd565b60085c1015905090565b5f612dc7826137f2565b6001600160a01b0384165f90815260066020526040812080549293508392909190612dfc9084906001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550815f5f828254612e3091906156dc565b90915550506001600160a01b0383165f9081526007602052604081208054839290612e659084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508160015f828254612e9a91906150bd565b90915550506040518281526001600160a01b038416907f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d9060200160405180910390a2505050565b805f5f828254612ef291906150bd565b90915550612f019050816137f2565b6001600160a01b0383165f9081526006602052604081208054909190612f319084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161219491815260200190565b341561189f573460085f612fa583835c6150bd565b92505081905d50565b6001600160a01b0382165f90815260076020526040902054612ffe907f000000000000000000000000000000000000000000000000000000000000004090600160701b900463ffffffff166150bd565b431161301d5760405163078e135760e51b815260040160405180910390fd5b5f613027826137f2565b6001600160a01b0384165f90815260066020526040902080549192509082908290600e90613066908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055508260015f82825461309b91906156dc565b90915550508054829082905f906130bc9084906001600160701b031661598f565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550825f5f8282546130f091906150bd565b90915550506040518381526001600160a01b038516907f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a690602001612130565b600160281b600160c81b03602884901b1664ffffffff00600884901b161760ff821617805f5d50505050565b600254608081901c916001600160801b0390911690565b5f6298968061318283826150bd565b61318c90856150d0565b6110669190615a8a565b5f6298968061318c83856150d0565b60035460075c9060045c9060065c905f9060055c82806131c361315c565b915091505f5a90505f6131d63a836150d0565b90506131e28184613173565b6131ec908a6156dc565b98508b60e001511561322c576132028185613196565b61320c90866156dc565b9650613218878b6150bd565b995061322487876150bd565b6003556132b6565b60035c80156132aa5761324b8561324386826150bd565b839190614052565b97505f61325889836156dc565b90505f61326d6132688d88614068565b614083565b90508082111561328e5761328181836156dc565b61328b908b6150bd565b99505b6132988a8e6150bd565b9c506132a48a8a6150bd565b60035550505b50505050505050613344565b60808c015160ff161561333d575f6132ce8a85614068565b90505f6207a1208e606001518f608001516132e99190615c1c565b6132f69060ff168f6150d0565b61330091906150bd565b90508084111561333a575f8461331683856150d0565b6133209190615a8a565b61332a90846156dc565b9050613336818c6150bd565b9a50505b50505b5050505050505b92959194509250565b5f5f613358856137f2565b6001600160a01b0387165f90815260076020908152604091829020825160a08101845290546001600160701b0380821680845263ffffffff600160701b8404169484019490945262ffffff600160901b8304811695840195909552600160a81b820490941660608301526001600160401b03600160c01b909104166080820152929350908316111561350f576001600160a01b0387165f9081526006602090815260408083208151808301909252546001600160701b038082168352600160701b9091048116928201839052845191939261343692909116906150bd565b905080846001600160701b031611156134a95761345381896156dc565b6001600160a01b038a165f90815260066020819052604082208054600160701b600160e01b031916905581865291965086919061349183835c6150bd565b92505081905d506134a285896156dc565b9750613508565b6134c46134bf6001600160701b038616836156dc565b6137f2565b6001600160a01b038a165f90815260066020526040812080546001600160701b0393909316600160701b02600160701b600160e01b03199093169290921790915583525b505061352d565b81815f018181516135209190615970565b6001600160701b03169052505b6135428185801561353c575084155b876140a5565b63ffffffff43811660208084019182526001600160a01b038a165f9081526007909152604080822085518154945192870151606088015160808901516001600160401b0316600160c01b026001600160c01b0362ffffff928316600160a81b0262ffffff60a81b1993909416600160901b029290921665ffffffffffff60901b1996909916600160701b026001600160901b03199098166001600160701b03909416939093179690961793909316959095179190911792909216929092179055600180548892906136149084906156dc565b9091555086905060085f61362983835c6150bd565b92505081905d505050949350505050565b6001600160a01b0383165f90815260076020908152604091829020825160a08101845290546001600160701b0381168252600160901b810462ffffff90811694830194909452600160a81b81049093166060820152600160c01b9092046001600160401b0316608083015263ffffffff4316908201526136b9836137f2565b815182906136c890839061598f565b6001600160701b0316905250600180548491905f906136e89084906150bd565b909155506136fa9050816001846140a5565b6001600160a01b0384165f908152600760208181526040808420855181549387015192870151606088015160808901516001600160701b039093166001600160901b031990961695909517600160701b63ffffffff909516949094029390931765ffffffffffff60901b1916600160901b62ffffff9485160262ffffff60a81b191617600160a81b9390941692909202929092176001600160c01b0316600160c01b6001600160401b039092169190910217905584916137bb83835c6150bd565b92505081905d5050505050565b5f6137d48484846121a0565b6001600160a01b0316856001600160a01b0316149050949350505050565b5f6001600160701b03821115613825576040516306dfcc6560e41b81526070600482015260248101839052604401610c16565b5090565b5f613833826137f2565b6001600160a01b0384165f9081526006602052604090208054919250906001600160701b03908116908316811061388e5761386e8382615970565b82546001600160701b0319166001600160701b0391909116178255610efb565b6001600160a01b0385165f908152600760205260409020546138de907f000000000000000000000000000000000000000000000000000000000000004090600160701b900463ffffffff166150bd565b43111561398a575f6138f08285615970565b83546001600160701b03191680855590915081908490600e90613924908490600160701b90046001600160701b0316615970565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505f816001600160701b03169050805f5f82825461396591906150bd565b925050819055508060015f82825461397d91906156dc565b90915550610efb92505050565b6040516307d2457d60e21b81526001600160701b038216600482015260248101859052604401610c16565b604080517f0e32c5b0f13b9c1504ccd7b3abad5a1c4549dccb88862cb7b52c51276e8ab74b602080830191909152606095861b6001600160601b0319908116838501529490951b909316605484015260e09190911b6001600160e01b03191660688301528051604c818403018152606c9092019052805191012090565b60605f5f7f000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf6001600160a01b031684604051613a6e9190615760565b5f60405180830381855af49150503d805f8114613aa6576040519150601f19603f3d011682016040523d82523d5f602084013e613aab565b606091505b50915091508161106657805160208201fd5b5f6003611b04565b5f6004611b04565b5f5f5a90505f84613bae577f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e96001600160a01b0316639f7e72b6888c5f01518b608001358e6101600151613b2a8f6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613b4a959493929190615c35565b602060405180830381865afa158015613b65573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b899190615092565b9050613bab613ba061014089016101208a01614b8d565b8a6040015183614111565b90505b80613cb3575f613bc08a89858561413d565b9092509050613bcf888b614246565b82179150613be08a878b8b866142d8565b915081613cb157613bef614927565b613bfc8c8a8a858a61431a565b909350905082613caf578a516001600160a01b0316613c1e60208b018b614b8d565b6001600160a01b0316613c3760e08c0160c08d01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613c736101408e016101208f01614b8d565b8c6001808a604051613c89959493929190615c76565b60405180910390a4600160e08d015262ffffff90921660408c015250519150613d629050565b505b505b62ffffff811660408b0152613ccb8783838815614550565b88516001600160a01b0316613ce36020890189614b8d565b6001600160a01b0316613cfc60e08a0160c08b01614b8d565b6001600160a01b03167f94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c613d386101408c016101208d01614b8d565b8a62fe0000871615155f88604051613d54959493929190615c76565b60405180910390a45f925050505b979650505050505050565b5f6010611b04565b5f5f5a90505f5f7f000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e96001600160a01b0316639f7e72b6878b5f01518a608001358d6101600151613dce8e6020015163ffffffff16614109565b6040518663ffffffff1660e01b8152600401613dee959493929190615c35565b602060405180830381865afa158015613e09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e2d9190615092565b9050613e4f613e4461014088016101208901614b8d565b896040015183614111565b9050613e5d8887858461413d565b92509050613e6b8689614246565b178015613e7d575f9350505050610e81565b613e90886020015163ffffffff16614109565b15613eae57613e9f8787614640565b613eae575f9350505050610e81565b5f5f306001600160a01b031684306001600160a01b031663966a1f9a8e8c8d61014001358d604051602401613ee69493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b939093179092529051613f1e9250615760565b5f604051808303815f8787f1925050503d805f8114613f58576040519150601f19603f3d011682016040523d82523d5f602084013e613f5d565b606091505b50915091508115613f815760405163039f249b60e61b815260040160405180910390fd5b63304680d760e01b613f9282615932565b6001600160e01b03191603613fb157805101519450610e819350505050565b505f9a9950505050505050505050565b80515f82528060051b8201601f19602084015b60200182811161400f5780518282018051828111613ff457505050613fd4565b5b602082015283018051828111613ff5575060200152613fd4565b5050509052565b5f5f61402061315c565b9092509050614030838383614756565b60065f61403e83835c6150bd565b92505081905d50505050565b5f6014611b04565b5f8161405e84866150d0565b61120e9190615a8a565b5f61407682629896806150bd565b61318c62989680856150d0565b5f62989680614095627a1200846150d0565b61409f9190615a8a565b92915050565b81156140c05760408301805160010162ffffff1690526140d1565b60608301805160010162ffffff1690525b6140e76140e2633b9aca0083615a8a565b61477a565b836080018181516140f89190615ce2565b6001600160401b0316905250505050565b5f6011611b04565b5f826001600160a01b0316846001600160a01b03161461413657506108008117611066565b5092915050565b5f5f856060015163ffffffff166207a12061415891906150bd565b84101561416e576020929092179182915061423d565b6201e84861418a8660600135886060015163ffffffff166147af565b61419491906150bd565b90505f6141af6141a86101608801886157e7565b90506147d5565b6141b9833a6150d0565b6141c391906150bd565b905047866040013511156141e25750618000929092179182915061423d565b6141ef6201e848836156dc565b91505f60078161420260208a018a614b8d565b6001600160a01b0316815260208101919091526040015f20546001600160701b03169050808211156142375761200094909417935b84935050505b94509492505050565b5f60a08301351580159061425d57508260a0013543115b1561428d57614275826020015163ffffffff16614109565b614280576008614283565b60025b6001901b1761409f565b5f60078161429e6020870187614b8d565b6001600160a01b0316815260208101919091526040015f2054600160701b900463ffffffff16905043811061413657506110001792915050565b5f6142ec866020015163ffffffff16614109565b80156142f6575084155b801561430957506143078484614640565b155b156125f95750608017949350505050565b5f614323614927565b5f5f306001600160a01b031686306001600160a01b031663966a1f9a8c8c8c8b6040516024016143569493929190615ca6565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b93909317909252905161438e9250615760565b5f604051808303815f8787f1925050503d805f81146143c8576040519150601f19603f3d011682016040523d82523d5f602084013e6143cd565b606091505b509150915081156143f357808060200190518101906143ec919061576b565b9250614544565b5f6143fd82615932565b90506353068ee960e11b6001600160e01b03198216016144255760065b6001901b9450614542565b630de8ea8f60e31b6001600160e01b031982160161444457600d61441a565b6317f387a160e21b6001600160e01b031982160161446357601061441a565b62a8476760e61b6001600160e01b031982160161448157601161441a565b633277ac1760e21b6001600160e01b03198216016144a057601261441a565b6305bb473560e21b6001600160e01b03198216016144bf57601361441a565b6350dbf98960e01b6001600160e01b03198216016144de57600a61441a565b63e28aacb160e01b6001600160e01b03198216016144fd57601561441a565b63753c9f6f60e01b6001600160e01b031982160161451c57601661441a565b637781055b60e01b6001600160e01b031982160161453b57600661441a565b6280000094505b505b50509550959350505050565b5f3a5a61455f611388876150bd565b61456991906156dc565b61457391906150d0565b90505f5f61457f61315c565b9150915083156145a75761459a6141a86101608901896157e7565b6145a490846150bd565b92505b60ff8516156145d5576145bb838383614756565b60065f6145c983835c6150bd565b92505081905d50614637565b5f6145e1848484614756565b90505f6145ee85836156dc565b90505f61460961460160208c018c614b8d565b84855f61334d565b9050808211156146335761461d81836156dc565b60035f61462b83835c6150bd565b92505081905d505b5050505b50505050505050565b5f614652610100830160e08401614b8d565b6001600160a01b031661466d61012085016101008601614b8d565b6001600160a01b03161461468257505f61409f565b60c08301351580614695575060a0820135155b806146a757508260c001358260a00135145b6146b257505f61409f565b5f6101008301356146c66020850185614b8d565b8460a001356040516020016146fb9392919092835260609190911b6001600160601b0319166020830152603482015260540190565b60408051601f1981840301815291815281516020928301205f818152600890935291205490915060ff1615614733575f91505061409f565b5f908152600860205260409020805460ff19166001908117909155905092915050565b5f629896808261476685836150bd565b61477091906150bd565b61405e90866150d0565b5f6001600160401b0382111561382557604080516306dfcc6560e41b8152600481019190915260248101839052604401610c16565b5f6147c06207a120629896806150bd565b629896808385106131825761318c90846150d0565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614827573a6008614813610260856150bd565b61481d91906150d0565b61409f91906150d0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016632c652d89614862610260856150bd565b6040518263ffffffff1660e01b815260040161488091815260200190565b602060405180830381865afa15801561489b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061409f9190615092565b919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518060a001604052805f81526020015f81526020015f81526020015f151581526020015f151581525090565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6110666020830184614955565b5f6101a082840312156149a6575f5ffd5b50919050565b5f5f83601f8401126149bc575f5ffd5b5081356001600160401b038111156149d2575f5ffd5b6020830191508360208260051b85010111156149ec575f5ffd5b9250929050565b6001600160a01b0381168114610f14575f5ffd5b80356148bf816149f3565b5f5f5f5f5f60808688031215614a26575f5ffd5b85356001600160401b03811115614a3b575f5ffd5b614a4788828901614995565b95505060208601356001600160401b03811115614a62575f5ffd5b614a6e888289016149ac565b90955093505060408601356001600160401b03811115614a8c575f5ffd5b86016101208189031215614a9e575f5ffd5b91506060860135614aae816149f3565b809150509295509295909350565b5f5f5f5f5f60a08688031215614ad0575f5ffd5b8535614adb816149f3565b94506020860135614aeb816149f3565b9350604086013592506060860135614b02816149f3565b91506080860135614aae816149f3565b5f60208284031215614b22575f5ffd5b5035919050565b5f5f60408385031215614b3a575f5ffd5b8235614b45816149f3565b91506020830135614b55816149f3565b809150509250929050565b6001600160a01b03169052565b5f5f60408385031215614b7e575f5ffd5b50508035926020909101359150565b5f60208284031215614b9d575f5ffd5b8135611066816149f3565b6001600160a01b0391909116815260200190565b634e487b7160e01b5f52604160045260245ffd5b604051608081016001600160401b0381118282101715614bf257614bf2614bbc565b60405290565b60405161018081016001600160401b0381118282101715614bf257614bf2614bbc565b604051601f8201601f191681016001600160401b0381118282101715614c4357614c43614bbc565b604052919050565b63ffffffff81168114610f14575f5ffd5b80356148bf81614c4b565b8015158114610f14575f5ffd5b80356148bf81614c67565b5f5f5f5f5f5f5f5f888a03610140811215614c98575f5ffd5b6080811215614ca5575f5ffd5b50614cae614bd0565b8935614cb9816149f3565b815260208a0135614cc981614c4b565b602082015260408a0135614cdc816149f3565b604082015260608a0135614cef81614c4b565b6060820152975060808901356001600160401b03811115614d0e575f5ffd5b614d1a8b828c01614995565b97505060a08901356001600160401b03811115614d35575f5ffd5b614d418b828c016149ac565b9097509550614d54905060c08a01614a07565b9350614d6260e08a01614a07565b92506101008901359150614d796101208a01614c74565b90509295985092959890939650565b805182526020810151614d9e6020840182614b60565b506040810151614db5604084018262ffffff169052565b506060810151614dca606084018260ff169052565b506080810151614ddf608084018260ff169052565b5060a0810151614df460a084018260ff169052565b5060c0810151614e0960c084018260ff169052565b5060e0810151614e1d60e084018215159052565b50610100810151614e3361010084018215159052565b50610120810151614e4961012084018215159052565b50610140810151614e5f61014084018215159052565b50610160810151611cf0610160840182614b60565b610180810161409f8284614d88565b62ffffff81168114610f14575f5ffd5b80356148bf81614e83565b60ff81168114610f14575f5ffd5b80356148bf81614e9e565b5f5f83601f840112614ec7575f5ffd5b5081356001600160401b03811115614edd575f5ffd5b6020830191508360208285010111156149ec575f5ffd5b5f5f5f5f5f8587036101e0811215614f0a575f5ffd5b610180811215614f18575f5ffd5b50614f21614bf8565b86358152614f3160208801614a07565b6020820152614f4260408801614e93565b6040820152614f5360608801614eac565b6060820152614f6460808801614eac565b6080820152614f7560a08801614eac565b60a0820152614f8660c08801614eac565b60c0820152614f9760e08801614c74565b60e0820152614fa96101008801614c74565b610100820152614fbc6101208801614c74565b610120820152614fcf6101408801614c74565b610140820152614fe26101608801614a07565b61016082015294506101808601356001600160401b03811115615003575f5ffd5b61500f88828901614995565b9450506101a086013592506101c08601356001600160401b03811115615033575f5ffd5b61503f88828901614eb7565b969995985093965092949392505050565b8051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b60a0810161409f8284615050565b5f602082840312156150a2575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561409f5761409f6150a9565b808202811582820484141761409f5761409f6150a9565b60018060a01b03815116825263ffffffff602082015116602083015260018060a01b03604082015116604083015263ffffffff60608201511660608301525050565b5f5f8335601e1984360301811261513e575f5ffd5b83016020810192503590506001600160401b0381111561515c575f5ffd5b8036038213156149ec575f5ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6151a48261519f83614a07565b614b60565b5f6151b160208301614a07565b6151be6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015260c080830135908401526151fd60e08301614a07565b61520a60e0850182614b60565b506152186101008301614a07565b615226610100850182614b60565b506152346101208301614c5c565b63ffffffff1661012084015261524d6101408301614a07565b61525b610140850182614b60565b5061526a610160830183615129565b6101a06101608601526152826101a08601828461516a565b915050615293610180840184615129565b85830361018087015261220f83828461516a565b6152b48261519f83614a07565b5f6152c160208301614a07565b6152ce6020850182614b60565b5060408281013590840152606080830135908401526080808301359084015260a0808301359084015261530360c08301614a07565b61531060c0850182614b60565b5061531d60e08301614a07565b61532a60e0850182614b60565b5061010082810135908401526153436101208301614a07565b615351610120850182614b60565b50610140828101359084015261526a610160830183615129565b5f8383855260208501945060208460051b820101835f5b868110156153cb57838303601f1901885281353687900361019e190181126153a8575f5ffd5b6153b4848883016152a7565b6020998a0199909450929092019150600101615382565b50909695505050505050565b6153e1818a6150e7565b61014060808201525f6153f861014083018a615192565b82810360a084015261540b81898b61536b565b905082810360c08401526154228161519f89614a07565b61542e60208801614a07565b61543b6020830182614b60565b50604087810135908201526060808801359082015261545c60808801614a07565b6154696080830182614b60565b5061547660a08801614a07565b61548360a0830182614b60565b5060c0878101359082015260e080880135908201526154a6610100880188615129565b6101206101008401526154be6101208401828461516a565b93505050508460e08301526154d7610100830185614b60565b8215156101208301529998505050505050505050565b5f602082840312156154fd575f5ffd5b8151601e8110611066575f5ffd5b634e487b7160e01b5f52602160045260245ffd5b60208101601e831061553f57634e487b7160e01b5f52602160045260245ffd5b91905290565b60ff818116838216019081111561409f5761409f6150a9565b615568818a6150e7565b61014060808201525f61557f61014083018a615192565b82810360a084015261559281898b61536b565b6001600160a01b0397881660c08501529590961660e08301525061010081019290925215156101209091015295945050505050565b80516148bf816149f3565b80516148bf81614e83565b80516148bf81614e9e565b80516148bf81614c67565b5f610180828403128015615605575f5ffd5b5061560e614bf8565b8251815261561e602084016155c7565b602082015261562f604084016155d2565b6040820152615640606084016155dd565b6060820152615651608084016155dd565b608082015261566260a084016155dd565b60a082015261567360c084016155dd565b60c082015261568460e084016155e8565b60e082015261569661010084016155e8565b6101008201526156a961012084016155e8565b6101208201526156bc61014084016155e8565b6101408201526156cf61016084016155c7565b6101608201529392505050565b8181038181111561409f5761409f6150a9565b5f602082840312156156ff575f5ffd5b815161106681614c4b565b848152606060208201525f61572260608301866152a7565b8281036040840152613d6281858761516a565b5f81518060208401855e5f93019283525090919050565b5f61120e61575a8386615735565b84615735565b5f6110668284615735565b5f60a082840312801561577c575f5ffd5b5060405160a081016001600160401b038111828210171561579f5761579f614bbc565b60409081528351825260208085015190830152838101519082015260608301516157c881614c67565b606082015260808301516157db81614c67565b60808201529392505050565b5f5f8335601e198436030181126157fc575f5ffd5b8301803591506001600160401b03821115615815575f5ffd5b6020019150368190038213156149ec575f5ffd5b6001600160a01b0388811682528781166020830152861660408201526060810185905260c0608082018190525f90615864908301858761516a565b82810360a08401526158768185614955565b9a9950505050505050505050565b60e081525f61589660e08301876152a7565b82810360208401526158a981868861516a565b915050610e816040830184615050565b602081525f6110666020830184615192565b5f60808284031280156158dc575f5ffd5b506158e5614bd0565b82516158f0816149f3565b8152602083015161590081614c4b565b60208201526040830151615913816149f3565b6040820152606083015161592681614c4b565b60608201529392505050565b805160208201516001600160e01b0319811691906004821015615969576001600160e01b0319600483900360031b81901b82161692505b5050919050565b6001600160701b03828116828216039081111561409f5761409f6150a9565b6001600160701b03818116838216019081111561409f5761409f6150a9565b6001600160a01b03948516815292909316602083015263ffffffff166040820152606081019190915260800190565b5f602082840312156159ed575f5ffd5b8151611066816149f3565b5f60208284031215615a08575f5ffd5b81516001600160401b03811115615a1d575f5ffd5b8201601f81018413615a2d575f5ffd5b80516001600160401b03811115615a4657615a46614bbc565b615a59601f8201601f1916602001614c1b565b818152856020838501011115615a6d575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f82615aa457634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b5f823561019e19833603018112615ad2575f5ffd5b9190910192915050565b5f60ff821660ff8103615af157615af16150a9565b60010192915050565b5f81615b0857615b086150a9565b505f190190565b60018060a01b0384168152826020820152606060408201525f610e816060830184614955565b5f60208284031215615b45575f5ffd5b815161106681614c67565b8215158152604060208201525f61120e6040830184614955565b60f81b6001600160f81b0319169052565b60608b901b6001600160601b031916815289151560f890811b6014830152891515811b601583015288901b6001600160f81b0319166016820152615bc26017820188615b6a565b615bcf6018820187615b6a565b615be8601982018660e81b6001600160e81b0319169052565b83151560f81b601c82015282151560f81b601d820152615c0b601e820183615b6a565b601f019a9950505050505050505050565b60ff828116828216039081111561409f5761409f6150a9565b60a081525f615c4760a08301886152a7565b60208301969096525060408101939093526001600160a01b039190911660608301521515608090910152919050565b6001600160a01b039590951685526020850193909352901515604084015215156060830152608082015260a00190565b615cb08186614d88565b6101e06101808201525f615cc86101e08301866152a7565b846101a08401528281036101c0840152613d628185614955565b6001600160401b03818116838216019081111561409f5761409f6150a956fea164736f6c634300081c000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000001e8480000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e9000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a4740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf
-----Decoded View---------------
Arg [0] : escrowDuration (uint256): 64
Arg [1] : atlasSurchargeRate (uint256): 500000
Arg [2] : bundlerSurchargeRate (uint256): 2000000
Arg [3] : verification (address): 0xf31cf8740Dc4438Bb89a56Ee2234Ba9d5595c0E9
Arg [4] : simulator (address): 0x702b0b3690642B880dF6B018ead7F3C30ECe5c6b
Arg [5] : initialSurchargeRecipient (address): 0x78C5d8DF575098a97A3bD1f8DCCEb22D71F3a474
Arg [6] : l2GasCalculator (address): 0x0000000000000000000000000000000000000000
Arg [7] : factoryLib (address): 0xA70aAf5dD6B3B7F06617780c964f2638f24394BF
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [2] : 00000000000000000000000000000000000000000000000000000000001e8480
Arg [3] : 000000000000000000000000f31cf8740dc4438bb89a56ee2234ba9d5595c0e9
Arg [4] : 000000000000000000000000702b0b3690642b880df6b018ead7f3c30ece5c6b
Arg [5] : 00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a474
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 000000000000000000000000a70aaf5dd6b3b7f06617780c964f2638f24394bf
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
POL | 100.00% | $0.218307 | 6,986.4028 | $1,525.18 |
Loading...
Loading
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.