Overview
S Balance
0 S
S Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 3 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
2193238 | 21 days ago | Contract Creation | 0 S | |||
2193231 | 21 days ago | Contract Creation | 0 S | |||
2193210 | 21 days ago | Contract Creation | 0 S |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
OnchainCLOBFactory
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {Errors} from "./Errors.sol"; import {OnchainCLOB} from "./OnchainCLOB.sol"; import {Proxy} from "./Proxy.sol"; import {IOnchainCLOBFactory} from "./IOnchainCLOBFactory.sol"; import {ITrieFactory} from "./ITrieFactory.sol"; /// @title LOB Factory for Protocol /// @dev This contract is responsible for creating OnchainCLOB instances. contract OnchainCLOBFactory is IOnchainCLOBFactory, Ownable2Step { /// @dev An instance of ITrieFactory. ITrieFactory immutable trieFactory; /// @dev An instance of OnchainCLOB OnchainCLOB immutable public lobImplementation; /// @dev Constructor for OnchainCLOBFactory. /// @param _owner The owner of the contract. /// @param _trieFactory The address of the trie factory. /// @param _watch_dog The address of the watch dog. constructor( address _owner, address _trieFactory, address _watch_dog ) Ownable(_owner) { require(_trieFactory != address(0), Errors.AddressIsZero()); require(_watch_dog != address(0), Errors.AddressIsZero()); trieFactory = ITrieFactory(_trieFactory); lobImplementation = new OnchainCLOB(_watch_dog); } /// @dev A mapping of deployers. mapping(address => bool) public deployers; /// @dev An event that is emitted when a OnchainCLOB is created. event OnchainCLOBCreated( address indexed creator, address OnchainCLOB, address tokenXAddress, address tokenYAddress, bool supports_native_eth, uint256 scaling_token_x, uint256 scaling_token_y, address administrator, address marketmaker, address pauser, bool should_invoke_on_trade, uint64 admin_commission_rate, uint64 total_aggressive_commission_rate, uint64 total_passive_commission_rate, uint64 passive_order_payout ); /// @dev Sets a deployer. /// @param deployer The address of the deployer. /// @param allowed A boolean indicating whether the deployer is allowed. function setDeployer(address deployer, bool allowed) external onlyOwner { deployers[deployer] = allowed; } /// @dev Creates a OnchainCLOB. /// @param tokenXAddress The address of token X. /// @param tokenYAddress The address of token Y. /// @param supports_native_eth A boolean indicating if the contract supports native ETH transactions. /// @param scaling_token_x The scaling factor for token X. /// @param scaling_token_y The scaling factor for token Y. /// @param administrator The address of the administrator. /// @param marketmaker The address of the market maker. /// @param pauser The address of the pauser. /// @param should_invoke_on_trade A boolean indicating whether to invoke on trade. /// @param admin_commission_rate The commission rate for the administrator /// @param total_aggressive_commission_rate The total commission rate for aggressive orders /// @param total_passive_commission_rate The total commission rate for passive orders /// @param passive_order_payout Payout for passive orders /// @return The address of the created OnchainCLOB. function createOnchainCLOB( address tokenXAddress, address tokenYAddress, bool supports_native_eth, bool is_token_x_weth, uint256 scaling_token_x, uint256 scaling_token_y, address administrator, address marketmaker, address pauser, bool should_invoke_on_trade, uint64 admin_commission_rate, uint64 total_aggressive_commission_rate, uint64 total_passive_commission_rate, uint64 passive_order_payout ) external returns (address) { require(deployers[msg.sender], Errors.Forbidden()); bytes memory initializeCallData = abi.encodeWithSignature( "initialize(address,address,address,bool,bool,uint256,uint256,address,address,address,bool,uint64,uint64,uint64,uint64)", address(trieFactory), tokenXAddress, tokenYAddress, supports_native_eth, is_token_x_weth, scaling_token_x, scaling_token_y, administrator, marketmaker, pauser, should_invoke_on_trade, admin_commission_rate, total_aggressive_commission_rate, total_passive_commission_rate, passive_order_payout ); Proxy lobProxy = new Proxy( address(lobImplementation), initializeCallData ); emit OnchainCLOBCreated( msg.sender, address(lobProxy), tokenXAddress, tokenYAddress, supports_native_eth, scaling_token_x, scaling_token_y, administrator, marketmaker, pauser, should_invoke_on_trade, admin_commission_rate, total_aggressive_commission_rate, total_passive_commission_rate, passive_order_payout ); return address(lobProxy); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; contract Errors { error AddressIsZero(); error ArrayLengthMismatch(); error ChainIsUnstableForTrades(); error ClaimNotAllowed(); error CommissionParamTooHigh(); error Disabled(); error EmptyOrderError(); error ExcessiveSignificantFigures(); error Expired(); error Forbidden(); error FractionalNumbersNotAllowed(); error InsufficientTokenXBalance(); error InsufficientTokenYBalance(); error InvalidCommissionRate(); error InvalidFloatingPointRepresentation(); error InvalidMarketMaker(); error InvalidPriceRange(); error InvalidTransfer(); error MarketOnlyAndPostOnlyFlagsConflict(); error MaxCommissionFailure(); error NativeETHDisabled(); error NonceExhaustedFailure(); error NotImplementedYet(); error OnlyOwnerCanCancelOrders(); error PointerAlreadyFreed(); error PriceExceedsMaximumAllowedValue(); error TransferFailed(); error UnknownOrderId(); error UnknownTrader(); error WrongOwner(); error ZeroMaxDelayNotAllowed(); error ZeroRecoveryTimeNotAllowed(); error ZeroTokenTransferNotAllowed(); error InvalidPrice(); error InvalidQuantity(); error InvalidCommission(); error InvalidExpiry(); error OrderExpired(); error InsufficientBalance(); error InsufficientAllowance(); error InvalidOrderId(); error OrderNotFound(); error OrderAlreadyCancelled(); error OrderAlreadyExecuted(); error InvalidExecutionPrice(); error InvalidExecutionQuantity(); error InvalidExecutionCommission(); error InvalidExecutionOrderId(); error InvalidExecutionOrderStatus(); error InvalidExecutionOrderExpiry(); error InvalidExecutionOrderPrice(); error InvalidExecutionOrderQuantity(); error InvalidExecutionOrderCommission(); }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {FixedPointMathLib} from "@solmate/src/utils/FixedPointMathLib.sol"; import {Errors} from "./Errors.sol"; import {FP24} from "./FP24.sol"; import {IWatchDog} from "./IWatchDog.sol"; import {IOnchainCLOB} from "./IOnchainCLOB.sol"; import {ITrie} from "./ITrie.sol"; import {ITrieFactory} from "./ITrieFactory.sol"; import {ITradeConsumer} from "./ITradeConsumer.sol"; import {IWETH} from "./IWETH.sol"; /// @title Trader structure /// @notice Used to represent a trader's state within the LOB contract /// @dev Stores trader's unique ID, token balances, and claimable status struct Trader { uint64 trader_id; ///< Unique identifier for the trader uint128 token_x; ///< Balance of token X for the trader uint128 token_y; ///< Balance of token Y for the trader bool claimable; ///< Flag indicating if the trader's orders are claimable "automatically" } /// @title Execution Result /// @notice Structure to store information about the result of aggressive or immediate part of order execution /// @dev Used to return data about the executed order from execution functions struct ExecutionResult { uint64 order_id; /// order_id Unique identifier of the order uint128 executed_shares; /// executed_shares Number of shares/tokens executed in the aggressive part uint128 executed_value; /// executed_value Total value of the aggressively executed part of the order uint128 aggressive_fee; /// aggressive_fee Fee for the aggressive execution } /// @title Market maker configuration struct MarketMakerConfig { address marketmaker; /// Market maker address bool should_invoke_on_trade; /// Invoke the onTrade method for the LP contract after each trade } /// @title Limit Order Book (LOB) Contract for Protocol /// @notice Implements an on-chain limit order book for trading pairs /// @dev Manages order placement, execution, and claiming processes contract OnchainCLOB is IOnchainCLOB, UUPSUpgradeable, Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable { using FixedPointMathLib for uint256; using SafeCast for uint256; using SafeERC20 for IERC20; event OrderPlaced( address indexed owner, uint64 order_id, bool indexed isAsk, uint128 quantity, uint72 price, uint128 passive_shares, uint128 passive_fee, uint128 aggressive_shares, uint128 aggressive_value, uint128 aggressive_fee, bool market_only, bool post_only ); event OrderClaimed( uint64 order_id, uint128 order_shares_remaining, uint128 token_x_sent, uint128 token_y_sent, uint128 passive_payout, bool only_claim ); event ClaimableStatusChanged( address indexed owner, bool status ); event MarketMakerChanged( address new_marketmaker, address old_marketmaker ); event PauserChanged( address new_pauser, address old_pauser ); event Deposited( address indexed owner, uint128 token_x, uint128 token_y ); event Withdrawn( address indexed owner, uint128 token_x, uint128 token_y ); uint8 constant nonce_length = 39; uint8 constant price_length = 24; uint256 constant wad = 1e18; uint256 scaling_factor_token_x; uint256 scaling_factor_token_y; IERC20 token_x; IERC20 token_y; bool supports_native_eth; bool is_token_x_weth; ITrie askTrie; ITrie bidTrie; uint64 admin_commission_rate; uint64 total_aggressive_commission_rate; // for market orders uint64 total_passive_commission_rate; // for out-of-money limit orders uint64 passive_order_payout_rate; MarketMakerConfig public marketmaker_config; address public pauser; uint64 public nonce; IWatchDog immutable watch_dog; uint64 last_used_trader_id; mapping (address => Trader) traders; uint256 accumulated_fees; modifier ensure(uint256 expires) { if (block.timestamp > expires) { revert Errors.Expired(); } _; } constructor(address _watch_dog) { watch_dog = IWatchDog(_watch_dog); _disableInitializers(); } /// @notice Initialize lob contract state /// @dev Method is used instead of a constructor to initialize the contract state for compatibility with Upgradeable logic /// @param _trie_factory Trie factory /// @param _tokenXAddress Token X address /// @param _tokenYAddress Token Y address /// @param _supports_native_eth Indicates if the contract supports native ETH transactions /// @param _is_token_x_weth Indicates if token X is WETH (Wrapped Ether) /// @param scaling_token_x Scaling factor for token X /// @param scaling_token_y Scaling factor for token Y /// @param _administrator Administrator address /// @param _marketmaker Market maker address /// @param _pauser Pauser address /// @param _should_invoke_on_trade Flag indicating whether to invoke the onTrade method for the LP contract after each trade /// @param _admin_commission_rate The commission rate for the administrator /// @param _total_aggressive_commission_rate The total commission rate for aggressive orders /// @param _total_passive_commission_rate The total commission rate for passive orders /// @param _passive_order_payout_rate Payout for passive orders function initialize( address _trie_factory, address _tokenXAddress, address _tokenYAddress, bool _supports_native_eth, bool _is_token_x_weth, uint256 scaling_token_x, uint256 scaling_token_y, address _administrator, address _marketmaker, address _pauser, bool _should_invoke_on_trade, uint64 _admin_commission_rate, uint64 _total_aggressive_commission_rate, uint64 _total_passive_commission_rate, uint64 _passive_order_payout_rate ) public initializer { __UUPSUpgradeable_init(); __Ownable_init(_administrator); __Ownable2Step_init(); __ReentrancyGuard_init(); __Pausable_init(); require(_trie_factory != address(0), Errors.AddressIsZero()); require(_tokenXAddress != address(0), Errors.AddressIsZero()); require(_tokenYAddress != address(0), Errors.AddressIsZero()); nonce = (uint64(1) << nonce_length) - uint64(1); last_used_trader_id = 0; scaling_factor_token_x = scaling_token_x; scaling_factor_token_y = scaling_token_y; token_x = IERC20(_tokenXAddress); token_y = IERC20(_tokenYAddress); supports_native_eth = _supports_native_eth; is_token_x_weth = _is_token_x_weth; ITrieFactory trie_factory = ITrieFactory(_trie_factory); address ask_trie_address = trie_factory.createTrie(address(this)); askTrie = ITrie(ask_trie_address); address bid_trie_address = trie_factory.createTrie(address(this)); bidTrie = ITrie(bid_trie_address); pauser = _pauser; _changeMarketMaker(_marketmaker, _should_invoke_on_trade); uint256 max_rate = 2e17; // 20% require( _admin_commission_rate <= 1e18 && _total_aggressive_commission_rate <= max_rate && _total_passive_commission_rate <= max_rate && _passive_order_payout_rate <= max_rate && (_passive_order_payout_rate == 0 || _total_passive_commission_rate == 0), Errors.InvalidCommissionRate() ); admin_commission_rate = _admin_commission_rate; total_aggressive_commission_rate = _total_aggressive_commission_rate; total_passive_commission_rate = _total_passive_commission_rate; passive_order_payout_rate = _passive_order_payout_rate; accumulated_fees = 1; // This is a simple trick to avoid zeroing out issue } /// @notice Returns the contract configuration /// @dev This function provides access to the main contract parameters such as scaling factors, commissions, and token addresses /// @return _scaling_factor_token_x Scaling factor for token X /// @return _scaling_factor_token_y Scaling factor for token Y /// @return _token_x Address of token X /// @return _token_y Address of token Y /// @return _supports_native_eth Indicates if the contract supports native ETH transactions /// @return _is_token_x_weth Indicates if token X is WETH (Wrapped Ether) /// @return _ask_trie Address of askTrie /// @return _bid_trie Address of bidTrie /// @return _admin_commission_rate The commission rate for the administrator /// @return _total_aggressive_commission_rate The total commission rate for aggressive orders /// @return _total_passive_commission_rate The total commission rate for passive orders /// @return _passive_order_payout_rate Payout for passive orders /// @return _should_invoke_on_trade Flag indicating whether to invoke the onTrade method for the LP contract after each trade function getConfig() external view returns ( uint256 _scaling_factor_token_x, uint256 _scaling_factor_token_y, address _token_x, address _token_y, bool _supports_native_eth, bool _is_token_x_weth, address _ask_trie, address _bid_trie, uint64 _admin_commission_rate, uint64 _total_aggressive_commission_rate, uint64 _total_passive_commission_rate, uint64 _passive_order_payout_rate, bool _should_invoke_on_trade ) { return ( scaling_factor_token_x, scaling_factor_token_y, address(token_x), address(token_y), supports_native_eth, is_token_x_weth, address(askTrie), address(bidTrie), admin_commission_rate, total_aggressive_commission_rate, total_passive_commission_rate, passive_order_payout_rate, marketmaker_config.should_invoke_on_trade ); } /// @notice Fallback function to handle incoming ETH deposits. receive() external payable { require(supports_native_eth && ( (is_token_x_weth && msg.sender == address(token_x)) ||(!is_token_x_weth && msg.sender == address(token_y)) ), Errors.Forbidden() ); } /// @notice Retrieves the balance of a trader by address in tokens stored on the LOB contract /// @dev Returns the balances of tokens X and Y, and the claimable status for the specified address /// @param address_ The address of the trader for whom the balance is being retrieved /// @return token_x Balance of token X for the trader /// @return token_y Balance of token Y for the trader /// @return claimable Status indicating whether the user's orders can be automatically claimed from other addresses function getTraderBalance(address address_) external view returns (uint128, uint128, bool) { Trader memory trader = traders[address_]; if (trader.trader_id == 0) { trader.claimable = true; // true by default } return (trader.token_x, trader.token_y, trader.claimable); } /// @notice Allows the administrator to change the market maker address /// @param _marketmaker The new address of the market maker /// @param _should_invoke_on_trade Flag indicating that the market maker must implement ITradeConsumer /// @param _admin_commission_rate The commission rate for the administrator /// @dev If the market maker address is null, it can be set by anyone function changeMarketMaker( address _marketmaker, bool _should_invoke_on_trade, uint64 _admin_commission_rate ) external nonReentrant { address administrator = owner(); require(msg.sender == administrator, Errors.Forbidden()); _transferFees(); require(_admin_commission_rate <= 1e18, Errors.InvalidCommissionRate()); admin_commission_rate = _admin_commission_rate; address marketmaker = marketmaker_config.marketmaker; if (marketmaker != _marketmaker) { emit MarketMakerChanged(_marketmaker, marketmaker); } _changeMarketMaker(_marketmaker, _should_invoke_on_trade); } /// @notice The new owner accepts the ownership transfer. function acceptOwnership() public override nonReentrant { _transferFees(); super.acceptOwnership(); } /// @notice Sets the claimable status for the trader calling the function /// @param status The new claimable status function setClaimableStatus(bool status) external nonReentrant whenNotPaused { _getOrCreateTraderId(msg.sender); traders[msg.sender].claimable = status; emit ClaimableStatusChanged(msg.sender, status); } /// @param isAsk Indicates if the order is a sell order (true) or a buy order (false) /// @param quantity The amount of tokens to order divided by the scaling factor. This amount would be multiplied by the scaling factor inside the function /// @param price The price per token in the order, no more than 6 significant digits /// @param max_commission The maximum commission, which may include passive and/or aggressive fee /// @param market_only Indicates if the order should be executed only against existing orders in the market /// @param post_only Indicates if the order should be posted only and not executed immediately /// @param transfer_executed_tokens Flag for transferring executed tokens (true) or crediting them to the balance (false) /// @param expires The time at which the order will expire /// @return order_id The identifier of the created order /// @return executed_shares Number of executed shares /// @return executed_value Executed value /// @return aggressive_fee Aggressive fee function placeOrder( bool isAsk, uint128 quantity, uint72 price, uint128 max_commission, bool market_only, bool post_only, bool transfer_executed_tokens, uint256 expires ) public payable ensure(expires) whenNotPaused returns ( uint64 order_id, uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ) { ExecutionResult memory result = _placeOrder( isAsk, quantity, price, max_commission, market_only, post_only, transfer_executed_tokens ); order_id = result.order_id; executed_shares = result.executed_shares; executed_value = result.executed_value; aggressive_fee = result.aggressive_fee; _invokeTradeConsumerCallback(result.executed_shares, isAsk); } /// @param isAsk Indicates if the order is a sell order (true) or a buy order (false) /// @param quantity The amount of tokens to order divided by the scaling factor. This amount would be multiplied by the scaling factor inside the function /// @param price The price per token in the order, no more than 6 significant digits /// @param max_commission The maximum commission, which may include passive and/or aggressive fee /// @param amount_to_approve The amount of tokens to approve divided by the scaling factor. This amount would be multiplied by the scaling factor inside the function /// @param market_only Indicates if the order should be executed only against existing orders in the market /// @param post_only Indicates if the order should be posted only and not executed immediately /// @param transfer_executed_tokens Flag for transferring executed tokens (true) or crediting them to the balance (false) /// @param expires The time at which the order will expire /// @param v The component V of the signature /// @param r The component R of the signature /// @param s The component S of the signature /// @return order_id The identifier of the created order /// @return executed_shares Number of executed shares /// @return executed_value Executed value /// @return aggressive_fee Aggressive fee function placeOrder( bool isAsk, uint128 quantity, uint72 price, uint128 max_commission, uint128 amount_to_approve, bool market_only, bool post_only, bool transfer_executed_tokens, uint256 expires, uint8 v, bytes32 r, bytes32 s ) public payable ensure(expires) whenNotPaused returns ( uint64 order_id, uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ) { address token_address = isAsk ? address(token_x) : address(token_y); IERC20Permit token = IERC20Permit(token_address); uint256 value = isAsk ? amount_to_approve * scaling_factor_token_x : amount_to_approve * scaling_factor_token_y; try token.permit(msg.sender, address(this), value, expires, v, r, s) {} catch {} ExecutionResult memory result = _placeOrder( isAsk, quantity, price, max_commission, market_only, post_only, transfer_executed_tokens ); order_id = result.order_id; executed_shares = result.executed_shares; executed_value = result.executed_value; aggressive_fee = result.aggressive_fee; _invokeTradeConsumerCallback(result.executed_shares, isAsk); } /// @notice Places a market order with a target token Y /// @param isAsk Order direction: true for sell (ask), false for buy (bid) /// @param target_token_y_value Target value of token Y for execution /// @param price Order price /// @param max_commission Maximum commission /// @param transfer_executed_tokens Flag for transferring executed tokens /// @param expires Time when the order expires /// @return executed_shares Number of executed shares /// @return executed_value Executed value /// @return aggressive_fee Aggressive fee function placeMarketOrderWithTargetValue( bool isAsk, uint128 target_token_y_value, uint72 price, uint128 max_commission, bool transfer_executed_tokens, uint256 expires ) public payable ensure(expires) whenNotPaused returns ( uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ) { uint24 packed_price = FP24.packFP24(price); uint64 price_id = _genPriceId(packed_price, isAsk); uint128 order_quantity; uint128 total_fees_and_payout_rate = total_aggressive_commission_rate + passive_order_payout_rate; if (isAsk) { uint128 adjusted_token_y_value = uint256(target_token_y_value).mulDivDown( wad, wad - total_fees_and_payout_rate ).toUint128(); (order_quantity, ) = bidTrie.previewExecuteRight( price_id, type(uint128).max, adjusted_token_y_value ); } else { uint128 adjusted_token_y_value = uint256(target_token_y_value).mulDivDown( wad, wad + total_fees_and_payout_rate ).toUint128(); (order_quantity, ) = askTrie.previewExecuteRight( price_id, type(uint128).max, adjusted_token_y_value ); } ExecutionResult memory result = _placeOrder( isAsk, order_quantity, price, max_commission, true, // market_only false, // post_only transfer_executed_tokens ); executed_shares = result.executed_shares; executed_value = result.executed_value; aggressive_fee = result.aggressive_fee; _invokeTradeConsumerCallback(result.executed_shares, isAsk); } /// @notice Places a market order with a target token Y value using EIP-2612 permit /// @param isAsk Order direction: true for sell (ask), false for buy (bid) /// @param target_token_y_value Target value of token Y for execution /// @param price Order price /// @param max_commission Maximum commission /// @param amount_to_approve The amount of tokens to approve divided by the scaling factor. This amount would be multiplied by the scaling factor inside the function /// @param transfer_executed_tokens Flag for transferring executed tokens /// @param expires Time when the order expires /// @param v Signature component v /// @param r Signature component r /// @param s Signature component s /// @return executed_shares Number of executed shares /// @return executed_value Executed value /// @return aggressive_fee Aggressive fee function placeMarketOrderWithTargetValue( bool isAsk, uint128 target_token_y_value, uint72 price, uint128 max_commission, uint128 amount_to_approve, bool transfer_executed_tokens, uint256 expires, uint8 v, bytes32 r, bytes32 s ) external payable ensure(expires) whenNotPaused returns ( uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ) { address token_address = isAsk ? address(token_x) : address(token_y); IERC20Permit token = IERC20Permit(token_address); uint256 value = isAsk ? amount_to_approve * scaling_factor_token_x : amount_to_approve * scaling_factor_token_y; try token.permit(msg.sender, address(this), value, expires, v, r, s) {} catch {} return placeMarketOrderWithTargetValue( isAsk, target_token_y_value, price, max_commission, transfer_executed_tokens, expires ); } /// @notice Allows a trader to claim or fully cancel the order /// @param order_id The identifier of the order to claim /// @param only_claim A flag indicating that only the executed part of the order should be sent /// without unnecessarily removing the order. /// @param transfer_tokens If true, transfers the tokens to the trader's address /// @param expires The time at which the order will expire function claimOrder( uint64 order_id, bool only_claim, bool transfer_tokens, uint256 expires ) public ensure(expires) nonReentrant whenNotPaused { _calculateAndSendOrderPayout(msg.sender, order_id, only_claim, transfer_tokens); } /// @notice Allows batch claiming of orders for multiple addresses /// @param addresses Array of trader addresses claiming orders /// @param order_ids Array of order IDs corresponding to trader addresses /// @param only_claim A flag indicating that only the executed part of the order should be sent /// without unnecessarily removing the order. /// @param expires The time at which the order will expire function batchClaim( address[] memory addresses, uint64[] memory order_ids, bool only_claim, uint256 expires ) external ensure(expires) nonReentrant whenNotPaused { require(addresses.length == order_ids.length, Errors.ArrayLengthMismatch()); for (uint i = 0; i < addresses.length; i++) { _calculateAndSendOrderPayout(addresses[i], order_ids[i], only_claim, true); } } /// @notice Claiming/canceling an existing order and creating the new one with the same (bid/ask) direction /// @param old_order_id The identifier of the order to modify /// @param new_quantity The amount of tokens for the new order /// @param new_price The price per token for new order, no more than 6 significant digits /// @param max_commission The maximum commission, which may include passive and/or aggressive fee /// @param post_only Indicates if the order should be posted only and not executed immediately /// @param transfer_tokens If true, tokens will be transferred to the order owner /// @param expires The time at which the order will expire function changeOrder( uint64 old_order_id, uint128 new_quantity, uint72 new_price, uint128 max_commission, bool post_only, bool transfer_tokens, uint256 expires ) public whenNotPaused returns (uint64 order_id) { if (old_order_id > 0x1) { claimOrder(old_order_id, false, transfer_tokens, expires); } if (new_quantity > 0) { bool isAsk = (old_order_id & uint64(0x1)) == 0x1; (order_id, , , ) = placeOrder( isAsk, new_quantity, new_price, max_commission, false, post_only, transfer_tokens, expires ); } } /// @notice Allows batch placing or changing of orders for multiple addresses /// @param order_ids Array of order IDs or directions corresponding to orders /// @param quantities Array of amounts of tokens for the new orders /// @param prices Array of prices per token for new orders, no more than 6 significant digits for every price /// @param max_commission_per_order The maximum commission per order, which may include passive and/or aggressive fee /// @param post_only Indicates if the order should be posted only and not executed immediately /// @param transfer_tokens If true, tokens will be transferred to the order owners /// @param expires The time at which the order will expire /// @return new_order_ids Array of new order IDs function batchChangeOrder( uint64[] memory order_ids, uint128[] memory quantities, uint72[] memory prices, uint128 max_commission_per_order, bool post_only, bool transfer_tokens, uint256 expires ) external ensure(expires) whenNotPaused returns (uint64[] memory new_order_ids) { require( order_ids.length == quantities.length && order_ids.length == prices.length, Errors.ArrayLengthMismatch() ); new_order_ids = new uint64[](order_ids.length); for (uint i = 0; i < order_ids.length; i++) { new_order_ids[i] = changeOrder( order_ids[i], quantities[i], prices[i], max_commission_per_order, post_only, transfer_tokens, expires ); } return new_order_ids; } /// @notice Deposits the specified amounts of token X and token Y into the trader's balance on the contract /// @param token_x_amount The amount of token X to deposit /// @param token_y_amount The amount of token Y to deposit function depositTokens( uint128 token_x_amount, uint128 token_y_amount ) public nonReentrant whenNotPaused { uint256 actual_token_x_to_receive = 0; uint256 actual_token_y_to_receive = 0; if (token_x_amount > 0) { traders[msg.sender].token_x += token_x_amount; actual_token_x_to_receive = _convertToActualTokenXAmount(token_x_amount); } if (token_y_amount > 0) { traders[msg.sender].token_y += token_y_amount; actual_token_y_to_receive = _convertToActualTokenYAmount(token_y_amount); } // actual erc20 transactions if (actual_token_x_to_receive > 0) { _safeTansferFromWithBalanceCheck(token_x, msg.sender, address(this), actual_token_x_to_receive); } if (actual_token_y_to_receive > 0) { _safeTansferFromWithBalanceCheck(token_y, msg.sender, address(this), actual_token_y_to_receive); } emit Deposited(msg.sender, token_x_amount, token_y_amount); } /// @notice Deposits the specified amounts of token X and token Y into the trader's balance on the contract /// @param token_x_amount The amount of token X to deposit /// @param token_y_amount The amount of token Y to deposit /// @param v_x The component V of the signature for token X /// @param r_x The component R of the signature for token X /// @param s_x The component S of the signature for token X /// @param v_y The component V of the signature for token Y /// @param r_y The component R of the signature for token Y /// @param s_y The component S of the signature for token Y /// @param expires The time at which the signatures will expire function depositTokens( uint128 token_x_amount, uint128 token_y_amount, uint8 v_x, bytes32 r_x, bytes32 s_x, uint8 v_y, bytes32 r_y, bytes32 s_y, uint256 expires ) external whenNotPaused { if (token_x_amount > 0) { IERC20Permit token_x_permit = IERC20Permit(address(token_x)); try token_x_permit.permit( msg.sender, address(this), token_x_amount * scaling_factor_token_x, expires, v_x, r_x, s_x ) {} catch {} } if (token_y_amount > 0) { IERC20Permit token_y_permit = IERC20Permit(address(token_y)); try token_y_permit.permit( msg.sender, address(this), token_y_amount * scaling_factor_token_y, expires, v_y, r_y, s_y ) {} catch {} } depositTokens(token_x_amount, token_y_amount); } /// @notice Withdraws specified amounts of token X and token Y from the trader's balance on the contract /// @param withdraw_all If set to true, withdraws all the trader's tokens; otherwise, uses the specified amounts /// @param token_x_amount The amount of token X to withdraw (ignored if withdraw_all = true) /// @param token_y_amount The amount of token Y to withdraw (ignored if withdraw_all = true) function withdrawTokens( bool withdraw_all, uint128 token_x_amount, uint128 token_y_amount ) external nonReentrant whenNotPaused { uint256 actual_token_x_to_send = 0; uint256 actual_token_y_to_send = 0; uint128 clients_shares = traders[msg.sender].token_x; uint128 clients_value = traders[msg.sender].token_y; if (withdraw_all) { token_x_amount = clients_shares; token_y_amount = clients_value; } if (token_x_amount > 0) { require(clients_shares >= token_x_amount, Errors.InsufficientTokenXBalance()); unchecked { traders[msg.sender].token_x = clients_shares - token_x_amount; } actual_token_x_to_send = _convertToActualTokenXAmount(token_x_amount); } if (token_y_amount > 0) { require(clients_value >= token_y_amount, Errors.InsufficientTokenYBalance()); unchecked { traders[msg.sender].token_y = clients_value - token_y_amount; } actual_token_y_to_send = _convertToActualTokenYAmount(token_y_amount); } // actual erc20 transactions if (actual_token_x_to_send > 0) { token_x.safeTransfer(msg.sender, actual_token_x_to_send); } if (actual_token_y_to_send > 0) { token_y.safeTransfer(msg.sender, actual_token_y_to_send); } emit Withdrawn(msg.sender, token_x_amount, token_y_amount); } /// @notice Returns the accumulated fees. /// @return The actual accumulated fees. function getAccumulatedFees() external view returns (uint256) { return (accumulated_fees - 1); } /// @notice Transfers the accumulated commissions to the administrator and marketmaker. function transferFees() external whenNotPaused { _transferFees(); } /// @notice Pause contract /// @dev Can be called by administrator and pauser function pause() external { require(msg.sender == owner() || msg.sender == pauser, Errors.Forbidden()); _pause(); } /// @notice Unpause contract /// @dev Can be called by administrator function unpause() external onlyOwner { _unpause(); } /// @notice Change pauser by administrator /// @param pauser_ New pauser address /// @dev Can be called only by administrator function changePauser(address pauser_) external onlyOwner { if (pauser == pauser_) { return; } emit PauserChanged(pauser_, pauser); pauser = pauser_; } /// @notice Extracts the direction and price from the given order ID. /// @param order_id The unique identifier of the order. /// @return isAsk A boolean indicating if the order is an ask (true) or a bid (false). /// @return price The price of the order. function _extractDirectionAndPrice(uint64 order_id) internal pure returns (bool isAsk, uint72 price) { // Orders with an order_id ending in 1 are asks, and those ending in 0 are bids. isAsk = (order_id & uint64(0x1)) == 0x1; uint24 packed_price = uint24(order_id >> (nonce_length + 1)); if (isAsk) { unchecked{ packed_price = type(uint24).max - packed_price; } } price = FP24.unPackFP24(packed_price); } function _authorizeUpgrade(address) internal override onlyOwner {} /// @param isAsk Indicates if the order is a sell order (true) or a buy order (false) /// @param quantity The amount of tokens to order divided by the scaling factor. This amount would be multiplied by the scaling factor inside the function /// @param price The price per token in the order, no more than 6 significant digits /// @param max_commission The maximum commission, which may include passive and/or aggressive fee /// @param market_only Indicates if the order should be executed only against existing orders in the market /// @param post_only Indicates if the order should be posted only and not executed immediately /// @param transfer_executed_tokens Flag for transferring executed tokens (true) or crediting them to the balance (false) /// @return execution_result ExecutionResult structure containing information about the executed order function _placeOrder( bool isAsk, uint128 quantity, uint72 price, uint128 max_commission, bool market_only, bool post_only, bool transfer_executed_tokens ) internal nonReentrant returns (ExecutionResult memory execution_result) { require(!market_only || !post_only, Errors.MarketOnlyAndPostOnlyFlagsConflict()); require(quantity != 0 && price != 0, Errors.ZeroTokenTransferNotAllowed()); require( msg.value == 0 || (supports_native_eth && (isAsk == is_token_x_weth)), Errors.NativeETHDisabled() ); uint24 packed_price = FP24.packFP24(price); uint64 price_id = _genPriceId(packed_price, isAsk); if (post_only) { bool aggressive_trade = false; if (isAsk) { if (price_id <= bidTrie.best_offer()) { aggressive_trade = true; } } else { if (price_id <= askTrie.best_offer()) { aggressive_trade = true; } } if (aggressive_trade) { if (msg.value > 0) { _sendETH(msg.sender, msg.value); } emit OrderPlaced( msg.sender, 0x0, // order_id isAsk, quantity, price, 0, // passive_shares, 0, // passive_fee 0, // executed_shares 0, // executed_value 0, // aggressive_fee false, // market_only, true // post_only ); return execution_result; } } uint128 x_to_send; uint128 y_to_send; uint128 x_to_receive; uint128 y_to_receive; // processing aggressive part uint128 executed_shares; uint128 executed_value; uint128 aggressive_fee; if (!post_only) { if (isAsk) { (executed_shares, executed_value) = bidTrie.executeRight(price_id, quantity); x_to_receive = executed_shares; y_to_send = executed_value; } else { (executed_shares, executed_value) = askTrie.executeRight(price_id, quantity); x_to_send = executed_shares; y_to_receive = executed_value; } aggressive_fee = _calculateAndTransferTotalAggressiveFeesAndPayout(executed_value); y_to_receive += aggressive_fee; if (executed_shares > 0){ require(watch_dog.isChainStable(), Errors.ChainIsUnstableForTrades()); } execution_result.executed_shares = executed_shares; execution_result.executed_value = executed_value; execution_result.aggressive_fee = aggressive_fee; } // processing passive part uint64 order_id; uint128 passive_shares = !market_only ? (quantity - executed_shares) : 0; uint128 passive_fee; if (passive_shares > 0) { order_id = _genOrderId(packed_price, isAsk); uint64 trader_id = _getOrCreateTraderId(msg.sender); uint128 total_value = passive_shares * price; passive_fee = _calculateTotalPassiveCommission(total_value); if (isAsk) { askTrie.addOrder(trader_id, order_id, passive_shares, total_value); x_to_receive += passive_shares; } else { bidTrie.addOrder(trader_id, order_id, passive_shares, total_value); // Orders with an order_id ending in 1 are asks, and those ending in 0 are bids. order_id ^= 0x1; y_to_receive += total_value + passive_fee; } execution_result.order_id = order_id; } require(passive_fee + aggressive_fee <= max_commission, Errors.MaxCommissionFailure()); emit OrderPlaced( msg.sender, order_id, isAsk, quantity, price, passive_shares, passive_fee, executed_shares, executed_value, aggressive_fee, market_only, post_only ); // actual token transfer _handleTokenTransfer( msg.sender, transfer_executed_tokens, x_to_send, x_to_receive, y_to_send, y_to_receive ); } /// @notice Change market maker address and should invoke on trade flag /// @param _marketmaker New market maker address /// @param _should_invoke_on_trade Flag indicating that the market maker must implement ITradeConsumer function _changeMarketMaker( address _marketmaker, bool _should_invoke_on_trade ) internal { if (_should_invoke_on_trade) { IERC165 maker = IERC165(_marketmaker); if (!maker.supportsInterface(type(ITradeConsumer).interfaceId)) { revert Errors.InvalidMarketMaker(); } } require(_marketmaker != address(0), Errors.AddressIsZero()); marketmaker_config = MarketMakerConfig ({ marketmaker: _marketmaker, should_invoke_on_trade: _should_invoke_on_trade }); } /// @notice Transfers the accumulated commissions to the administrator and marketmaker. function _transferFees() internal { uint256 total_fees = (accumulated_fees - 1) / wad; accumulated_fees -= total_fees * wad; if (total_fees == 0) { return; } address administrator = owner(); uint256 admin_fees = total_fees.mulWadUp(admin_commission_rate); uint256 marketmaker_fees = total_fees - admin_fees; if (marketmaker_fees > 0) { traders[marketmaker_config.marketmaker].token_y += marketmaker_fees.toUint128(); } uint256 actual_token_y_to_send = _convertToActualTokenYAmount(admin_fees.toUint128()); if (actual_token_y_to_send > 0){ token_y.safeTransfer(administrator, actual_token_y_to_send); } } /// @notice Retrieves or creates a trader ID for a given address. /// @param trader_address The address of the trader for whom the ID is to be retrieved or created. /// @return trader_id The trader ID associated with the given address. function _getOrCreateTraderId(address trader_address) internal returns (uint64 trader_id) { trader_id = traders[trader_address].trader_id; if (trader_id == 0) { // initialize a new Trader structure trader_id = ++last_used_trader_id; traders[trader_address].trader_id = trader_id; traders[trader_address].claimable = true; } } /// @notice Calculates and transfers the total fees and payout. /// @param executed_value The value of the executed order. /// @return The total aggressive fees calculated and transferred. function _calculateAndTransferTotalAggressiveFeesAndPayout(uint128 executed_value) internal returns (uint128) { if (executed_value == 0) { return 0; } uint128 total_fees_and_payout_rate = total_aggressive_commission_rate + passive_order_payout_rate; if (total_fees_and_payout_rate == 0) { return 0; } uint256 total_aggressive_fees_and_payout = uint256(executed_value).mulWadUp( total_fees_and_payout_rate ); accumulated_fees += ( total_aggressive_fees_and_payout * wad - executed_value * uint256(passive_order_payout_rate) + executed_value * uint256(total_passive_commission_rate) ); return total_aggressive_fees_and_payout.toUint128(); } /// @notice Calculates the total passive commission for a given value. /// @param total_value The total value for which the passive commission is to be calculated. /// @return The total passive commission calculated. function _calculateTotalPassiveCommission(uint128 total_value) internal view returns (uint128) { if (total_passive_commission_rate == 0){ return 0; } uint256 total_passive_commissions = uint256(total_value).mulWadUp(total_passive_commission_rate); return total_passive_commissions.toUint128(); } /// @notice Calculates the passive order payout or refunded commissions based on the remaining shares. /// @param isAsk A boolean flag indicating whether the order is an ask (true) or a bid (false). /// @param price The price of the order. /// @param remain_shares The remaining shares of the order. /// @param total_shares The total shares of the order. /// @return refund_value The calculated passive payout or refunded commissions. /// @return fee_rounding_error The rounding error in the fee calculation. function _calculatePassiveOrderPayoutOrRefundedCommissions( bool isAsk, uint72 price, uint128 remain_shares, uint128 total_shares ) internal view returns(uint128 refund_value, uint256 fee_rounding_error) { if (passive_order_payout_rate > 0) { uint256 executed_value = price * (total_shares - remain_shares); uint256 passive_payout = executed_value.mulWadDown(passive_order_payout_rate); refund_value = passive_payout.toUint128(); fee_rounding_error = executed_value * passive_order_payout_rate - refund_value * wad; } else { // Refunding part of the passive commission. uint128 executed_value = price * (total_shares - remain_shares); uint256 executed_fees = _calculateTotalPassiveCommission(executed_value); fee_rounding_error = executed_fees * wad - executed_value * total_passive_commission_rate; if (!isAsk) { uint128 total_value = price * total_shares; uint128 total_fees = _calculateTotalPassiveCommission(total_value); refund_value = total_fees - executed_fees.toUint128(); } } } /// @notice Decrements the nonce and returns the new value, reverts if nonce reaches zero. /// @dev This function is used to ensure unique order identifiers by decrementing the nonce. /// If the nonce reaches zero, the function will revert to prevent identifier collisions. /// @return c_nonce The decremented nonce value. function _getAndUpdateNonce() internal returns (uint64 c_nonce) { c_nonce = nonce; unchecked { nonce -= 1; } require(nonce > 0, Errors.NonceExhaustedFailure()); } /// @notice Generates a unique price identifier based on the given price and order type. /// @param packed_price The FP2 price of the order. /// @param isAsk A boolean indicating whether the order is an ask (true) or a bid (false). /// @return price_id The generated unique identifier for the price. function _genPriceId(uint24 packed_price, bool isAsk) internal pure returns (uint64 price_id) { if (isAsk) { price_id = uint64(packed_price) << nonce_length; } else { uint64 max_price = type(uint24).max; unchecked { price_id = (max_price - packed_price) << nonce_length; } } price_id = price_id << 1 ^ 0x1; } /// @notice Generates a unique order identifier based on the price and order type. /// @param packed_price The FP24 price of the order. /// @param isAsk A boolean indicating whether the order is an ask (true) or a bid (false). /// @return order_id The generated unique identifier for the order. function _genOrderId(uint24 packed_price, bool isAsk) internal returns (uint64 order_id) { uint64 c_nonce = _getAndUpdateNonce(); if (isAsk) { unchecked { order_id = ((uint64(type(uint24).max - packed_price) << nonce_length) | c_nonce); } } else { order_id = ((uint64(packed_price) << nonce_length) | c_nonce); } order_id = order_id << 1 ^ 0x1; } /// @notice Converts the amount of token X from a simplified representation to the actual ERC20 amount. /// @dev Multiplies the amount of token X by the scaling factor to obtain the actual amount. /// @param token The amount of token X in a simplified representation. /// @return Returns the actual amount of token X after scaling. function _convertToActualTokenXAmount(uint128 token) internal view returns (uint256) { return token * scaling_factor_token_x; } /// @notice Converts the amount of token Y from a simplified representation to the actual ERC20 amount. /// @dev Multiplies the amount of token Y by the scaling factor to obtain the actual amount. /// @param token The amount of token Y in a simplified representation. /// @return Returns the actual amount of token Y after scaling. function _convertToActualTokenYAmount(uint128 token) internal view returns (uint256) { return token * scaling_factor_token_y; } /// @dev Calculates the payout for an order and, if necessary, transfers the tokens. /// @param owner The owner of the order for which the payout is being calculated. /// @param order_id The identifier of the order for which the payout is being calculated. /// @param only_claim A flag indicating that only the executed part of the order should be sent /// without unnecessarily removing the order. /// @param transfer_tokens If true, tokens will be transferred to the order owner. function _calculateAndSendOrderPayout( address owner, uint64 order_id, bool only_claim, bool transfer_tokens ) internal { uint64 trader_id = _getOrCreateTraderId(owner); require(traders[owner].claimable || (msg.sender == owner), Errors.ClaimNotAllowed()); (bool isAsk, uint72 price) = _extractDirectionAndPrice(order_id); uint128 x_to_send; uint128 y_to_send; uint128 total_shares; uint128 remain_shares; uint128 order_shares_remaining = 0; if (isAsk) { if (only_claim) { uint128 executed_shares; (executed_shares, order_shares_remaining) = askTrie.claimExecuted(order_id, trader_id); total_shares = executed_shares; remain_shares = 0; } else { (total_shares, remain_shares) = askTrie.removeOrder(order_id, trader_id); } uint128 executed_value = (total_shares - remain_shares) * price; uint128 fees = _calculateTotalPassiveCommission(executed_value); x_to_send = remain_shares; y_to_send = executed_value - fees; } else { if (only_claim) { uint128 executed_shares; (executed_shares, order_shares_remaining) = bidTrie.claimExecuted(order_id|0x1, trader_id); total_shares = executed_shares; remain_shares = 0; } else { (total_shares, remain_shares) = bidTrie.removeOrder(order_id|0x1, trader_id); } x_to_send = total_shares - remain_shares; y_to_send = remain_shares * price; } (uint128 passive_payout, uint256 fee_rounding_error) = _calculatePassiveOrderPayoutOrRefundedCommissions( isAsk, price, remain_shares, total_shares ); emit OrderClaimed(order_id, order_shares_remaining, x_to_send, y_to_send, passive_payout, only_claim); y_to_send += passive_payout; accumulated_fees += fee_rounding_error; require((remain_shares == 0) || (msg.sender == owner), Errors.OnlyOwnerCanCancelOrders()); _handleTokenTransfer(owner, transfer_tokens, x_to_send, 0, y_to_send, 0); } /// @dev Handles the transfer of tokens during the execution or claiming/cancelling of an order. /// @param client The address of the trader executing the order. /// @param transfer_tokens A boolean flag indicating whether to transfer the tokens immediately. /// @param x_to_send The amount of token X to send. /// @param x_to_receive The amount of token X to receive. /// @param y_to_send The amount of token Y to send. /// @param y_to_receive The amount of token Y to receive. function _handleTokenTransfer( address client, bool transfer_tokens, uint128 x_to_send, uint128 x_to_receive, uint128 y_to_send, uint128 y_to_receive ) internal { uint256 actual_token_x_to_send = 0; uint256 actual_token_x_to_receive = 0; uint256 actual_token_y_to_send = 0; uint256 actual_token_y_to_receive = 0; IWETH weth = is_token_x_weth ? IWETH(address(token_x)) : IWETH(address(token_y)); if (msg.value > 0) { if (is_token_x_weth) { uint128 extra_x = (msg.value / scaling_factor_token_x).toUint128(); uint256 actual_value = _convertToActualTokenXAmount(extra_x); x_to_send += extra_x; uint256 rounded_value = msg.value - actual_value; actual_token_x_to_send = rounded_value; } else { uint128 extra_y = (msg.value / scaling_factor_token_y).toUint128(); uint256 actual_value = _convertToActualTokenYAmount(extra_y); y_to_send += extra_y; uint256 rounded_value = msg.value - actual_value; actual_token_y_to_send = rounded_value; } } // processing token_x if (x_to_send > x_to_receive) { uint128 shares_to_send; unchecked { shares_to_send = x_to_send - x_to_receive; } if (transfer_tokens) { actual_token_x_to_send += _convertToActualTokenXAmount(shares_to_send); } else { traders[client].token_x += shares_to_send; emit Deposited(client, shares_to_send, 0); } } else if (x_to_send < x_to_receive) { uint128 shares_to_receive; unchecked { shares_to_receive = x_to_receive - x_to_send; } uint128 clients_shares = traders[client].token_x; if (clients_shares >= shares_to_receive) { unchecked { traders[client].token_x -= shares_to_receive; } emit Withdrawn(client, shares_to_receive, 0); } else { unchecked { shares_to_receive -= clients_shares; } actual_token_x_to_receive = _convertToActualTokenXAmount(shares_to_receive); traders[client].token_x = 0; emit Withdrawn(client, clients_shares, 0); } } // processing token_y if (y_to_send > y_to_receive) { uint128 value_to_send; unchecked { value_to_send = y_to_send - y_to_receive; } if (transfer_tokens) { actual_token_y_to_send += _convertToActualTokenYAmount(value_to_send); } else { traders[client].token_y += value_to_send; emit Deposited(client, 0, value_to_send); } } else if (y_to_send < y_to_receive) { uint128 value_to_receive; unchecked { value_to_receive = y_to_receive - y_to_send; } uint128 clients_value = traders[client].token_y; if (clients_value >= value_to_receive) { unchecked { traders[client].token_y -= value_to_receive; } emit Withdrawn(client, 0, value_to_receive); } else { unchecked { value_to_receive -= clients_value; } actual_token_y_to_receive = _convertToActualTokenYAmount(value_to_receive); traders[client].token_y = 0; emit Withdrawn(client, 0, clients_value); } } // Withdrawing WETH if (supports_native_eth) { uint256 value_to_withdraw; if (is_token_x_weth && (actual_token_x_to_send > address(this).balance)) { value_to_withdraw = actual_token_x_to_send - address(this).balance; } if (!is_token_x_weth && (actual_token_y_to_send > address(this).balance)) { value_to_withdraw = actual_token_y_to_send - address(this).balance; } if (value_to_withdraw > 0) { weth.withdraw(value_to_withdraw); } } // actual erc20 transactions if (actual_token_x_to_send > 0) { if (supports_native_eth && is_token_x_weth) { _sendETH(client, actual_token_x_to_send); } else { token_x.safeTransfer(client, actual_token_x_to_send); } } if (actual_token_x_to_receive > 0) { _safeTansferFromWithBalanceCheck(token_x, client, address(this), actual_token_x_to_receive); } if (actual_token_y_to_send > 0) { if (supports_native_eth && !is_token_x_weth) { _sendETH(client, actual_token_y_to_send); } else { token_y.safeTransfer(client, actual_token_y_to_send); } } if (actual_token_y_to_receive > 0) { _safeTansferFromWithBalanceCheck(token_y, client, address(this), actual_token_y_to_receive); } // Depositing WETH if (address(this).balance > 0) { weth.deposit{value: address(this).balance}(); } } /// @dev Transfer tokens safely with balance check /// @param token Token contract /// @param from The address from which tokens are sent /// @param to The address to which tokens are sent /// @param value Amount of tokens function _safeTansferFromWithBalanceCheck(IERC20 token, address from, address to, uint256 value) internal { uint256 balance_before = token.balanceOf(address(this)); token.safeTransferFrom(from, to, value); uint256 balance_after = token.balanceOf(address(this)); require(balance_after - balance_before == value, Errors.InvalidTransfer()); } /// @notice Sends ETH to the specified address /// @dev Uses a low-level call to send ETH, which allows bypassing the 2300 gas limit imposed by transfer function /// @param to The recipient address for ETH /// @param value The amount of ETH to send (in wei) function _sendETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(""); require(success, Errors.TransferFailed()); } /// @dev Invoke TradeConsumer onTrade callback if executed shares are greater than zero, msg.sender is not /// market maker and should_invoke_on_trade is true /// @param executed_shares Executed shares /// @param isAsk A boolean indicating whether the order is an ask (true) or a bid (false) function _invokeTradeConsumerCallback(uint128 executed_shares, bool isAsk) internal { if (executed_shares == 0) return; if (marketmaker_config.should_invoke_on_trade && msg.sender != marketmaker_config.marketmaker) { ITradeConsumer(marketmaker_config.marketmaker).onTrade(isAsk); } } }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract Proxy is ERC1967Proxy { constructor(address _implementation, bytes memory _data) ERC1967Proxy(_implementation, _data) {} }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; interface IOnchainCLOBFactory { function setDeployer(address deployer, bool allowed) external; function createOnchainCLOB( address tokenXAddress, address tokenYAddress, bool supports_native_eth, bool is_token_x_weth, uint256 scaling_token_x, uint256 scaling_token_y, address administrator, address marketmaker, address pauser, bool should_invoke_on_trade, uint64 admin_commission_rate, uint64 total_aggressive_commission_rate, uint64 total_passive_commission_rate, uint64 passive_order_payout ) external returns (address); }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; interface ITrieFactory { function createTrie(address lob) external returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {OwnableUpgradeable} from "./OwnableUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step struct Ownable2StepStorage { address _pendingOwner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00; function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) { assembly { $.slot := Ownable2StepStorageLocation } } event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); function __Ownable2Step_init() internal onlyInitializing { } function __Ownable2Step_init_unchained() internal onlyInitializing { } /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); return $._pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); $._pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); delete $._pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Pausable struct PausableStorage { bool _paused; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300; function _getPausableStorage() private pure returns (PausableStorage storage $) { assembly { $.slot := PausableStorageLocation } } /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { PausableStorage storage $ = _getPausableStorage(); $._paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { PausableStorage storage $ = _getPausableStorage(); return $._paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// 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: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC1967-compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. 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. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, 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(y, 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 // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; import {Errors} from "./Errors.sol"; library FP24 { /// @dev Converts a uint72 number into a uint24 floating point representation. /// @param a The uint72 number to be converted. /// @return p The uint24 floating point representation of the input number. function packFP24(uint72 a) internal pure returns (uint24) { require(0 < a && a <= 999999000000000000000, Errors.InvalidPriceRange()); uint72 threshold_number = 999999; uint8 e = 0; while (a > threshold_number) { require(a % 10 == 0, Errors.ExcessiveSignificantFigures()); a /= 10; e++; } uint24 p = (uint24(e) << 20) | uint24(a); return p; } /// @dev Converts a uint24 floating point number into a uint72 number. /// @param p The uint24 floating point number to be converted. /// @return a The uint72 number representation of the input floating point number. function unPackFP24(uint24 p) internal pure returns (uint72) { uint72 e = uint72(p >> 20); uint72 a = uint72(p & 0xfffff); require(0 < a && a <= 999999, Errors.InvalidFloatingPointRepresentation()); a *= uint72(10 ** e); return a; } }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; interface IWatchDog { function touch() external; function isChainStable() external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; interface IOnchainCLOB { function getConfig() external view returns ( uint256 _scaling_factor_token_x, uint256 _scaling_factor_token_y, address _token_x, address _token_y, bool _supports_native_eth, bool _is_token_x_weth, address _ask_trie, address _bid_trie, uint64 _admin_commission_rate, uint64 _total_aggressive_commission_rate, uint64 _total_passive_commission_rate, uint64 _passive_order_payout_rate, bool _should_invoke_on_trade ); receive() external payable; function getTraderBalance(address address_) external view returns (uint128, uint128, bool); function changeMarketMaker( address _marketmaker, bool _should_invoke_on_trade, uint64 _admin_commission_rate ) external; function setClaimableStatus(bool status) external; function placeOrder( bool isAsk, uint128 quantity, uint72 price, uint128 max_commission, bool market_only, bool post_only, bool transfer_executed_tokens, uint256 expires ) external payable returns ( uint64 order_id, uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ); function placeOrder( bool isAsk, uint128 quantity, uint72 price, uint128 max_commission, uint128 amount_to_approve, bool market_only, bool post_only, bool transfer_executed_tokens, uint256 expires, uint8 v, bytes32 r, bytes32 s ) external payable returns ( uint64 order_id, uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ); function placeMarketOrderWithTargetValue( bool isAsk, uint128 target_token_y_value, uint72 price, uint128 max_commission, uint128 amount_to_approve, bool transfer_executed_tokens, uint256 expires, uint8 v, bytes32 r, bytes32 s ) external payable returns ( uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ); function placeMarketOrderWithTargetValue( bool isAsk, uint128 target_token_y_value, uint72 price, uint128 max_commission, bool transfer_executed_tokens, uint256 expires ) external payable returns ( uint128 executed_shares, uint128 executed_value, uint128 aggressive_fee ); function claimOrder( uint64 order_id, bool only_claim, bool transfer_tokens, uint256 expires ) external; function batchClaim( address[] memory addresses, uint64[] memory order_ids, bool only_claim, uint256 expires ) external; function changeOrder( uint64 old_order_id, uint128 new_quantity, uint72 new_price, uint128 max_commission, bool post_only, bool transfer_tokens, uint256 expires ) external returns (uint64); function batchChangeOrder( uint64[] memory order_ids, uint128[] memory quantities, uint72[] memory prices, uint128 max_commission_per_order, bool post_only, bool transfer_tokens, uint256 expires ) external returns (uint64[] memory new_order_ids); function depositTokens(uint128 token_x_amount, uint128 token_y_amount) external; function depositTokens( uint128 token_x_amount, uint128 token_y_amount, uint8 v_x, bytes32 r_x, bytes32 s_x, uint8 v_y, bytes32 r_y, bytes32 s_y, uint256 expires ) external; function withdrawTokens(bool withdraw_all, uint128 token_x_amount, uint128 token_y_amount) external; function getAccumulatedFees() external returns (uint256); function transferFees() external; }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; interface ITrie { function best_offer() external view returns (uint64); function rightmost_map() external view returns (uint64); function addOrder(uint64 trader_id, uint64 order_id, uint128 shares, uint128 value) external; function removeOrder(uint64 order_id, uint64 order_trader_id) external returns (uint128 total_shares, uint128 remain_shares); function claimExecuted(uint64 order_id, uint64 order_trader_id) external returns (uint128 executed_shares, uint128 remain_shares); function getOrderInfo(uint64 order_id) external view returns (uint128 total_shares, uint128 remain_shares); function executeRight(uint64 order_id, uint128 order_total_shares) external returns (uint128 executed_shares, uint128 executed_value); function previewExecuteRight(uint64 order_id, uint128 max_shares, uint128 max_value) external view returns (uint128 executed_shares, uint128 executed_value); function assembleOrderbookFromOrders(uint24 max_price_levels) external view returns (uint24[] memory array_price_ids, uint128[] memory array_shares); }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.0; interface ITradeConsumer { function onTrade(bool isAsk) external; }
// SPDX-License-Identifier: BUSL-1.1 // Central Limit Order Book (CLOB) exchange // (c) Long Gamma Labs, 2023. pragma solidity ^0.8.26; interface IWETH { function deposit() external payable; function withdraw(uint wad) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.20; import {Proxy} from "../Proxy.sol"; import {ERC1967Utils} from "./ERC1967Utils.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`. * * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. * * Requirements: * * - If `data` is empty, `msg.value` must be zero. */ constructor(address implementation, bytes memory _data) payable { ERC1967Utils.upgradeToAndCall(implementation, _data); } /** * @dev Returns the current implementation address. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function _implementation() internal view virtual override returns (address) { return ERC1967Utils.getImplementation(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.20; import {IBeacon} from "../beacon/IBeacon.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. // This will be fixed in Solidity 0.8.21. At that point we should remove these events. /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol) pragma solidity ^0.8.20; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback * function and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
{ "remappings": [ "forge-std/=lib/forge-std/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@solmate/src/=lib/solmate/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_trieFactory","type":"address"},{"internalType":"address","name":"_watch_dog","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressIsZero","type":"error"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"OnchainCLOB","type":"address"},{"indexed":false,"internalType":"address","name":"tokenXAddress","type":"address"},{"indexed":false,"internalType":"address","name":"tokenYAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"supports_native_eth","type":"bool"},{"indexed":false,"internalType":"uint256","name":"scaling_token_x","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaling_token_y","type":"uint256"},{"indexed":false,"internalType":"address","name":"administrator","type":"address"},{"indexed":false,"internalType":"address","name":"marketmaker","type":"address"},{"indexed":false,"internalType":"address","name":"pauser","type":"address"},{"indexed":false,"internalType":"bool","name":"should_invoke_on_trade","type":"bool"},{"indexed":false,"internalType":"uint64","name":"admin_commission_rate","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"total_aggressive_commission_rate","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"total_passive_commission_rate","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"passive_order_payout","type":"uint64"}],"name":"OnchainCLOBCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenXAddress","type":"address"},{"internalType":"address","name":"tokenYAddress","type":"address"},{"internalType":"bool","name":"supports_native_eth","type":"bool"},{"internalType":"bool","name":"is_token_x_weth","type":"bool"},{"internalType":"uint256","name":"scaling_token_x","type":"uint256"},{"internalType":"uint256","name":"scaling_token_y","type":"uint256"},{"internalType":"address","name":"administrator","type":"address"},{"internalType":"address","name":"marketmaker","type":"address"},{"internalType":"address","name":"pauser","type":"address"},{"internalType":"bool","name":"should_invoke_on_trade","type":"bool"},{"internalType":"uint64","name":"admin_commission_rate","type":"uint64"},{"internalType":"uint64","name":"total_aggressive_commission_rate","type":"uint64"},{"internalType":"uint64","name":"total_passive_commission_rate","type":"uint64"},{"internalType":"uint64","name":"passive_order_payout","type":"uint64"}],"name":"createOnchainCLOB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deployers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lobImplementation","outputs":[{"internalType":"contract OnchainCLOB","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c03461017f57601f6169ef38819003918201601f19168301916001600160401b038311848410176101495780849260609460405283398101031261017f5761004781610183565b61005f604061005860208501610183565b9301610183565b6001600160a01b0390911691821561016c57600180546001600160a01b03199081169091555f80549182168517815560405194916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36001600160a01b031690811561015d576001600160a01b031690811561015d57608052615f3c8281016001600160401b03811184821017610149576020928492610ab3843981520301905ff0801561013e5760a05260405161091b908161019882396080518161034c015260a05181818161042401526105bd0152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b63867915ab60e01b5f5260045ffd5b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b51906001600160a01b038216820361017f5756fe6080806040526004361015610012575f80fd5b5f3560e01c9081636a2385e8146105ec575080636f5cbf15146105a8578063715018a61461054557806378c918f01461021c57806379ba5097146101975780638da5cb5b14610170578063a34b5ee81461011d578063e30c3978146100f55763f2fde38b1461007f575f80fd5b346100f15760203660031901126100f157610098610625565b6100a061063b565b60018060a01b0316806bffffffffffffffffffffffff60a01b600154161760015560018060a01b035f54167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b5f80fd5b346100f1575f3660031901126100f1576001546040516001600160a01b039091168152602090f35b346100f15760403660031901126100f157610136610625565b602435908115158092036100f15761014c61063b565b60018060a01b03165f52600260205260405f209060ff801983541691161790555f80f35b346100f1575f3660031901126100f1575f546040516001600160a01b039091168152602090f35b346100f1575f3660031901126100f157600154336001600160a01b039091160361020957600180546001600160a01b03199081169091555f805433928116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b63118cdaa760e01b5f523360045260245ffd5b346100f1576101c03660031901126100f157610236610625565b6024356001600160a01b038116908190036100f157604435918215158093036100f1576064358015158091036100f15760843560a43560c4356001600160a01b038116908190036100f15760e4356001600160a01b038116908190036100f157610104356001600160a01b038116908190036100f15761012435918215158093036100f157610144359367ffffffffffffffff85168095036100f157610164359567ffffffffffffffff87168097036100f157610184359767ffffffffffffffff89168099036100f1576101a4359967ffffffffffffffff8b16809b036100f157335f52600260205260ff60405f20541615610536578c9b8e9160405192602084019263783678c360e01b845260018060a01b037f000000000000000000000000000000000000000000000000000000000000000016602486015260018060a01b03169e8f60448601526064850152608484015260a48301528260c48301528360e48301528461010483015285610124830152866101448301528761016483015288610184830152896101a48301528a6101c48301528b6101e48301526101e4825261022082019180831067ffffffffffffffff8411176105225782604052610297908181019161022083019285841067ffffffffffffffff851117610522576060936102209261064f88397f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316905260406102408201528251610260820181905294859061028083015e5f848387840101015261021f1994601f80199101160101030101905ff09c8d156105175760209d60018060a01b03169c8d9c8f6040519e8f908152015260408d015260608c015260808b015260a08a015260c089015260e08801526101008701526101208601526101408501526101608401526101808301526101a08201527f04b3d813686f2d1061e11e5a0d93455065f32174906b0c037cf1176818af86be6101c03392a2604051908152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b631dd2188d60e31b5f5260045ffd5b346100f1575f3660031901126100f15761055d61063b565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346100f1575f3660031901126100f1576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100f15760203660031901126100f1576020906001600160a01b03610610610625565b165f526002825260ff60405f20541615158152f35b600435906001600160a01b03821682036100f157565b5f546001600160a01b031633036102095756fe60806040523461015e575f610297908138038061001b81610162565b938439820160408382031261015e5782516001600160a01b0381169390919084830361015e576020810151906001600160401b03821161015e57019381601f8601121561015e5784516100756100708261019b565b610162565b9581875260208701936020838301011161015e57815f926020809301865e87010152823b1561014c577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28351156101435782809161012a955190845af4903d1561013a573d61011a6100708261019b565b908152809360203d92013e6101b6565b505b604051608290816102158239f35b606092506101b6565b5050505061012c565b634c9c8ce360e01b5f5260045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761018757604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161018757601f01601f191660200190565b906101da57508051156101cb57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061020b575b6101eb575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156101e356fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea26469706673582212204213b01ce51043145a896961fd42155a794e91743452dbe5362f72369eaa2d5c64736f6c634300081c0033a26469706673582212205286711af21e1a990f14bf36ea55a4a01bd1f7a85e82466be78418e090839d5564736f6c634300081c003360c03461012657601f615f3c38819003918201601f19168301916001600160401b0383118484101761012a5780849260209460405283398101031261012657516001600160a01b03811690819003610126573060805260a0525f516020615f1c5f395f51905f525460ff8160401c16610117576002600160401b03196001600160401b038216016100c1575b604051615ddd908161013f82396080518181816124570152612526015260a051818181613da80152818161526e01526159750152f35b6001600160401b0319166001600160401b039081175f516020615f1c5f395f51905f52556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f61008b565b63f92ee8a960e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6101e080604052600436101561009c575b50361561001b575f80fd5b60035460ff8160a01c169081610043575b501561003457005b631dd2188d60e31b5f5260045ffd5b905060ff8160a81c16908180610087575b8215610063575b50505f61002c565b15915081610074575b505f8061005b565b6001600160a01b0316331490505f61006c565b6002546001600160a01b031633149250610054565b5f905f3560e01c908163151465f614612e155750806317911a49146127bf5780632cd271e7146127965780633f4ba83a146127185780634587c05f146126b65780634f1ef286146124ab57806352d1902d146124455780635671e8c9146123a95780635c975abb1461237b5780635df45a371461233e578063715018a6146122c15780637527527e1461216a578063783678c314611bbe578063789f290414611b185780637980e2cb146119bc57806379ba50971461195f5780637a94a42d146118285780638456cb59146117745780638da5cb5b1461173f5780639fd0506d14611716578063a38b6421146115f0578063ad3cb1cc14611594578063ad73d32e14611288578063affed0e01461125e578063c2fbe7bc1461123a578063c3f909d414611170578063db45bbfd14610ee2578063e30c397814610ead578063e4e117c114610874578063ead9b57f146105d0578063f2ba9102146103c2578063f2fde38b1461033c5763f513ef4c036100105761010036600319011261033957610224612f74565b61022c612fa1565b610234612ff9565b61023c612fb7565b610244612f56565b9061024d612f65565b92610256612f83565b9460e435421161032a578661029c979861026e6137d6565b6040519061027b82612e46565b808252806020830152806040830152606082015261029761379e565b613f28565b9060015f516020615d285f395f51905f52556103266001600160401b03835116916001600160801b03602085015116936102eb6001600160801b03606081604085015116930151169286613f44565b6040519485948592936001600160801b0380929695816060956001600160401b03608089019a16885216602087015216604085015216910152565b0390f35b630407b05b60e31b8852600488fd5b80fd5b503461033957602036600319011261033957610356612ead565b61035e613840565b5f516020615d685f395f51905f5280546001600160a01b0319166001600160a01b039283169081179091555f516020615ca85f395f51905f52549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b5034610339576060366003190112610339576103dc612f74565b6103e4612fa1565b6044356001600160801b03811681036105cc576103ff61379e565b6104076137d6565b9091838491338652600a6020526001600160801b03604087205460401c16338752600a6020526001600160801b03600160408920015416916105c1575b6001600160801b0386169081610573575b50506001600160801b0384169081610503575b5050916104b091835f516020615ce85f395f51905f52946104e5575b50806104c7575b50604080516001600160801b0395861681529490911660208501523393918291820190565b0390a260015f516020615d285f395f51905f525580f35b6003546104df919033906001600160a01b031661421b565b5f61048b565b6002546104fd919033906001600160a01b031661421b565b5f610484565b90809293508110610565579161055b5f516020615ce85f395f51905f5294926104b094338952600a6020526001600160801b038086600160408d2001930316166001600160801b0319825416179055600154906136e5565b9281929450610468565b6201f70160e21b8652600486fd5b908092935081106105b257906105a26001600160801b03876105aa94338b52600a6020520316604089206136a0565b8654906136e5565b905f80610455565b63d0dd2cf360e01b8752600487fd5b945092508284610444565b8380fd5b50346103395760e0366003190112610339576004356001600160401b03811161087057610601903690600401612ed9565b90602435916001600160401b038311610870573660238401121561087057826004013561062d81612e96565b9361063b6040519586612e75565b8185526024602086019260051b8201019036821161086c57602401915b81831061084c575050506044356001600160401b038111610848573660238201121561084857806004013561068c81612e96565b9161069a6040519384612e75565b8183526024602084019260051b8201019036821161084457602401915b818310610820575050506106c9612fb7565b6106d1612f56565b906106da612f65565b9560c43593844211610811576106ee6137d6565b8551825181149081610806575b50156107f75785519561072661071088612e96565b9761071e604051998a612e75565b808952612e96565b602088019890601f1901368a37805b82518110156107aa578061078e898d8a8a8a8a6001600160481b03610786896001600160801b0361077e8f9d6001600160401b0360019f826107769161302a565b51169761302a565b51169361302a565b5116916130bf565b6001600160401b036107a0838d61302a565b9116905201610735565b508789604051928392602084019060208552518091526040840192915b8181106107d5575050500390f35b82516001600160401b03168452859450602093840193909201916001016107c7565b63512509d360e11b8752600487fd5b90508151145f6106fb565b630407b05b60e31b8752600487fd5b82356001600160481b0381168103610840578152602092830192016106b7565b8680fd5b8580fd5b8280fd5b82356001600160801b038116810361084457815260209283019201610658565b8480fd5b5080fd5b50346103395760803660031901126103395761088e612ec3565b610896612f92565b9161089f612f47565b916064354211610e9e576108b161379e565b6108b96137d6565b6108c233613873565b93338352600a60205260ff600160408520015460801c168015610e96575b15610e87576001808316148062ffffff8460281c1690610e7a575b620fffff81169060141c600f1681151580610e6d575b15610e5e57604d8111610e4a576001600160481b0390600a0a1602926001600160481b038416938403610e365784959685835f14610d18578415610c89575060048054604080516347ca7d2960e11b81526001600160401b03868116948201949094529390921660248401529196909187916044918391906001600160a01b03165af18015610c7e5786958791610c49575b50949086935b6109bc866109b787866137fd565b61381d565b956109d06109c988614256565b87986137fd565b935b600654608081901c6001600160401b031696908b908815610b43575050506001600160801b0391610a0688610a0c936137fd565b9061381d565b1693805f19048511810215670de0b6b3a76400000215610b3f5780610a3f670de0b6b3a7640000610a45938802046141ea565b956136e5565b6001600160801b03851690670de0b6b3a7640000820291808304670de0b6b3a76400001490151715610b2b5760c0610adb946001600160801b0398979489610a9f610ae499965f516020615c885f395f51905f5296613673565b9c5b6001600160401b0360405194168452166020830152898b16604083015289851660608301528986166080830152151560a0820152a1613680565b94600b54613759565b600b5516158015610b23575b15610b1457610b0092933361428d565b60015f516020615d285f395f51905f525580f35b6396e6bb8760e01b8352600483fd5b506001610af0565b634e487b7160e01b8a52601160045260248afd5b8880fd5b92919a93909750610b5d610b578a846137fd565b8261381d565b926001600160801b03610b6f85614256565b1693670de0b6b3a7640000850291858304670de0b6b3a76400001486151715610c355792610bcc610adb9996936001600160801b03610bc5819f9e9b98956001600160401b03610ae49f9c9960401c169061381d565b1690613673565b9d15610bef575b5050509160c091895f516020615c885f395f51905f5294610aa1565b5f516020615c885f395f51905f529593975060c09492610c24610c1e610c198f95610c2a9561381d565b614256565b916141ea565b906137fd565b969294829450610bd3565b634e487b7160e01b8f52601160045260248ffd5b9050610c6e91955060403d604011610c77575b610c668183612e75565b81019061377a565b9490945f6109a3565b503d610c5c565b6040513d88823e3d90fd5b6004805460408051631f43d3d960e31b81526001600160401b0387811694820194909452949092166024850152919792959392909186916044918391906001600160a01b03165af18015610d0d5787948891610ce8575b5093916109a9565b9050610d0491945060403d604011610c7757610c668183612e75565b9390935f610ce0565b6040513d89823e3d90fd5b8415610db55750600554604080516347ca7d2960e11b81526001600160401b0360018617811660048301529390931660248401529196879160449183916001600160a01b03165af18015610c7e5786958791610d90575b50949086935b610d7f85846137fd565b95610d8a818761381d565b936109d2565b9050610dac91955060403d604011610c7757610c668183612e75565b9490945f610d6f565b60055460408051631f43d3d960e31b81526001600160401b036001871781166004830152949094166024850152919792959392869160449183916001600160a01b03165af18015610d0d5787948891610e11575b509391610d75565b9050610e2d91945060403d604011610c7757610c668183612e75565b9390935f610e09565b634e487b7160e01b85526011600452602485fd5b634e487b7160e01b86526011600452602486fd5b63a25f85b760e01b8652600486fd5b50620f423f821115610911565b62ffffff908103166108fb565b6326831c8760e21b8352600483fd5b5060016108e0565b630407b05b60e31b8252600482fd5b50346103395780600319360112610339575f516020615d685f395f51905f52546040516001600160a01b039091168152602090f35b50346103395761012036600319011261033957610efd612fcd565b610f05612fa1565b6044359060ff821682036105cc5760a4359160ff8316830361086c576101043592610f2e6137d6565b6001600160801b03851690868215159384611103575b506001600160801b038516958615159283611089575b505050905f516020615c685f395f51905f52946104b0949392610f7b61379e565b610f836137d6565b88928994611048575b50610ffe575b5080610fde575b5080610fc45750604080516001600160801b0395861681529490911660208501523393918291820190565b6003546104df9190309033906001600160a01b0316613977565b600254610ff89190309033906001600160a01b0316613977565b5f610f99565b611041919250338852600a602052600160408920016001600160801b036110288682845416613680565b166001600160801b0319825416179055600154906136e5565b905f610f92565b611082919350338a52600a60205261107a60408b206110748b6001600160801b03835460401c16613680565b906136a0565b8954906136e5565b915f610f8c565b60018060a01b0360035416916110a16001548a6136e5565b92803b1561086c576110d7938580946040519687958694859363d505accf60e01b855260e4359260c435923033600489016136f8565b03925af16110e6575b80610f5a565b816110f5919695949396612e75565b61084057909192865f6110e0565b60018060a01b03600254169061111a8354866136e5565b90823b156105cc57611152928492838b936040519687958694859363d505accf60e01b855260843592606435923033600489016136f8565b03925af115610f44578161116591612e75565b61084057865f610f44565b50346103395780600319360112610339576101a090546001546001600160401b0360018060a01b03600254168160035460018060a01b036004541660ff60055492600654958260075460a01c16986040519a8b5260208b015260408a015260018060a01b03811660608a0152818160a01c16151560808a015260a81c16151560a088015260c087015260018060a01b03811660e087015260a01c16610100850152818116610120850152818160401c1661014085015260801c166101608301521515610180820152f35b50346103395780600319360112610339576112536137d6565b61125b613fe5565b80f35b503461033957806003193601126103395760206001600160401b0360085460a01c16604051908152f35b5060c03660031901126103395761129d612f74565b6112a5612fa1565b6112ad612ff9565b6112b5612fb7565b906112be612f56565b9260a4354211611585576112d06137d6565b6112e2856112dd846140fc565b6141a5565b906001600160801b036001600160401b0361130760065482808260801c169116613739565b169187156114a4571690670de0b6b3a76400000390670de0b6b3a76400008211611490577812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111670de0b6b3a7640000021582021561148c57606461137a604093670de0b6b3a76400006001600160401b039402046141ea565b600554845163e146af4760e01b81529590931660048601526001600160801b0360248601819052166044850152839182906001600160a01b03165afa908115610c7e579486916113fd9682989161146c575b50915b604051906113dc82612e46565b80825280602083015280604083015260608201526113f861379e565b613c2a565b9060015f516020615d285f395f51905f52556103266001600160801b03602084015116916114406001600160801b03606081604088015116960151169184613f44565b604051938493849160409194936001600160801b03809281606087019816865216602085015216910152565b611485915060403d604011610c7757610c668183612e75565b505f6113cc565b8780fd5b634e487b7160e01b88526011600452602488fd5b1690670de0b6b3a7640000019081670de0b6b3a764000011611490577812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111670de0b6b3a7640000021582021561148c57606461150f604093670de0b6b3a76400006001600160401b039402046141ea565b9360018060a01b03600454166001600160801b038551968795869463e146af4760e01b86521660048501528160248501521660448301525afa908115610c7e579486916113fd96829891611565575b50916113cf565b61157e915060403d604011610c7757610c668183612e75565b505f61155e565b630407b05b60e31b8652600486fd5b5034610339578060031936011261033957604080516115b38282612e75565b6005815260208101640352e302e360dc1b81528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b50346103395760603660031901126103395761160a612ead565b90611613612f92565b604435926001600160401b0384168085036105cc5761163061379e565b5f516020615ca85f395f51905f52546001600160a01b0316330361170757670de0b6b3a764000090611660613fe5565b116116f8576005805467ffffffffffffffff60a01b191660a09590951b67ffffffffffffffff60a01b16949094179093556007549192610b00926001600160a01b0390811690821681036116b5575b50613acc565b604080516001600160a01b0384811682529290921660208301527fe6603343f7aaffa5196c214e2249898291a999fa77d7f5f2ec1457d518724be791a15f6116af565b63047f2a9760e51b8352600483fd5b631dd2188d60e31b8452600484fd5b50346103395780600319360112610339576008546040516001600160a01b039091168152602090f35b50346103395780600319360112610339575f516020615ca85f395f51905f52546040516001600160a01b039091168152602090f35b50346103395780600319360112610339575f516020615ca85f395f51905f52546001600160a01b031633148015611814575b15611805576117b36137d6565b600160ff195f516020615d085f395f51905f525416175f516020615d085f395f51905f52557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b631dd2188d60e31b8152600490fd5b506008546001600160a01b031633146117a6565b506101403660031901126103395761183e612f74565b611846612fa1565b61184e612ff9565b611856612fb7565b9061185f612fe3565b92611868612f65565b9360e43560c43560ff82168203610b3f57804211611950579088929161188c6137d6565b881561193f576002546001600160a01b03165b6001600160a01b03169289156119245784546118c3916001600160801b03166136e5565b925b803b1561086c576118fc938580946040519687958694859363d505accf60e01b8552610124359261010435923033600489016136f8565b03925af161190f575b50506112d06137d6565b8161191991612e75565b61084457855f611905565b600154611939916001600160801b03166136e5565b926118c5565b6003546001600160a01b031661189f565b630407b05b60e31b8952600489fd5b503461033957806003193601126103395761197861379e565b611980613fe5565b5f516020615d685f395f51905f5254336001600160a01b03909116036119a957610b003361390c565b63118cdaa760e01b815233600452602490fd5b50610180366003190112611ad9576119d2612f74565b906119db612fa1565b6119e3612ff9565b906119ec612fb7565b916119f5612fe3565b926119fe612f65565b91611a07612f83565b9360e435958615158703611ad95761010435976101243560ff81168103611ad957894211611b0957611a376137d6565b8a15611af8576002546001600160a01b03165b6001600160a01b0316928b15611add575f54611a6e916001600160801b03166136e5565b905b833b15611ad95761029c9a8c94611aad935f80946040519687958694859363d505accf60e01b8552610164359261014435923033600489016136f8565b03925af1611ac4575b506040519061027b82612e46565b611ad192505f9150612e75565b875f5f611ab6565b5f80fd5b600154611af2916001600160801b03166136e5565b90611a70565b6003546001600160a01b0316611a4a565b630407b05b60e31b5f5260045ffd5b34611ad9576020366003190112611ad9576001600160a01b03611b39612ead565b165f52600a602052606060405f20604051611b5381612e46565b815460016001600160801b036001600160401b0383169283855260401c169384602085015201549060ff856001600160801b03841694856040820152019260801c161515825215611bb5575b5115159060405192835260208301526040820152f35b60018152611b9f565b34611ad9576101e0366003190112611ad957611bd8612ead565b6024356001600160a01b0381168103611ad9576044356001600160a01b0381168103611ad957606435908115158203611ad957611c13612f56565b60e435939091906001600160a01b0385168503611ad957610104356001600160a01b0381168103611ad95761012435906001600160a01b0382168203611ad95761014435918215158303611ad95761016435946001600160401b0386168603611ad95761018435976001600160401b0389168903611ad9576101a435976001600160401b0389168903611ad9576101c4359b6001600160401b038d168d03611ad9575f516020615d485f395f51905f52549b8c6001600160401b0381168015918261215b575b506001149081612151575b159081612148575b506121395760018d6001600160401b031916175f516020615d485f395f51905f525560ff8d60401c161561210d575b611d23614c0b565b611d2b614c0b565b611d33614c0b565b6001600160a01b038116156120fa57611d4b9061390c565b611d53614c0b565b611d5b614c0b565b611d63614c0b565b60015f516020615d285f395f51905f5255611d7c614c0b565b611d84614c0b565b5f516020615d085f395f51905f52805460ff191690556001600160a01b03169687156120eb576001600160a01b038116156120eb576001600160a01b038416156120eb576008805467ffffffffffffffff60a01b1916647fffffffff60a01b1790556009805467ffffffffffffffff1916905560a4355f90815560c435600155600280546001600160a01b0319166001600160a01b039384161790556003805494151560a01b60ff60a01b166001600160b01b031990951695909216949094179290921790151560a81b60ff60a81b161790556040516330b9c35160e01b81523060048201529060209082906024908290895af19485156120c3575f9560209287916120ce575b5060018060a01b03166001600160601b0360a01b60045416176004556024604051809781936330b9c35160e01b83523060048401525af180156120c357611f0f945f91612094575b5060018060a01b03166001600160601b0360a01b600554161760055560018060a01b03166001600160601b0360a01b6008541617600855613acc565b670de0b6b3a76400006001600160401b038216111580612079575b8061205e575b80612043575b80612021575b156120125760ff946fffffffffffffffff000000000000000091600554906001600160401b0360a01b9060a01b16906001600160401b0360a01b1916176005556001600160401b03600654918160801b9060801b169416906001600160401b0360c01b16179160401b1617176006556001600b5560401c1615611fbb57005b68ff0000000000000000195f516020615d485f395f51905f5254165f516020615d485f395f51905f52557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b63047f2a9760e51b5f5260045ffd5b506001600160401b0385161580611f3c57506001600160401b03821615611f3c565b506702c68af0bb1400006001600160401b0386161115611f36565b506702c68af0bb1400006001600160401b0383161115611f30565b506702c68af0bb1400006001600160401b0384161115611f2a565b6120b6915060203d6020116120bc575b6120ae8183612e75565b8101906136c6565b8a611ed3565b503d6120a4565b6040513d5f823e3d90fd5b6120e59150833d85116120bc576120ae8183612e75565b8c611e8b565b63867915ab60e01b5f5260045ffd5b631e4fbdf760e01b5f525f60045260245ffd5b68ffffffffffffffffff198d1668010000000000000001175f516020615d485f395f51905f5255611d1b565b63f92ee8a960e01b5f5260045ffd5b9050158f611cec565b303b159150611ce4565b60401c60ff161591508e611cd9565b34611ad9576040366003190112611ad957612183612fcd565b5f516020615c685f395f51905f5261220161219c612fa1565b6121a461379e565b6121ac6137d6565b5f806001600160801b03861680612288575b506001600160801b03831680612257575b5080612237575b50806122175750604080516001600160801b0395861681529490911660208501523393918291820190565b0390a260015f516020615d285f395f51905f5255005b6003546122319190309033906001600160a01b0316613977565b8461048b565b6002546122519190309033906001600160a01b0316613977565b856121d6565b612281919250335f52600a602052600160405f20016001600160801b036110288682845416613680565b90866121cf565b6122bb9150335f52600a6020526122b360405f20611074896001600160801b03835460401c16613680565b5f54906136e5565b866121be565b34611ad9575f366003190112611ad9576122d9613840565b5f516020615d685f395f51905f5280546001600160a01b03199081169091555f516020615ca85f395f51905f52805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34611ad9575f366003190112611ad957600b545f19810190811161236757602090604051908152f35b634e487b7160e01b5f52601160045260245ffd5b34611ad9575f366003190112611ad957602060ff5f516020615d085f395f51905f5254166040519015158152f35b34611ad9576020366003190112611ad9576123c2612f74565b6123ca61379e565b6123d26137d6565b6123db33613873565b50335f52600a602052600160405f200190151590805460ff60801b8360801b169060ff60801b19161790556040519081527fef2c823b0511fc89fd3e836ef444a74fb1cc0c6eff36f283e7f349c59a15da9860203392a260015f516020615d285f395f51905f5255005b34611ad9575f366003190112611ad9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361249c5760206040515f516020615cc85f395f51905f528152f35b63703e46dd60e11b5f5260045ffd5b6040366003190112611ad9576124bf612ead565b602435906001600160401b038211611ad95736602383011215611ad9578160040135906124eb8261300f565b916124f96040519384612e75565b80835260208301933660248383010111611ad957815f926024602093018737840101526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016308114908115612694575b5061249c5761255e613840565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa5f9181612660575b506125a05784634c9c8ce360e01b5f5260045260245ffd5b805f516020615cc85f395f51905f5286920361264e5750823b1561263c575f516020615cc85f395f51905f5280546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2825115612623575f8091612621945190845af461261b614c36565b91614ddc565b005b5050503461262d57005b63b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f5260045260245ffd5b632a87526960e21b5f5260045260245ffd5b9091506020813d60201161268c575b8161267c60209383612e75565b81010312611ad957519086612588565b3d915061266f565b5f516020615cc85f395f51905f52546001600160a01b03161415905084612551565b34611ad95760e0366003190112611ad95760206127076126d4612ec3565b6126dc612fa1565b6126e4612ff9565b6126ec612fb7565b6126f4612f56565b916126fd612f65565b9360c435956130bf565b6001600160401b0360405191168152f35b34611ad9575f366003190112611ad957612730613840565b5f516020615d085f395f51905f525460ff8116156127875760ff19165f516020615d085f395f51905f52557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b638dfc202b60e01b5f5260045ffd5b34611ad9576020366003190112611ad9576126216127b2612ead565b6127ba613840565b613052565b34611ad9576080366003190112611ad9576004356001600160401b038111611ad95736602382011215611ad95780600401356127fa81612e96565b916128086040519384612e75565b8183526024602084019260051b82010190368211611ad957602401915b818310612df557836024356001600160401b038111611ad95761284c903690600401612ed9565b90612855612f47565b916064354211611b095761286761379e565b61286f6137d6565b8151815103612de6578215155f5b8351811015612dd3576001600160a01b03612898828661302a565b5116906128a5818561302a565b51916001600160401b038316926128bb82613873565b93825f52600a60205260ff600160405f20015460801c168015612dca575b15612dbb576001808316149160281c62ffffff1682612dae575b620fffff81169060141c600f1681151580612da1575b15612d9257604d8111612367576001600160481b0390600a0a1602946001600160481b038616958603612367575f8315612c6f578a15612bf0575060048054604080516347ca7d2960e11b81526001600160401b038681169482019490945293909216602484015291939291849060449082905f906001600160a01b03165af180156120c3575f935f91612bcc575b5092915f915b6129ac886109b785876137fd565b976129c06129b98a614256565b859a6137fd565b945b600654608081901c6001600160401b031694905f8615612afc575050506001600160801b0391610a06866129f5936137fd565b1691805f19048311810215670de0b6b3a76400000215611ad95780612a28670de0b6b3a7640000612a2e938602046141ea565b936136e5565b916001600160801b03811694670de0b6b3a7640000860295808704670de0b6b3a76400001490151715612367575f516020615c885f395f51905f5260c0612ab7946001600160801b03612a85819a612ac099613673565b9a5b604051928352166020820152888d166040820152888416606082015288851660808201528d60a0820152a1613680565b93600b54613759565b600b5516158015612af3575b15612ae45760019384612ade9361428d565b0161287d565b6396e6bb8760e01b5f5260045ffd5b50813314612acc565b9395509691939097612b17612b1188876137fd565b8761381d565b946001600160801b03612b2987614256565b1690670de0b6b3a7640000820297828904670de0b6b3a7640000148315171561236757612b77612ac0996001600160801b03610bc5612ab79b829f6001600160401b039060401c169061381d565b9b15612b99575b5050505f516020615c885f395f51905f52918860c092612a87565b60c09396505f516020615c885f395f51905f529492610c24610c1e610c198e95612bc29561381d565b9592829450612b7e565b9050612be791935060403d8111610c7757610c668183612e75565b9290928b612998565b6004805460408051631f43d3d960e31b81526001600160401b0387811694820194909452949092166024850152919491839060449082905f906001600160a01b03165af180156120c3575f925f91612c4b575b50919261299e565b9050612c6691925060403d8111610c7757610c668183612e75565b9190918c612c43565b8a15612d115750600554604080516347ca7d2960e11b81526001600160401b0360018617811660048301529093166024840152919392919084906001600160a01b0316815f816044810103925af180156120c3575f935f91612ced575b5092915f915b612cdc83856137fd565b97612ce7818561381d565b946129c2565b9050612d0891935060403d8111610c7757610c668183612e75565b9290928b612ccc565b60055460408051631f43d3d960e31b81526001600160401b03600187178116600483015290941660248501529194919083906001600160a01b0316815f816044810103925af180156120c3575f925f91612d6e575b509192612cd2565b9050612d8991925060403d8111610c7757610c668183612e75565b9190918c612d66565b63a25f85b760e01b5f5260045ffd5b50620f423f821115612909565b62ffffff908103166128f3565b6326831c8760e21b5f5260045ffd5b508233146128d9565b60015f516020615d285f395f51905f5255005b63512509d360e11b5f5260045ffd5b82356001600160a01b0381168103611ad957815260209283019201612825565b34611ad9575f366003190112611ad9576007546001600160a01b038116825260a01c60ff1615156020820152604090f35b608081019081106001600160401b03821117612e6157604052565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b03821117612e6157604052565b6001600160401b038111612e615760051b60200190565b600435906001600160a01b0382168203611ad957565b600435906001600160401b0382168203611ad957565b9080601f83011215611ad957813590612ef182612e96565b92612eff6040519485612e75565b82845260208085019360051b820101918211611ad957602001915b818310612f275750505090565b82356001600160401b0381168103611ad957815260209283019201612f1a565b604435908115158203611ad957565b608435908115158203611ad957565b60a435908115158203611ad957565b600435908115158203611ad957565b60c435908115158203611ad957565b602435908115158203611ad957565b602435906001600160801b0382168203611ad957565b606435906001600160801b0382168203611ad957565b600435906001600160801b0382168203611ad957565b608435906001600160801b0382168203611ad957565b604435906001600160481b0382168203611ad957565b6001600160401b038111612e6157601f01601f191660200190565b805182101561303e5760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b6008546001600160a01b03828116929082168381146130b957604080516001600160a01b0393841681529190921660208201527f95bb211a5a393c4d30c3edc9a745825fba4e6ad3e3bb949e6bf8ccdfe431a8119190a16001600160a01b03191617600855565b50505050565b9594919390926130cd6137d6565b5f9660016001600160401b03821611613189575b6001600160801b0385166130fa575b5050505050505090565b60019192939495969750811614954211611b095761317d9461314d9461311e6137d6565b8760405161312b81612e46565b5f81525f60208201525f60408201525f606082015261314861379e565b613f0f565b9160015f516020615d285f395f51905f52556001600160801b0360206001600160401b0385511694015116613f44565b5f8080808080806130f0565b864211611b095761319861379e565b6131a06137d6565b5f6131aa33613873565b335f818152600a602052604090206001015460801c60ff16801561366a575b15612dbb576001808516148062ffffff8660281c169061365d575b620fffff81169060141c600f1681151580613650575b15612d9257604d8111612367576001600160481b0390600a0a1602926001600160481b038416938403612367575f82156135b057851561352f575060048054604080516347ca7d2960e11b81526001600160401b038a81169482019490945293909216602484015291959392918690604490829087906001600160a01b03165af1801561352457839584916134ff575b50949083915b61329e866109b785846137fd565b956132b26132ab88614256565b85986137fd565b915b600654608081901c6001600160401b031694908890861561341b575050506001600160801b0391610a06866132e8936137fd565b1691805f19048311810215670de0b6b3a764000002156108445780612a28670de0b6b3a764000061331b938602046141ea565b6001600160801b03831690670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561340757926133b8925f516020615c885f395f51905f5260c08c6001600160801b036133746133af97829b9a613673565b9d5b6001600160401b0360405193168352166020820152888c166040820152888416606082015288851660808201528a60a0820152a1613680565b96600b54613759565b600b5516159081156133fd575b50156133ee5750906133d891863361428d565b60015f516020615d285f395f51905f52556130e1565b6396e6bb8760e01b8152600490fd5b905033145f6133c5565b634e487b7160e01b87526011600452602487fd5b92919a9390955061342f610b5788846137fd565b926001600160801b0361344185614256565b1693670de0b6b3a7640000850291858304670de0b6b3a764000014861517156134eb57938e936134966133af98946001600160801b03610bc5819e9d9a966001600160401b036133b89e9b60401c169061381d565b9e156134b8575b5050505f516020615c885f395f51905f52918860c092613376565b60c09396505f516020615c885f395f51905f529492610c24610c1e610c198e956134e19561381d565b959282945061349d565b634e487b7160e01b8c52601160045260248cfd5b905061351b91955060403d604011610c7757610c668183612e75565b9490945f61328a565b6040513d85823e3d90fd5b6004805460408051631f43d3d960e31b81526001600160401b038b8116948201949094529490921660248501529196949391839060449082905f906001600160a01b03165af180156120c3575f925f9161358b575b5091613290565b90506135a791925060403d604011610c7757610c668183612e75565b9190915f613584565b60055460408051631f43d3d960e31b81526001600160401b0360018b1781166004830152909416602485015291965091945f9493909290919086906001600160a01b03168187816044810103925af19485156120c3575f905f9661362c575b5085926136268161362089856137fd565b9861381d565b916132b4565b905061364891955060403d604011610c7757610c668183612e75565b94905f61360f565b50620f423f8211156131fa565b62ffffff908103166131e4565b508033146131c9565b9190820391821161236757565b906001600160801b03809116911601906001600160801b03821161236757565b90600160401b600160c01b0382549160401b1690600160401b600160c01b031916179055565b90816020910312611ad957516001600160a01b0381168103611ad95790565b8181029291811591840414171561236757565b9360c095919897969360ff9360e087019a60018060a01b0316875260018060a01b031660208701526040860152606085015216608083015260a08201520152565b906001600160401b03809116911601906001600160401b03821161236757565b9190820180921161236757565b51906001600160801b0382168203611ad957565b9190826040910312611ad95761379b602061379484613766565b9301613766565b90565b60025f516020615d285f395f51905f5254146137c75760025f516020615d285f395f51905f5255565b633ee5aeb560e01b5f5260045ffd5b60ff5f516020615d085f395f51905f5254166137ee57565b63d93c066560e01b5f5260045ffd5b906001600160801b03809116911603906001600160801b03821161236757565b906001600160801b03809116911602906001600160801b03821691820361236757565b5f516020615ca85f395f51905f52546001600160a01b0316330361386057565b63118cdaa760e01b5f523360045260245ffd5b6001600160a01b03165f818152600a60205260409020546001600160401b03169190821561389e5750565b9150600954916001600160401b0383166001600160401b0381146123675767ffffffffffffffff199384166001600160401b0360019283019081169182176009555f938452600a6020526040909320805490951617845592909201805460ff60801b1916600160801b179055565b5f516020615d685f395f51905f5280546001600160a01b03199081169091555f516020615ca85f395f51905f5280549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6040516370a0823160e01b815230600482015291926001600160a01b0382169190602084602481865afa9384156120c3575f94613a79575b50602494602093926139fe92604051926323b872dd60e01b8785015260018060a01b03168884015260018060a01b03166044830152876064830152606482526139f9608483612e75565b614d44565b6040516370a0823160e01b815230600482015293849182905afa80156120c3575f90613a45575b613a2f9250613673565b03613a3657565b632f35253160e01b5f5260045ffd5b506020823d602011613a71575b81613a5f60209383612e75565b81010312611ad957613a2f9151613a25565b3d9150613a52565b9093506020929192813d602011613aac575b81613a9860209383612e75565b81010312611ad957519290919060246139af565b3d9150613a8b565b90816020910312611ad957518015158103611ad95790565b81613b3a575b6001600160a01b031680156120eb5760405160408101928184106001600160401b03851117612e6157602093604052828252151592839101526001600160601b0360a01b60075416176007556007549060ff60a01b9060a01b169060ff60a01b191617600755565b6040516301ffc9a760e01b8152630920cbe360e31b60048201526020816024816001600160a01b0386165afa9081156120c3575f91613b88575b50613ad2576309bfcb9b60e31b5f5260045ffd5b613baa915060203d602011613bb0575b613ba28183612e75565b810190613ab4565b5f613b74565b503d613b98565b90816020910312611ad957516001600160401b0381168103611ad95790565b6001600160401b0390911681526001600160801b03909116602082015260400190565b6001600160401b039182168152911660208201526001600160801b0391821660408201529116606082015260800190565b9594929391928691906001600160801b03851680151580613efd575b15613eef5734158015613ec3575b15613eb457613c66836112dd896140fc565b5f9390849081808415613e3a5750506005546040805163a558898f60e01b81529a90928b926001600160a01b03169183915f918391613ca9919060048401613bd6565b03925af19586156120c3575f985f97613e13575b50868997985b6001600160801b03613cde613cd784614c8c565b8096613680565b9b169182613d93575b6001600160801b03613d146060968280948760208a0152169687604082015283821698899101525f613680565b9216911611613d84576001600160481b03613d829b604051965f885260208801521660408601525f60608601525f608086015260a085015260c084015260e083015260016101008301525f6101208301521515905f516020615d885f395f51905f526101403392a33361468c565b565b6352866ea560e11b5f5260045ffd5b60405163371da77d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156120c3575f91613df4575b50613ce75763ab655c5560e01b5f5260045ffd5b613e0d915060203d602011613bb057613ba28183612e75565b5f613de0565b909650613e3091985060403d604011610c7757610c668183612e75565b979097955f613cbd565b979650979150613e6f9860409160018060a01b0360045416905f8451809d8195829463a558898f60e01b845260048401613bd6565b03925af19485156120c3575f985f96613e8d575b5085899692613cc3565b909550613eaa91985060403d604011610c7757610c668183612e75565b979097945f613e83565b6328745eb160e01b5f5260045ffd5b5060035460ff8160a01c169081613edb575b50613c54565b60ff915060a81c161515831515145f613ed5565b62f8653360e71b5f5260045ffd5b506001600160481b0387161515613c46565b613f2196610120525f61014052614e3a565b6101405190565b9096613f3e976101005260c0525f60e052615544565b60e05190565b6001600160801b031615613fa75760075460ff8160a01c1680613fb4575b613f6a575050565b6001600160a01b031690813b15611ad9575f91602483926040519485938492630920cbe360e31b8452151560048401525af180156120c357613faa575b50565b5f613d8291612e75565b50336001600160a01b0382161415613f62565b8115613fd1570490565b634e487b7160e01b5f52601260045260245ffd5b600b545f19810181811161236757670de0b6b3a7640000900490670de0b6b3a7640000820290821591838104670de0b6b3a7640000148317156123675761402b91613673565b600b55613fa75761409061407e60018060a01b035f516020615ca85f395f51905f5254169261407261406b6001600160401b0360055460a01c1683614daf565b8092613673565b806140af575b506141ea565b6001600160801b0360015491166136e5565b80614099575050565b600354613d8292906001600160a01b031661421b565b6140b8906141ea565b60018060a01b03600754165f52600a6020526001600160801b036140e6600160405f20019282845416613680565b166001600160801b03198254161790555f614078565b906001600160481b0382168015159081614191575b5015614182575f915b6001600160481b03811690620f423f82111561416a57506001600160481b03600a82061661415b57600a60ff9104921660ff8114612367576001019161411a565b632f17742b60e21b5f5260045ffd5b62f00000915062ffffff90939293169160141b161790565b6323f5f0b960e11b5f5260045ffd5b683635c6204739d98000915011155f614111565b67fffffffffffffffe906001925f146141cd5760271b677fffff8000000000165b821b161890565b62ffffff67ffffff8000000000911662ffffff0360271b166141c6565b6001600160801b038111614204576001600160801b031690565b6306dfcc6560e41b5f52608060045260245260445ffd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152613d82916139f9606483612e75565b6001600160401b0360065460401c169081156142875761379b916001600160801b036142829216614daf565b6141ea565b50505f90565b9091925f80945f945f916003549660ff8860a81c1697885f1461467d57506002546001600160a01b0316975b34614601575b50906001600160801b031680156145f157821561459e576001600160801b03916142ee6142f4925f54906136e5565b90613759565b945b16908115614596571561453557906142ee61431492600154906136e5565b915b60035460ff8160a01c1661447d575b50918183819461442b575b5061440b575b806143bf575b506143a1575b50504761434d575050565b47906001600160a01b0316803b15610848578290600460405180948193630d0e30db60e41b83525af1801561439657614384575050565b61438f828092612e75565b6103395750565b6040513d84823e3d90fd5b6003546143b89230916001600160a01b0316613977565b5f82614342565b600354908460ff8360a01c16806143fd575b156143e6576143e09250614c65565b5f61433c565b6143f8926001600160a01b031661421b565b6143e0565b5060ff8360a81c16156143d1565b600254614426908390309087906001600160a01b0316613977565b614336565b60035460ff8160a01c16908161446f575b50156144525761444c9086614c65565b5f614330565b60025461446a919087906001600160a01b031661421b565b61444c565b60ff915060a81c165f61443c565b5f9060a81c60ff16808061452c575b61451a575b1580614511575b614501575b8015614325579091506001600160a01b03851690813b15611ad9575f91602483926040519485938492632e1a7d4d60e01b845260048401525af180156120c3576144ea575b908591614325565b6144f8919295505f90612e75565b5f93905f6144e2565b5061450c4784613673565b61449d565b50478411614498565b90506145264783613673565b90614491565b5047831161448c565b5f516020615c685f395f51905f52604060018060a09795971b03871692835f52600a6020526001825f20016001600160801b036145758382845416613680565b166001600160801b03198254161790558151905f82526020820152a2614316565b505091614316565b946001600160801b0391955f516020615c685f395f51905f52604060018060a01b038a1692835f52600a6020526145e0825f2061107483898354871c16613680565b81519081525f6020820152a26142f6565b50936001600160801b03906142f6565b1561464657506001600160801b0361463d6146365f546146306146276142828334613fc7565b918583166136e5565b94613680565b9234613673565b915b91906142bf565b9092506001600160801b0361467761467060015461466a6146276142828334613fc7565b98613680565b9634613673565b9361463f565b6001600160a01b0316976142b9565b92919390945f955f905f925f925f966003549960ff8b60a81c169a8b5f14614bfc57506002546001600160a01b03169a5b34614b94575b506001600160801b0382166001600160801b0382168181115f14614aaa575050036001600160801b03168315614a5857906142ee614703925f54906136e5565b945b6001600160801b0382166001600160801b0382168181115f14614964575050036001600160801b0316901561490357906142ee61474592600154906136e5565b915b60035460ff8160a01c16614858575b5080614806575b50806147e6575b508061479a575b508061477c5750504761434d575050565b6003546147939230916001600160a01b0316613977565b5f80614342565b600354908360ff8360a01c16806147d8575b156147c1576147bb9250614c65565b5f61476b565b6147d3926001600160a01b031661421b565b6147bb565b5060ff8360a81c16156147ac565b6002546148009190309086906001600160a01b0316613977565b5f614764565b60035460ff8160a01c16908161484a575b501561482d576148279085614c65565b5f61475d565b600254614845919086906001600160a01b031661421b565b614827565b60ff915060a81c165f614817565b5f9060a81c60ff1680806148fa575b6148e8575b15806148df575b6148cf575b8015614756576001600160a01b03871690813b15611ad9575f91602483926040519485938492632e1a7d4d60e01b845260048401525af180156120c35715614756576148c79197505f90612e75565b5f955f614756565b506148da4784613673565b614878565b50478411614873565b90506148f44783613673565b9061486c565b50478311614867565b5f516020615c685f395f51905f52604060018060a09795971b03881692835f52600a6020526001825f20016001600160801b036149438382845416613680565b166001600160801b03198254161790558151905f82526020820152a2614747565b909192935095939510614979575b5050614747565b6001600160a01b0387165f818152600a602052604090206001015490926001600160801b0392900382169116818110614a00575060405f516020615ce85f395f51905f5291835f52600a6020526001825f20016001600160801b038083818454160316166001600160801b03198254161790558151905f82526020820152a25b5f80614972565b95506040614a2a5f516020615ce85f395f51905f52926001600160801b03896001549203166136e5565b96835f52600a6020526001825f20016001600160801b031981541690558151905f82526020820152a26149f9565b5f516020615c685f395f51905f52604060018060a09a959a1b038b1692835f52600a602052614a99825f20611074836001600160801b038354871c16613680565b81519081525f6020820152a2614705565b98939810614aba575b5050614705565b6001600160801b0391031660018060a01b03891690815f52600a6020526001600160801b0360405f205460401c16818110155f14614b3d575060405f516020615ce85f395f51905f5291835f52600a602052614b29825f206001600160801b0383818354871c160316906136a0565b81519081525f6020820152a25b5f80614ab3565b96506040614b665f516020615ce85f395f51905f52926001600160801b038a5f549203166136e5565b97835f52600a602052815f20600160401b600160c01b0319815416905581519081525f6020820152a2614b36565b90929015614bcd5750614bc56146365f54614630614bb56142828334613fc7565b916001600160801b0383166136e5565b915b5f6146c3565b919450614bf6614bef600154614be9614bb56142828334613fc7565b99613680565b9734613673565b94614bc7565b6001600160a01b03169a6146bd565b60ff5f516020615d485f395f51905f525460401c1615614c2757565b631afcd79f60e31b5f5260045ffd5b3d15614c60573d90614c478261300f565b91614c556040519384612e75565b82523d5f602084013e565b606090565b5f80809381935af1614c75614c36565b5015614c7d57565b6312171d8360e31b5f5260045ffd5b6001600160801b03168015614d3f576006546001600160401b038160801c16916001600160401b03614cc084828516613739565b168015614d3757614cd19082614daf565b91670de0b6b3a7640000830290838204670de0b6b3a76400001484151715612367576142ee836001600160401b03614d1c614d2795614d1661379b9a614d2f996136e5565b90613673565b9360401c16906136e5565b600b54613759565b600b556141ea565b505050505f90565b505f90565b5f80614d6c9260018060a01b03169360208151910182865af1614d65614c36565b9083614ddc565b8051908115159182614d94575b5050614d825750565b635274afe760e01b5f5260045260245ffd5b614da79250602080918301019101613ab4565b155f80614d79565b815f19048111820215670de0b6b3a76400000215611ad95702670de0b6b3a7640000808204910615150190565b90614e005750805115614df157805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580614e31575b614e11575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b15614e09565b9491939492909280610140525f916001600160801b038616151580615532575b15613eef5734159687159788615506575b15613eb4578492614e7b836140fc565b98614e86888b6141a5565b94615377575b50505f6101808190526101a08190526101c0819052978893849384939188156151a0575b505f99614ebd85826137fd565b925f946001600160801b038516614fae575b506001600160801b0380614ee38a88613680565b9216911611614f9f576040519a6001600160401b03168b526001600160801b031660208b01526001600160481b031660408a01526001600160801b031660608901526001600160801b031660808801526001600160801b031660a08701526001600160801b031660c08601526001600160801b031660e0850152610100840152151561012083015215159033906101405f516020615d885f395f51905f5291a36101c0516101a0516101805161012051613d829491903361468c565b6352866ea560e11b8852600488fd5b9194509b9a50600854906001600160401b03808360a01c16928160a01b5f19850160a01b16908260a01b1916178060085560a01c161561519157677fffff8000000000908b156151865762ffffff0360271b1617925b600167fffffffffffffffe85821b16189a61501e33613873565b6150316001600160481b0385168661381d565b6101605261504161016051614256565b958c156150e557506004546001600160a01b0316803b156150e157615088918b918f83899160405196879586948593635919321160e11b8552610160519260048601613bf9565b03925af180156150d65785918b916150bd575b50506150a691613680565b9b5b6001600160401b038c1661014051525f614ecf565b819250906150ca91612e75565b610b3f5783895f61509b565b6040513d8c823e3d90fd5b8a80fd5b600554929e9d90926001600160a01b031691823b15611ad95761512892875f809460405196879586948593635919321160e11b8552610160519260048601613bf9565b03925af180156120c357615169575b5067fffffffffffffffe9060011b169a6151606151578661016051613680565b6101c051613680565b6101c0526150a8565b6151769199505f90612e75565b5f9767fffffffffffffffe615137565b60271b161792615004565b63888ea83960e01b5f5260045ffd5b93509450925097865f146152fc57506040876151de9260018060a01b0360055416905f845180968195829463a558898f60e01b845260048401613bd6565b03925af19788156120c3575f915f996152d9575b50889282996101a0525b61520584614c8c565b94615213866101c051613680565b6101c0526001600160801b03841680615259575b60206101405101526001600160801b03851660406101405101526001600160801b03861660606101405101525f614eb0565b60405163371da77d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156120c3575f916152ba575b506152275763ab655c5560e01b5f5260045ffd5b6152d3915060203d602011613bb057613ba28183612e75565b5f6152a6565b9098506152f5915060403d604011610c7757610c668183612e75565b975f6151f2565b9760408861532c9360018060a01b0360045416905f845180978195829463a558898f60e01b845260048401613bd6565b03925af19283156120c3575f925f94615350575b508383610180526101c0526151fc565b90935061536d91925060403d604011610c7757610c668183612e75565b919091925f615340565b5f881561549357600554604051632e28668360e01b815290602090829060049082906001600160a01b03165afa80156120c3576001600160401b03915f91615464575b50166001600160401b038716111561545c575b15614e8c57935097505091506001600160481b03925061544d575b6001600160801b03604051945f86521660208501521660408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f61010083015260016101208301521515905f516020615d885f395f51905f526101403392a361014052565b6154573433614c65565b6153e8565b5060016153cd565b615486915060203d60201161548c575b61547e8183612e75565b810190613bb7565b5f6153ba565b503d615474565b60048054604051632e28668360e01b81529160209183919082906001600160a01b03165afa80156120c3576001600160401b03915f916154e7575b50166001600160401b038716116153cd575060016153cd565b615500915060203d60201161548c5761547e8183612e75565b5f6154ce565b5060035460ff8160a01c16908161551e575b50614e6b565b60ff915060a81c161515861515145f615518565b506001600160481b0381161515614e5a565b939291909594958460e052831584615c5f575b15615c50575f916001600160801b038216151580615c3e575b15613eef5734159182159283615c0f575b15613eb4578896615591836140fc565b9361559f61010051866141a5565b9a615a86575b50505f6101608190526101a081905260808190526101c081905298899586959189156158a8575b505f61018052876158a1576155e186846137fd565b945b5f60a0526001600160801b0386166156ca575b506001600160801b038061560c8d60a051613680565b92169116116156bb57506001600160801b0397989388809693946001600160481b038296839560206040519e8f926001600160401b0361018051168452169101521660408c01521660608a01528160a0511660808a01521660a08801521660c08601521660e084015215156101008301521515610120820152610100511515905f516020615d885f395f51905f526101403392a3613d826101c0516101a0516080516101605160c0513361468c565b6352866ea560e11b8152600490fd5b600854906001600160401b03808360a01c16928160a01b5f19850160a01b16908260a01b1916178060085560a01c161561519157677fffff800000000090610100515f146158975762ffffff0360271b16175b600167fffffffffffffffe82821b16186101805261573a33613873565b610120526157516001600160481b0386168761381d565b6101405261576161014051614256565b60a05261010051156157fd57506004546001600160a01b0316803b1561084857826040518092635919321160e11b82528183816157ad610140518d610180516101205160048601613bf9565b03925af18015613524579083916157e8575b50506157cd85608051613680565b6080525b6001600160401b03610180511660e051525f6155f6565b816157f291612e75565b61087057815f6157bf565b6005546001600160a01b0316803b15611ad9575f6040518092635919321160e11b825281838161583d8d6101405190610180516101205160048601613bf9565b03925af180156120c35761587a575b5067fffffffffffffffe9060011b166101805261587161515760a05161014051613680565b6101c0526157d1565b6158879193505f90612e75565b5f9167fffffffffffffffe61584c565b60271b161761571d565b5f946155e3565b955099509450610100515f14615a07576040816158e79560018060a01b0360055416905f845180998195829463a558898f60e01b845260048401613bd6565b03925af19485156120c3575f945f966159e0575b5085856080526101a0525b61590f86614c8c565b9961591d8b6101c051613680565b6101c0526001600160801b03861680615960575b602060e05101526001600160801b038716604060e05101526001600160801b038b16606060e05101525f6155cc565b60405163371da77d60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156120c3575f916159c1575b506159315763ab655c5560e01b5f5260045ffd5b6159da915060203d602011613bb057613ba28183612e75565b5f6159ad565b9095506159fd91945060403d604011610c7757610c668183612e75565b939093945f6158fb565b600480546040805163a558898f60e01b815296909287926001600160a01b03169183915f918391615a3b9189918401613bd6565b03925af19485156120c3575f945f96615a5f575b508585610160526101c052615906565b909550615a7c91945060403d604011610c7757610c668183612e75565b939093945f615a4f565b5f610100515f14615b9c57600554604051632e28668360e01b815290602090829060049082906001600160a01b03165afa80156120c3576001600160401b03915f91615b7d575b50166001600160401b038d161115615b75575b156155a557945097985095509250506001600160481b039250615b66575b6001600160801b03604051935f85521660208401521660408201525f60608201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201526001610120820152610100511515905f516020615d885f395f51905f526101403392a360e052565b615b703433614c65565b615afe565b506001615ae0565b615b96915060203d60201161548c5761547e8183612e75565b5f615acd565b60048054604051632e28668360e01b81529160209183919082906001600160a01b03165afa80156120c3576001600160401b03915f91615bf0575b50166001600160401b038d1611615ae057506001615ae0565b615c09915060203d60201161548c5761547e8183612e75565b5f615bd7565b5060035460ff8160a01c169081615c27575b50615581565b60ff915060a81c161515610100511515145f615c21565b506001600160481b0381161515615570565b639aa6df0360e01b5f5260045ffd5b50861561555756fe91a0eb2c39ca4d8b85d038e494302fb14bda4920d009c0aa44f26960104adb97921a8ce27b6521c36c2f7901104535739cfb9dc28cd1bca46f5fe5913f0d079d9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc46a85bb068360778f28161eb8ac970939d29cc684f100323a8e5f120adc45ff1cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c007cbbf9e533e963aebd385f66fc01e69558a4fe08eb6c6bc0127fa292b0442800a2646970667358221220d6c6dd7d00db3d8928d1597ced112522ac59ce7379c0dc88729955f7d184034c64736f6c634300081c0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a000000000000000000000000000a998351d4f13a6217ea041b7ffd654280f89898000000000000000000000000a306462ec7b5f4ce91fa05af3ea1f9dccccb5fc300000000000000000000000014f9c800390e0f1027a30e54cf883bbc722cc387
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f3560e01c9081636a2385e8146105ec575080636f5cbf15146105a8578063715018a61461054557806378c918f01461021c57806379ba5097146101975780638da5cb5b14610170578063a34b5ee81461011d578063e30c3978146100f55763f2fde38b1461007f575f80fd5b346100f15760203660031901126100f157610098610625565b6100a061063b565b60018060a01b0316806bffffffffffffffffffffffff60a01b600154161760015560018060a01b035f54167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b5f80fd5b346100f1575f3660031901126100f1576001546040516001600160a01b039091168152602090f35b346100f15760403660031901126100f157610136610625565b602435908115158092036100f15761014c61063b565b60018060a01b03165f52600260205260405f209060ff801983541691161790555f80f35b346100f1575f3660031901126100f1575f546040516001600160a01b039091168152602090f35b346100f1575f3660031901126100f157600154336001600160a01b039091160361020957600180546001600160a01b03199081169091555f805433928116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b63118cdaa760e01b5f523360045260245ffd5b346100f1576101c03660031901126100f157610236610625565b6024356001600160a01b038116908190036100f157604435918215158093036100f1576064358015158091036100f15760843560a43560c4356001600160a01b038116908190036100f15760e4356001600160a01b038116908190036100f157610104356001600160a01b038116908190036100f15761012435918215158093036100f157610144359367ffffffffffffffff85168095036100f157610164359567ffffffffffffffff87168097036100f157610184359767ffffffffffffffff89168099036100f1576101a4359967ffffffffffffffff8b16809b036100f157335f52600260205260ff60405f20541615610536578c9b8e9160405192602084019263783678c360e01b845260018060a01b037f000000000000000000000000a306462ec7b5f4ce91fa05af3ea1f9dccccb5fc316602486015260018060a01b03169e8f60448601526064850152608484015260a48301528260c48301528360e48301528461010483015285610124830152866101448301528761016483015288610184830152896101a48301528a6101c48301528b6101e48301526101e4825261022082019180831067ffffffffffffffff8411176105225782604052610297908181019161022083019285841067ffffffffffffffff851117610522576060936102209261064f88397f000000000000000000000000ed50c171f85a9c8b8f875079b256f7b9123d295f6001600160a01b0316905260406102408201528251610260820181905294859061028083015e5f848387840101015261021f1994601f80199101160101030101905ff09c8d156105175760209d60018060a01b03169c8d9c8f6040519e8f908152015260408d015260608c015260808b015260a08a015260c089015260e08801526101008701526101208601526101408501526101608401526101808301526101a08201527f04b3d813686f2d1061e11e5a0d93455065f32174906b0c037cf1176818af86be6101c03392a2604051908152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b631dd2188d60e31b5f5260045ffd5b346100f1575f3660031901126100f15761055d61063b565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346100f1575f3660031901126100f1576040517f000000000000000000000000ed50c171f85a9c8b8f875079b256f7b9123d295f6001600160a01b03168152602090f35b346100f15760203660031901126100f1576020906001600160a01b03610610610625565b165f526002825260ff60405f20541615158152f35b600435906001600160a01b03821682036100f157565b5f546001600160a01b031633036102095756fe60806040523461015e575f610297908138038061001b81610162565b938439820160408382031261015e5782516001600160a01b0381169390919084830361015e576020810151906001600160401b03821161015e57019381601f8601121561015e5784516100756100708261019b565b610162565b9581875260208701936020838301011161015e57815f926020809301865e87010152823b1561014c577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a28351156101435782809161012a955190845af4903d1561013a573d61011a6100708261019b565b908152809360203d92013e6101b6565b505b604051608290816102158239f35b606092506101b6565b5050505061012c565b634c9c8ce360e01b5f5260045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761018757604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161018757601f01601f191660200190565b906101da57508051156101cb57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061020b575b6101eb575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156101e356fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea26469706673582212204213b01ce51043145a896961fd42155a794e91743452dbe5362f72369eaa2d5c64736f6c634300081c0033a26469706673582212205286711af21e1a990f14bf36ea55a4a01bd1f7a85e82466be78418e090839d5564736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000a998351d4f13a6217ea041b7ffd654280f89898000000000000000000000000a306462ec7b5f4ce91fa05af3ea1f9dccccb5fc300000000000000000000000014f9c800390e0f1027a30e54cf883bbc722cc387
-----Decoded View---------------
Arg [0] : _owner (address): 0x0A998351d4F13A6217Ea041b7fFd654280F89898
Arg [1] : _trieFactory (address): 0xA306462ec7b5f4ce91Fa05Af3Ea1F9dCcCCB5fC3
Arg [2] : _watch_dog (address): 0x14F9C800390E0f1027a30E54cF883Bbc722cc387
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000a998351d4f13a6217ea041b7ffd654280f89898
Arg [1] : 000000000000000000000000a306462ec7b5f4ce91fa05af3ea1f9dccccb5fc3
Arg [2] : 00000000000000000000000014f9c800390e0f1027a30e54cf883bbc722cc387
Deployed Bytecode Sourcemap
630:4804:33:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;;;:::i;:::-;1500:62:7;;:::i;:::-;630:4804:33;;;;;;;;;;1255:24:8;630:4804:33;;;1255:24:8;630:4804:33;;;;;;;;;1294:43:8;630:4804:33;1294:43:8;;630:4804:33;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;;;;;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;;;:::i;:::-;;;;;;;;;;;;1500:62:7;;:::i;:::-;630:4804:33;;;;;;;;2414:9;630:4804;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;;;;;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;;;735:10:18;-1:-1:-1;;;;;630:4804:33;;;1856:24:8;1852:96;;953:13;630:4804:33;;-1:-1:-1;;;;;;630:4804:33;;;;;;-1:-1:-1;630:4804:33;;735:10:18;630:4804:33;;;;;;;-1:-1:-1;;;;;630:4804:33;;3052:40:7;;-1:-1:-1;3052:40:7;630:4804:33;1852:96:8;1903:34;;;630:4804:33;1903:34:8;735:10:18;630:4804:33;;;;1903:34:8;630:4804:33;;;;;;-1:-1:-1;;630:4804:33;;;;;;:::i;:::-;;;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4043:10;630:4804;;4033:9;630:4804;;;;;;;;;;;;;;;;;4120:641;630:4804;4120:641;;;;;;;;630:4804;;;;;4299:11;630:4804;;4120:641;;630:4804;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4120:641;;630:4804;;;;;;;;;;;;;;;;4789:91;;;;;;630:4804;4789:91;;;;;;630:4804;4789:91;;;;;630:4804;4789:91;630:4804;4789:91;;;;4820:17;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4789:91;;4120:641;630:4804;4120:641;;630:4804;;;;;4789:91;;;;630:4804;4789:91;;;;;;630:4804;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4896:494;630:4804;4043:10;4896:494;;630:4804;;;;;;4789:91;630:4804;;;;;;;;;4789:91;630:4804;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;1500:62:7;;:::i;:::-;1610:20:8;630:4804:33;;-1:-1:-1;;;;;;630:4804:33;;;;;;-1:-1:-1;630:4804:33;;;;;;;-1:-1:-1;;;;;;630:4804:33;3052:40:7;-1:-1:-1;;3052:40:7;630:4804:33;;;;;;;-1:-1:-1;;630:4804:33;;;;;;824:46;-1:-1:-1;;;;;630:4804:33;;;;;;;;;;;;-1:-1:-1;;630:4804:33;;;;;;-1:-1:-1;;;;;630:4804:33;;:::i;:::-;;;;1503:41;630:4804;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;630:4804:33;;;;;;:::o;1796:162:7:-;1710:6;630:4804:33;-1:-1:-1;;;;;630:4804:33;735:10:18;1855:23:7;1851:101;;1796:162::o
Swarm Source
ipfs://d6c6dd7d00db3d8928d1597ced112522ac59ce7379c0dc88729955f7d184034c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.