Source Code
Overview
HYPE Balance
HYPE Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Atlas
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 18 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 { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.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 { GasAccLib, GasLedger } from "../libraries/GasAccLib.sol";
/// @title Atlas V1.6.4
/// @author FastLane Labs
/// @notice The Execution Abstraction protocol.
contract Atlas is Escrow, Factory {
using SafeCast for uint256;
using CallBits for uint32;
using SafetyBits for Context;
using GasAccLib for uint256;
using GasAccLib for GasLedger;
constructor(
uint256 escrowDuration,
uint256 atlasSurchargeRate,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator,
address factoryLib
)
Escrow(escrowDuration, atlasSurchargeRate, 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. NOTE: The msg.sender (bundler) should be able to receive ETH without reverting.
/// @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)
{
// _gasMarker calculated as (Execution gas cost) + (Calldata gas cost). Any gas left at the end of the metacall
// is deducted from this _gasMarker, resulting in actual execution gas used + calldata gas costs + buffer.
// The calldata component is added below, only if exPostBids = false.
uint256 _gasLeft = gasleft();
uint256 _gasMarker = _gasLeft + _BASE_TX_GAS_USED + _POST_SETTLE_METACALL_GAS; // This is only execution gas.
DAppConfig memory _dConfig;
bool _isSimulation = msg.sender == SIMULATOR;
address _executionEnvironment;
address _bundler = _isSimulation ? dAppOp.bundler : msg.sender;
(_executionEnvironment, _dConfig) = _getOrCreateExecutionEnvironment(userOp);
// Validate metacall params, and get back vars used in gas accounting logic
(
uint256 _allSolversGasLimit,
uint256 _allSolversCalldataGas,
uint256 _bidFindOverhead,
ValidCallsResult _validCallsResult
) = VERIFICATION.validateCalls({
dConfig: _dConfig,
userOp: userOp,
solverOps: solverOps,
dAppOp: dAppOp,
metacallGasLeft: _gasLeft,
msgValue: msg.value,
msgSender: _bundler,
isSimulation: _isSimulation
});
// Solvers pay for calldata when exPostBids = false
if (!_dConfig.callConfig.exPostBids()) {
// total calldata gas = solver calldata gas + (userOp + dAppOp + offset) calldata gas
_gasMarker += _allSolversCalldataGas
+ GasAccLib.metacallCalldataGas(
userOp.data.length + USER_OP_STATIC_LENGTH + DAPP_OP_LENGTH + _EXTRA_CALLDATA_LENGTH, L2_GAS_CALCULATOR
);
}
// Handle the ValidCallsResult
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()) {
// Refund the bundler if they sent any msg.value, then return false and end early.
if (msg.value != 0) SafeTransferLib.safeTransferETH(msg.sender, msg.value);
return false;
}
// Revert for all other results
revert ValidCalls(_validCallsResult);
}
// Initialize the environment lock and accounting values
_setEnvironmentLock(_dConfig, _executionEnvironment);
// If in `multipleSuccessfulSolvers` mode, solvers are only liable for their own (C + E) gas costs, even if they
// execute successfully. In this case we set `remainingMaxGas` and `unreachedSolverGas` to the same value - the
// sum of all solvers' (C + E) gas limits. Then, `solverGasLiability()` will report just the current solver's
// gas costs with surcharges.
// In all other cases, `remainingMaxGas` includes non-solver gas limits and overheads that the winning solver
// may be liable for. In `exPostBids` mode, we also subtract the gas limit of the bid-finding solverOp
// iterations, as that gas will be written off (winning solver not liable for them).
uint256 _initialRemainingMaxGas =
_dConfig.callConfig.multipleSuccessfulSolvers() ? _allSolversGasLimit : _gasMarker - _bidFindOverhead;
// `userOp.bundlerSurchargeRate` is checked against the value set in the DAppControl in `validateCalls()` above,
// so it is safe to use here.
_initializeAccountingValues({
initialRemainingMaxGas: _initialRemainingMaxGas,
allSolverOpsGas: _allSolversGasLimit,
bundlerSurchargeRate: userOp.bundlerSurchargeRate
});
// Calculate `execute` gas limit such that it can fail due to an OOG error caused by any of the hook calls, and
// the metacall will still have enough gas to gracefully finish and return, storing any nonces required.
uint256 _gasLimit = gasleft() * 63 / 64 - _GRACEFUL_RETURN_GAS_OFFSET;
// 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{ gas: _gasLimit }(
_dConfig, userOp, solverOps, dAppOp.userOpHash, _executionEnvironment, _bundler, _isSimulation
) returns (Context memory ctx) {
GasLedger memory _gL = t_gasLedger.toGasLedger(); // Final load, no need to persist changes after this
uint256 _unreachedCalldataValuePaid;
// Only charge unreached solverOps for their calldata if NOT in exPostBids mode
if (!_dConfig.callConfig.exPostBids()) {
_unreachedCalldataValuePaid = _chargeUnreachedSolversForCalldata(
solverOps,
_gL,
ctx.solverIndex,
dAppOp.userOpHash,
userOp.maxFeePerGas,
_bundler,
_dConfig.callConfig.allowsTrustedOpHash()
);
}
// Gas Refund to sender only if execution is successful, or if multipleSuccessfulSolvers
(uint256 _ethPaidToBundler, uint256 _netGasSurcharge) = _settle(
ctx,
_gL,
_gasMarker,
gasRefundBeneficiary,
_unreachedCalldataValuePaid,
_dConfig.callConfig.multipleSuccessfulSolvers()
);
auctionWon = ctx.solverSuccessful;
emit MetacallResult(msg.sender, userOp.from, auctionWon, _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, 0, 0);
}
// The environment lock is explicitly released here to allow multiple (sequential, not nested) 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 userOpHash The hash of the UserOperation.
/// @param executionEnvironment The address of the execution environment.
/// @param bundler The address of the bundler.
/// @param isSimulation Whether the current execution is a simulation.
/// @return ctx Context struct containing relevant context information for the Atlas auction.
function execute(
DAppConfig memory dConfig,
UserOperation calldata userOp,
SolverOperation[] calldata solverOps,
bytes32 userOpHash,
address executionEnvironment,
address bundler,
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(
userOpHash, executionEnvironment, bundler, dConfig.dappGasLimit, 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
_allocateValue(ctx, dConfig, _winningBidAmount, _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 _gasWaterMark = gasleft(); // track bid-finding gas, to be written off.
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 _solverExecutionGas;
uint256 _bidsAndIndicesLastIndex = solverOpsLength - 1; // Start from the last index
// Get a snapshot of the GasLedger from transient storage, to reset to after bid-finding below
uint256 _gasLedgerSnapshot = t_gasLedger;
// 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);
// In `_getBidAmount()` above, unreachedSolverGas is decreased while remainingMaxGas does not change, as it
// is normally decreased in `_handleSolverFailAccounting()` which is not called in a bid-finding context. To
// adjust for this difference so GasLedger.solverGasLiability() still works, we have to decrease
// remainingMaxGas separately here. This decrease does not include calldata gas as solvers are not charged
// for calldata gas in exPostBids mode.
GasLedger memory _gL = t_gasLedger.toGasLedger();
// Deduct solverOp.gas (with a ceiling of dConfig.solverGasLimit) from remainingMaxGas
_solverExecutionGas = Math.min(solverOps[i].gas, dConfig.solverGasLimit);
_gL.remainingMaxGas -= _solverExecutionGas.toUint40();
t_gasLedger = _gL.pack();
// 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;
}
}
}
// Reset transient GasLedger to its state before the bid-finding loop above
t_gasLedger = _gasLedgerSnapshot;
// 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.
_writeOffBidFindGas(_gasWaterMark - gasleft());
// Finally, iterate through sorted bidsAndIndices array in descending order of bidAmount.
for (uint256 i = _bidsAndIndicesLastIndex;; /* breaks when 0 */ --i) {
// Now, track gas watermark to charge/writeoff gas for each solverOp
_gasWaterMark = gasleft();
// 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, _gasWaterMark, 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 solverOpsLen = uint8(solverOps.length);
for (; ctx.solverIndex < solverOpsLen; ctx.solverIndex++) {
// track gas watermark to charge/writeoff gas for each solverOp
uint256 _gasWaterMark = gasleft();
SolverOperation calldata solverOp = solverOps[ctx.solverIndex];
// if multipleSuccessfulSolvers = true, solver bids are summed here. Otherwise, 0 bids are returned on
// solverOp failure, and only the first successful solver's bid is added to `_bidAmount`.
_bidAmount += _executeSolverOperation(
ctx, dConfig, userOp, solverOp, solverOp.bidAmount, _gasWaterMark, false, returnData
);
// If a winning solver is found, stop iterating through the solverOps and return the winning bid
if (ctx.solverSuccessful) {
return _bidAmount;
}
}
// If no winning solver, but multipleSuccessfulSolvers is true, return the sum of solver bid amounts
if (dConfig.callConfig.multipleSuccessfulSolvers()) {
// Considered a fail for simulation purposes when only one solverOp in the metacall, and it fails. If more
// than 1 solverOp, any of them could fail and simulation could still be successful.
if (ctx.isSimulation && solverOpsLen == 1 && ctx.solverOutcome != 0) {
revert SolverSimFail(uint256(ctx.solverOutcome));
}
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
) {
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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// 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 { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";
import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import { AtlETH } from "./AtlETH.sol";
import { IExecutionEnvironment } from "../interfaces/IExecutionEnvironment.sol";
import { ISolverContract } from "../interfaces/ISolverContract.sol";
import { IAtlasVerification } from "../interfaces/IAtlasVerification.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 { GasAccLib, GasLedger } from "../libraries/GasAccLib.sol";
import { SafeBlockNumber } from "../libraries/SafeBlockNumber.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;
using SafeCast for uint256;
using AccountingMath for uint256;
using GasAccLib for uint256;
using GasAccLib for GasLedger;
constructor(
uint256 escrowDuration,
uint256 atlasSurchargeRate,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator
)
AtlETH(escrowDuration, atlasSurchargeRate, 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)
{
uint256 _dappGasWaterMark = gasleft();
(bool _success, bytes memory _data) = ctx.executionEnvironment.call{ gas: ctx.dappGasLeft }(
abi.encodePacked(
abi.encodeCall(IExecutionEnvironment.preOpsWrapper, userOp), ctx.setAndPack(ExecutionPhase.PreOps)
)
);
_updateDAppGasLeft(ctx, _dappGasWaterMark);
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;
if (!_borrow(userOp.value)) {
revert InsufficientEscrow();
}
(_success, _data) = ctx.executionEnvironment.call{ value: userOp.value, gas: userOp.gas }(
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 gasWaterMark The gas left at the start of the current solverOp's execution, to be used to charge/write
/// off solverOp gas.
/// @param prevalidated Boolean flag indicating if the solverOp has been prevalidated in bidFind (exPostBids).
/// @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,
uint256 gasWaterMark,
bool prevalidated,
bytes memory returnData
)
internal
returns (uint256)
{
GasLedger memory _gL = t_gasLedger.toGasLedger();
uint256 _result;
// Decrease unreachedSolverGas and reset maxApprovedGasSpend at the start of each solverOp
_adjustGasLedgerAtSolverOpStart(_gL, dConfig, solverOp);
t_gasLedger = _gL.pack(); // Persist changes to transient storage
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(_gL, 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);
// First successful solver call that paid what it bid
if (_result.executionSuccessful()) {
// Logic done above `_handleSolverFailAccounting()` is to charge solver for gas used here
ctx.solverOutcome = _result.toUint24();
emit SolverTxResult(
solverOp.solver,
solverOp.from,
dConfig.to,
solverOp.bidToken,
_solverTracker.bidAmount,
true,
true,
_result
);
// Keep executing solvers without ending the auction if multipleSuccessfulSolvers is set
if (dConfig.callConfig.multipleSuccessfulSolvers()) {
// multipleSuccessfulSolvers mode:
// - `ctx.solverSuccessful` is implicitly left as false
// - `_result` should be 0 (successful) below, which should charge the solver for their own
// gas + surcharges, as 0 is not captured in the bundler fault block.
// - exPostBids is not supported in multipleSuccessfulSolvers mode, so exPostBids = false here.
_handleSolverFailAccounting(solverOp, dConfig.solverGasLimit, gasWaterMark, _result, false);
} else {
// If not in multipleSuccessfulSolvers mode, end the auction with the first successful solver
// that paid what it bid.
// We intentionally do not change GasLedger here as we have found a winning solver and don't
// need it anymore
ctx.solverSuccessful = true;
}
return _solverTracker.bidAmount;
}
}
}
// If we reach this point, the solver call did not execute successfully.
ctx.solverOutcome = _result.toUint24();
emit SolverTxResult(
solverOp.solver,
solverOp.from,
dConfig.to,
solverOp.bidToken,
bidAmount,
_result.executedWithError(),
false,
_result
);
// Account for failed SolverOperation gas costs
_handleSolverFailAccounting(
solverOp, dConfig.solverGasLimit, gasWaterMark, _result, dConfig.callConfig.exPostBids()
);
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)
{
uint256 _dappGasWaterMark = gasleft();
(bool _success,) = ctx.executionEnvironment.call{ gas: ctx.dappGasLeft }(
abi.encodePacked(
abi.encodeCall(
IExecutionEnvironment.allocateValue, (ctx.solverSuccessful, dConfig.bidToken, bidAmount, returnData)
),
ctx.setAndPack(ExecutionPhase.AllocateValue)
)
);
_updateDAppGasLeft(ctx, _dappGasWaterMark);
// Revert if allocateValue failed at any point.
if (!_success) {
if (ctx.isSimulation) revert AllocateValueSimFail();
revert AllocateValueFail();
}
}
/// @notice Adjusts the gas ledger before evaluating a SolverOperation.
/// @dev Updates the in-memory `gL` by decreasing `unreachedSolverGas` based on the current solverOp's max potential
/// gas (execution + calldata if not exPostBids) and resets `maxApprovedGasSpend` to 0. Caller must persist `gL`
/// changes to transient storage separately.
/// @param gL The GasLedger struct (in memory) to modify.
/// @param dConfig DApp configuration containing `solverGasLimit` and `callConfig`.
/// @param solverOp The SolverOperation being evaluated.
function _adjustGasLedgerAtSolverOpStart(
GasLedger memory gL,
DAppConfig memory dConfig,
SolverOperation calldata solverOp
)
internal
view
{
// Decrease unreachedSolverGas by the current solverOp's (C + E) max gas
uint256 _calldataGas;
// Solver's execution gas is solverOp.gas with a ceiling of dConfig.solverGasLimit
uint256 _executionGas = Math.min(solverOp.gas, dConfig.solverGasLimit);
// Calldata gas is only included if NOT in exPostBids mode.
if (!dConfig.callConfig.exPostBids()) {
_calldataGas = GasAccLib.solverOpCalldataGas(solverOp.data.length, L2_GAS_CALCULATOR);
}
// Reset solver's max approved gas spend to 0 at start of each new solver execution
gL.maxApprovedGasSpend = 0;
gL.unreachedSolverGas -= (_executionGas + _calldataGas).toUint40();
// NOTE: GasLedger changes must be persisted to transient storage separately after this function call
}
/// @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 gL The GasLedger memory struct containing the current gas accounting state.
/// @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(
GasLedger memory gL,
DAppConfig memory dConfig,
SolverOperation calldata solverOp,
uint256 gasWaterMark,
uint256 result
)
internal
view
returns (uint256, uint256 gasLimit)
{
// gasLimit is solverOp.gas, with a ceiling of dConfig.solverGasLimit
gasLimit = Math.min(solverOp.gas, dConfig.solverGasLimit);
if (gasWaterMark < _VALIDATION_GAS_LIMIT + gasLimit) {
// Make sure to leave enough gas for dApp validation calls
result |= 1 << uint256(SolverOutcome.UserOutOfGas);
return (result, gasLimit);
}
// Verify that we can lend the solver their tx value
if (solverOp.value > address(this).balance) {
result |= 1 << uint256(SolverOutcome.CallValueTooHigh);
return (result, gasLimit);
}
uint256 _solverBalance = S_accessData[solverOp.from].bonded;
// Checks if solver's bonded balance is enough to cover the max charge should they win, including surcharges
if (_solverBalance < gL.solverGasLiability()) {
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 && SafeBlockNumber.get() > 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 >= SafeBlockNumber.get()) {
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 'onchain bid finding' gas usage.
uint256 _gasWaterMark = gasleft();
uint256 _gasLimit;
GasLedger memory _gL = t_gasLedger.toGasLedger();
// Decrease unreachedSolverGas and reset maxApprovedGasSpend at the start of each solverOp
_adjustGasLedgerAtSolverOpStart(_gL, dConfig, solverOp);
t_gasLedger = _gL.pack(); // Persist changes to transient storage
uint256 _result = VERIFICATION.verifySolverOp(
solverOp, ctx.userOpHash, userOp.maxFeePerGas, ctx.bundler, dConfig.callConfig.allowsTrustedOpHash()
);
_result = _checkSolverBidToken(solverOp.bidToken, dConfig.bidToken, _result);
(_result, _gasLimit) = _validateSolverOpGasAndValue(_gL, 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();
// Load callConfig from transient storage once here, to be used below.
uint32 _callConfig = _activeCallConfig();
// NOTE: The solver's bidAmount is always sent to their solver contract during the solver call. In exPostBids
// mode, it is possible for a solver to encode some infomation calculated during the bid-finding process, which
// the bundler pays for as that gas cost is written off, in the least significant bits of their bidAmount. This
// information can be used to minimize the gas cost a solver is charged for during real execution. This is seen
// as a feature, because the decrease in gas cost paid by the solver should result in a higher bid they are able
// to make - a better outcome for the bid recipient.
// 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
_callConfig.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 _multiSuccesfulSolvers = _callConfig.multipleSuccessfulSolvers();
(, bool _calledback, bool _fulfilled) = _solverLockData();
if (!_calledback) revert CallbackNotCalled();
if (!_fulfilled && !_isBalanceReconciled(_multiSuccesfulSolvers)) 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);
}
/// Updates ctx.dappGasLeft based on the gas used in the DApp hook call just performed.
/// @dev Measure the gasWaterMarkBefore using `gasleft()` just before performing the DApp hook call.
/// @dev Will revert if the gas used exceeds the remaining dappGasLeft.
/// @param ctx Memory pointer to the metacalls' Context object.
/// @param gasWaterMarkBefore The gasleft() value just before the DApp hook call.
function _updateDAppGasLeft(Context memory ctx, uint256 gasWaterMarkBefore) internal view {
uint256 _gasUsed = gasWaterMarkBefore - gasleft();
if (_gasUsed > ctx.dappGasLeft) revert DAppGasLimitReached();
// No need to SafeCast - will revert above if too large for uint32
ctx.dappGasLeft -= uint32(_gasUsed);
}
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_STATIC_LENGTH` 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,uint32 dappGasLimit,uint32 solverGasLimit,uint24 bundlerSurchargeRate,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,uint32 dappGasLimit,uint32 solverGasLimit,uint24 bundlerSurchargeRate,address sessionKey)"
);
// Length of UserOperation in hex chars, assuming empty signature field, excluding the dynamic userOp.data field.
uint256 constant USER_OP_STATIC_LENGTH = 608;
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`
uint32 dappGasLimit; // Gas limit set by the DAppControl for preOps and allocateValue hook execution
uint32 solverGasLimit; // Gas limit set by the DAppControl for solverOp execution
uint24 bundlerSurchargeRate; // Bundler surcharge rate, set by the DAppControl
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 bidFind;
bool isSimulation;
address bundler;
uint32 dappGasLeft; // Gas used on preOps and allocateValue hooks
}
enum ExecutionPhase {
Uninitialized,
PreOps,
UserOperation,
PreSolver,
SolverOperation,
PostSolver,
AllocateValue,
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 solverOp (including preSolver and postSolver) execution
uint32 dappGasLimit; // Max shared gas limit for preOps and allocateValue hook execution
uint128 bundlerSurchargeRate; // Bundler surcharge rate
}
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;
// 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;
// multipleSolvers: If true, the metacall will proceed even if a solver successfully pays their bid, and will be
// charged in gas as if it was reverted. If false, the auction ends after the first successful solver.
bool multipleSuccessfulSolvers;
// checkMetacallGasLimit: If true, the execution gas measured by `gasleft()` at the start of the metacall is
// verified to be in line with the expected gas limit, based on the userOp, solverOps, and dAppOp.
bool checkMetacallGasLimit;
}
enum CallConfigIndex {
UserNoncesSequential,
DAppNoncesSequential,
RequirePreOps,
TrackPreOpsReturnData,
TrackUserReturnData,
DelegateUser,
RequirePreSolver,
RequirePostSolver,
ZeroSolvers,
ReuseUserOp,
UserAuctioneer,
SolverAuctioneer,
UnknownAuctioneer,
// Default = DAppAuctioneer
VerifyCallChainHash,
ForwardReturnData,
RequireFulfillment,
TrustedOpHash,
InvertBidValue,
ExPostBids,
MultipleSuccessfulSolvers,
CheckMetacallGasLimit
}//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)"
);
// Length of DAppOperation in hex chars, assuming empty signature field
uint256 constant DAPP_OP_LENGTH = 352;
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,
MetacallGasLimitTooLow,
MetacallGasLimitTooHigh,
DAppGasLimitMismatch,
SolverGasLimitMismatch,
BundlerSurchargeRateMismatch,
ExPostBidsAndMultipleSuccessfulSolversNotSupportedTogether,
InvertsBidValueAndMultipleSuccessfulSolversNotSupportedTogether,
NeedSolversForMultipleSuccessfulSolvers,
SolverCannotBeAuctioneerForMultipleSuccessfulSolvers,
CannotRequireFulfillmentForMultipleSuccessfulSolvers
}//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.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.multipleSuccessfulSolvers) {
encodedCallConfig ^= _ONE << uint32(CallConfigIndex.MultipleSuccessfulSolvers);
}
if (callConfig.checkMetacallGasLimit) {
encodedCallConfig ^= _ONE << uint32(CallConfigIndex.CheckMetacallGasLimit);
}
}
function decodeCallConfig(uint32 encodedCallConfig) internal pure returns (CallConfig memory callConfig) {
callConfig.userNoncesSequential = needsSequentialUserNonces(encodedCallConfig);
callConfig.dappNoncesSequential = needsSequentialDAppNonces(encodedCallConfig);
callConfig.requirePreOps = needsPreOpsCall(encodedCallConfig);
callConfig.trackPreOpsReturnData = needsPreOpsReturnData(encodedCallConfig);
callConfig.trackUserReturnData = needsUserReturnData(encodedCallConfig);
callConfig.delegateUser = needsDelegateUser(encodedCallConfig);
callConfig.requirePreSolver = needsPreSolverCall(encodedCallConfig);
callConfig.requirePostSolver = needsPostSolverCall(encodedCallConfig);
callConfig.zeroSolvers = allowsZeroSolvers(encodedCallConfig);
callConfig.reuseUserOp = allowsReuseUserOps(encodedCallConfig);
callConfig.userAuctioneer = allowsUserAuctioneer(encodedCallConfig);
callConfig.solverAuctioneer = allowsSolverAuctioneer(encodedCallConfig);
callConfig.unknownAuctioneer = allowsUnknownAuctioneer(encodedCallConfig);
callConfig.verifyCallChainHash = verifyCallChainHash(encodedCallConfig);
callConfig.forwardReturnData = forwardReturnData(encodedCallConfig);
callConfig.requireFulfillment = needsFulfillment(encodedCallConfig);
callConfig.trustedOpHash = allowsTrustedOpHash(encodedCallConfig);
callConfig.invertBidValue = invertsBidValue(encodedCallConfig);
callConfig.exPostBids = exPostBids(encodedCallConfig);
callConfig.multipleSuccessfulSolvers = multipleSuccessfulSolvers(encodedCallConfig);
callConfig.checkMetacallGasLimit = checkMetacallGasLimit(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 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 multipleSuccessfulSolvers(uint32 callConfig) internal pure returns (bool) {
return (callConfig & (1 << uint32(CallConfigIndex.MultipleSuccessfulSolvers))) != 0;
}
function checkMetacallGasLimit(uint32 callConfig) internal pure returns (bool) {
return (callConfig & (1 << uint32(CallConfigIndex.CheckMetacallGasLimit))) != 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))
);
// 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))
);
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.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;
import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";
import { AccountingMath } from "./AccountingMath.sol";
import { IL2GasCalculator } from "../interfaces/IL2GasCalculator.sol";
// All GasLedger vars are measured in units of gas.
// All GasLedger vars also include calldata and execution gas components.
// remainingMaxGas and unreachedSolverGas measure max gas limits (C + E).
// writeoffsGas and solverFaultFailureGas measure actual gas used (C + E).
// Only stores base gas values. Does not include the surcharges or gasprice components.
// type(uint40).max ~= 1.09 x 10^12, plenty even for gigagas (10^9) blocks
struct GasLedger {
uint40 remainingMaxGas; // Measured at start, decreased by solverOp gas limits when reached
uint40 writeoffsGas; // Gas used for solverOps but written off due to bundler fault
uint40 solverFaultFailureGas; // Gas used by solverOps that failed due to solver fault
uint40 unreachedSolverGas; // Sum of gas limits of solverOps not yet reached in the current metacall
uint40 maxApprovedGasSpend; // Max gas units approved by current solver to be spent from their bonded atlETH
uint24 atlasSurchargeRate; // Scale is 10_000 (100%) --> max atlas surcharge rate ~= 167.77x or 16777%
uint24 bundlerSurchargeRate; // Scale is 10_000 (100%) --> max bundler surcharge rate ~= 167.77x or 16777%
// NOTE: 8 bits unused.
}
// All BorrowsLedger vars are measured in units of native token (wei).
struct BorrowsLedger {
uint128 borrows; // Total native token value borrowed in the current metacall
uint128 repays; // Total native token value repaid in the current metacall
}
library GasAccLib {
using AccountingMath for uint256;
using SafeCast for uint256;
uint256 internal constant _SOLVER_OP_STATIC_LENGTH = 608;
uint256 internal constant _GAS_PER_CALLDATA_BYTE = 8; // Half of the upper 16 gas per non-zero byte, applied to all
// calldata bytes.
function pack(GasLedger memory gasLedger) internal pure returns (uint256) {
return uint256(gasLedger.remainingMaxGas) | (uint256(gasLedger.writeoffsGas) << 40)
| (uint256(gasLedger.solverFaultFailureGas) << 80) | (uint256(gasLedger.unreachedSolverGas) << 120)
| (uint256(gasLedger.maxApprovedGasSpend) << 160) | (uint256(gasLedger.atlasSurchargeRate) << 200)
| (uint256(gasLedger.bundlerSurchargeRate) << 224);
}
function pack(BorrowsLedger memory borrowsLedger) internal pure returns (uint256) {
return uint256(borrowsLedger.borrows) | (uint256(borrowsLedger.repays) << 128);
}
function toGasLedger(uint256 gasLedgerPacked) internal pure returns (GasLedger memory) {
return GasLedger({
remainingMaxGas: uint40(gasLedgerPacked),
writeoffsGas: uint40(gasLedgerPacked >> 40),
solverFaultFailureGas: uint40(gasLedgerPacked >> 80),
unreachedSolverGas: uint40(gasLedgerPacked >> 120),
maxApprovedGasSpend: uint40(gasLedgerPacked >> 160),
atlasSurchargeRate: uint24(gasLedgerPacked >> 200),
bundlerSurchargeRate: uint24(gasLedgerPacked >> 224)
});
}
function toBorrowsLedger(uint256 borrowsLedgerPacked) internal pure returns (BorrowsLedger memory) {
return BorrowsLedger({ borrows: uint128(borrowsLedgerPacked), repays: uint128(borrowsLedgerPacked >> 128) });
}
function netRepayments(BorrowsLedger memory bL) internal pure returns (int256) {
return uint256(bL.repays).toInt256() - uint256(bL.borrows).toInt256();
}
// Returns the max gas liability (in native token units) for the current solver.
// `remainingMaxGas` is max gas limit as measured at start of metacall, with the gas limit of each solverOp
// subtracted at the end of its execution.
// `unreachedSolverGas` is the sum of solverOp gas limits not yet reached, with gas limit of current solverOp
// subtracted at the start of its execution, before bonded balance check.
// Thus `remainingMaxGas - unreachedSolverGas` is the max gas the current solver might need to pay for if they win,
// including dApp hook gas limits and userOp gas limit.
function solverGasLiability(GasLedger memory gL) internal view returns (uint256) {
return uint256(gL.remainingMaxGas - gL.unreachedSolverGas).withSurcharge(
uint256(gL.atlasSurchargeRate + gL.bundlerSurchargeRate)
) * tx.gasprice;
}
// Returns the sum of the Atlas and bundler surcharge rates.
// Scale of the returned value is 10_000 (100%).
function totalSurchargeRate(GasLedger memory gL) internal pure returns (uint256) {
return uint256(gL.atlasSurchargeRate + gL.bundlerSurchargeRate);
}
function solverOpCalldataGas(uint256 calldataLength, address l2GasCalculator) internal view returns (uint256 gas) {
if (l2GasCalculator == address(0)) {
// Default to using mainnet gas calculations
// _SOLVER_OP_STATIC_LENGTH = SolverOperation calldata length excluding solverOp.data
gas = (calldataLength + _SOLVER_OP_STATIC_LENGTH) * _GAS_PER_CALLDATA_BYTE;
} else {
gas = IL2GasCalculator(l2GasCalculator).getCalldataGas(calldataLength + _SOLVER_OP_STATIC_LENGTH);
}
}
function calldataGas(uint256 calldataLength, address l2GasCalculator) internal view returns (uint256 gas) {
if (l2GasCalculator == address(0)) {
// Default to using mainnet gas calculations
gas = calldataLength * _GAS_PER_CALLDATA_BYTE;
} else {
gas = IL2GasCalculator(l2GasCalculator).getCalldataGas(calldataLength);
}
}
function metacallCalldataGas(
uint256 msgDataLength,
address l2GasCalculator
)
internal
view
returns (uint256 calldataGas)
{
if (l2GasCalculator == address(0)) {
calldataGas = msgDataLength * _GAS_PER_CALLDATA_BYTE;
} else {
calldataGas = IL2GasCalculator(l2GasCalculator).initialGasUsed(msgDataLength);
}
}
}//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 { SafeBlockNumber } from "../libraries/SafeBlockNumber.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,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator
)
Permit69(escrowDuration, atlasSurchargeRate, 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 (SafeBlockNumber.get() > 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(SafeBlockNumber.get());
s_balanceOf[owner].unbonding += _amt;
emit Unbond(owner, amount, SafeBlockNumber.get() + 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 (SafeBlockNumber.get() <= 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);
}
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import "../types/SolverOperation.sol";
import "../types/UserOperation.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 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(
bool solved,
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;
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/ValidCalls.sol";
interface IAtlasVerification {
// AtlasVerification.sol
function validateCalls(
DAppConfig calldata dConfig,
UserOperation calldata userOp,
SolverOperation[] calldata solverOps,
DAppOperation calldata dAppOp,
uint256 metacallGasLeft,
uint256 msgValue,
address msgSender,
bool isSimulation
)
external
returns (
uint256 allSolversGasLimit,
uint256 allSolversCalldataGas,
uint256 bidFindOverhead,
ValidCallsResult verifyCallsResult
);
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 = 8000; // out of 10_000 = 80%
uint256 internal constant _SCALE = 10_000; // 10_000 / 10_000 = 100%
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;
}
// 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;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import { ArbSys } from "nitro-contracts/src/precompiles/ArbSys.sol";
library SafeBlockNumber {
// https://arbiscan.io/address/0x0000000000000000000000000000000000000064
// https://github.com/OffchainLabs/nitro/blob/9270a057fa8b30fb960872d74f7632aae8f5efbe/precompiles/ArbSys.go#L35
ArbSys internal constant ARB_SYS = ArbSys(address(0x0000000000000000000000000000000000000064));
uint256 internal constant ARBITRUM_ONE_CHAIN_ID = 42_161;
uint256 internal constant ARBITRUM_NOVA_CHAIN_ID = 42_170;
uint256 internal constant ARBITRUM_SEPOLIA_CHAIN_ID = 421_614;
uint256 internal constant PLUME_CHAIN_ID = 98_866;
uint256 internal constant PLUME_TESTNET_CHAIN_ID = 98_867;
function get() internal view returns (uint256) {
uint256 chainId = block.chainid;
if (
chainId == ARBITRUM_ONE_CHAIN_ID || chainId == ARBITRUM_NOVA_CHAIN_ID
|| chainId == ARBITRUM_SEPOLIA_CHAIN_ID || chainId == PLUME_CHAIN_ID || chainId == PLUME_TESTNET_CHAIN_ID
) {
// Arbitrum One or Nova chain
return ARB_SYS.arbBlockNumber();
} else {
return block.number;
}
}
}//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 "../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 allocateValueCall(bool solved, 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 CALL_CONFIG() external view returns (uint32);
function getSolverGasLimit() external view returns (uint32);
function getDAppGasLimit() external view returns (uint32);
function getBundlerSurchargeRate() external view returns (uint24);
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 userDelegated() external view returns (bool delegated);
function transferGovernance(address newGovernance) external;
function acceptGovernance() external;
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
// aderyn-fp-next-line(unused-import)
import { ValidCallsResult } from "./ValidCalls.sol";
contract AtlasErrors {
// Simulator
error SimulatorBalanceTooLow();
error Unauthorized();
error Unreachable();
error NoAuctionWinner();
error InvalidEntryFunction();
error SimulationPassed();
error UserNotFulfilled();
error BidFindSuccessful(uint256 bidAmount);
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 ValidCalls(ValidCallsResult);
error InsufficientGasForMetacallSimulation(uint256 gasLeft, uint256 estimatedMetacallGas, uint256 suggestedSimGas);
// Execution Environment
error InvalidTo();
error PreOpsDelegatecallFail();
error UserOpValueExceedsBalance();
error UserWrapperDelegatecallFail();
error UserWrapperCallFail();
error AllocateValueDelegatecallFail();
error NotEnvironmentOwner();
error ExecutionEnvironmentBalanceTooLow();
// Atlas
error PreOpsFail();
error UserOpFail();
error AllocateValueFail();
error InvalidAccess();
// Escrow
error InvalidEscrowDuration();
error DAppGasLimitReached();
// AtlETH
error EscrowLockActive();
error InsufficientBalanceForDeduction(uint256 balance, uint256 requested);
// DAppIntegration
error OnlyGovernance();
error SignatoryActive();
error InvalidCaller();
error DAppNotEnabled();
error AtlasLockActive();
// Permit69
error InvalidEnvironment();
error EnvironmentMismatch();
error InvalidLockState();
// GasAccounting
error InvalidExecutionEnvironment(address correctEnvironment);
error InsufficientAtlETHBalance(uint256 actual, uint256 needed);
error BorrowsNotRepaid(uint256 borrows, uint256 repays);
error AssignDeficitTooLarge(uint256 deficit, uint256 bundlerRefund);
// SafetyLocks
error AlreadyInitialized();
// Storage
error SurchargeRateTooHigh();
// DAppControl
error BothUserAndDAppNoncesCannotBeSequential();
error BothPreOpsAndUserReturnDataCannotBeTracked();
error InvalidControl();
error NoDelegatecall();
error MustBeDelegatecalled();
error OnlyAtlas();
error WrongPhase();
error InsufficientLocalFunds();
error NotImplemented();
error InvertBidValueCannotBeExPostBids();
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IL2GasCalculator {
/// @notice Calculate the cost (in gas units) of calldata in ETH on a L2 with a different fee structure than mainnet
function getCalldataGas(uint256 calldataLength) external view returns (uint256 calldataGas);
/// @notice Gets the cost (in gas units) of initial gas used for a tx 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 { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { GasAccounting } from "./GasAccounting.sol";
import { SAFE_USER_TRANSFER, SAFE_DAPP_TRANSFER } from "../libraries/SafetyBits.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,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator
)
GasAccounting(
escrowDuration,
atlasSurchargeRate,
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();
}
}
}// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.4.21 <0.9.0;
/**
* @title System level functionality
* @notice For use by contracts to interact with core L2-specific functionality.
* Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064.
*/
interface ArbSys {
/**
* @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
* @return block number as int
*/
function arbBlockNumber() external view returns (uint256);
/**
* @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum)
* @return block hash
*/
function arbBlockHash(
uint256 arbBlockNum
) external view returns (bytes32);
/**
* @notice Gets the rollup's unique chain identifier
* @return Chain identifier as int
*/
function arbChainID() external view returns (uint256);
/**
* @notice Get internal version number identifying an ArbOS build, this is `55 + nitroArbOS version number`
* e.g. on ArbOS 31 this would return 86. This is the only function that have the 55 offset.
* @return version number as int
*/
function arbOSVersion() external view returns (uint256);
/**
* @notice Returns 0 since Nitro has no concept of storage gas
* @return uint 0
*/
function getStorageGasAvailable() external view returns (uint256);
/**
* @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract)
* @dev this call has been deprecated and may be removed in a future release
* @return true if current execution frame is not a call by another L2 contract
*/
function isTopLevelCall() external view returns (bool);
/**
* @notice map L1 sender contract address to its L2 alias
* @param sender sender address
* @param unused argument no longer used
* @return aliased sender address
*/
function mapL1SenderContractAddressToL2Alias(
address sender,
address unused
) external pure returns (address);
/**
* @notice check if the caller (of this caller of this) is an aliased L1 contract address
* @return true iff the caller's address is an alias for an L1 contract address
*/
function wasMyCallersAddressAliased() external view returns (bool);
/**
* @notice return the address of the caller (of this caller of this), without applying L1 contract address aliasing
* @return address of the caller's caller, without applying L1 contract address aliasing
*/
function myCallersAddressWithoutAliasing() external view returns (address);
/**
* @notice Send given amount of Eth to dest from sender.
* This is a convenience function, which is equivalent to calling sendTxToL1 with empty data.
* @param destination recipient address on L1
* @return unique identifier for this L2-to-L1 transaction.
*/
function withdrawEth(
address destination
) external payable returns (uint256);
/**
* @notice Send a transaction to L1
* @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data
* to a contract address without any code (as enforced by the Bridge contract).
* @param destination recipient address on L1
* @param data (optional) calldata for L1 contract call
* @return a unique identifier for this L2-to-L1 transaction.
*/
function sendTxToL1(
address destination,
bytes calldata data
) external payable returns (uint256);
/**
* @notice Get send Merkle tree state
* @return size number of sends in the history
* @return root root hash of the send history
* @return partials hashes of partial subtrees in the send history tree
*/
function sendMerkleTreeState()
external
view
returns (uint256 size, bytes32 root, bytes32[] memory partials);
/**
* @notice creates a send txn from L2 to L1
* @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf
*/
event L2ToL1Tx(
address caller,
address indexed destination,
uint256 indexed hash,
uint256 indexed position,
uint256 arbBlockNum,
uint256 ethBlockNum,
uint256 timestamp,
uint256 callvalue,
bytes data
);
/// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade
event L2ToL1Transaction(
address caller,
address indexed destination,
uint256 indexed uniqueId,
uint256 indexed batchNumber,
uint256 indexInBatch,
uint256 arbBlockNum,
uint256 ethBlockNum,
uint256 timestamp,
uint256 callvalue,
bytes data
);
/**
* @notice logs a merkle branch for proof synthesis
* @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event
* @param hash the merkle hash
* @param position = (level << 192) + leaf
*/
event SendMerkleUpdate(
uint256 indexed reserved, bytes32 indexed hash, uint256 indexed position
);
error InvalidBlockNumber(uint256 requested, uint256 current);
}//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,
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: BUSL-1.1
pragma solidity 0.8.28;
import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol";
import { SafeCast } from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";
import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import { SafetyLocks } from "./SafetyLocks.sol";
import { EscrowBits } from "../libraries/EscrowBits.sol";
import { CallBits } from "../libraries/CallBits.sol";
import { AccountingMath } from "../libraries/AccountingMath.sol";
import { GasAccLib, GasLedger, BorrowsLedger } from "../libraries/GasAccLib.sol";
import { SafeBlockNumber } from "../libraries/SafeBlockNumber.sol";
import { SolverOperation } from "../types/SolverOperation.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 CallBits for uint32;
using AccountingMath for uint256;
using SafeCast for uint256;
using GasAccLib for uint256;
using GasAccLib for GasLedger;
using GasAccLib for BorrowsLedger;
using FixedPointMathLib for uint256;
constructor(
uint256 escrowDuration,
uint256 atlasSurchargeRate,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator
)
SafetyLocks(escrowDuration, atlasSurchargeRate, verification, simulator, initialSurchargeRecipient, l2GasCalculator)
{ }
/// @notice Sets the initial gas accounting values for the metacall transaction in transient storage.
/// @dev Resets `t_gasLedger`, `t_borrowsLedger`, `t_solverLock`, and `t_solverTo` at the start of each metacall.
/// Initializes `remainingMaxGas` with the overall gas estimate and `unreachedSolverGas` with the precalculated
/// gas for all potential solver operations. Sets initial `repays` based on `msg.value`.
/// @param initialRemainingMaxGas The gas measurement at the start of the metacall, which generally includes
/// Execution gas limits, Calldata gas costs, and an additional buffer for safety. NOTE: If in exPostBids mode,
/// this param does not include calldata gas as solvers are not liable for calldata gas costs. And in
/// multipleSuccessfulSolvers mode, this param is the same value as `allSolverOpsGas`, because solvers are only
/// liable for their own solverOp gas, even if they execute successfully.
/// @param allSolverOpsGas The sum of (C + E) gas limits for all solverOps in the metacall.
function _initializeAccountingValues(
uint256 initialRemainingMaxGas,
uint256 allSolverOpsGas,
uint24 bundlerSurchargeRate
)
internal
{
t_gasLedger = GasLedger({
remainingMaxGas: initialRemainingMaxGas.toUint40(),
writeoffsGas: 0,
solverFaultFailureGas: 0,
unreachedSolverGas: allSolverOpsGas.toUint40(),
maxApprovedGasSpend: 0,
atlasSurchargeRate: _atlasSurchargeRate(),
bundlerSurchargeRate: bundlerSurchargeRate
}).pack();
// If any native token sent in the metacall, add to the repays account
t_borrowsLedger = BorrowsLedger({ borrows: 0, repays: uint128(msg.value) }).pack();
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 {
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 gasLiability The total gas charge (base + surcharges) owed by the solver. Can be repaid using bonded
/// balance or native token.
/// @return borrowLiability The total value of ETH borrowed but not yet repaid, only repayable using native token.
function shortfall() external view returns (uint256 gasLiability, uint256 borrowLiability) {
gasLiability = t_gasLedger.toGasLedger().solverGasLiability();
BorrowsLedger memory _bL = t_borrowsLedger.toBorrowsLedger();
borrowLiability = (_bL.borrows < _bL.repays) ? 0 : _bL.borrows - _bL.repays;
}
/// @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 gas and borrow liability owed by the solver. The full gasLiability + borrowLiability amount is
/// returned, unless the fulfilled, in which case 0 is returned.
/// @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 the borrows values
// can be increased.
(, uint32 _callConfig, uint8 _currentPhase) = _lock();
// 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 (_currentPhase != uint8(ExecutionPhase.SolverOperation)) revert WrongPhase();
if (msg.sender != t_solverTo) revert InvalidAccess();
(address _currentSolver, bool _calledBack,) = _solverLockData();
uint256 _bondedBalance = uint256(S_accessData[_currentSolver].bonded);
// Solver can only approve up to their bonded balance, not more
if (maxApprovedGasSpend > _bondedBalance) maxApprovedGasSpend = _bondedBalance;
GasLedger memory _gL = t_gasLedger.toGasLedger();
BorrowsLedger memory _bL = t_borrowsLedger.toBorrowsLedger();
uint256 _borrows = _bL.borrows; // total native borrows
uint256 _repays = _bL.repays; // total native repayments of borrows
uint256 _maxGasLiability = _gL.solverGasLiability(); // max gas liability of winning solver
// Store update to repays in t_borrowLedger, if any msg.value sent
if (msg.value > 0) {
_repays += msg.value;
_bL.repays = _repays.toUint128();
t_borrowsLedger = _bL.pack();
}
// Store solver's maxApprovedGasSpend for use in the _isBalanceReconciled() check
if (maxApprovedGasSpend > 0) {
// Convert maxApprovedGasSpend from wei (native token) units to gas units
_gL.maxApprovedGasSpend = (maxApprovedGasSpend / tx.gasprice).toUint40();
t_gasLedger = _gL.pack();
}
// Check if fullfilled:
// - native borrows must be repaid (using only native token)
// - gas liabilities must be repaid (using bonded AtlETH or native token)
if (_borrows > _repays) {
if (!_calledBack) t_solverLock = (uint256(uint160(_currentSolver)) | _SOLVER_CALLED_BACK_MASK);
return _maxGasLiability + (_borrows - _repays);
} else {
// If multipleSuccessfulSolvers = true, the solver's gas liability cannot be paid in ETH - must be fully
// paid by the solver's bonded AtlETH balance.
uint256 _excess;
if (!_callConfig.multipleSuccessfulSolvers()) _excess = _repays - _borrows;
if (maxApprovedGasSpend + _excess < _maxGasLiability) {
if (!_calledBack) t_solverLock = (uint256(uint160(_currentSolver)) | _SOLVER_CALLED_BACK_MASK);
return _maxGasLiability - _excess;
}
}
// If we get here, native borrows have been repaid, and enough approved to cover gas liabilities
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) return;
BorrowsLedger memory _bL = t_borrowsLedger.toBorrowsLedger();
_bL.repays += msg.value.toUint128();
t_borrowsLedger = _bL.pack();
}
/// @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;
BorrowsLedger memory _bL = t_borrowsLedger.toBorrowsLedger();
_bL.borrows += amount.toUint128();
t_borrowsLedger = _bL.pack();
return true;
}
/// @notice Takes AtlETH from the owner's bonded balance and, if necessary, from the owner's unbonding balance.
/// @dev No GasLedger accounting changes are made in this function - should be done separately.
/// @param accountData The EscrowAccountAccessData memory struct of the account being charged.
/// @param account The address of the account from which AtlETH is taken.
/// @param amount The amount of AtlETH to be taken.
/// @return deficit The amount of AtlETH that was not repaid, if any.
function _assign(
EscrowAccountAccessData memory accountData,
address account,
uint256 amount
)
internal
returns (uint256 deficit)
{
uint112 _amt = amount.toUint112();
if (_amt > accountData.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[account];
uint256 _total = uint256(_bData.unbonding) + uint256(accountData.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[account].unbonding = 0;
accountData.bonded = 0;
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[account].unbonding = _total.toUint112() - _amt;
accountData.bonded = 0;
}
} else {
// The bonded balance is sufficient to cover the amount owed.
accountData.bonded -= _amt;
}
S_bondedTotalSupply -= amount;
// update lastAccessedBlock since bonded balance is decreasing
accountData.lastAccessedBlock = uint32(SafeBlockNumber.get());
// NOTE: accountData changes must be persisted to storage separately
}
/// @notice Increases the owner's bonded balance by the specified amount.
/// @param accountData The EscrowAccountAccessData memory struct of the account being credited.
/// @param amount The amount by which to increase the owner's bonded balance.
function _credit(EscrowAccountAccessData memory accountData, uint256 amount) internal {
accountData.bonded += SafeCast.toUint112(amount);
S_bondedTotalSupply += amount;
// NOTE: accountData changes must be persisted to storage separately
}
/// @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 dConfigSolverGasLimit The gas limit for the solver operation, as specified in the DAppConfig.
/// @param gasWaterMark The `gasleft()` watermark taken at the start of executing the SolverOperation.
/// @param result The result bitmap of the SolverOperation execution.
/// @param exPostBids A boolean indicating whether exPostBids is set to true in the current metacall.
function _handleSolverFailAccounting(
SolverOperation calldata solverOp,
uint256 dConfigSolverGasLimit,
uint256 gasWaterMark,
uint256 result,
bool exPostBids
)
internal
{
GasLedger memory _gL = t_gasLedger.toGasLedger();
// Solvers do not pay for calldata gas in exPostBids mode.
uint256 _calldataGas;
if (!exPostBids) {
_calldataGas = GasAccLib.solverOpCalldataGas(solverOp.data.length, L2_GAS_CALCULATOR);
}
// Solver execution max gas is calculated as solverOp.gas, with a ceiling of dConfig.solverGasLimit
uint256 _executionMaxGas = Math.min(solverOp.gas, dConfigSolverGasLimit);
// Deduct solver's max (C + E) gas from remainingMaxGas, for future solver gas liability calculations
_gL.remainingMaxGas -= (_executionMaxGas + _calldataGas).toUint40();
uint256 _gasUsed = _calldataGas + (gasWaterMark - gasleft());
// 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
_gasUsed += _BUNDLER_FAULT_OFFSET;
_gL.writeoffsGas += _gasUsed.toUint40();
} else {
// CASE: Solver failed, so we calculate what they owe.
_gasUsed += _SOLVER_FAULT_OFFSET;
uint256 _gasValueWithSurcharges = _gasUsed.withSurcharge(_gL.totalSurchargeRate()) * tx.gasprice;
EscrowAccountAccessData memory _solverAccountData = S_accessData[solverOp.from];
// In `_assign()`, the solver's bonded AtlETH balance is reduced by `_gasValueWithSurcharges`. Any deficit
// from that operation is returned as `_assignDeficit` below. GasLedger is not modified in _assign().
uint256 _assignDeficit = _assign(_solverAccountData, solverOp.from, _gasValueWithSurcharges);
// Solver's analytics updated:
// - increment auctionFails
// - increase totalGasValueUsed by gas cost + surcharges paid by solver, less any deficit
_updateAnalytics(_solverAccountData, false, _gasValueWithSurcharges - _assignDeficit);
// Persist the updated solver account data to storage
S_accessData[solverOp.from] = _solverAccountData;
if (_assignDeficit > 0) {
// If any deficit, calculate the gas units unpaid for due to assign deficit.
// Gas units written off = gas used * (deficit / gas value with surcharges) ratio.
// `mulDivUp()` rounds in favor of writeoffs, so we don't overestimate gas that was actually paid for
// and end up reimbursing the bundler for more than was actually taken from the solvers.
uint256 _gasWrittenOff = _gasUsed.mulDivUp(_assignDeficit, _gasValueWithSurcharges);
// No risk of underflow in subtraction below, because:
// _assignDeficit is <= _gasValueWithSurcharges, so _gasWrittenOff is <= _gasUsed.
// Deduct gas written off from gas tracked as "paid for" by failed solver
_gasUsed -= _gasWrittenOff;
_gL.writeoffsGas += _gasWrittenOff.toUint40(); // add to writeoffs in gasLedger
}
// The gas paid for here by failed solver, and gas written off due to shortfall in `_assign()`, will offset
// what the winning solver owes in `_settle()`.
_gL.solverFaultFailureGas += _gasUsed.toUint40();
}
// Persist the updated gas ledger to transient storage
t_gasLedger = _gL.pack();
}
/// @notice Records the gas used during the `bidFind` phase of exPostBids as a write-off.
/// @dev Gas used for `bidFind` is considered an overhead paid by the bundler (via reduced refund)
/// and is not charged to any specific solver. It's added to `writeoffsGas` in the GasLedger.
/// @param gasUsed The amount of gas consumed during the `bidFind` phase.
function _writeOffBidFindGas(uint256 gasUsed) internal {
GasLedger memory _gL = t_gasLedger.toGasLedger();
_gL.writeoffsGas += gasUsed.toUint40();
t_gasLedger = _gL.pack();
}
/// @notice Charges solvers that were not reached during the metacall for the calldata gas cost of their solverOps.
/// @dev Iterates through `solverOps` starting from the index *after* `winningSolverIdx`. For each unreached
/// operation, `VERIFICATION.verifySolverOp` is called to determine fault.
/// - If bundler fault: The calldata gas is added to `gL.writeoffsGas` (reducing bundler's refund).
/// - If solver fault: Attempts to charge the solver's bonded `AtlETH` using `_assign` for the calldata
/// gas cost (no surcharges added). Any deficit is added to `gL.writeoffsGas`.
/// The gas cost of executing this loop is also added to `gL.writeoffsGas` to ensure the bundler pays for it.
/// @param solverOps The SolverOperation array containing the solvers' transaction data.
/// @param gL The GasLedger struct (memory); `gL.writeoffsGas` is updated within this function.
/// @param winningSolverIdx Index of the winning/last attempted solver; the loop starts after this index.
/// @param userOpHash Hash of the UserOperation, used for verification.
/// @param maxFeePerGas userOp.maxFeePerGas, used for verification.
/// @param bundler The metacall caller (msg.sender), used for verification.
/// @param allowsTrustedOpHash Flag indicating with trustedOpHash is enabled in the metacall.
/// @return unreachedCalldataValuePaid Total value successfully charged to unreached solvers (cost - deficits).
function _chargeUnreachedSolversForCalldata(
SolverOperation[] calldata solverOps,
GasLedger memory gL,
uint256 winningSolverIdx,
bytes32 userOpHash,
uint256 maxFeePerGas,
address bundler,
bool allowsTrustedOpHash
)
internal
returns (uint256 unreachedCalldataValuePaid)
{
uint256 _writeoffGasMarker = gasleft();
// Start at the solver after the current solverIdx, because current solverIdx is the winner
for (uint256 i = winningSolverIdx + 1; i < solverOps.length; ++i) {
address _from = solverOps[i].from;
uint256 _calldataGasCost =
GasAccLib.solverOpCalldataGas(solverOps[i].data.length, L2_GAS_CALCULATOR) * tx.gasprice;
// Verify the solverOp, and write off solver's calldata gas if included due to bundler fault
uint256 _result =
VERIFICATION.verifySolverOp(solverOps[i], userOpHash, maxFeePerGas, bundler, allowsTrustedOpHash);
if (_result.bundlersFault()) {
gL.writeoffsGas += _calldataGasCost.divUp(tx.gasprice).toUint40();
continue;
}
// If solverOp inclusion was not bundler fault, charge solver for calldata gas
EscrowAccountAccessData memory _solverData = S_accessData[_from];
// No surcharges added to calldata cost for unreached solvers
uint256 _deficit = _assign(_solverData, _from, _calldataGasCost);
// Persist _assign() changes to solver account data to storage
S_accessData[_from] = _solverData;
// The sum of value paid less deficits is tracked and used in `_settle()`
unreachedCalldataValuePaid += _calldataGasCost - _deficit;
// Any deficits from the `_assign()` operations are converted to gas units and written off so as not to
// charge the winning solver for calldata that is not their responsibility, in `_settle()`.
if (_deficit > 0) gL.writeoffsGas += _deficit.divUp(tx.gasprice).toUint40();
}
// The gas cost of this loop is always paid by the bundler so as not to charge the winning solver for an
// excessive number of loops and SSTOREs via `_assign()`. This gas is therefore added to writeoffs.
gL.writeoffsGas += (_writeoffGasMarker - gasleft()).toUint40();
}
/// @notice Finalizes gas accounting at the end of the metacall, settles balances, and pays refunds/surcharges.
/// @param ctx The context struct (memory), used for ctx.bundler and ctx.solverSuccessful.
/// @param gL The final state of the GasLedger struct (memory), used for gas calculations.
/// @param gasMarker The initial gas measurement taken at the start of the metacall.
/// @param gasRefundBeneficiary The address designated to receive the bundler's gas refund. Defaults to
/// `ctx.bundler`.
/// @param unreachedCalldataValuePaid The total value successfully collected from unreached solvers for their
/// calldata costs (from `_chargeUnreachedSolversForCalldata`).
/// @param multipleSuccessfulSolvers A boolean indicating whether the multipleSuccessfulSolvers mode is enabled.
/// @return claimsPaidToBundler The net amount of ETH transferred to the `gasRefundBeneficiary`.
/// @return netAtlasGasSurcharge The net amount of ETH taken as Atlas surcharge during the metacall.
function _settle(
Context memory ctx,
GasLedger memory gL,
uint256 gasMarker,
address gasRefundBeneficiary,
uint256 unreachedCalldataValuePaid,
bool multipleSuccessfulSolvers
)
internal
returns (uint256 claimsPaidToBundler, uint256 netAtlasGasSurcharge)
{
EscrowAccountAccessData memory _winningSolverData;
BorrowsLedger memory _bL = t_borrowsLedger.toBorrowsLedger();
(address _winningSolver,,) = _solverLockData();
// No need to SLOAD bonded balance etc. if no winning solver
if (ctx.solverSuccessful) _winningSolverData = S_accessData[_winningSolver];
// Send gas refunds to bundler if no gas refund beneficiary specified
if (gasRefundBeneficiary == address(0)) gasRefundBeneficiary = ctx.bundler;
// First check if all borrows have been repaid.
// Borrows can only be repaid in native token, not bonded AtlETH.
// This is also done at end of solverCall(), so check here only needed for zero solvers case.
int256 _netRepayments = _bL.netRepayments();
if (_netRepayments < 0) revert BorrowsNotRepaid(_bL.borrows, _bL.repays);
uint256 _winnerGasCharge;
uint256 _gasLeft = gasleft();
// NOTE: Trivial for bundler to run a different EOA for solver so no bundler == solver carveout.
if (ctx.solverSuccessful) {
// CASE: Winning solver.
// Winning solver should pay for:
// - Gas (C + E) used by their solverOp
// - Gas (C + E) used by userOp, dapp hooks, and other metacall overhead
// Winning solver should not pay for:
// - Gas (C + E) used by other reached solvers (bundler or solver fault failures)
// - Gas (C only) used by unreached solvers
// - Gas (E only) used during the bid-finding or unreached solver calldata charge loops
_winnerGasCharge = gasMarker - gL.writeoffsGas - gL.solverFaultFailureGas
- (unreachedCalldataValuePaid / tx.gasprice) - _gasLeft;
uint256 _surchargedGasPaidBySolvers = gL.solverFaultFailureGas + _winnerGasCharge;
// Bundler gets base gas cost + bundler surcharge of (solver fault fails + winning solver charge)
// Bundler also gets reimbursed for the calldata of unreached solvers (only base, no surcharge)
claimsPaidToBundler = (_surchargedGasPaidBySolvers.withSurcharge(gL.bundlerSurchargeRate) * tx.gasprice)
+ unreachedCalldataValuePaid;
// Atlas gets only the Atlas surcharge of (solver fault fails + winning solver charge)
netAtlasGasSurcharge = _surchargedGasPaidBySolvers.getSurcharge(gL.atlasSurchargeRate) * tx.gasprice;
// Calculate what winning solver pays: add surcharges and multiply by gas price
_winnerGasCharge = _winnerGasCharge.withSurcharge(gL.totalSurchargeRate()) * tx.gasprice;
uint256 _deficit; // Any shortfall that the winning solver is not able to repay from bonded balance
if (_winnerGasCharge < uint256(_netRepayments)) {
// CASE: solver recieves more than they pay --> net credit to account
_credit(_winningSolverData, uint256(_netRepayments) - _winnerGasCharge);
} else {
// CASE: solver pays more than they recieve --> net assign to account
_deficit = _assign(_winningSolverData, _winningSolver, _winnerGasCharge - uint256(_netRepayments));
}
if (_deficit > claimsPaidToBundler) revert AssignDeficitTooLarge(_deficit, claimsPaidToBundler);
claimsPaidToBundler -= _deficit;
_updateAnalytics(_winningSolverData, true, _winnerGasCharge);
// Persist the updated winning solver account data to storage
S_accessData[_winningSolver] = _winningSolverData;
} else {
// CASE: No winning solver.
// Bundler may still recover a partial refund (from solver fault failure charges) up to 80% of the gas cost
// of the metacall. The remaining 20% could be recovered through storage refunds, and it is important that
// metacalls with no winning solver are not profitable for the bundler.
// The exception to this rule is when multipleSuccessfulSolvers is set to true. In this case, all solvers
// should be able to execute and pay for their own gas + surcharges, but the bundler refund should not be
// capped.
uint256 _maxRefund;
if (multipleSuccessfulSolvers) {
_maxRefund = type(uint256).max;
} else {
_maxRefund = (gasMarker - gL.writeoffsGas - _gasLeft).maxBundlerRefund() * tx.gasprice;
}
// Bundler gets (base gas cost + bundler surcharge) of solver fault failures, plus base gas cost of
// unreached solver calldata. This is compared to _maxRefund below. Net repayments is added after the 80%
// cap has been applied to the gas refund components.
// `unreachedCalldataValuePaid` is not added here as it should always be 0 when solverSuccessful = false,
// because there should then be no unreached solvers.
uint256 _bundlerCutBeforeLimit =
uint256(gL.solverFaultFailureGas).withSurcharge(gL.bundlerSurchargeRate) * tx.gasprice;
// Atlas only keeps the Atlas surcharge of solver fault failures, and any gas due to bundler that exceeds
// the 80% limit.
netAtlasGasSurcharge = uint256(gL.solverFaultFailureGas).getSurcharge(gL.atlasSurchargeRate) * tx.gasprice;
if (_bundlerCutBeforeLimit > _maxRefund) {
// More than max gas refund was taken by failed/unreached solvers, excess goes to Atlas
claimsPaidToBundler = _maxRefund;
netAtlasGasSurcharge += _bundlerCutBeforeLimit - _maxRefund;
} else {
// Otherwise, the bundler can receive the full solver fault failure gas
claimsPaidToBundler = _bundlerCutBeforeLimit;
}
// Finally, add any net repayments, which should not be subject to the 80% cap, to the bundler's claims
claimsPaidToBundler += uint256(_netRepayments);
}
S_cumulativeSurcharge += netAtlasGasSurcharge;
// Set lock to FullyLocked to prevent any reentrancy possibility in refund transfer below
_setLockPhase(uint8(ExecutionPhase.FullyLocked));
if (claimsPaidToBundler != 0) SafeTransferLib.safeTransferETH(gasRefundBeneficiary, claimsPaidToBundler);
}
/// @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 Checks all obligations have been reconciled: native borrows AND gas liabilities.
/// @return True if both dimensions are reconciled, false otherwise.
function _isBalanceReconciled(bool multipleSuccessfulSolvers) internal view returns (bool) {
GasLedger memory gL = t_gasLedger.toGasLedger();
BorrowsLedger memory bL = t_borrowsLedger.toBorrowsLedger();
// DApp's excess repayments via `contribute()` can offset solverGasLiability.
// NOTE: This solver gas subsidy feature is disabled in multipleSuccessfulSolvers mode.
uint256 _netRepayments;
if (!multipleSuccessfulSolvers && bL.repays > bL.borrows) _netRepayments = bL.repays - bL.borrows;
// gL.maxApprovedGasSpend only stores the gas units, must be scaled by tx.gasprice
uint256 _maxApprovedGasValue = gL.maxApprovedGasSpend * tx.gasprice;
return (bL.repays >= bL.borrows) && (_maxApprovedGasValue + _netRepayments >= gL.solverGasLiability());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if gt(x, div(not(0), y)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if iszero(eq(div(z, y), x)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := add(iszero(iszero(mod(z, WAD))), div(z, WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(mul(y, eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
/// Note: This function is an approximation.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
/// Note: This function is an approximation. Monotonically increasing.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
(int256 wad, int256 p) = (int256(WAD), x);
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (uint256(w >> 63) == uint256(0)) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == uint256(0)) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != uint256(0));
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c == uint256(0)) return w;
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Temporarily use `result` as `p0` to save gas.
result := mul(x, y) // Lower 256 bits of `x * y`.
for {} 1 {} {
// If overflows.
if iszero(mul(or(iszero(x), eq(div(result, x), y)), d)) {
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(result, lt(mm, result))) // Upper 256 bits of `x * y`.
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
let r := mulmod(x, y, d) // Compute remainder using mulmod.
let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
// Placing the check here seems to give more optimal stack operations.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
d := div(d, t) // Divide `d` by `t`, which is a power of two.
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
)
break
}
result := div(result, d)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
/// Performs the full 512 bit calculation regardless.
function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := mul(x, y)
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(result, lt(mm, result)))
let t := and(d, sub(0, d))
let r := mulmod(x, y, d)
d := div(d, t)
let inv := xor(2, mul(3, d))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
result :=
mul(
or(mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)), div(sub(result, r), t)),
mul(sub(2, mul(d, inv)), inv)
)
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(z, d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(z, d))), div(z, d))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
result := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if x {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`, rounded down.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`, rounded down.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// Makeshift lookup table to nudge the approximate log2 result.
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
// Newton-Raphson's.
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
// Round down.
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
z = (1 + sqrt(x)) * 10 ** 9;
z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
}
/// @solidity memory-safe-assembly
assembly {
z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down.
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
z = (1 + cbrt(x)) * 10 ** 12;
z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
}
/// @solidity memory-safe-assembly
assembly {
let p := x
for {} 1 {} {
if iszero(shr(229, p)) {
if iszero(shr(199, p)) {
p := mul(p, 100000000000000000) // 10 ** 17.
break
}
p := mul(p, 100000000) // 10 ** 8.
break
}
if iszero(shr(249, p)) { p := mul(p, 100) }
break
}
let t := mulmod(mul(z, z), z, p)
z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down.
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for {} x { x := sub(x, 1) } { result := mul(result, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards zero.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
unchecked {
z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255);
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
internal
pure
returns (uint256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
unchecked {
if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
return a - fullMulDiv(a - b, t - begin, end - begin);
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
internal
pure
returns (int256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
// forgefmt: disable-next-item
unchecked {
if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a),
uint256(t - begin), uint256(end - begin)));
return int256(uint256(a) - fullMulDiv(uint256(a - b),
uint256(t - begin), uint256(end - begin)));
}
}
/// @dev Returns if `x` is an even number. Some people may need this.
function isEven(uint256 x) internal pure returns (bool) {
return x & uint256(1) == uint256(0);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import { Storage } from "./Storage.sol";
import { CallBits } from "../libraries/CallBits.sol";
import "../types/ConfigTypes.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,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator
)
Storage(escrowDuration, atlasSurchargeRate, 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 userOpHash The hash of the UserOperation.
/// @param executionEnvironment The address of the execution environment.
/// @param bundler The address of the bundler.
/// @param dappGasLimit The DAppControl's gas limit for preOps and allocateValue hooks.
/// @param solverOpCount The count of SolverOperations.
/// @param isSimulation Whether the current execution is a simulation.
/// @return An Context struct initialized with the provided parameters.
function _buildContext(
bytes32 userOpHash,
address executionEnvironment,
address bundler,
uint32 dappGasLimit,
uint8 solverOpCount,
bool isSimulation
)
internal
pure
returns (Context memory)
{
return Context({
executionEnvironment: executionEnvironment,
userOpHash: userOpHash,
bundler: bundler,
solverSuccessful: false,
solverIndex: 0,
solverCount: solverOpCount,
phase: uint8(ExecutionPhase.PreOps),
solverOutcome: 0,
bidFind: false,
isSimulation: isSimulation,
callDepth: 0,
dappGasLeft: dappGasLimit
});
}
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import "../types/EscrowTypes.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;
// 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
// Tracks gas accounting vars - see GasAccLib.sol for more details
uint256 internal transient t_gasLedger;
// Tracks borrows and repayments of native token - see GasAccLib.sol for more details
uint256 internal transient t_borrowsLedger;
// AtlETH storage
uint256 internal S_totalSupply;
uint256 internal S_bondedTotalSupply;
// Surcharge-related storage
uint256 internal S_atlasSurchargeRate; // Loaded into GasLedger during metacall, scale = 10_000
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,
address verification,
address simulator,
address initialSurchargeRecipient,
address l2GasCalculator
)
payable
{
VERIFICATION = IAtlasVerification(verification);
SIMULATOR = simulator;
L2_GAS_CALCULATOR = l2GasCalculator;
ESCROW_DURATION = escrowDuration;
// Check Atlas gas surcharge fits in 24 bits
if(atlasSurchargeRate > type(uint24).max) {
revert SurchargeRateTooHigh();
}
S_atlasSurchargeRate = atlasSurchargeRate;
S_cumulativeSurcharge = msg.value;
S_surchargeRecipient = initialSurchargeRecipient;
emit SurchargeRecipientTransferred(initialSurchargeRecipient);
}
// ---------------------------------------------------- //
// Storage Setters //
// ---------------------------------------------------- //
function setAtlasSurchargeRate(uint256 newAtlasRate) external {
_onlySurchargeRecipient();
_checkIfUnlocked(); // Should not be able to change Atlas surcharge during a metacall
// Check Atlas gas surcharge fits in 24 bits
if(newAtlasRate > type(uint24).max) {
revert SurchargeRateTooHigh();
}
S_atlasSurchargeRate = newAtlasRate;
}
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 getAtlasSurchargeRate() external view returns (uint256) {
return S_atlasSurchargeRate;
}
// ---------------------------------------------------- //
// Storage Internal Getters //
// ---------------------------------------------------- //
function _atlasSurchargeRate() internal view returns (uint24) {
return uint24(S_atlasSurchargeRate);
}
// ---------------------------------------------------- //
// 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;
}
// Will revert if Atlas is not in the unlocked state (i.e. will revert during a metacall).
function _checkIfUnlocked() internal view {
if (!_isUnlocked()) revert InvalidLockState();
}
// ---------------------------------------------------- //
// 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";
import { GasAccLib } from "../libraries/GasAccLib.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 _GRACEFUL_RETURN_GAS_OFFSET = 40_000;
// Gas Accounting constants
uint256 internal constant _GAS_PER_CALLDATA_BYTE = GasAccLib._GAS_PER_CALLDATA_BYTE;
// Calldata bytes charged at half the upper rate of 16 gas per byte (i.e. charged at 8 gas per byte), for both zero
// and non-zero bytes of calldata.
uint256 internal constant _BASE_TX_GAS_USED = 21_000;
uint256 internal constant _PRE_EXECUTE_METACALL_GAS = 150_000; // Approx gas used from start of metacall to the
// `execute()` function call, including EE deployment cost. For gas limit estimation purposes.
uint256 internal constant _POST_SETTLE_METACALL_GAS = 70_000; // Approx gas used from the gasleft() measurement
// taken at the start of `_settle()`. For full metacall gas reimbursement purposes.
uint256 internal constant _EXECUTE_SOLVER_OVERHEAD = 45_000; // Approx upper bound gas used by each
// `_executeSolverOperation()` call, excluding the `_solverOpWrapper()` gas. For gas limit estimation purposes.
uint256 internal constant _SOLVER_OP_STATIC_LENGTH = GasAccLib._SOLVER_OP_STATIC_LENGTH; // SolverOperation calldata
// length excluding solverOp.data
uint256 internal constant _BUNDLER_FAULT_OFFSET = 4500; // Extra gas to write off if solverOp failure is bundler
// fault in `_handleSolverFailAccounting()`. Value is worst-case gas measured for bundler fault.
uint256 internal constant _SOLVER_FAULT_OFFSET = 28_800; // Extra gas to charge solver if solverOp failure is solver
// fault in `_handleSolverFailAccounting()`. Value is worst-case gas measured for solver fault.
uint256 internal constant _EXTRA_CALLDATA_LENGTH = 238; // incl. gasRefundBeneficiary address and dynamic offset
// calldata
// 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;
uint256 internal constant _BID_FIND_OVERHEAD = 5000; // Overhead gas for the logic required to execute and sort each
// solverOp in `_bidFindingIteration()`
// Params below are used to calculate the tolerated max diff between actual gasleft and expected gasleft, in the
// `_getAndVerifyGasLimits()` function. This tolerance is mostly for calldata gas cost differences.
uint256 internal constant _UPPER_BASE_EXEC_GAS_TOLERANCE = 20_000;
uint256 internal constant _LOWER_BASE_EXEC_GAS_TOLERANCE = 60_000;
uint256 internal constant _TOLERANCE_PER_SOLVER = 33_000;
}{
"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/",
"nitro-contracts/=lib/nitro-contracts/",
"@offchainlabs/upgrade-executor/=lib/nitro-contracts/node_modules/@offchainlabs/upgrade-executor/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@uniswap/lib/=lib/nitro-contracts/node_modules/@uniswap/lib/contracts/",
"@uniswap/v2-core/=lib/nitro-contracts/node_modules/@uniswap/v2-core/contracts/",
"chainlink/=lib/chainlink/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"redstone-oracles-monorepo/=lib/redstone-oracles-monorepo/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 18
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}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":"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":[{"internalType":"uint256","name":"deficit","type":"uint256"},{"internalType":"uint256","name":"bundlerRefund","type":"uint256"}],"name":"AssignDeficitTooLarge","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":[{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"repays","type":"uint256"}],"name":"BorrowsNotRepaid","type":"error"},{"inputs":[],"name":"BothPreOpsAndUserReturnDataCannotBeTracked","type":"error"},{"inputs":[],"name":"BothUserAndDAppNoncesCannotBeSequential","type":"error"},{"inputs":[],"name":"CallbackNotCalled","type":"error"},{"inputs":[],"name":"DAppGasLimitReached","type":"error"},{"inputs":[],"name":"DAppNotEnabled","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":[{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"internalType":"uint256","name":"estimatedMetacallGas","type":"uint256"},{"internalType":"uint256","name":"suggestedSimGas","type":"uint256"}],"name":"InsufficientGasForMetacallSimulation","type":"error"},{"inputs":[],"name":"InsufficientLocalFunds","type":"error"},{"inputs":[],"name":"InvalidAccess","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidControl","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":"InvalidSolver","type":"error"},{"inputs":[],"name":"InvalidTo","type":"error"},{"inputs":[],"name":"InvertBidValueCannotBeExPostBids","type":"error"},{"inputs":[],"name":"InvertedBidExceedsCeiling","type":"error"},{"inputs":[],"name":"MustBeDelegatecalled","type":"error"},{"inputs":[],"name":"NoAuctionWinner","type":"error"},{"inputs":[],"name":"NoDelegatecall","type":"error"},{"inputs":[],"name":"NotEnvironmentOwner","type":"error"},{"inputs":[],"name":"NotImplemented","type":"error"},{"inputs":[],"name":"OnlyAtlas","type":"error"},{"inputs":[],"name":"OnlyGovernance","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":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintToInt","type":"error"},{"inputs":[],"name":"SignatoryActive","type":"error"},{"inputs":[],"name":"SimulationPassed","type":"error"},{"inputs":[],"name":"SimulatorBalanceTooLow","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":"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":"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":"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":"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":"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":[{"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":"nonpayable","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":"uint32","name":"dappGasLimit","type":"uint32"},{"internalType":"uint128","name":"bundlerSurchargeRate","type":"uint128"}],"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":"uint32","name":"dappGasLimit","type":"uint32"},{"internalType":"uint32","name":"solverGasLimit","type":"uint32"},{"internalType":"uint24","name":"bundlerSurchargeRate","type":"uint24"},{"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":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"address","name":"executionEnvironment","type":"address"},{"internalType":"address","name":"bundler","type":"address"},{"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":"bidFind","type":"bool"},{"internalType":"bool","name":"isSimulation","type":"bool"},{"internalType":"address","name":"bundler","type":"address"},{"internalType":"uint32","name":"dappGasLeft","type":"uint32"}],"internalType":"struct Context","name":"ctx","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAtlasSurchargeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"uint32","name":"dappGasLimit","type":"uint32"},{"internalType":"uint32","name":"solverGasLimit","type":"uint32"},{"internalType":"uint24","name":"bundlerSurchargeRate","type":"uint24"},{"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"}],"name":"setAtlasSurchargeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shortfall","outputs":[{"internalType":"uint256","name":"gasLiability","type":"uint256"},{"internalType":"uint256","name":"borrowLiability","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":"bidFind","type":"bool"},{"internalType":"bool","name":"isSimulation","type":"bool"},{"internalType":"address","name":"bundler","type":"address"},{"internalType":"uint32","name":"dappGasLeft","type":"uint32"}],"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
61014080604052346101d75760e081616219803803809161002082856101db565b8339810103126101d75780519060208101519061003f60408201610212565b9161004c60608301610212565b9161005960808201610212565b9261007260c061006b60a08501610212565b9301610212565b6001600160a01b0390951660805260a05260c05260e084905262ffffff81116101c8576002555f6003819055600480546001600160a01b0319166001600160a01b039390931692831790556040519391907f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde439859080a2156101b9576101005260208101904682523060601b6040820152603481526101106054826101db565b51902061012052604051615ff290816102278239608051818181610ecc015281816120b901528181613714015281816151e601526156ce015260a051818181610f10015281816120440152613b7c015260c051818181610a6201528181612476015281816136be01526159ae015260e05181818161065b0152818161077b0152818161143e015261255b015261010051818181610e1601526150b80152610120518161503a0152f35b63b4ff4a4d60e01b5f5260045ffd5b6359b9784760e01b5f5260045ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176101fe57604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101d75756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806306fdde03146102f957806318160ddd146102f457806319b1faef146102ef578063234b7ede146102ea57806327de9e32146102e55780632e1a7d4d146102e0578063313ce567146102db5780634317ca01146102d657806345112906146102d15780635270182c146102cc5780635b651b05146102c75780635cd6ef67146102c25780635e8edccc146102bd578063635c7e71146102b857806367f7c8e0146102b35780636ef5ac7a146102ae57806370a08231146102a9578063791ae748146102a457806379b797651461029f5780637c20857a1461029a5780637c3c3160146102955780637e29c68414610290578063825ad6071461028b5780638380edb714610286578063890c2854146102815780638ebf091f1461027c57806395d89b41146102775780639940686e14610272578063a0531b021461026d578063a495d28d14610268578063a6efccf914610263578063aa7d2dc81461025e578063aebaa5f714610259578063b2c5c51014610254578063c41d54da1461024f578063c5471d9e1461024a578063c5ebeaec14610245578063d0e30db014610240578063d7bb99ba1461023b578063db006a7514610236578063e3de91a314610231578063eced55261461022c578063f05f88e014610227578063f68b84f714610222578063f83d08ba1461021d5763fc61c5410361000e576117bf565b61177f565b611766565b611744565b611728565b6116e6565b6115e3565b6115a9565b611594565b611578565b61155b565b611504565b6114e2565b61149c565b611461565b611427565b61130f565b6111bf565b6111a2565b61115a565b6110e5565b6110c8565b6110ab565b611068565b610fab565b610f83565b610f3f565b610efb565b610eb7565b610e74565b610e45565b610e01565b610d09565b610a91565b610a4d565b610a30565b610a01565b610953565b610885565b61082b565b6106a3565b610593565b61056a565b610467565b61044b565b6103f8565b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b0382111761032d57604052565b6102fe565b60c081019081106001600160401b0382111761032d57604052565b604081019081106001600160401b0382111761032d57604052565b90601f801991011681019081106001600160401b0382111761032d57604052565b6040519061039961018083610368565b565b6040519061039960e083610368565b60405190610399604083610368565b6001600160401b03811161032d57601f01601f191660200190565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610447575f36600319011261044757610443604051610419604082610368565b6009815268082e8d8c2e6408aa8960bb1b60208201526040519182916020835260208301906103d4565b0390f35b5f80fd5b34610447575f3660031901126104475760205f54604051908152f35b34610447575f3660031901126104475761048a61048560035c612f1c565b61302a565b61049560045c613076565b80516020909101516001600160801b039182169116808210156104d15750505f5b604080519283526001600160801b0391909116602083015290f35b6104da916117fb565b6104b6565b6001600160a01b0381160361044757565b6101243590610399826104df565b6101443590610399826104df565b60243590610399826104df565b3590610399826104df565b60a09060031901126104475760043561053c816104df565b90602435610549816104df565b906044359060643561055a816104df565b90608435610567816104df565b90565b346104475761001861058e602e61058036610524565b9195929490939291846130ae565b613124565b34610447576020366003190112610447576004356105af613170565b6106276105bb82614c4c565b335f5260076020526105fa60405f206105e66105e08460018060701b03845416613178565b82613191565b63ffffffff6105f3614c7d565b16906131b0565b335f908152600660205260409020805490916106219160701c6001600160701b03166131d3565b906131ec565b7f7659747cd8571f1071eea946fdc648adcf181cad916f32a05f82c3a52597604861069e610685610680610659614c7d565b7f0000000000000000000000000000000000000000000000000000000000000000906118b3565b61183c565b6040805194855260208501919091523393918291820190565b0390a2005b34610447576020366003190112610447576004356106bf613170565b6106c881614c4c565b906106d233612501565b80549092906001600160701b03166001600160701b03818116908316811061074d57509261070661070c9261001895613178565b90613191565b610717815f54611e16565b5f5560405181815233907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca590602090a233613215565b610758929192614c7d565b6107a16107746107673361251a565b5460701c63ffffffff1690565b63ffffffff7f000000000000000000000000000000000000000000000000000000000000000091166118b3565b10156108135750610018936107ec6107bf61080e9461080994613178565b82546001600160701b031916835591805461062190849060701c6001600160701b0316613178565b613178565b60018060701b03166107ff815f546118b3565b5f55600154611e16565b600155565b61070c565b6307d2457d60e21b5f52600452602483905260445b5ffd5b34610447575f36600319011261044757602060405160128152f35b90816102009103126104475790565b9181601f84011215610447578235916001600160401b038311610447576020808501948460051b01011161044757565b6080366003190112610447576004356001600160401b038111610447576108b0903690600401610846565b6024356001600160401b038111610447576108cf903690600401610855565b91604435906001600160401b038211610447576101206003198336030112610447576104439361090f9360643593610906856104df565b6004019261201d565b60405190151581529081906020820190565b604090600319011261044757600435610939816104df565b90602435610567816104df565b6001600160a01b03169052565b346104475761096136610921565b6040516311a4252f60e31b815291906020836004816001600160a01b0385165afa9182156109fc5763ffffffff935f936109c7575b506109a2918391613ced565b604080516001600160a01b03831681529390921660208401523b151590820152606090f35b6109a29293506109ee9060203d6020116109f5575b6109e68183610368565b8101906124ec565b9291610996565b503d6109dc565b611d9f565b34610447576020366003190112610447576020610a28600435610a23816104df565b612533565b604051908152f35b34610447575f366003190112610447576020600254604051908152f35b34610447575f366003190112610447576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461044757602036600319011261044757600435610aae816104df565b60018060a01b03165f52600760205260405f2060405190610ace82610312565b5460018060701b0381168252610443602083019163ffffffff8160701c168352604084019362ffffff8260901c168552610b7d610b6f610b65610b5b610b50610b326060870197610b2c62ffffff8260a81c168a9062ffffff169052565b60c01c90565b6001600160401b03166080870190815295516001600160701b031690565b975163ffffffff1690565b975162ffffff1690565b935162ffffff1690565b91516001600160401b031690565b604080516001600160701b03909616865263ffffffff909616602086015262ffffff928316958501959095521660608301526001600160401b03909216608082015290819060a0820190565b63ffffffff81160361044757565b610164359061039982610bc9565b359061039982610bc9565b6001600160801b0381160361044757565b60a4359061039982610bf0565b8015150361044757565b610164359061039982610c0e565b60e4359061039982610c0e565b610104359061039982610c0e565b610124359061039982610c0e565b90610160806103999380518452610c6e60208201516020860190610946565b60408181015162ffffff169085015260608181015160ff169085015260808181015160ff169085015260a08181015160ff169085015260c08181015160ff169085015260e0818101511515908501526101008181015115159085015261012081810151151590850152610ceb610140820151610140860190610946565b015163ffffffff16910152565b610180810192916103999190610c4f565b366003190161018081126104475760c01361044757604051610d2a81610332565b600435610d36816104df565b8152602435610d4481610bc9565b6020820152604435610d55816104df565b6040820152606435610d6681610bc9565b6060820152608435610d7781610bc9565b6080820152610d84610c01565b60a082015260c4356001600160401b03811161044757610da8903690600401610846565b9060e435906001600160401b0382116104475761044392610dd0610df5933690600401610855565b6101043590610ddd6104f0565b92610de66104fe565b94610def610c18565b96612644565b60405191829182610cf8565b34610447575f366003190112610447576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610447576020366003190112610447576004355f526008602052602060ff60405f2054166040519015158152f35b3461044757602036600319011261044757600435610e91816104df565b60018060a01b03165f526006602052602060018060701b0360405f205416604051908152f35b34610447575f366003190112610447576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610447575f366003190112610447576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461044757602036600319011261044757600435610f5c816104df565b60018060a01b03165f526007602052602063ffffffff60405f205460701c16604051908152f35b34610447575f366003190112610447576005546040516001600160a01b039091168152602090f35b3461044757610fb936610921565b336001600160a01b038316141580611055575b611047576040516311a4252f60e31b8152906020826004816001600160a01b0385165afa9081156109fc576104439361100c935f93611026575b506144a8565b6040516001600160a01b0390911681529081906020820190565b61104091935060203d6020116109f5576109e68183610368565b915f611006565b6282b42960e81b5f5260045ffd5b50336001600160a01b0382161415610fcc565b3461044757602036600319011261044757600435611085816104df565b60018060a01b03165f526007602052602060018060701b0360405f205416604051908152f35b34610447575f3660031901126104475760205f5c15604051908152f35b34610447575f366003190112610447576020600154604051908152f35b34610447575f366003190112610447576005546001600160a01b038116330361114b5760048054336001600160a01b03199182168117909255919091166005557f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde439855f80a2005b633006171960e21b5f5260045ffd5b34610447575f3660031901126104475761044360405161117b604082610368565b60068152650c2e8d88aa8960d31b60208201526040519182916020835260208301906103d4565b3461044757602036600319011261044757610018600435336144db565b34610447576020366003190112610447576004356111dc816104df565b6111e461458f565b600454600580546001600160a01b0319166001600160a01b0393841690811790915591167ffc722bcd56a71612cd14b287fbf50545429e6c9e8de86ea7c3febdecd34882fd5f80a3005b62ffffff81160361044757565b604435906103998261122e565b35906103998261122e565b60ff81160361044757565b6064359061039982611253565b6084359061039982611253565b60a4359061039982611253565b60c4359061039982611253565b90816101a09103126104475790565b9181601f84011215610447578235916001600160401b038311610447576020838186019501011161044757565b6080809180518452602081015160208501526040810151604085015260608101511515606085015201511515910152565b60a08101929161039991906112ce565b36600319016101e0811261044757610180136104475761132d610389565b600435815261133a61050c565b602082015261134761123b565b604082015261135461125e565b606082015261136161126b565b608082015261136e611278565b60a082015261137b611285565b60c0820152611388610c26565b60e0820152611395610c33565b6101008201526113a3610c41565b6101208201526113b16104fe565b6101408201526113bf610bd7565b610160820152610184356001600160401b038111610447576113e5903690600401611292565b906101a435916101c435916001600160401b038311610447576104439361141361141b9436906004016112a1565b939092612949565b604051918291826112ff565b34610447575f3660031901126104475760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610447575f36600319011261044757606061147b6148d7565b604080516001600160a01b0390941684529115156020840152151590820152f35b34610447576020366003190112610447576004356114b9816104df565b60018060a01b03165f526006602052602060018060701b0360405f205460701c16604051908152f35b3461044757610018606a61058e6114f836610524565b809493959296916130ae565b34610447575f3660031901126104475761151c61458f565b6003545f60035561152d8133613215565b6040519081527f87fa2ce024d3bdae31517696c13905fc0882bc1b4f4508060eb29358056de22b60203392a2005b34610447575f366003190112610447576020600354604051908152f35b3461044757602036600319011261044757610018600435612c39565b5f366003190112610447576100183433614a1f565b5f366003190112610447575f5c60281c6001600160a01b03163381036115d157610018614a98565b6346ba7eb160e11b5f5260045260245ffd5b34610447576020366003190112610447576004356115ff613170565b611607614c7d565b335f52600760205261163361065961162a60405f205463ffffffff9060701c1690565b63ffffffff1690565b10156116d75761169661164582614c4c565b61070661165133612501565b80549092906116779061167190839060701c6001600160701b0316613178565b846131ec565b61168661080986600154611e16565b82546001600160701b03166131d3565b6116a1815f546118b3565b5f5560405190815233907f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a690806020810161069e565b63078e135760e51b5f5260045ffd5b346104475760203660031901126104475760043561170261458f565b61170a613170565b62ffffff811161171957600255005b6359b9784760e01b5f5260045ffd5b34610447575f3660031901126104475760206040516127108152f35b6020366003190112610447576100186004356117603433614a1f565b336144db565b6020366003190112610447576020610a28600435612cd0565b34610447575f36600319011261044757606063ffffffff60ff6117a06149fc565b9193906040519460018060a01b03168552166020840152166040820152f35b34610447575f366003190112610447576004546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161181457565b6117e7565b634e487b7160e01b5f52602160045260245ffd5b6008111561183757565b611819565b906001820180921161181457565b90615208820180921161181457565b9062011170820180921161181457565b90610260820180921161181457565b90610160820180921161181457565b9060ee820180921161181457565b90617080820180921161181457565b90611194820180921161181457565b9190820180921161181457565b604051906118cd82610332565b5f60a0838281528260208201528260408201528260608201528260808201520152565b35610567816104df565b9190826080910312610447578151916020810151916060604083015192015160288110156104475790565b60a090600180831b03815116835263ffffffff6020820151166020840152600180831b03604082015116604084015263ffffffff606082015116606084015263ffffffff60808201511660808401528160018060801b0391015116910152565b9035601e19823603018112156104475701602081359101916001600160401b03821161044757813603831361044757565b908060209392818452848401375f828201840152601f01601f1916010190565b610567916119ec816119e784610519565b610946565b611a056119fb60208401610519565b6020830190610946565b60408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c0820152611a50611a4660e08401610519565b60e0830190610946565b611a6b611a606101008401610519565b610100830190610946565b611a89611a7b6101208401610be5565b63ffffffff16610120830152565b611aa7611a996101408401610be5565b63ffffffff16610140830152565b611ac5611ab76101608401610be5565b63ffffffff16610160830152565b611ae2611ad56101808401611248565b62ffffff16610180830152565b611afd611af26101a08401610519565b6101a0830190610946565b611b31611b25611b116101c0850185611985565b6102006101c08601526102008501916119b6565b926101e0810190611985565b916101e08185039101526119b6565b61056791611b51816119e784610519565b611b606119fb60208401610519565b60408201356040820152606082013560608201526080820135608082015260a082013560a0820152611ba1611b9760c08401610519565b60c0830190610946565b611bb0611a4660e08401610519565b610100820135610100820152611bd7611bcc6101208401610519565b610120830190610946565b610140820135610140820152611c17611c0b611bf7610160850185611985565b6101a06101608601526101a08501916119b6565b92610180810190611985565b916101808185039101526119b6565b90602083828152019060208160051b85010193835f915b838310611c4d5750505050505090565b909192939495601f19828203018652863561019e1984360301811215610447576020611c7e60019386839401611b40565b980196019493019190611c3d565b94610120611d6e611cd96103999b96611d97986101809b9f9e9c97611ccb906101a060c08e611cbe81611d7f9d611925565b01526101a08d01906119d6565b918b830360e08d0152611c26565b928884036101008a0152611cf0846119e783610519565b611d09611cff60208301610519565b6020860190610946565b6040810135604085015260608101356060850152611d36611d2c60808301610519565b6080860190610946565b611d4f611d4560a08301610519565b60a0860190610946565b60c081013560c085015260e081013560e0850152610100810190611985565b9190928161010082015201916119b6565b98610120850152610140840152610160830190610946565b019015159052565b6040513d5f823e3d90fd5b903590601e198136030182121561044757018035906001600160401b0382116104475760200191813603831361044757565b6028111561183757565b90602491602881101561183757600452565b619c3f1981019190821161181457565b5f1981019190821161181457565b9190820391821161181457565b356105678161122e565b90603f820291808304603f149015171561181457565b8181029291811591840414171561181457565b8115611e60570490565b634e487b7160e01b5f52601260045260245ffd5b5190610399826104df565b51906103998261122e565b519061039982611253565b519061039982610c0e565b519061039982610bc9565b908161018091031261044757611f80610160611ec5610389565b9280518452611ed660208201611e74565b6020850152611ee760408201611e7f565b6040850152611ef860608201611e8a565b6060850152611f0960808201611e8a565b6080850152611f1a60a08201611e8a565b60a0850152611f2b60c08201611e8a565b60c0850152611f3c60e08201611e95565b60e0850152611f4e6101008201611e95565b610100850152611f616101208201611e95565b610120850152611f746101408201611e74565b61014085015201611ea0565b61016082015290565b9693611fb8611fc693611fa58a6101609a97959d9c999d611925565b61018060c08b01526101808a01906119d6565b9188830360e08a0152611c26565b6101008601979097526001600160a01b03908116610120860152166101408401521515910152565b3d15612018573d90611fff826103b9565b9161200d6040519384610368565b82523d5f602084013e565b606090565b91949290945f945a966120376120328961184a565b611859565b906120406118c0565b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161498899182156124e15786888761208560a084016118f0565b80965b612091846132d1565b94859391986040519e8f9663439e2ef360e01b88528a349460048a01986120b799611c8c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316918b9103815a6080945f91f19889156109fc575f905f9a5f915f916124a9575b50602084019b8d8d516121179063ffffffff1690565b62040000161561243f575b505061212d81611ddc565b806123c25750918b9c9d9e8b9c9286946121636121598e9f61214f8c8861341d565b5163ffffffff1690565b6208000016151590565b156123b25750805b6121786101808601611e23565b9061218292613458565b875a61218d90611e2d565b60061c61219990611df8565b9560c0013597886040519e8f97889763635c7e7160e01b895260048901976121c098611f89565b0381305f9061018095f15f9781612381575b5061226557505050505050506121fe906121f86121ed611fee565b915163ffffffff1690565b90613b6e565b612206613c68565b34612256575b6001600160a01b039061221e906118f0565b166040515f516020615fc65f395f51905f5233918061224d81905f604060608401938281528260208201520152565b0390a35b5f805d565b6122603433613215565b61220c565b889a50936122e093879860e09a61232198955f516020615fc65f395f51905f529a956122ea9961229660035c612f1c565b80995f996122bc6122b86122ae8a5163ffffffff1690565b6204000016151590565b1590565b612329575b505050505050506121596122d9915163ffffffff1690565b9389613822565b9590940151151590565b956001600160a01b03906122fd906118f0565b16936040519182913395898460409194939260608201951515825260208201520152565b0390a3612251565b879a50926122d9979261215997959260ff61236c612362608061235460606123749d9b015160ff1690565b9a0135975163ffffffff1690565b6201000016151590565b971692613617565b94918e915f88818f6122c1565b6123a49198506101803d81116123ab575b61239c8183610368565b810190611eab565b965f6121d2565b503d612392565b6123bc908b611e16565b9061216b565b9d50505050505050505050509193905061242c576123df82611ddc565b600a60ff83161015908161241e575b5061240657631eb2e74960e01b5f5261082890611de6565b5034612410575f90565b61241a3433613215565b5f90565b51610200161590505f6123ee565b634e47c97160e01b5f5261082882611de6565b6124a1929a9161249b61247461246f61246a612463866101c061249b980190611daa565b9050611869565b611878565b611887565b7f00000000000000000000000000000000000000000000000000000000000000009061339e565b906118b3565b975f8d612122565b925050506124d091995060803d6080116124da575b6124c88183610368565b8101906118fa565b919a92915f612101565b503d6124be565b868887338096612088565b90816020910312610447575161056781610bc9565b6001600160a01b03165f90815260066020526040902090565b6001600160a01b03165f90815260076020526040902090565b6001600160a01b03165f9081526007602052604090205460701c63ffffffff168015612586577f000000000000000000000000000000000000000000000000000000000000000081018091116118145790565b505f90565b9060405161259881610312565b91546001600160701b038116835263ffffffff607082901c16602084015262ffffff609082901c8116604085015260a882901c16606084015260c01c6080830152565b6040519061018082018281106001600160401b0382111761032d576040525f610160838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201520152565b929491959097966126536125db565b5030330361114b57608084015163ffffffff169261266f6125db565b506040519561268061018088610368565b86526001600160a01b031660208601525f604086018190526060860181905260ff8716608087015260a0860152600160c08601525f60e0860181905261010086015215156101208501526001600160a01b031661014084015263ffffffff166101608301528195606093602083019081516126fe9063ffffffff1690565b6004161515966122ae966103999861274e575b61272061272d9186888a613eae565b9788945163ffffffff1690565b156127435761273d938587614161565b916143a9565b61273d938587613f94565b5061272d61272061276086888a613d46565b915050612711565b6040519061277582610312565b5f6080838281528260208201528260408201528260608201520152565b60015d565b60045d565b60035d565b5f60015d565b6002805c6001600160a01b0319166001600160a01b039290921691909117905d565b6002805c6001600160a01b031916905d565b929061056794926127f9918552606060208601526060850190611b40565b9260408185039101526119b6565b805191908290602001825e015f815290565b908160a09103126104475760806040519161283383610312565b805183526020810151602084015260408101516040840152606081015161285981610c0e565b6060840152015161286981610c0e565b608082015290565b60405190612880602083610368565b5f808352366020840137565b929192612898826103b9565b916128a66040519384610368565b829481845281830111610447578281602093845f960137010152565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260c06080820181905261056794919391926129069291850191906119b6565b9160a08184039101526103d4565b949391612941906103999461293360409460e08a5260e08a0190611b40565b9188830360208a01526119b6565b9401906112ce565b9290919493612956612768565b50303303612c2a5761298161297c612970612970866118f0565b6001600160a01b031690565b612792565b60c0830191612997612992846118f0565b6127a7565b61299f613c75565b6020850180519093905f9081906001600160a01b0316876129e98c6129db898960405195869463ff939f0960e01b6020870152602486016127db565b03601f198101835282610368565b826129db612a136129f98d614632565b604051928391612a0d602084018098612807565b90612807565b51925af1612a1f611fee565b9015612bf45780602080612a3893518301019101612819565b90612a41613c82565b604086013598612a536122b88b61486c565b612c1b575f5c60081c63ffffffff1699612a6d8b936118f0565b905a612a788a6118f0565b89516001600160a01b031693908990898d612a9661012082016118f0565b906101608101612aa591611daa565b909a6140001615155f149a6122b89a612afb96612aed95612b009e612c0b57612acf91369161288c565b935b604051630120c0d360e11b60208201529b8c97602489016128c2565b03601f198101865285610368565b6148c5565b612bfc575f946129db612b4492612b278897612b1a613c8f565b516001600160a01b031690565b95604051958694634667020160e11b602087015260248601612914565b826129db612b546129f9886146c3565b51925af1612b60611fee565b9015612bf457612b7c81602080612b8794518301019101612819565b936208000016151590565b612b8f6148d7565b915015612be557159081612bd1575b50612bc2576101000151612bae57565b815163304680d760e01b5f5260045260245ffd5b631d75534f60e01b5f5260045ffd5b612bdf91506122b8906148fa565b5f612b9e565b638ac3609160e01b5f5260045ffd5b602081519101fd5b630357b89960e61b5f5260045ffd5b5050612c15612871565b93612ad1565b631217157160e31b5f5260045ffd5b63887efaa560e01b5f5260045ffd5b8015612ccd57612c476149fc565b919050336001600160a01b03821603612cb2575060ff6004911611612ca357612c6e6148d7565b509050612ca357612c7e8161486c565b15612c8d576103999033613215565b63029d54f560e21b5f524760045260245260445ffd5b6338961af360e21b5f5260045ffd5b6346ba7eb160e11b5f526001600160a01b031660045260245ffd5b50565b60ff6004612cdc6149fc565b909391501603612ca357612cfa6001600160a01b0360025c16612970565b330361114b57612d086148d7565b509092612d33612d27612d1a8661251a565b546001600160701b031690565b6001600160701b031690565b808211612ece575b50612d4760035c612f1c565b91612d5360045c613076565b8051909490612d72906001600160801b03165b6001600160801b031690565b926020860194612d8b612d66875160018060801b031690565b95612d958261302a565b9734612e90575b505081612e56575b5084841115612de3575050906105679461249b939215612dc5575b50611e16565b612ddd906001600160a01b0316600160a11b17612792565b5f612dbf565b9192909493612dfa6122b85f976208000016151590565b612e3e575b5050612e0c8484926118b3565b10612e2e575061241a926001600160a01b0316600360a11b1791506127929050565b926105679315612dc55750611e16565b84929550612e0c91612e4f91611e16565b9491612dff565b612e85612e8a91612e80612e72612e6d3a87611e56565b614b30565b64ffffffffff166080830152565b614b5d565b61279c565b5f612da4565b612ec290612ebd612ea6612ec7949a34906118b3565b99612eb08b614ada565b6001600160801b03169052565b614b0b565b612797565b5f80612d9c565b90505f612d3b565b6040519060e082018281106001600160401b0382111761032d576040525f60c0838281528260208201528260408201528260608201528260808201528260a08201520152565b61056764ffffffffff91612f2e612ed6565b50612fea838260281c16612fde858460501c16612fd0878660781c16612fc2612f64612f5a8960a01c90565b64ffffffffff1690565b93612fb4612f7d612f758b60c81c90565b62ffffff1690565b97612fa6612f8e612f758d60e01c90565b9b612f9761039b565b9e168e9064ffffffffff169052565b64ffffffffff1660208d0152565b64ffffffffff1660408b0152565b64ffffffffff166060890152565b64ffffffffff166080870152565b62ffffff1660a0850152565b62ffffff1660c0830152565b9064ffffffffff8091169116039064ffffffffff821161181457565b9062ffffff8091169116019062ffffff821161181457565b61306f6105679162ffffff61306864ffffffffff613052818551168260608701511690612ff6565b16928260c08160a0840151169201511690613012565b1690614c2c565b3a90611e43565b5f60206040516130858161034d565b8281520152604051906130978261034d565b6001600160801b038116825260801c602082015290565b9190916130b96149fc565b9491336001600160a01b0390911603613115576001600160a01b03926130df9290613ced565b16330361310657600160ff8093161b1616156130f757565b630106530b60e21b5f5260045ffd5b6343fcae1b60e01b5f5260045ffd5b631e6d8cfb60e21b5f5260045ffd5b601c5f60649281946020966040519860605260405260601b602c526323b872dd60601b600c525af13d1560015f5114171615613163575f606052604052565b637939f4245f526004601cfd5b5f5c6130f757565b6001600160701b03918216908216039190821161181457565b80546001600160701b0319166001600160701b03909216919091179055565b805463ffffffff60701b191660709290921b63ffffffff60701b16919091179055565b6001600160701b03918216908216019190821161181457565b8054600160701b600160e01b03191660709290921b600160701b600160e01b0316919091179055565b5f80809338935af11561322457565b63b12d13eb5f526004601cfd5b519061039982610bf0565b908160c0910312610447576132b860a06040519261325984610332565b8051613264816104df565b8452602081015161327481610bc9565b60208501526040810151613287816104df565b6040850152606081015161329a81610bc9565b606085015260808101516132ad81610bc9565b608085015201613231565b60a082015290565b9060206105679281815201906119d6565b6132d96118c0565b50610100810180356132ea816104df565b60405163e514a79d60e01b815260206004820152919060c09083906001600160a01b0316818061331d60248201896119d6565b03915afa80156109fc5761335d925f91613360575b50613357602061334b61334584976118f0565b946118f0565b92015163ffffffff1690565b916144a8565b91565b613382915060c03d60c011613388575b61337a8183610368565b81019061323c565b5f613332565b503d613370565b90816020910312610447575190565b906001600160a01b0316806133c457508060031b90808204600814901517156118145790565b906020906024604051809481936336d2da6b60e21b835260048301525afa9081156109fc575f916133f4575b5090565b610567915060203d602011613416575b61340e8183610368565b81019061338f565b503d613404565b905f5c61344a5764ffffffff006020600193015160081b16908260281b8360c81b039060281b1617175f5d565b62dc149f60e41b5f5260045ffd5b90612e806134c993612fea613478613472612e8596614b30565b94614b30565b6134b762ffffff600254169164ffffffffff6040519761349960e08a610368565b1687525f60208801819052604088015264ffffffffff166060870152565b5f608086015262ffffff1660a0850152565b6134ee612ec26134d76103aa565b5f8152346001600160801b03166020820152614b0b565b6134f66127a1565b6103996127c9565b634e487b7160e01b5f52603260045260245ffd5b91908110156135355760051b8101359061019e1981360301821215610447570190565b6134fe565b9390926135556080949796939760a0875260a0870190611b40565b602086019790975260408501526001600160a01b031660608401521515910152565b9064ffffffffff8091169116019064ffffffffff821161181457565b9060806001600160401b03916135b260018060701b0382511685613191565b6135c663ffffffff602083015116856131b0565b60408101518454606083015193909201516001600160901b0390921660909190911b62ffffff60901b161760a89290921b62ffffff60a81b1691909117911660c01b6001600160c01b031916179055565b90919492979596935f9761362b5a9a61183c565b955b848710613675575050505050505061366a6020613653612e6d6103999596975a90611e16565b920191613665835164ffffffffff1690565b613577565b64ffffffffff169052565b909192869987876020876136f06136e86136b56136aa8d9e9f8e8b9f61369f836136a4928f613512565b6118f0565b9b613512565b610160810190611daa565b90506136e33a917f000000000000000000000000000000000000000000000000000000000000000090614cfe565b611e43565b948c8c613512565b613710888a6040519687958695634fbf395b60e11b87526004870161353a565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156109fc57613758915f91613804575b5060ff16151590565b6137e7576137658361251a565b61376e9061258b565b9261377a828286614dae565b93613785859261251a565b9061378f91613593565b61379891611e16565b6137a1916118b3565b99600191806137b9575b505b0195949392919061362d565b6137ca612e6d6137e1923a90614d65565b61366a60208c0191613665835164ffffffffff1690565b5f6137ab565b600192506137ca612e6d6137ff929d939d3a90614d65565b6137ad565b61381c915060203d81116134165761340e8183610368565b5f61374f565b959394909161382f612768565b9261383b60045c613076565b916138446148d7565b50509360e08a01996138568b51151590565b613b18575b6001600160a01b03881615613b02575b5061387584614ee1565b935f8512613ad957506138895a9a51151590565b15613a085750906136e361394d61392e61390b8b6139066138f8612f5a9e9f6138f36138cd6139589b6138c7612f5a60208e015164ffffffffff1690565b90611e16565b946138c76138eb60408d01976138c7612f5a8a5164ffffffffff1690565b913a90611e56565b611e16565b9d8e925164ffffffffff1690565b6118b3565b9b6139068d6136e33a91613928612f7560c08b015162ffffff1690565b90614c2c565b9a6136e33a91613947612f7560a088015162ffffff1690565b90614f43565b986139283a93614f50565b96875f928082105f146139ec576139789161397291611e16565b85614f6c565b8082116139d4579161399b6139946139a0936139a59695611e16565b9884614fc5565b61251a565b613593565b6139b96139b4846003546118b3565b600355565b6139c1613c68565b83806139cb575050565b61039991613215565b63039a3a8b60e11b5f5260049190915260245260445ffd5b613a029293506139fb91611e16565b8385614dae565b90613978565b9295989350935095505f14613aac5750505f195b613a7860408501946136e3613a64612f5a613a5861306f613a45612f5a8c5164ffffffffff1690565b613928612f7560c089015162ffffff1690565b985164ffffffffff1690565b613947612f7560a03a95015162ffffff1690565b9080851115613aa057613a9a929161249b82613a949397611e16565b936118b3565b926139a5565b509290613a9a916118b3565b613acf61306f916138f3613ad4946138c7612f5a60208b015164ffffffffff1690565b614f26565b613a1c565b8051602090910151635ad100a360e01b5f526001600160801b039182166004521660245260445ffd5b61014001516001600160a01b031696505f61386b565b9550613b2b613b268661251a565b61258b565b9561385b565b80516020909101516001600160e01b0319811692919060048210613b53575050565b6001600160e01b031960049290920360031b82901b16169150565b90613b7882613b31565b91337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613be4575b506001600160e01b03198216634011dcb760e11b14908115613bd6575b50613bcf5750565b5f5260045ffd5b61020016151590505f613bc7565b91906001600160e01b0319821663e49c0b2560e01b8103613c1657835184015163e49c0b2560e01b5f5260045260245ffd5b91925090635933e62b60e11b8114908115613c57575b8115613c46575b50613c3e575f613baa565b505f5260045ffd5b63a695d44360e01b1490505f613c33565b63bdc56ad160e01b81149150613c2c565b600760ff195f5c16175f5d565b600360ff195f5c16175f5d565b600460ff195f5c16175f5d565b600560ff195f5c16175f5d565b600660ff195f5c16175f5d565b6001600160a01b0391821681529116602082015263ffffffff9091166040820152606081019190915260800190565b908160209103126104475751610567816104df565b613d20906129db613d2594613d03818685615034565b9060405195869463d447616160e01b602087015260248601613ca9565b6150ad565b80516001600160a01b0391613d4291810160209081019101613cd8565b1690565b906105679291600160ff195f5c16175f5d613dbe565b602081830312610447578051906001600160401b038211610447570181601f8201121561044757805190613d8f826103b9565b92613d9d6040519485610368565b8284526020838301011161044757815f9260208093018386015e8301015290565b9291905f805a6020870151909490613e109083906001600160a01b0316613e1e613df361162a6101608d015163ffffffff1690565b94604051948591638a83e68160e01b6020840152602483016132c0565b03601f198101855284610368565b6129db613e41613e2d8c614727565b604051928391612a0d602084018099612807565b5193f1613e56613e4f611fee565b93866150ea565b613e8257610120840151613e7357635b47d49f60e11b5f5260045ffd5b635933e62b60e11b5f5260045ffd5b602001519192509060081615613ea5578060208061056793518301019101613d5c565b50610567612871565b90610567939291600260ff195f5c16175f5d9392916040810135613ed46122b88261486c565b612c1b5760208601515f9283929091613e1091906001600160a01b0316613f1660608501359460405194859163cb6e0ea360e01b6020840152602483016132c0565b6129db613f25613e2d8c61478b565b5193f190613f31611fee565b91613f5e57610120850151613f4f57639f885ee560e01b5f5260045ffd5b63bdc56ad160e01b5f5260045ffd5b602001519293509091601016156133f057610567915060208082518301019101613d5c565b60ff1660ff81146118145760010190565b9594929160ff85165f5b613fb5613faf60608b015160ff1690565b60ff1690565b82811015614025579061249b87613fe1938c613fd35a928d8c613512565b888a61014083013593615166565b95613fef60e08a0151151590565b61401a5761401460608a0161400d614008825160ff1690565b613f83565b60ff169052565b95613f9e565b509496505050505050565b5094509596945050602091500192614044612159855163ffffffff1690565b6140a957505061012081015161408157505161406a9063ffffffff165b61800016151590565b614072575f90565b634011dcb760e11b5f5260045ffd5b614097612f75604061082893015162ffffff1690565b63e49c0b2560e01b5f52600452602490565b9092506140ba610120830151151590565b90816140ed575b50806140d0575b614081575090565b5062ffffff6140e5604083015162ffffff1690565b1615156140c8565b60019150145f6140c1565b6001600160401b03811161032d5760051b60200190565b90614119826140f8565b6141266040519182610368565b8281528092614137601f19916140f8565b0190602036910137565b80518210156135355760209160051b010190565b8015611814575f190190565b9294919093945a9186156143725761010085019161417f8360019052565b6141888861410f565b9361419289611e08565b60035c905f5b8b858c8b8d8a8587106142a95750505050505050506141de916141bd6141d99261279c565b5f6141c78c611e08565b966141d189615848565b525a90611e16565b6158b1565b825b5a6141eb8287614141565b5160101c80156142995761424691889161423e8d614237613faf61ffff8f8a8f8f61422f936060614222613faf8661422a95611e16565b60ff16910152565b614141565b511660ff1690565b9088613512565b878d8d61546f565b60e088015161428c575080156142645761425f90614155565b6141e0565b5050505050509091505b61012081015161408157506020015161406a9063ffffffff16614061565b9850505050505050505090565b505050505050505090915061426e565b61430e612e6d8561430861162a6060806142fa8e6142e88f9c6143279f9d9c612e859f9c8f9d612e809f61431c9f6142e2918891613512565b9261564f565b9e6142f460035c612f1c565b9c613512565b013593015163ffffffff1690565b90615836565b835164ffffffffff16612ff6565b64ffffffffff168252565b80151580614361575b61433e575b50600101614198565b909160019160101b61ffff841617614356828b614141565b525f19019190614335565b506001600160f01b03811115614330565b505050506101200151909150614395576020015161406a9063ffffffff16614061565b63e49c0b2560e01b5f90815260045260245ffd5b92915f848192828261442b61444d976143c0613c9c565b613e105a9a61440e60406143ff60e06143f761162a6101606143eb60208d015160018060a01b031690565b9b015163ffffffff1690565b9b0151151590565b9401516001600160a01b031690565b9660405197889463fe88e61360e01b60208701526024860161447b565b6129db61443a613e2d8b6147ef565b5193f191614446611fee565b50836150ea565b156144555750565b610120015161446c5762d14f5160e11b5f5260045ffd5b63a695d44360e01b5f5260045ffd5b909260809261056795941515835260018060a01b03166020830152604082015281606082015201906103d4565b613d20906129db613d25946144be818685615034565b90604051958694630cfce7b160e11b602087015260248601613ca9565b906144e581614c4c565b6001600160a01b0383165f81815260066020526040902080549194929161451b91906107069084906001600160701b0316613178565b5f54918383039283116118145761453a6107069161454d945f5561251a565b80549092906001600160701b03166131d3565b60015490808201809211611814576001919091556040519081527f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d90602090a2565b6004546001600160a01b0316330361114b57565b60609190911b6001600160601b031916815290151560f890811b601483015291821b6001600160f81b0319908116601583015292821b8316601682015292901b16601782015260e89190911b6001600160e81b0319166018820152601e929091614624919061461890151560f81b601b850152565b151560f81b601c830152565b600160f81b601d8201520190565b600360c0820152610140810151610567906001600160a01b03166129db61465c60e0850151151590565b9361466b606082015160ff1690565b9061467a608082015160ff1690565b614684600361182d565b6003614696604084015162ffffff1690565b916146b36101206146ab610100870151151590565b950151151590565b94604051998a9860208a016145a3565b600560c0820152610140810151610567906001600160a01b03166129db6146ed60e0850151151590565b936146fc606082015160ff1690565b9061470b608082015160ff1690565b614715600561182d565b6005614696604084015162ffffff1690565b600160c0820152610140810151610567906001600160a01b03166129db61475160e0850151151590565b93614760606082015160ff1690565b9061476f608082015160ff1690565b614779600161182d565b6001614696604084015162ffffff1690565b600260c0820152610140810151610567906001600160a01b03166129db6147b560e0850151151590565b936147c4606082015160ff1690565b906147d3608082015160ff1690565b6147dd600261182d565b6002614696604084015162ffffff1690565b600660c0820152610140810151610567906001600160a01b03166129db61481960e0850151151590565b93614828606082015160ff1690565b90614837608082015160ff1690565b614841600661182d565b6006614696604084015162ffffff1690565b6001600160801b03918216908216019190821161181457565b80156148bf57804710612586576148b79061488860045c613076565b906001600160801b03906148af9061489f90614ada565b83516001600160801b0316614853565b168152614b0b565b60045d600190565b50600190565b905f939192849360208451940192f190565b60015c6001600160a01b03811691600160a11b8216151591600160a21b16151590565b61490560035c612f1c565b61491060045c613076565b915f9015806149c8575b61499b575b614942614934608084015164ffffffffff1690565b64ffffffffff3a9116611e43565b6020840151935190936001600160801b03908116916149619116612d66565b6001600160801b039091161015928361497b575b50505090565b6149919293509061498b916118b3565b9161302a565b11155f8080614975565b5060208201516149c390612d66906001600160801b031684516001600160801b0316906117fb565b61491f565b5060208301516001600160801b031683516149eb906001600160801b0316612d66565b6001600160801b039091161161491a565b5f5c602881901c6001600160a01b031691600882901c63ffffffff169160ff1690565b905f54818101809111611814577f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885916020915f55614a8f614a5f82614c4c565b6001600160a01b039095165f818152600685526040902080549196909161070691906001600160701b03166131d3565b604051908152a2565b341561039957612797614aac60045c613076565b614ab534614ada565b60208201805190916001600160801b0391614ad291908316614853565b169052614b0b565b6001600160801b038111614af4576001600160801b031690565b6306dfcc6560e41b5f52608060045260245260445ffd5b805160209091015160801b6001600160801b0319166001600160801b03919091161790565b64ffffffffff8111614b465764ffffffffff1690565b6306dfcc6560e41b5f52602860045260245260445ffd5b614c28614c22612f7560c0614b7e64ffffffffff86511664ffffffffff1690565b614b9c614b96612f5a602089015164ffffffffff1690565b60281b90565b17614bbb614bb5612f5a604089015164ffffffffff1690565b60501b90565b17614bda614bd4612f5a606089015164ffffffffff1690565b60781b90565b17614bf9614bf3612f5a608089015164ffffffffff1690565b60a01b90565b17614c16614c10612f7560a089015162ffffff1690565b60c81b90565b1794015162ffffff1690565b60e01b90565b1790565b90612710019081612710116118145761271091614c4891611e43565b0490565b6001600160701b038111614c66576001600160701b031690565b6306dfcc6560e41b5f52607060045260245260445ffd5b61a4b146148015614cf3575b8015614ce7575b8015614cdb575b8015614ccf575b15614ccb5760405163a3b1b31d60e01b815260208160048160645afa9081156109fc575f916133f4575090565b4390565b50620182334614614c9e565b50620182324614614c97565b5062066eee4614614c90565b5061a4ba4614614c89565b6001600160a01b039091169081614d2f57614d199150611869565b8060031b90808204600814901517156118145790565b614d3a602091611869565b60246040518094819363577ad82160e11b835260048301525afa9081156109fc575f916133f4575090565b908015614d7757808204910615150190565b6365244e4e5f526004601cfd5b90604051614d918161034d565b91546001600160701b03808216845260709190911c166020830152565b92915f614dba82614c4c565b85516001600160701b038083169392911680841115614eb25750614e12614dfe612d276020614df0614deb8a612501565b614d84565b01516001600160701b031690565b885161249b906001600160701b0316612d27565b8093115f14614e7f575050610809614e5f6103999484614e57614e3c614e6796614e449b98611e16565b998a93612501565b8054600160701b600160e01b0319169055565b5f8652611e16565b600154611e16565b6020614e7461162a614c7d565b63ffffffff16910152565b92614eaa61039995614ea5614e9f610809959a976107e7614e6798614c4c565b91612501565b6131ec565b5f8452614e5f565b6103999550614e679350614ecf61080993989592614edc92613178565b6001600160701b03168552565b614e5f565b6020810151614f0c90614efc906001600160801b03166158e8565b91516001600160801b03166158e8565b905f82820392128183128116918313901516176118145790565b611f40810290808204611f40149015171561181457612710900490565b61271091614c4891611e43565b613d4262ffffff918260c08160a0840151169201511690613012565b6001600160701b03614f90614f8084614c4c565b83516001600160701b03166131d3565b16905260015490810180911161181457600155565b906001600160401b03809116911601906001600160401b03821161181457565b906150006080614ff4633b9aca006001600160401b03946040870162ffffff600181835116011690520461590b565b93019282845116614fa5565b169052565b906150006080614ff4633b9aca006001600160401b03946060870162ffffff600181835116011690520461590b565b604080517f000000000000000000000000000000000000000000000000000000000000000060208201908152606093841b6001600160601b0319908116938301939093529390921b16605482015260e09290921b6001600160e01b0319166068830152604c8252906150a7606c82610368565b51902090565b5f80916020815191017f00000000000000000000000000000000000000000000000000000000000000005af46150e1611fee565b9015612bf45790565b5a820391821161181457610160019063ffffffff825116811161512b5763ffffffff1663ffffffff8251160363ffffffff81116118145763ffffffff169052565b63942a59bb60e01b5f5260045ffd5b60809194939260a082019560018060a01b03168252602082015260016040820152600160608201520152565b9161236295939296949661517b60035c612f1c565b9561518785858961593c565b615193612e8588614b5d565b81516101408301519093906020906080830135906001600160a01b0316956151e26151c6848a019d8e5163ffffffff1690565b604051634fbf395b60e11b815298899485948d6004870161353a565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9384156109fc575f9461544e575b50615246610120870194615231866118f0565b60408801516001600160a01b03165b906159da565b97881561532c575b505050615319606063ffffffff946153249461241a9b6152806122ae9660406152768e615c7b565b62ffffff16910152565b8a5f516020615fa65f395f51905f5261529b60c08c016118f0565b926152a58c6118f0565b865190959061530b906152c2906001600160a01b03165b926118f0565b9462fe0000811615155b604080516001600160a01b0398891681526020810196909652901515908501525f606085015260808401529084169584169490931692819060a0820190565b0390a4015163ffffffff1690565b965163ffffffff1690565b941690615e0d565b9061533e8799898989615353966159f6565b999061534a8883615a71565b17915f88615ae3565b968715615361575b8061524e565b61537892975061536f612768565b50898689615b28565b819691968061535b57965097509561215990615416926153a661539a89615c7b565b62ffffff1660408b0152565b6153b260c087016118f0565b6153bb876118f0565b86519092905f516020615fa65f395f51905f52906153e1906001600160a01b03166152bc565b8d516040516001600160a01b039485169685169590941693918291615409918f91908461513a565b0390a45163ffffffff1690565b1561543d576060015161543994506154339063ffffffff1661162a565b90615ca4565b5190565b5050505060e0615439910160019052565b61546891945060203d6020116134165761340e8183610368565b925f61521e565b90949293956154bd85936154a75f87878b61548b60035c612f1c565b61549683838361593c565b6154a2612e8582614b5d565b6159f6565b97906154b38a83615a71565b179160018a615ae3565b948515615559575b5050946154da61241a96604061527687615c7b565b6154e660c083016118f0565b6154ef836118f0565b86519092905f516020615fa65f395f51905f52906001600160a01b03169161551a61012087016118f0565b9261552c8962fe0000811615156152cc565b0390a463ffffffff6153246122ae602061554d606089015163ffffffff1690565b97015163ffffffff1690565b615570929550615567612768565b50878487615b28565b81949194806154c557945095509361559661558a85615c7b565b62ffffff166040870152565b6155a260c083016118f0565b6155ab836118f0565b82519091906001600160a01b03165f516020615fa65f395f51905f526155d461012087016118f0565b8a516040516001600160a01b0394851696851695909416939182916155fc918c91908461513a565b0390a4615416612159602083015163ffffffff1690565b9061056794926156268361563a93610c4f565b6101e06101808401526101e0830190611b40565b926101a08201526101c08184039101526103d4565b929093915a9461566060035c612f1c565b61566b84838361593c565b615677612e8582614b5d565b8551610140870151909260808501359290916020906001600160a01b031693818401956156ca6156ae612362895163ffffffff1690565b604051634fbf395b60e11b815297889485948d6004870161353a565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156109fc5761574799878461573861573e9561574d985f91615817575b5061572561012085016118f0565b60408401516001600160a01b0316615240565b936159f6565b98909186615a71565b17151590565b61580d57516157619063ffffffff16612362565b6157e6575b50915f80949261579982956129db61014082013593604051948593602085019863a495d28d60e01b8a5260248601615613565b51923090f16157a6611fee565b906157d75763304680d760e01b6001600160e01b03196157c583613b31565b16146157d057505f90565b8051015190565b63039f249b60e61b5f5260045ffd5b6122b8826157f8929694959396615e82565b615805579190925f615766565b505050505f90565b5050505050505f90565b615830915060203d6020116134165761340e8183610368565b5f615717565b9080821015615843575090565b905090565b8051905f81528160051b81019260208201935b60208501918183116158aa5782519580518781111561589d575b6020820152601f1901805187811161587557506020909691949295939601525b91909261585b565b5050929093919450615895565b9450505052565b61279c906158c96158c360035c612f1c565b91614b30565b64ffffffffff6158e0602084019282845116613577565b169052614b5d565b6001600160ff1b0381116158f95790565b63123baf0360e11b5f5260045260245ffd5b6001600160401b038111615925576001600160401b031690565b6306dfcc6560e41b5f52604060045260245260445ffd5b915f9062040000602061595e606084013563ffffffff60608801511690615836565b9401511615615998575b505f6080840152810180911161181457615000606061598c64ffffffffff93614b30565b93019282845116612ff6565b6159d49150806101606159ac920190611daa565b7f00000000000000000000000000000000000000000000000000000000000000009150614cfe565b5f615968565b6001600160a01b039182169116036159ef5790565b6108001790565b60609182015193959493909291615a169163ffffffff1690830135615836565b94856207a1200190816207a120116118145710615a685760408101354710615a5e5761498b612d27612d1a61399b615a4d946118f0565b11615a56579190565b612000179190565b5050618000179190565b50506020179190565b5f929160a08201358015159081615ad2575b50615ab5575061162a610767615a9d923561399b816104df565b615aa5614c7d565b1115615aad57565b906110001790565b6020015191925050620100001615615acc57600490565b61010090565b9050615adc614c7d565b115f615a83565b602001516201000016151592919083615b1f575b5082615b0d575b5050615b075790565b60801790565b615b179250615e82565b155f80615afe565b1592505f615af7565b925f9293838093979695615b6182996129db615b42612768565b99604051948593602085019863a495d28d60e01b8a5260248601615613565b51923090f190615b6f611fee565b9115615b8957508060208061056793518301019101612819565b9192506001600160e01b031990615b9f90613b31565b16632cf9711760e11b8103615bb45750604091565b631217157160e31b8103615bc9575061200091565b63280c785f60e21b8103615bdf57506201000091565b630357b89960e61b8103615bf557506202000091565b630d8853e960e21b8103615c0b57506204000091565b633a44b8cb60e21b8103615c2157506208000091565b63af24067760e01b8103615c36575061040091565b631d75534f60e01b8103615c4c57506220000091565b638ac3609160e01b8103615c6257506240000091565b63887efaa560e01b03615c7457604091565b6280000091565b62ffffff8111615c8d5762ffffff1690565b6306dfcc6560e41b5f52601860045260245260445ffd5b9261039993615d18615d0f61390661249b612e8597615d08615cfd615cef612e6d615cd060035c612f1c565b9b615ce26159ac6101608d018d611daa565b97889160608d0135615836565b8a5164ffffffffff16612ff6565b64ffffffffff168952565b5a90611e16565b9260ff16151590565b15615d445750615d2d612e6d612e80926118a4565b61366a6020840191613665835164ffffffffff1690565b615db790615d54612e8093611895565b90615d6a61306f615d6487614f50565b84614c2c565b90615daa615d7d613b2661399b846118f0565b6139a061399b615d9686615d90876118f0565b85614dae565b9461369f615da48789611e16565b85615005565b80615dce575b5050614b30565b61366a6040840191613665835164ffffffffff1690565b615de9615de2615e0693615def9386615f7a565b8094611e16565b92614b30565b61366a6020870191613665835164ffffffffff1690565b5f80615db0565b615d18615d0f612e85959361039997615e2760035c612f1c565b965f9115615e4f575b615d08615cfd615cef612e6d8561390661249b979860608d0135615836565b61249b9150615d08615cfd615cef612e6d61390696615e756159ac6101608d018d611daa565b9650965050505050615e30565b615e8f61010082016118f0565b615e9e61297060e085016118f0565b6001600160a01b0390911603615f745760c001358015908115615f67575b8115615f59575b50156125865761010081013590615f0f60a0615ede836118f0565b604080516020810196875260609290921b6001600160601b03191690820152920135605483015281607481016129db565b519020615f2e615f27825f52600860205260405f2090565b5460ff1690565b61258657615f47615f54915f52600860205260405f2090565b805460ff19166001179055565b600190565b905060a0820135145f615ec3565b60a0830135159150615ebc565b50505f90565b818102929181159184041417810215615f9857808204910615150190565b63ad251c275f526004601cfdfe94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c1c8af9222013876e762969f616bf76d9bd3a356e39ce598256dd515b6cb7f82ba164736f6c634300081c000a00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b1000000000000000000000000baf4fbb4fd65199d5795ee4990b9661387ce3b6e00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a47400000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cc5c5c0d75b021f5b1e7038464744f7011d21fd
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806306fdde03146102f957806318160ddd146102f457806319b1faef146102ef578063234b7ede146102ea57806327de9e32146102e55780632e1a7d4d146102e0578063313ce567146102db5780634317ca01146102d657806345112906146102d15780635270182c146102cc5780635b651b05146102c75780635cd6ef67146102c25780635e8edccc146102bd578063635c7e71146102b857806367f7c8e0146102b35780636ef5ac7a146102ae57806370a08231146102a9578063791ae748146102a457806379b797651461029f5780637c20857a1461029a5780637c3c3160146102955780637e29c68414610290578063825ad6071461028b5780638380edb714610286578063890c2854146102815780638ebf091f1461027c57806395d89b41146102775780639940686e14610272578063a0531b021461026d578063a495d28d14610268578063a6efccf914610263578063aa7d2dc81461025e578063aebaa5f714610259578063b2c5c51014610254578063c41d54da1461024f578063c5471d9e1461024a578063c5ebeaec14610245578063d0e30db014610240578063d7bb99ba1461023b578063db006a7514610236578063e3de91a314610231578063eced55261461022c578063f05f88e014610227578063f68b84f714610222578063f83d08ba1461021d5763fc61c5410361000e576117bf565b61177f565b611766565b611744565b611728565b6116e6565b6115e3565b6115a9565b611594565b611578565b61155b565b611504565b6114e2565b61149c565b611461565b611427565b61130f565b6111bf565b6111a2565b61115a565b6110e5565b6110c8565b6110ab565b611068565b610fab565b610f83565b610f3f565b610efb565b610eb7565b610e74565b610e45565b610e01565b610d09565b610a91565b610a4d565b610a30565b610a01565b610953565b610885565b61082b565b6106a3565b610593565b61056a565b610467565b61044b565b6103f8565b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b0382111761032d57604052565b6102fe565b60c081019081106001600160401b0382111761032d57604052565b604081019081106001600160401b0382111761032d57604052565b90601f801991011681019081106001600160401b0382111761032d57604052565b6040519061039961018083610368565b565b6040519061039960e083610368565b60405190610399604083610368565b6001600160401b03811161032d57601f01601f191660200190565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b34610447575f36600319011261044757610443604051610419604082610368565b6009815268082e8d8c2e6408aa8960bb1b60208201526040519182916020835260208301906103d4565b0390f35b5f80fd5b34610447575f3660031901126104475760205f54604051908152f35b34610447575f3660031901126104475761048a61048560035c612f1c565b61302a565b61049560045c613076565b80516020909101516001600160801b039182169116808210156104d15750505f5b604080519283526001600160801b0391909116602083015290f35b6104da916117fb565b6104b6565b6001600160a01b0381160361044757565b6101243590610399826104df565b6101443590610399826104df565b60243590610399826104df565b3590610399826104df565b60a09060031901126104475760043561053c816104df565b90602435610549816104df565b906044359060643561055a816104df565b90608435610567816104df565b90565b346104475761001861058e602e61058036610524565b9195929490939291846130ae565b613124565b34610447576020366003190112610447576004356105af613170565b6106276105bb82614c4c565b335f5260076020526105fa60405f206105e66105e08460018060701b03845416613178565b82613191565b63ffffffff6105f3614c7d565b16906131b0565b335f908152600660205260409020805490916106219160701c6001600160701b03166131d3565b906131ec565b7f7659747cd8571f1071eea946fdc648adcf181cad916f32a05f82c3a52597604861069e610685610680610659614c7d565b7f00000000000000000000000000000000000000000000000000000000000001ad906118b3565b61183c565b6040805194855260208501919091523393918291820190565b0390a2005b34610447576020366003190112610447576004356106bf613170565b6106c881614c4c565b906106d233612501565b80549092906001600160701b03166001600160701b03818116908316811061074d57509261070661070c9261001895613178565b90613191565b610717815f54611e16565b5f5560405181815233907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca590602090a233613215565b610758929192614c7d565b6107a16107746107673361251a565b5460701c63ffffffff1690565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000001ad91166118b3565b10156108135750610018936107ec6107bf61080e9461080994613178565b82546001600160701b031916835591805461062190849060701c6001600160701b0316613178565b613178565b60018060701b03166107ff815f546118b3565b5f55600154611e16565b600155565b61070c565b6307d2457d60e21b5f52600452602483905260445b5ffd5b34610447575f36600319011261044757602060405160128152f35b90816102009103126104475790565b9181601f84011215610447578235916001600160401b038311610447576020808501948460051b01011161044757565b6080366003190112610447576004356001600160401b038111610447576108b0903690600401610846565b6024356001600160401b038111610447576108cf903690600401610855565b91604435906001600160401b038211610447576101206003198336030112610447576104439361090f9360643593610906856104df565b6004019261201d565b60405190151581529081906020820190565b604090600319011261044757600435610939816104df565b90602435610567816104df565b6001600160a01b03169052565b346104475761096136610921565b6040516311a4252f60e31b815291906020836004816001600160a01b0385165afa9182156109fc5763ffffffff935f936109c7575b506109a2918391613ced565b604080516001600160a01b03831681529390921660208401523b151590820152606090f35b6109a29293506109ee9060203d6020116109f5575b6109e68183610368565b8101906124ec565b9291610996565b503d6109dc565b611d9f565b34610447576020366003190112610447576020610a28600435610a23816104df565b612533565b604051908152f35b34610447575f366003190112610447576020600254604051908152f35b34610447575f366003190112610447576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461044757602036600319011261044757600435610aae816104df565b60018060a01b03165f52600760205260405f2060405190610ace82610312565b5460018060701b0381168252610443602083019163ffffffff8160701c168352604084019362ffffff8260901c168552610b7d610b6f610b65610b5b610b50610b326060870197610b2c62ffffff8260a81c168a9062ffffff169052565b60c01c90565b6001600160401b03166080870190815295516001600160701b031690565b975163ffffffff1690565b975162ffffff1690565b935162ffffff1690565b91516001600160401b031690565b604080516001600160701b03909616865263ffffffff909616602086015262ffffff928316958501959095521660608301526001600160401b03909216608082015290819060a0820190565b63ffffffff81160361044757565b610164359061039982610bc9565b359061039982610bc9565b6001600160801b0381160361044757565b60a4359061039982610bf0565b8015150361044757565b610164359061039982610c0e565b60e4359061039982610c0e565b610104359061039982610c0e565b610124359061039982610c0e565b90610160806103999380518452610c6e60208201516020860190610946565b60408181015162ffffff169085015260608181015160ff169085015260808181015160ff169085015260a08181015160ff169085015260c08181015160ff169085015260e0818101511515908501526101008181015115159085015261012081810151151590850152610ceb610140820151610140860190610946565b015163ffffffff16910152565b610180810192916103999190610c4f565b366003190161018081126104475760c01361044757604051610d2a81610332565b600435610d36816104df565b8152602435610d4481610bc9565b6020820152604435610d55816104df565b6040820152606435610d6681610bc9565b6060820152608435610d7781610bc9565b6080820152610d84610c01565b60a082015260c4356001600160401b03811161044757610da8903690600401610846565b9060e435906001600160401b0382116104475761044392610dd0610df5933690600401610855565b6101043590610ddd6104f0565b92610de66104fe565b94610def610c18565b96612644565b60405191829182610cf8565b34610447575f366003190112610447576040517f0000000000000000000000006cc5c5c0d75b021f5b1e7038464744f7011d21fd6001600160a01b03168152602090f35b34610447576020366003190112610447576004355f526008602052602060ff60405f2054166040519015158152f35b3461044757602036600319011261044757600435610e91816104df565b60018060a01b03165f526006602052602060018060701b0360405f205416604051908152f35b34610447575f366003190112610447576040517f0000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b16001600160a01b03168152602090f35b34610447575f366003190112610447576040517f000000000000000000000000baf4fbb4fd65199d5795ee4990b9661387ce3b6e6001600160a01b03168152602090f35b3461044757602036600319011261044757600435610f5c816104df565b60018060a01b03165f526007602052602063ffffffff60405f205460701c16604051908152f35b34610447575f366003190112610447576005546040516001600160a01b039091168152602090f35b3461044757610fb936610921565b336001600160a01b038316141580611055575b611047576040516311a4252f60e31b8152906020826004816001600160a01b0385165afa9081156109fc576104439361100c935f93611026575b506144a8565b6040516001600160a01b0390911681529081906020820190565b61104091935060203d6020116109f5576109e68183610368565b915f611006565b6282b42960e81b5f5260045ffd5b50336001600160a01b0382161415610fcc565b3461044757602036600319011261044757600435611085816104df565b60018060a01b03165f526007602052602060018060701b0360405f205416604051908152f35b34610447575f3660031901126104475760205f5c15604051908152f35b34610447575f366003190112610447576020600154604051908152f35b34610447575f366003190112610447576005546001600160a01b038116330361114b5760048054336001600160a01b03199182168117909255919091166005557f53960c2e64e72b2c1326635f0c002d5cf63e7844d12ed107404693fedde439855f80a2005b633006171960e21b5f5260045ffd5b34610447575f3660031901126104475761044360405161117b604082610368565b60068152650c2e8d88aa8960d31b60208201526040519182916020835260208301906103d4565b3461044757602036600319011261044757610018600435336144db565b34610447576020366003190112610447576004356111dc816104df565b6111e461458f565b600454600580546001600160a01b0319166001600160a01b0393841690811790915591167ffc722bcd56a71612cd14b287fbf50545429e6c9e8de86ea7c3febdecd34882fd5f80a3005b62ffffff81160361044757565b604435906103998261122e565b35906103998261122e565b60ff81160361044757565b6064359061039982611253565b6084359061039982611253565b60a4359061039982611253565b60c4359061039982611253565b90816101a09103126104475790565b9181601f84011215610447578235916001600160401b038311610447576020838186019501011161044757565b6080809180518452602081015160208501526040810151604085015260608101511515606085015201511515910152565b60a08101929161039991906112ce565b36600319016101e0811261044757610180136104475761132d610389565b600435815261133a61050c565b602082015261134761123b565b604082015261135461125e565b606082015261136161126b565b608082015261136e611278565b60a082015261137b611285565b60c0820152611388610c26565b60e0820152611395610c33565b6101008201526113a3610c41565b6101208201526113b16104fe565b6101408201526113bf610bd7565b610160820152610184356001600160401b038111610447576113e5903690600401611292565b906101a435916101c435916001600160401b038311610447576104439361141361141b9436906004016112a1565b939092612949565b604051918291826112ff565b34610447575f3660031901126104475760206040517f00000000000000000000000000000000000000000000000000000000000001ad8152f35b34610447575f36600319011261044757606061147b6148d7565b604080516001600160a01b0390941684529115156020840152151590820152f35b34610447576020366003190112610447576004356114b9816104df565b60018060a01b03165f526006602052602060018060701b0360405f205460701c16604051908152f35b3461044757610018606a61058e6114f836610524565b809493959296916130ae565b34610447575f3660031901126104475761151c61458f565b6003545f60035561152d8133613215565b6040519081527f87fa2ce024d3bdae31517696c13905fc0882bc1b4f4508060eb29358056de22b60203392a2005b34610447575f366003190112610447576020600354604051908152f35b3461044757602036600319011261044757610018600435612c39565b5f366003190112610447576100183433614a1f565b5f366003190112610447575f5c60281c6001600160a01b03163381036115d157610018614a98565b6346ba7eb160e11b5f5260045260245ffd5b34610447576020366003190112610447576004356115ff613170565b611607614c7d565b335f52600760205261163361065961162a60405f205463ffffffff9060701c1690565b63ffffffff1690565b10156116d75761169661164582614c4c565b61070661165133612501565b80549092906116779061167190839060701c6001600160701b0316613178565b846131ec565b61168661080986600154611e16565b82546001600160701b03166131d3565b6116a1815f546118b3565b5f5560405190815233907f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a690806020810161069e565b63078e135760e51b5f5260045ffd5b346104475760203660031901126104475760043561170261458f565b61170a613170565b62ffffff811161171957600255005b6359b9784760e01b5f5260045ffd5b34610447575f3660031901126104475760206040516127108152f35b6020366003190112610447576100186004356117603433614a1f565b336144db565b6020366003190112610447576020610a28600435612cd0565b34610447575f36600319011261044757606063ffffffff60ff6117a06149fc565b9193906040519460018060a01b03168552166020840152166040820152f35b34610447575f366003190112610447576004546040516001600160a01b039091168152602090f35b634e487b7160e01b5f52601160045260245ffd5b6001600160801b03918216908216039190821161181457565b6117e7565b634e487b7160e01b5f52602160045260245ffd5b6008111561183757565b611819565b906001820180921161181457565b90615208820180921161181457565b9062011170820180921161181457565b90610260820180921161181457565b90610160820180921161181457565b9060ee820180921161181457565b90617080820180921161181457565b90611194820180921161181457565b9190820180921161181457565b604051906118cd82610332565b5f60a0838281528260208201528260408201528260608201528260808201520152565b35610567816104df565b9190826080910312610447578151916020810151916060604083015192015160288110156104475790565b60a090600180831b03815116835263ffffffff6020820151166020840152600180831b03604082015116604084015263ffffffff606082015116606084015263ffffffff60808201511660808401528160018060801b0391015116910152565b9035601e19823603018112156104475701602081359101916001600160401b03821161044757813603831361044757565b908060209392818452848401375f828201840152601f01601f1916010190565b610567916119ec816119e784610519565b610946565b611a056119fb60208401610519565b6020830190610946565b60408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c0820152611a50611a4660e08401610519565b60e0830190610946565b611a6b611a606101008401610519565b610100830190610946565b611a89611a7b6101208401610be5565b63ffffffff16610120830152565b611aa7611a996101408401610be5565b63ffffffff16610140830152565b611ac5611ab76101608401610be5565b63ffffffff16610160830152565b611ae2611ad56101808401611248565b62ffffff16610180830152565b611afd611af26101a08401610519565b6101a0830190610946565b611b31611b25611b116101c0850185611985565b6102006101c08601526102008501916119b6565b926101e0810190611985565b916101e08185039101526119b6565b61056791611b51816119e784610519565b611b606119fb60208401610519565b60408201356040820152606082013560608201526080820135608082015260a082013560a0820152611ba1611b9760c08401610519565b60c0830190610946565b611bb0611a4660e08401610519565b610100820135610100820152611bd7611bcc6101208401610519565b610120830190610946565b610140820135610140820152611c17611c0b611bf7610160850185611985565b6101a06101608601526101a08501916119b6565b92610180810190611985565b916101808185039101526119b6565b90602083828152019060208160051b85010193835f915b838310611c4d5750505050505090565b909192939495601f19828203018652863561019e1984360301811215610447576020611c7e60019386839401611b40565b980196019493019190611c3d565b94610120611d6e611cd96103999b96611d97986101809b9f9e9c97611ccb906101a060c08e611cbe81611d7f9d611925565b01526101a08d01906119d6565b918b830360e08d0152611c26565b928884036101008a0152611cf0846119e783610519565b611d09611cff60208301610519565b6020860190610946565b6040810135604085015260608101356060850152611d36611d2c60808301610519565b6080860190610946565b611d4f611d4560a08301610519565b60a0860190610946565b60c081013560c085015260e081013560e0850152610100810190611985565b9190928161010082015201916119b6565b98610120850152610140840152610160830190610946565b019015159052565b6040513d5f823e3d90fd5b903590601e198136030182121561044757018035906001600160401b0382116104475760200191813603831361044757565b6028111561183757565b90602491602881101561183757600452565b619c3f1981019190821161181457565b5f1981019190821161181457565b9190820391821161181457565b356105678161122e565b90603f820291808304603f149015171561181457565b8181029291811591840414171561181457565b8115611e60570490565b634e487b7160e01b5f52601260045260245ffd5b5190610399826104df565b51906103998261122e565b519061039982611253565b519061039982610c0e565b519061039982610bc9565b908161018091031261044757611f80610160611ec5610389565b9280518452611ed660208201611e74565b6020850152611ee760408201611e7f565b6040850152611ef860608201611e8a565b6060850152611f0960808201611e8a565b6080850152611f1a60a08201611e8a565b60a0850152611f2b60c08201611e8a565b60c0850152611f3c60e08201611e95565b60e0850152611f4e6101008201611e95565b610100850152611f616101208201611e95565b610120850152611f746101408201611e74565b61014085015201611ea0565b61016082015290565b9693611fb8611fc693611fa58a6101609a97959d9c999d611925565b61018060c08b01526101808a01906119d6565b9188830360e08a0152611c26565b6101008601979097526001600160a01b03908116610120860152166101408401521515910152565b3d15612018573d90611fff826103b9565b9161200d6040519384610368565b82523d5f602084013e565b606090565b91949290945f945a966120376120328961184a565b611859565b906120406118c0565b50337f000000000000000000000000baf4fbb4fd65199d5795ee4990b9661387ce3b6e6001600160a01b03161498899182156124e15786888761208560a084016118f0565b80965b612091846132d1565b94859391986040519e8f9663439e2ef360e01b88528a349460048a01986120b799611c8c565b7f0000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b16001600160a01b0316918b9103815a6080945f91f19889156109fc575f905f9a5f915f916124a9575b50602084019b8d8d516121179063ffffffff1690565b62040000161561243f575b505061212d81611ddc565b806123c25750918b9c9d9e8b9c9286946121636121598e9f61214f8c8861341d565b5163ffffffff1690565b6208000016151590565b156123b25750805b6121786101808601611e23565b9061218292613458565b875a61218d90611e2d565b60061c61219990611df8565b9560c0013597886040519e8f97889763635c7e7160e01b895260048901976121c098611f89565b0381305f9061018095f15f9781612381575b5061226557505050505050506121fe906121f86121ed611fee565b915163ffffffff1690565b90613b6e565b612206613c68565b34612256575b6001600160a01b039061221e906118f0565b166040515f516020615fc65f395f51905f5233918061224d81905f604060608401938281528260208201520152565b0390a35b5f805d565b6122603433613215565b61220c565b889a50936122e093879860e09a61232198955f516020615fc65f395f51905f529a956122ea9961229660035c612f1c565b80995f996122bc6122b86122ae8a5163ffffffff1690565b6204000016151590565b1590565b612329575b505050505050506121596122d9915163ffffffff1690565b9389613822565b9590940151151590565b956001600160a01b03906122fd906118f0565b16936040519182913395898460409194939260608201951515825260208201520152565b0390a3612251565b879a50926122d9979261215997959260ff61236c612362608061235460606123749d9b015160ff1690565b9a0135975163ffffffff1690565b6201000016151590565b971692613617565b94918e915f88818f6122c1565b6123a49198506101803d81116123ab575b61239c8183610368565b810190611eab565b965f6121d2565b503d612392565b6123bc908b611e16565b9061216b565b9d50505050505050505050509193905061242c576123df82611ddc565b600a60ff83161015908161241e575b5061240657631eb2e74960e01b5f5261082890611de6565b5034612410575f90565b61241a3433613215565b5f90565b51610200161590505f6123ee565b634e47c97160e01b5f5261082882611de6565b6124a1929a9161249b61247461246f61246a612463866101c061249b980190611daa565b9050611869565b611878565b611887565b7f00000000000000000000000000000000000000000000000000000000000000009061339e565b906118b3565b975f8d612122565b925050506124d091995060803d6080116124da575b6124c88183610368565b8101906118fa565b919a92915f612101565b503d6124be565b868887338096612088565b90816020910312610447575161056781610bc9565b6001600160a01b03165f90815260066020526040902090565b6001600160a01b03165f90815260076020526040902090565b6001600160a01b03165f9081526007602052604090205460701c63ffffffff168015612586577f00000000000000000000000000000000000000000000000000000000000001ad81018091116118145790565b505f90565b9060405161259881610312565b91546001600160701b038116835263ffffffff607082901c16602084015262ffffff609082901c8116604085015260a882901c16606084015260c01c6080830152565b6040519061018082018281106001600160401b0382111761032d576040525f610160838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201520152565b929491959097966126536125db565b5030330361114b57608084015163ffffffff169261266f6125db565b506040519561268061018088610368565b86526001600160a01b031660208601525f604086018190526060860181905260ff8716608087015260a0860152600160c08601525f60e0860181905261010086015215156101208501526001600160a01b031661014084015263ffffffff166101608301528195606093602083019081516126fe9063ffffffff1690565b6004161515966122ae966103999861274e575b61272061272d9186888a613eae565b9788945163ffffffff1690565b156127435761273d938587614161565b916143a9565b61273d938587613f94565b5061272d61272061276086888a613d46565b915050612711565b6040519061277582610312565b5f6080838281528260208201528260408201528260608201520152565b60015d565b60045d565b60035d565b5f60015d565b6002805c6001600160a01b0319166001600160a01b039290921691909117905d565b6002805c6001600160a01b031916905d565b929061056794926127f9918552606060208601526060850190611b40565b9260408185039101526119b6565b805191908290602001825e015f815290565b908160a09103126104475760806040519161283383610312565b805183526020810151602084015260408101516040840152606081015161285981610c0e565b6060840152015161286981610c0e565b608082015290565b60405190612880602083610368565b5f808352366020840137565b929192612898826103b9565b916128a66040519384610368565b829481845281830111610447578281602093845f960137010152565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260c06080820181905261056794919391926129069291850191906119b6565b9160a08184039101526103d4565b949391612941906103999461293360409460e08a5260e08a0190611b40565b9188830360208a01526119b6565b9401906112ce565b9290919493612956612768565b50303303612c2a5761298161297c612970612970866118f0565b6001600160a01b031690565b612792565b60c0830191612997612992846118f0565b6127a7565b61299f613c75565b6020850180519093905f9081906001600160a01b0316876129e98c6129db898960405195869463ff939f0960e01b6020870152602486016127db565b03601f198101835282610368565b826129db612a136129f98d614632565b604051928391612a0d602084018098612807565b90612807565b51925af1612a1f611fee565b9015612bf45780602080612a3893518301019101612819565b90612a41613c82565b604086013598612a536122b88b61486c565b612c1b575f5c60081c63ffffffff1699612a6d8b936118f0565b905a612a788a6118f0565b89516001600160a01b031693908990898d612a9661012082016118f0565b906101608101612aa591611daa565b909a6140001615155f149a6122b89a612afb96612aed95612b009e612c0b57612acf91369161288c565b935b604051630120c0d360e11b60208201529b8c97602489016128c2565b03601f198101865285610368565b6148c5565b612bfc575f946129db612b4492612b278897612b1a613c8f565b516001600160a01b031690565b95604051958694634667020160e11b602087015260248601612914565b826129db612b546129f9886146c3565b51925af1612b60611fee565b9015612bf457612b7c81602080612b8794518301019101612819565b936208000016151590565b612b8f6148d7565b915015612be557159081612bd1575b50612bc2576101000151612bae57565b815163304680d760e01b5f5260045260245ffd5b631d75534f60e01b5f5260045ffd5b612bdf91506122b8906148fa565b5f612b9e565b638ac3609160e01b5f5260045ffd5b602081519101fd5b630357b89960e61b5f5260045ffd5b5050612c15612871565b93612ad1565b631217157160e31b5f5260045ffd5b63887efaa560e01b5f5260045ffd5b8015612ccd57612c476149fc565b919050336001600160a01b03821603612cb2575060ff6004911611612ca357612c6e6148d7565b509050612ca357612c7e8161486c565b15612c8d576103999033613215565b63029d54f560e21b5f524760045260245260445ffd5b6338961af360e21b5f5260045ffd5b6346ba7eb160e11b5f526001600160a01b031660045260245ffd5b50565b60ff6004612cdc6149fc565b909391501603612ca357612cfa6001600160a01b0360025c16612970565b330361114b57612d086148d7565b509092612d33612d27612d1a8661251a565b546001600160701b031690565b6001600160701b031690565b808211612ece575b50612d4760035c612f1c565b91612d5360045c613076565b8051909490612d72906001600160801b03165b6001600160801b031690565b926020860194612d8b612d66875160018060801b031690565b95612d958261302a565b9734612e90575b505081612e56575b5084841115612de3575050906105679461249b939215612dc5575b50611e16565b612ddd906001600160a01b0316600160a11b17612792565b5f612dbf565b9192909493612dfa6122b85f976208000016151590565b612e3e575b5050612e0c8484926118b3565b10612e2e575061241a926001600160a01b0316600360a11b1791506127929050565b926105679315612dc55750611e16565b84929550612e0c91612e4f91611e16565b9491612dff565b612e85612e8a91612e80612e72612e6d3a87611e56565b614b30565b64ffffffffff166080830152565b614b5d565b61279c565b5f612da4565b612ec290612ebd612ea6612ec7949a34906118b3565b99612eb08b614ada565b6001600160801b03169052565b614b0b565b612797565b5f80612d9c565b90505f612d3b565b6040519060e082018281106001600160401b0382111761032d576040525f60c0838281528260208201528260408201528260608201528260808201528260a08201520152565b61056764ffffffffff91612f2e612ed6565b50612fea838260281c16612fde858460501c16612fd0878660781c16612fc2612f64612f5a8960a01c90565b64ffffffffff1690565b93612fb4612f7d612f758b60c81c90565b62ffffff1690565b97612fa6612f8e612f758d60e01c90565b9b612f9761039b565b9e168e9064ffffffffff169052565b64ffffffffff1660208d0152565b64ffffffffff1660408b0152565b64ffffffffff166060890152565b64ffffffffff166080870152565b62ffffff1660a0850152565b62ffffff1660c0830152565b9064ffffffffff8091169116039064ffffffffff821161181457565b9062ffffff8091169116019062ffffff821161181457565b61306f6105679162ffffff61306864ffffffffff613052818551168260608701511690612ff6565b16928260c08160a0840151169201511690613012565b1690614c2c565b3a90611e43565b5f60206040516130858161034d565b8281520152604051906130978261034d565b6001600160801b038116825260801c602082015290565b9190916130b96149fc565b9491336001600160a01b0390911603613115576001600160a01b03926130df9290613ced565b16330361310657600160ff8093161b1616156130f757565b630106530b60e21b5f5260045ffd5b6343fcae1b60e01b5f5260045ffd5b631e6d8cfb60e21b5f5260045ffd5b601c5f60649281946020966040519860605260405260601b602c526323b872dd60601b600c525af13d1560015f5114171615613163575f606052604052565b637939f4245f526004601cfd5b5f5c6130f757565b6001600160701b03918216908216039190821161181457565b80546001600160701b0319166001600160701b03909216919091179055565b805463ffffffff60701b191660709290921b63ffffffff60701b16919091179055565b6001600160701b03918216908216019190821161181457565b8054600160701b600160e01b03191660709290921b600160701b600160e01b0316919091179055565b5f80809338935af11561322457565b63b12d13eb5f526004601cfd5b519061039982610bf0565b908160c0910312610447576132b860a06040519261325984610332565b8051613264816104df565b8452602081015161327481610bc9565b60208501526040810151613287816104df565b6040850152606081015161329a81610bc9565b606085015260808101516132ad81610bc9565b608085015201613231565b60a082015290565b9060206105679281815201906119d6565b6132d96118c0565b50610100810180356132ea816104df565b60405163e514a79d60e01b815260206004820152919060c09083906001600160a01b0316818061331d60248201896119d6565b03915afa80156109fc5761335d925f91613360575b50613357602061334b61334584976118f0565b946118f0565b92015163ffffffff1690565b916144a8565b91565b613382915060c03d60c011613388575b61337a8183610368565b81019061323c565b5f613332565b503d613370565b90816020910312610447575190565b906001600160a01b0316806133c457508060031b90808204600814901517156118145790565b906020906024604051809481936336d2da6b60e21b835260048301525afa9081156109fc575f916133f4575b5090565b610567915060203d602011613416575b61340e8183610368565b81019061338f565b503d613404565b905f5c61344a5764ffffffff006020600193015160081b16908260281b8360c81b039060281b1617175f5d565b62dc149f60e41b5f5260045ffd5b90612e806134c993612fea613478613472612e8596614b30565b94614b30565b6134b762ffffff600254169164ffffffffff6040519761349960e08a610368565b1687525f60208801819052604088015264ffffffffff166060870152565b5f608086015262ffffff1660a0850152565b6134ee612ec26134d76103aa565b5f8152346001600160801b03166020820152614b0b565b6134f66127a1565b6103996127c9565b634e487b7160e01b5f52603260045260245ffd5b91908110156135355760051b8101359061019e1981360301821215610447570190565b6134fe565b9390926135556080949796939760a0875260a0870190611b40565b602086019790975260408501526001600160a01b031660608401521515910152565b9064ffffffffff8091169116019064ffffffffff821161181457565b9060806001600160401b03916135b260018060701b0382511685613191565b6135c663ffffffff602083015116856131b0565b60408101518454606083015193909201516001600160901b0390921660909190911b62ffffff60901b161760a89290921b62ffffff60a81b1691909117911660c01b6001600160c01b031916179055565b90919492979596935f9761362b5a9a61183c565b955b848710613675575050505050505061366a6020613653612e6d6103999596975a90611e16565b920191613665835164ffffffffff1690565b613577565b64ffffffffff169052565b909192869987876020876136f06136e86136b56136aa8d9e9f8e8b9f61369f836136a4928f613512565b6118f0565b9b613512565b610160810190611daa565b90506136e33a917f000000000000000000000000000000000000000000000000000000000000000090614cfe565b611e43565b948c8c613512565b613710888a6040519687958695634fbf395b60e11b87526004870161353a565b03817f0000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b16001600160a01b03165afa80156109fc57613758915f91613804575b5060ff16151590565b6137e7576137658361251a565b61376e9061258b565b9261377a828286614dae565b93613785859261251a565b9061378f91613593565b61379891611e16565b6137a1916118b3565b99600191806137b9575b505b0195949392919061362d565b6137ca612e6d6137e1923a90614d65565b61366a60208c0191613665835164ffffffffff1690565b5f6137ab565b600192506137ca612e6d6137ff929d939d3a90614d65565b6137ad565b61381c915060203d81116134165761340e8183610368565b5f61374f565b959394909161382f612768565b9261383b60045c613076565b916138446148d7565b50509360e08a01996138568b51151590565b613b18575b6001600160a01b03881615613b02575b5061387584614ee1565b935f8512613ad957506138895a9a51151590565b15613a085750906136e361394d61392e61390b8b6139066138f8612f5a9e9f6138f36138cd6139589b6138c7612f5a60208e015164ffffffffff1690565b90611e16565b946138c76138eb60408d01976138c7612f5a8a5164ffffffffff1690565b913a90611e56565b611e16565b9d8e925164ffffffffff1690565b6118b3565b9b6139068d6136e33a91613928612f7560c08b015162ffffff1690565b90614c2c565b9a6136e33a91613947612f7560a088015162ffffff1690565b90614f43565b986139283a93614f50565b96875f928082105f146139ec576139789161397291611e16565b85614f6c565b8082116139d4579161399b6139946139a0936139a59695611e16565b9884614fc5565b61251a565b613593565b6139b96139b4846003546118b3565b600355565b6139c1613c68565b83806139cb575050565b61039991613215565b63039a3a8b60e11b5f5260049190915260245260445ffd5b613a029293506139fb91611e16565b8385614dae565b90613978565b9295989350935095505f14613aac5750505f195b613a7860408501946136e3613a64612f5a613a5861306f613a45612f5a8c5164ffffffffff1690565b613928612f7560c089015162ffffff1690565b985164ffffffffff1690565b613947612f7560a03a95015162ffffff1690565b9080851115613aa057613a9a929161249b82613a949397611e16565b936118b3565b926139a5565b509290613a9a916118b3565b613acf61306f916138f3613ad4946138c7612f5a60208b015164ffffffffff1690565b614f26565b613a1c565b8051602090910151635ad100a360e01b5f526001600160801b039182166004521660245260445ffd5b61014001516001600160a01b031696505f61386b565b9550613b2b613b268661251a565b61258b565b9561385b565b80516020909101516001600160e01b0319811692919060048210613b53575050565b6001600160e01b031960049290920360031b82901b16169150565b90613b7882613b31565b91337f000000000000000000000000baf4fbb4fd65199d5795ee4990b9661387ce3b6e6001600160a01b031614613be4575b506001600160e01b03198216634011dcb760e11b14908115613bd6575b50613bcf5750565b5f5260045ffd5b61020016151590505f613bc7565b91906001600160e01b0319821663e49c0b2560e01b8103613c1657835184015163e49c0b2560e01b5f5260045260245ffd5b91925090635933e62b60e11b8114908115613c57575b8115613c46575b50613c3e575f613baa565b505f5260045ffd5b63a695d44360e01b1490505f613c33565b63bdc56ad160e01b81149150613c2c565b600760ff195f5c16175f5d565b600360ff195f5c16175f5d565b600460ff195f5c16175f5d565b600560ff195f5c16175f5d565b600660ff195f5c16175f5d565b6001600160a01b0391821681529116602082015263ffffffff9091166040820152606081019190915260800190565b908160209103126104475751610567816104df565b613d20906129db613d2594613d03818685615034565b9060405195869463d447616160e01b602087015260248601613ca9565b6150ad565b80516001600160a01b0391613d4291810160209081019101613cd8565b1690565b906105679291600160ff195f5c16175f5d613dbe565b602081830312610447578051906001600160401b038211610447570181601f8201121561044757805190613d8f826103b9565b92613d9d6040519485610368565b8284526020838301011161044757815f9260208093018386015e8301015290565b9291905f805a6020870151909490613e109083906001600160a01b0316613e1e613df361162a6101608d015163ffffffff1690565b94604051948591638a83e68160e01b6020840152602483016132c0565b03601f198101855284610368565b6129db613e41613e2d8c614727565b604051928391612a0d602084018099612807565b5193f1613e56613e4f611fee565b93866150ea565b613e8257610120840151613e7357635b47d49f60e11b5f5260045ffd5b635933e62b60e11b5f5260045ffd5b602001519192509060081615613ea5578060208061056793518301019101613d5c565b50610567612871565b90610567939291600260ff195f5c16175f5d9392916040810135613ed46122b88261486c565b612c1b5760208601515f9283929091613e1091906001600160a01b0316613f1660608501359460405194859163cb6e0ea360e01b6020840152602483016132c0565b6129db613f25613e2d8c61478b565b5193f190613f31611fee565b91613f5e57610120850151613f4f57639f885ee560e01b5f5260045ffd5b63bdc56ad160e01b5f5260045ffd5b602001519293509091601016156133f057610567915060208082518301019101613d5c565b60ff1660ff81146118145760010190565b9594929160ff85165f5b613fb5613faf60608b015160ff1690565b60ff1690565b82811015614025579061249b87613fe1938c613fd35a928d8c613512565b888a61014083013593615166565b95613fef60e08a0151151590565b61401a5761401460608a0161400d614008825160ff1690565b613f83565b60ff169052565b95613f9e565b509496505050505050565b5094509596945050602091500192614044612159855163ffffffff1690565b6140a957505061012081015161408157505161406a9063ffffffff165b61800016151590565b614072575f90565b634011dcb760e11b5f5260045ffd5b614097612f75604061082893015162ffffff1690565b63e49c0b2560e01b5f52600452602490565b9092506140ba610120830151151590565b90816140ed575b50806140d0575b614081575090565b5062ffffff6140e5604083015162ffffff1690565b1615156140c8565b60019150145f6140c1565b6001600160401b03811161032d5760051b60200190565b90614119826140f8565b6141266040519182610368565b8281528092614137601f19916140f8565b0190602036910137565b80518210156135355760209160051b010190565b8015611814575f190190565b9294919093945a9186156143725761010085019161417f8360019052565b6141888861410f565b9361419289611e08565b60035c905f5b8b858c8b8d8a8587106142a95750505050505050506141de916141bd6141d99261279c565b5f6141c78c611e08565b966141d189615848565b525a90611e16565b6158b1565b825b5a6141eb8287614141565b5160101c80156142995761424691889161423e8d614237613faf61ffff8f8a8f8f61422f936060614222613faf8661422a95611e16565b60ff16910152565b614141565b511660ff1690565b9088613512565b878d8d61546f565b60e088015161428c575080156142645761425f90614155565b6141e0565b5050505050509091505b61012081015161408157506020015161406a9063ffffffff16614061565b9850505050505050505090565b505050505050505090915061426e565b61430e612e6d8561430861162a6060806142fa8e6142e88f9c6143279f9d9c612e859f9c8f9d612e809f61431c9f6142e2918891613512565b9261564f565b9e6142f460035c612f1c565b9c613512565b013593015163ffffffff1690565b90615836565b835164ffffffffff16612ff6565b64ffffffffff168252565b80151580614361575b61433e575b50600101614198565b909160019160101b61ffff841617614356828b614141565b525f19019190614335565b506001600160f01b03811115614330565b505050506101200151909150614395576020015161406a9063ffffffff16614061565b63e49c0b2560e01b5f90815260045260245ffd5b92915f848192828261442b61444d976143c0613c9c565b613e105a9a61440e60406143ff60e06143f761162a6101606143eb60208d015160018060a01b031690565b9b015163ffffffff1690565b9b0151151590565b9401516001600160a01b031690565b9660405197889463fe88e61360e01b60208701526024860161447b565b6129db61443a613e2d8b6147ef565b5193f191614446611fee565b50836150ea565b156144555750565b610120015161446c5762d14f5160e11b5f5260045ffd5b63a695d44360e01b5f5260045ffd5b909260809261056795941515835260018060a01b03166020830152604082015281606082015201906103d4565b613d20906129db613d25946144be818685615034565b90604051958694630cfce7b160e11b602087015260248601613ca9565b906144e581614c4c565b6001600160a01b0383165f81815260066020526040902080549194929161451b91906107069084906001600160701b0316613178565b5f54918383039283116118145761453a6107069161454d945f5561251a565b80549092906001600160701b03166131d3565b60015490808201809211611814576001919091556040519081527f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d90602090a2565b6004546001600160a01b0316330361114b57565b60609190911b6001600160601b031916815290151560f890811b601483015291821b6001600160f81b0319908116601583015292821b8316601682015292901b16601782015260e89190911b6001600160e81b0319166018820152601e929091614624919061461890151560f81b601b850152565b151560f81b601c830152565b600160f81b601d8201520190565b600360c0820152610140810151610567906001600160a01b03166129db61465c60e0850151151590565b9361466b606082015160ff1690565b9061467a608082015160ff1690565b614684600361182d565b6003614696604084015162ffffff1690565b916146b36101206146ab610100870151151590565b950151151590565b94604051998a9860208a016145a3565b600560c0820152610140810151610567906001600160a01b03166129db6146ed60e0850151151590565b936146fc606082015160ff1690565b9061470b608082015160ff1690565b614715600561182d565b6005614696604084015162ffffff1690565b600160c0820152610140810151610567906001600160a01b03166129db61475160e0850151151590565b93614760606082015160ff1690565b9061476f608082015160ff1690565b614779600161182d565b6001614696604084015162ffffff1690565b600260c0820152610140810151610567906001600160a01b03166129db6147b560e0850151151590565b936147c4606082015160ff1690565b906147d3608082015160ff1690565b6147dd600261182d565b6002614696604084015162ffffff1690565b600660c0820152610140810151610567906001600160a01b03166129db61481960e0850151151590565b93614828606082015160ff1690565b90614837608082015160ff1690565b614841600661182d565b6006614696604084015162ffffff1690565b6001600160801b03918216908216019190821161181457565b80156148bf57804710612586576148b79061488860045c613076565b906001600160801b03906148af9061489f90614ada565b83516001600160801b0316614853565b168152614b0b565b60045d600190565b50600190565b905f939192849360208451940192f190565b60015c6001600160a01b03811691600160a11b8216151591600160a21b16151590565b61490560035c612f1c565b61491060045c613076565b915f9015806149c8575b61499b575b614942614934608084015164ffffffffff1690565b64ffffffffff3a9116611e43565b6020840151935190936001600160801b03908116916149619116612d66565b6001600160801b039091161015928361497b575b50505090565b6149919293509061498b916118b3565b9161302a565b11155f8080614975565b5060208201516149c390612d66906001600160801b031684516001600160801b0316906117fb565b61491f565b5060208301516001600160801b031683516149eb906001600160801b0316612d66565b6001600160801b039091161161491a565b5f5c602881901c6001600160a01b031691600882901c63ffffffff169160ff1690565b905f54818101809111611814577f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885916020915f55614a8f614a5f82614c4c565b6001600160a01b039095165f818152600685526040902080549196909161070691906001600160701b03166131d3565b604051908152a2565b341561039957612797614aac60045c613076565b614ab534614ada565b60208201805190916001600160801b0391614ad291908316614853565b169052614b0b565b6001600160801b038111614af4576001600160801b031690565b6306dfcc6560e41b5f52608060045260245260445ffd5b805160209091015160801b6001600160801b0319166001600160801b03919091161790565b64ffffffffff8111614b465764ffffffffff1690565b6306dfcc6560e41b5f52602860045260245260445ffd5b614c28614c22612f7560c0614b7e64ffffffffff86511664ffffffffff1690565b614b9c614b96612f5a602089015164ffffffffff1690565b60281b90565b17614bbb614bb5612f5a604089015164ffffffffff1690565b60501b90565b17614bda614bd4612f5a606089015164ffffffffff1690565b60781b90565b17614bf9614bf3612f5a608089015164ffffffffff1690565b60a01b90565b17614c16614c10612f7560a089015162ffffff1690565b60c81b90565b1794015162ffffff1690565b60e01b90565b1790565b90612710019081612710116118145761271091614c4891611e43565b0490565b6001600160701b038111614c66576001600160701b031690565b6306dfcc6560e41b5f52607060045260245260445ffd5b61a4b146148015614cf3575b8015614ce7575b8015614cdb575b8015614ccf575b15614ccb5760405163a3b1b31d60e01b815260208160048160645afa9081156109fc575f916133f4575090565b4390565b50620182334614614c9e565b50620182324614614c97565b5062066eee4614614c90565b5061a4ba4614614c89565b6001600160a01b039091169081614d2f57614d199150611869565b8060031b90808204600814901517156118145790565b614d3a602091611869565b60246040518094819363577ad82160e11b835260048301525afa9081156109fc575f916133f4575090565b908015614d7757808204910615150190565b6365244e4e5f526004601cfd5b90604051614d918161034d565b91546001600160701b03808216845260709190911c166020830152565b92915f614dba82614c4c565b85516001600160701b038083169392911680841115614eb25750614e12614dfe612d276020614df0614deb8a612501565b614d84565b01516001600160701b031690565b885161249b906001600160701b0316612d27565b8093115f14614e7f575050610809614e5f6103999484614e57614e3c614e6796614e449b98611e16565b998a93612501565b8054600160701b600160e01b0319169055565b5f8652611e16565b600154611e16565b6020614e7461162a614c7d565b63ffffffff16910152565b92614eaa61039995614ea5614e9f610809959a976107e7614e6798614c4c565b91612501565b6131ec565b5f8452614e5f565b6103999550614e679350614ecf61080993989592614edc92613178565b6001600160701b03168552565b614e5f565b6020810151614f0c90614efc906001600160801b03166158e8565b91516001600160801b03166158e8565b905f82820392128183128116918313901516176118145790565b611f40810290808204611f40149015171561181457612710900490565b61271091614c4891611e43565b613d4262ffffff918260c08160a0840151169201511690613012565b6001600160701b03614f90614f8084614c4c565b83516001600160701b03166131d3565b16905260015490810180911161181457600155565b906001600160401b03809116911601906001600160401b03821161181457565b906150006080614ff4633b9aca006001600160401b03946040870162ffffff600181835116011690520461590b565b93019282845116614fa5565b169052565b906150006080614ff4633b9aca006001600160401b03946060870162ffffff600181835116011690520461590b565b604080517ff47f691b821c4bcc06a159044bbe9070e4124eba0822a476c1d5331270565a6060208201908152606093841b6001600160601b0319908116938301939093529390921b16605482015260e09290921b6001600160e01b0319166068830152604c8252906150a7606c82610368565b51902090565b5f80916020815191017f0000000000000000000000006cc5c5c0d75b021f5b1e7038464744f7011d21fd5af46150e1611fee565b9015612bf45790565b5a820391821161181457610160019063ffffffff825116811161512b5763ffffffff1663ffffffff8251160363ffffffff81116118145763ffffffff169052565b63942a59bb60e01b5f5260045ffd5b60809194939260a082019560018060a01b03168252602082015260016040820152600160608201520152565b9161236295939296949661517b60035c612f1c565b9561518785858961593c565b615193612e8588614b5d565b81516101408301519093906020906080830135906001600160a01b0316956151e26151c6848a019d8e5163ffffffff1690565b604051634fbf395b60e11b815298899485948d6004870161353a565b03817f0000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b16001600160a01b03165afa9384156109fc575f9461544e575b50615246610120870194615231866118f0565b60408801516001600160a01b03165b906159da565b97881561532c575b505050615319606063ffffffff946153249461241a9b6152806122ae9660406152768e615c7b565b62ffffff16910152565b8a5f516020615fa65f395f51905f5261529b60c08c016118f0565b926152a58c6118f0565b865190959061530b906152c2906001600160a01b03165b926118f0565b9462fe0000811615155b604080516001600160a01b0398891681526020810196909652901515908501525f606085015260808401529084169584169490931692819060a0820190565b0390a4015163ffffffff1690565b965163ffffffff1690565b941690615e0d565b9061533e8799898989615353966159f6565b999061534a8883615a71565b17915f88615ae3565b968715615361575b8061524e565b61537892975061536f612768565b50898689615b28565b819691968061535b57965097509561215990615416926153a661539a89615c7b565b62ffffff1660408b0152565b6153b260c087016118f0565b6153bb876118f0565b86519092905f516020615fa65f395f51905f52906153e1906001600160a01b03166152bc565b8d516040516001600160a01b039485169685169590941693918291615409918f91908461513a565b0390a45163ffffffff1690565b1561543d576060015161543994506154339063ffffffff1661162a565b90615ca4565b5190565b5050505060e0615439910160019052565b61546891945060203d6020116134165761340e8183610368565b925f61521e565b90949293956154bd85936154a75f87878b61548b60035c612f1c565b61549683838361593c565b6154a2612e8582614b5d565b6159f6565b97906154b38a83615a71565b179160018a615ae3565b948515615559575b5050946154da61241a96604061527687615c7b565b6154e660c083016118f0565b6154ef836118f0565b86519092905f516020615fa65f395f51905f52906001600160a01b03169161551a61012087016118f0565b9261552c8962fe0000811615156152cc565b0390a463ffffffff6153246122ae602061554d606089015163ffffffff1690565b97015163ffffffff1690565b615570929550615567612768565b50878487615b28565b81949194806154c557945095509361559661558a85615c7b565b62ffffff166040870152565b6155a260c083016118f0565b6155ab836118f0565b82519091906001600160a01b03165f516020615fa65f395f51905f526155d461012087016118f0565b8a516040516001600160a01b0394851696851695909416939182916155fc918c91908461513a565b0390a4615416612159602083015163ffffffff1690565b9061056794926156268361563a93610c4f565b6101e06101808401526101e0830190611b40565b926101a08201526101c08184039101526103d4565b929093915a9461566060035c612f1c565b61566b84838361593c565b615677612e8582614b5d565b8551610140870151909260808501359290916020906001600160a01b031693818401956156ca6156ae612362895163ffffffff1690565b604051634fbf395b60e11b815297889485948d6004870161353a565b03817f0000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b16001600160a01b03165afa9081156109fc5761574799878461573861573e9561574d985f91615817575b5061572561012085016118f0565b60408401516001600160a01b0316615240565b936159f6565b98909186615a71565b17151590565b61580d57516157619063ffffffff16612362565b6157e6575b50915f80949261579982956129db61014082013593604051948593602085019863a495d28d60e01b8a5260248601615613565b51923090f16157a6611fee565b906157d75763304680d760e01b6001600160e01b03196157c583613b31565b16146157d057505f90565b8051015190565b63039f249b60e61b5f5260045ffd5b6122b8826157f8929694959396615e82565b615805579190925f615766565b505050505f90565b5050505050505f90565b615830915060203d6020116134165761340e8183610368565b5f615717565b9080821015615843575090565b905090565b8051905f81528160051b81019260208201935b60208501918183116158aa5782519580518781111561589d575b6020820152601f1901805187811161587557506020909691949295939601525b91909261585b565b5050929093919450615895565b9450505052565b61279c906158c96158c360035c612f1c565b91614b30565b64ffffffffff6158e0602084019282845116613577565b169052614b5d565b6001600160ff1b0381116158f95790565b63123baf0360e11b5f5260045260245ffd5b6001600160401b038111615925576001600160401b031690565b6306dfcc6560e41b5f52604060045260245260445ffd5b915f9062040000602061595e606084013563ffffffff60608801511690615836565b9401511615615998575b505f6080840152810180911161181457615000606061598c64ffffffffff93614b30565b93019282845116612ff6565b6159d49150806101606159ac920190611daa565b7f00000000000000000000000000000000000000000000000000000000000000009150614cfe565b5f615968565b6001600160a01b039182169116036159ef5790565b6108001790565b60609182015193959493909291615a169163ffffffff1690830135615836565b94856207a1200190816207a120116118145710615a685760408101354710615a5e5761498b612d27612d1a61399b615a4d946118f0565b11615a56579190565b612000179190565b5050618000179190565b50506020179190565b5f929160a08201358015159081615ad2575b50615ab5575061162a610767615a9d923561399b816104df565b615aa5614c7d565b1115615aad57565b906110001790565b6020015191925050620100001615615acc57600490565b61010090565b9050615adc614c7d565b115f615a83565b602001516201000016151592919083615b1f575b5082615b0d575b5050615b075790565b60801790565b615b179250615e82565b155f80615afe565b1592505f615af7565b925f9293838093979695615b6182996129db615b42612768565b99604051948593602085019863a495d28d60e01b8a5260248601615613565b51923090f190615b6f611fee565b9115615b8957508060208061056793518301019101612819565b9192506001600160e01b031990615b9f90613b31565b16632cf9711760e11b8103615bb45750604091565b631217157160e31b8103615bc9575061200091565b63280c785f60e21b8103615bdf57506201000091565b630357b89960e61b8103615bf557506202000091565b630d8853e960e21b8103615c0b57506204000091565b633a44b8cb60e21b8103615c2157506208000091565b63af24067760e01b8103615c36575061040091565b631d75534f60e01b8103615c4c57506220000091565b638ac3609160e01b8103615c6257506240000091565b63887efaa560e01b03615c7457604091565b6280000091565b62ffffff8111615c8d5762ffffff1690565b6306dfcc6560e41b5f52601860045260245260445ffd5b9261039993615d18615d0f61390661249b612e8597615d08615cfd615cef612e6d615cd060035c612f1c565b9b615ce26159ac6101608d018d611daa565b97889160608d0135615836565b8a5164ffffffffff16612ff6565b64ffffffffff168952565b5a90611e16565b9260ff16151590565b15615d445750615d2d612e6d612e80926118a4565b61366a6020840191613665835164ffffffffff1690565b615db790615d54612e8093611895565b90615d6a61306f615d6487614f50565b84614c2c565b90615daa615d7d613b2661399b846118f0565b6139a061399b615d9686615d90876118f0565b85614dae565b9461369f615da48789611e16565b85615005565b80615dce575b5050614b30565b61366a6040840191613665835164ffffffffff1690565b615de9615de2615e0693615def9386615f7a565b8094611e16565b92614b30565b61366a6020870191613665835164ffffffffff1690565b5f80615db0565b615d18615d0f612e85959361039997615e2760035c612f1c565b965f9115615e4f575b615d08615cfd615cef612e6d8561390661249b979860608d0135615836565b61249b9150615d08615cfd615cef612e6d61390696615e756159ac6101608d018d611daa565b9650965050505050615e30565b615e8f61010082016118f0565b615e9e61297060e085016118f0565b6001600160a01b0390911603615f745760c001358015908115615f67575b8115615f59575b50156125865761010081013590615f0f60a0615ede836118f0565b604080516020810196875260609290921b6001600160601b03191690820152920135605483015281607481016129db565b519020615f2e615f27825f52600860205260405f2090565b5460ff1690565b61258657615f47615f54915f52600860205260405f2090565b805460ff19166001179055565b600190565b905060a0820135145f615ec3565b60a0830135159150615ebc565b50505f90565b818102929181159184041417810215615f9857808204910615150190565b63ad251c275f526004601cfdfe94e79da376f3bc5202c947c2466a329832d3e9af2f4e094a18c160868453273c1c8af9222013876e762969f616bf76d9bd3a356e39ce598256dd515b6cb7f82ba164736f6c634300081c000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b1000000000000000000000000baf4fbb4fd65199d5795ee4990b9661387ce3b6e00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a47400000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cc5c5c0d75b021f5b1e7038464744f7011d21fd
-----Decoded View---------------
Arg [0] : escrowDuration (uint256): 429
Arg [1] : atlasSurchargeRate (uint256): 1000
Arg [2] : verification (address): 0x2B072C802605cd2A0FFA4631529fBCFf1E4843b1
Arg [3] : simulator (address): 0xbAf4fBB4FD65199D5795Ee4990B9661387ce3B6e
Arg [4] : initialSurchargeRecipient (address): 0x78C5d8DF575098a97A3bD1f8DCCEb22D71F3a474
Arg [5] : l2GasCalculator (address): 0x0000000000000000000000000000000000000000
Arg [6] : factoryLib (address): 0x6cc5C5C0d75B021f5B1e7038464744f7011d21fD
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000001ad
Arg [1] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [2] : 0000000000000000000000002b072c802605cd2a0ffa4631529fbcff1e4843b1
Arg [3] : 000000000000000000000000baf4fbb4fd65199d5795ee4990b9661387ce3b6e
Arg [4] : 00000000000000000000000078c5d8df575098a97a3bd1f8dcceb22d71f3a474
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000006cc5c5c0d75b021f5b1e7038464744f7011d21fd
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.