Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
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:
LiquidityVault
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 1000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ReentrancyGuardTransient} from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import {IBookManager} from "clober-dex/v2-core/interfaces/IBookManager.sol"; import {ILocker} from "clober-dex/v2-core/interfaces/ILocker.sol"; import {BookId, BookIdLibrary} from "clober-dex/v2-core/libraries/BookId.sol"; import {Currency, CurrencyLibrary} from "clober-dex/v2-core/libraries/Currency.sol"; import {OrderId, OrderIdLibrary} from "clober-dex/v2-core/libraries/OrderId.sol"; import {Tick, TickLibrary} from "clober-dex/v2-core/libraries/Tick.sol"; import {FeePolicy, FeePolicyLibrary} from "clober-dex/v2-core/libraries/FeePolicy.sol"; import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; import {ILiquidityVault} from "./interfaces/ILiquidityVault.sol"; import {IStrategy} from "./interfaces/IStrategy.sol"; import {ERC6909Supply} from "./libraries/ERC6909Supply.sol"; contract LiquidityVault is ILiquidityVault, ILocker, Ownable2Step, ERC6909Supply, ReentrancyGuardTransient, Initializable, UUPSUpgradeable { using BookIdLibrary for IBookManager.BookKey; using SafeERC20 for IERC20; using SafeCast for uint256; using CurrencyLibrary for Currency; using OrderIdLibrary for OrderId; using TickLibrary for Tick; using FeePolicyLibrary for FeePolicy; uint256 public constant RATE_PRECISION = 1e6; IBookManager public immutable bookManager; uint256 public immutable burnFeeRate; mapping(bytes32 key => Pool) private _pools; mapping(BookId => BookId) public bookPair; mapping(Currency => uint256) public fees; string public name; string public symbol; modifier selfOnly() { if (msg.sender != address(this)) revert NotSelf(); _; } constructor(IBookManager bookManager_, uint256 burnFeeRate_, string memory name_, string memory symbol_) Ownable(msg.sender) { if (burnFeeRate_ >= RATE_PRECISION) revert InvalidRate(); bookManager = bookManager_; burnFeeRate = burnFeeRate_; name = name_; symbol = symbol_; } function initialize(address initialOwner) external initializer { _transferOwnership(initialOwner); } function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} function decimals(uint256) external pure returns (uint8) { return 18; } function getPool(bytes32 key) external view returns (Pool memory) { return _pools[key]; } function getBookPairs(bytes32 key) external view returns (BookId, BookId) { return (_pools[key].bookIdA, _pools[key].bookIdB); } function getLiquidity(bytes32 key) public view returns (Liquidity memory liquidityA, Liquidity memory liquidityB) { Pool storage pool = _pools[key]; liquidityA.reserve = pool.reserveA; liquidityB.reserve = pool.reserveB; OrderId[] memory orderListA = pool.orderListA; OrderId[] memory orderListB = pool.orderListB; if (orderListA.length > 0) { IBookManager.BookKey memory bookKeyA = bookManager.getBookKey(pool.bookIdA); for (uint256 i; i < orderListA.length; ++i) { (uint256 cancelable, uint256 claimable) = _getLiquidity(bookKeyA.makerPolicy, bookKeyA.unitSize, orderListA[i]); liquidityA.cancelable += cancelable; liquidityB.claimable += claimable; } } if (orderListB.length > 0) { IBookManager.BookKey memory bookKeyB = bookManager.getBookKey(pool.bookIdB); for (uint256 i; i < orderListB.length; ++i) { (uint256 cancelable, uint256 claimable) = _getLiquidity(bookKeyB.makerPolicy, bookKeyB.unitSize, orderListB[i]); liquidityA.claimable += claimable; liquidityB.cancelable += cancelable; } } } function _getLiquidity(FeePolicy makerPolicy, uint64 unitSize, OrderId orderId) internal view returns (uint256 cancelable, uint256 claimable) { IBookManager.OrderInfo memory orderInfo = bookManager.getOrder(orderId); cancelable = uint256(orderInfo.open) * unitSize; claimable = orderId.getTick().quoteToBase(uint256(orderInfo.claimable) * unitSize, false); if (makerPolicy.usesQuote()) { int256 fee = makerPolicy.calculateFee(cancelable, true); cancelable = uint256(int256(cancelable) + fee); } else { int256 fee = makerPolicy.calculateFee(claimable, false); claimable = uint256(int256(claimable) - fee); } } function open( IBookManager.BookKey calldata bookKeyA, IBookManager.BookKey calldata bookKeyB, bytes32 salt, address strategy ) external nonReentrant returns (bytes32) { return abi.decode( bookManager.lock( address(this), abi.encodeWithSelector(this._open.selector, bookKeyA, bookKeyB, salt, strategy) ), (bytes32) ); } function mint(bytes32 key, uint256 amountA, uint256 amountB, uint256 minLpAmount) external payable nonReentrant returns (uint256 mintAmount) { Pool storage pool = _pools[key]; IBookManager.BookKey memory bookKeyA = bookManager.getBookKey(pool.bookIdA); uint256 supply = totalSupply[uint256(key)]; if (supply == 0) { if (amountA == 0 || amountB == 0) revert InvalidAmount(); // @dev If the decimals > 18, it will revert. uint256 complementA = bookKeyA.quote.isNative() ? 1 : 10 ** (18 - IERC20Metadata(Currency.unwrap(bookKeyA.quote)).decimals()); uint256 complementB = bookKeyA.base.isNative() ? 1 : 10 ** (18 - IERC20Metadata(Currency.unwrap(bookKeyA.base)).decimals()); uint256 _amountA = amountA * complementA; uint256 _amountB = amountB * complementB; mintAmount = _amountA > _amountB ? _amountA : _amountB; } else { (Liquidity memory liquidityA, Liquidity memory liquidityB) = getLiquidity(key); uint256 totalLiquidityA = liquidityA.reserve + liquidityA.claimable + liquidityA.cancelable; uint256 totalLiquidityB = liquidityB.reserve + liquidityB.claimable + liquidityB.cancelable; if (totalLiquidityA == 0 && totalLiquidityB == 0) { mintAmount = amountA = amountB = 0; } else if (totalLiquidityA == 0) { mintAmount = FixedPointMathLib.mulDivDown(amountB, supply, totalLiquidityB); amountA = 0; } else if (totalLiquidityB == 0) { mintAmount = FixedPointMathLib.mulDivDown(amountA, supply, totalLiquidityA); amountB = 0; } else { uint256 mintA = FixedPointMathLib.mulDivDown(amountA, supply, totalLiquidityA); uint256 mintB = FixedPointMathLib.mulDivDown(amountB, supply, totalLiquidityB); if (mintA > mintB) { mintAmount = mintB; amountA = FixedPointMathLib.mulDivUp(totalLiquidityA, mintAmount, supply); } else { mintAmount = mintA; amountB = FixedPointMathLib.mulDivUp(totalLiquidityB, mintAmount, supply); } } } if (mintAmount < minLpAmount) revert Slippage(); uint256 refund = msg.value; if (bookKeyA.quote.isNative()) { if (msg.value < amountA) { revert InvalidValue(); } else { unchecked { refund -= amountA; } } } else { IERC20(Currency.unwrap(bookKeyA.quote)).safeTransferFrom(msg.sender, address(this), amountA); } if (bookKeyA.base.isNative()) { if (msg.value < amountB) { revert InvalidValue(); } else { unchecked { refund -= amountB; } } } else { IERC20(Currency.unwrap(bookKeyA.base)).safeTransferFrom(msg.sender, address(this), amountB); } pool.reserveA += amountA; pool.reserveB += amountB; _mint(msg.sender, uint256(key), mintAmount); if (refund > 0) { CurrencyLibrary.NATIVE.transfer(msg.sender, refund); } emit Mint(msg.sender, key, amountA, amountB, mintAmount); pool.strategy.mintHook(msg.sender, key, mintAmount, supply); } function burn(bytes32 key, uint256 amount, uint256 minAmountA, uint256 minAmountB) external nonReentrant returns (uint256 withdrawalA, uint256 withdrawalB) { (withdrawalA, withdrawalB) = abi.decode( bookManager.lock(address(this), abi.encodeWithSelector(this._burn.selector, key, msg.sender, amount)), (uint256, uint256) ); if (withdrawalA < minAmountA || withdrawalB < minAmountB) revert Slippage(); } function rebalance(bytes32 key) external nonReentrant { bookManager.lock(address(this), abi.encodeWithSelector(this._rebalance.selector, key)); } function lockAcquired(address lockCaller, bytes calldata data) external returns (bytes memory) { if (msg.sender != address(bookManager)) revert InvalidLockAcquiredSender(); if (lockCaller != address(this)) revert InvalidLockCaller(); (bool success, bytes memory returnData) = address(this).call(data); if (success) return returnData; if (returnData.length == 0) revert LockFailure(); // if the call failed, bubble up the reason /// @solidity memory-safe-assembly assembly { revert(add(returnData, 32), mload(returnData)) } } function _open( IBookManager.BookKey calldata bookKeyA, IBookManager.BookKey calldata bookKeyB, bytes32 salt, address strategy ) public selfOnly returns (bytes32 key) { if ( !(bookKeyA.quote.equals(bookKeyB.base) && bookKeyA.base.equals(bookKeyB.quote)) || bookKeyA.quote.equals(bookKeyA.base) ) revert InvalidBookPair(); if (address(bookKeyA.hooks) != address(0) || address(bookKeyB.hooks) != address(0)) revert InvalidHook(); if (strategy == address(0)) revert InvalidStrategy(); BookId bookIdA = bookKeyA.toId(); BookId bookIdB = bookKeyB.toId(); if (!bookManager.isOpened(bookIdA)) bookManager.open(bookKeyA, ""); if (!bookManager.isOpened(bookIdB)) bookManager.open(bookKeyB, ""); key = _encodeKey(bookIdA, bookIdB, salt); if (_pools[key].strategy != IStrategy(address(0))) revert AlreadyOpened(); _pools[key].bookIdA = bookIdA; _pools[key].bookIdB = bookIdB; _pools[key].strategy = IStrategy(strategy); bookPair[bookIdA] = bookIdB; bookPair[bookIdB] = bookIdA; emit Open(key, bookIdA, bookIdB, salt, strategy); } function _burn(bytes32 key, address user, uint256 burnAmount) public selfOnly returns (uint256 withdrawalA, uint256 withdrawalB) { Pool storage pool = _pools[key]; uint256 supply = totalSupply[uint256(key)]; _burn(user, uint256(key), burnAmount); IBookManager.BookKey memory bookKeyA = bookManager.getBookKey(pool.bookIdA); _clearPool(key, pool, burnAmount, supply); pool.reserveA = _settleCurrency(bookKeyA.quote, pool.reserveA); pool.reserveB = _settleCurrency(bookKeyA.base, pool.reserveB); (Liquidity memory liquidityA, Liquidity memory liquidityB) = getLiquidity(key); withdrawalA = (liquidityA.reserve + liquidityA.claimable + liquidityA.cancelable) * burnAmount / supply; withdrawalB = (liquidityB.reserve + liquidityB.claimable + liquidityB.cancelable) * burnAmount / supply; pool.reserveA -= withdrawalA; pool.reserveB -= withdrawalB; uint256 feeA; uint256 feeB; if (withdrawalA > 0) { feeA = (withdrawalA * burnFeeRate + RATE_PRECISION - 1) / RATE_PRECISION; withdrawalA -= feeA; bookKeyA.quote.transfer(user, withdrawalA); fees[bookKeyA.quote] += feeA; } if (withdrawalB > 0) { feeB = (withdrawalB * burnFeeRate + RATE_PRECISION - 1) / RATE_PRECISION; withdrawalB -= feeB; bookKeyA.base.transfer(user, withdrawalB); fees[bookKeyA.base] += feeB; } emit Burn(user, key, burnAmount, withdrawalA, withdrawalB, feeA, feeB); pool.strategy.burnHook(msg.sender, key, burnAmount, supply); } function _rebalance(bytes32 key) public selfOnly { Pool storage pool = _pools[key]; uint256 reserveA = pool.reserveA; uint256 reserveB = pool.reserveB; IBookManager.BookKey memory bookKeyA = bookManager.getBookKey(pool.bookIdA); IBookManager.BookKey memory bookKeyB = bookManager.getBookKey(pool.bookIdB); // Compute allocation try pool.strategy.computeOrders(key) returns ( IStrategy.Order[] memory liquidityA, IStrategy.Order[] memory liquidityB ) { if (liquidityA.length == 0 && liquidityB.length == 0) return; _clearPool(key, pool, 1, 1); uint256 amountA = _setLiquidity(bookKeyA, liquidityA, pool.orderListA); uint256 amountB = _setLiquidity(bookKeyB, liquidityB, pool.orderListB); pool.reserveA = _settleCurrency(bookKeyA.quote, reserveA); pool.reserveB = _settleCurrency(bookKeyA.base, reserveB); pool.strategy.rebalanceHook(msg.sender, key, liquidityA, liquidityB, amountA, amountB); emit Rebalance(key); } catch { _clearPool(key, pool, 1, 1); pool.reserveA = _settleCurrency(bookKeyA.quote, reserveA); pool.reserveB = _settleCurrency(bookKeyA.base, reserveB); } } function _clearPool(bytes32 key, Pool storage pool, uint256 cancelNumerator, uint256 cancelDenominator) internal { (uint256 canceledAmountA, uint256 claimedAmountB) = _clearOrders(pool.orderListA, cancelNumerator, cancelDenominator); (uint256 canceledAmountB, uint256 claimedAmountA) = _clearOrders(pool.orderListB, cancelNumerator, cancelDenominator); emit Claim(key, claimedAmountA, claimedAmountB); emit Cancel(key, canceledAmountA, canceledAmountB); } function _clearOrders(OrderId[] storage orderIds, uint256 cancelNumerator, uint256 cancelDenominator) internal returns (uint256 canceledAmount, uint256 claimedAmount) { OrderId[] memory mOrderIds = orderIds; for (uint256 i = 0; i < mOrderIds.length; ++i) { OrderId orderId = mOrderIds[i]; IBookManager.OrderInfo memory orderInfo = bookManager.getOrder(orderId); if (orderInfo.claimable > 0) { claimedAmount += bookManager.claim(orderId, ""); } if (orderInfo.open > 0) { canceledAmount += bookManager.cancel( IBookManager.CancelParams({ id: orderId, toUnit: (orderInfo.open * (cancelDenominator - cancelNumerator) / cancelDenominator).toUint64() }), "" ); } } if (cancelDenominator == cancelNumerator) { assembly { sstore(orderIds.slot, 0) } } } function _setLiquidity( IBookManager.BookKey memory bookKey, IStrategy.Order[] memory liquidity, OrderId[] storage emptyOrderIds ) internal returns (uint256 amount) { for (uint256 i = 0; i < liquidity.length; ++i) { if (liquidity[i].rawAmount == 0) continue; (OrderId orderId, uint256 quoteAmount) = bookManager.make( IBookManager.MakeParams({ key: bookKey, tick: liquidity[i].tick, unit: liquidity[i].rawAmount, provider: address(0) }), "" ); amount += quoteAmount; emptyOrderIds.push(orderId); } } function _settleCurrency(Currency currency, uint256 liquidity) internal returns (uint256) { bookManager.settle(currency); int256 delta = bookManager.getCurrencyDelta(address(this), currency); if (delta > 0) { bookManager.withdraw(currency, address(this), uint256(delta)); liquidity += uint256(delta); } else if (delta < 0) { currency.transfer(address(bookManager), uint256(-delta)); bookManager.settle(currency); liquidity -= uint256(-delta); } return liquidity; } function _encodeKey(BookId bookIdA, BookId bookIdB, bytes32 salt) internal pure returns (bytes32) { if (BookId.unwrap(bookIdA) > BookId.unwrap(bookIdB)) (bookIdA, bookIdB) = (bookIdB, bookIdA); return keccak256(abi.encodePacked(bookIdA, bookIdB, salt)); } receive() external payable {} function collect(Currency currency, address to) external onlyOwner { uint256 fee = fees[currency]; fees[currency] = 0; currency.transfer(to, fee); emit Collect(currency, to, fee); } }
// 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.1.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. * * This extension of the {Ownable} contract includes a two-step mechanism to transfer * ownership, where the new owner must call {acceptOwnership} in order to replace the * old one. This can help prevent common mistakes, such as transfers of ownership to * incorrect accounts, or to contracts that are unable to interact with the * permission system. * * 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. * * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer. */ 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: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: 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.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// 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.1.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.22; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @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 ERC-1967 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 IERC1967.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 ERC-1967) 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 ERC-1967 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 IERC1967.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 ERC-1967 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 IERC1967.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/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.1.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.22; import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "../ERC1967/ERC1967Utils.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 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 ERC-1967) 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 ERC-1167 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(); _; } /** * @dev Implementation of the ERC-1822 {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 ERC-1967 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 ERC-1967. * * 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: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC-20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ 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.1.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 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 { /** * @dev An operation with an ERC-20 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. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ 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. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ 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. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ 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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { 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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { 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 silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC-721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @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 Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @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 * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); } (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. */ 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 assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// 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.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * 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[ERC 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.1.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/bool 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); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol) pragma solidity ^0.8.24; import {TransientSlot} from "./TransientSlot.sol"; /** * @dev Variant of {ReentrancyGuard} that uses transient storage. * * NOTE: This variant only works on networks where EIP-1153 is available. * * _Available since v5.1._ */ abstract contract ReentrancyGuardTransient { using TransientSlot for *; // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant REENTRANCY_GUARD_STORAGE = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_reentrancyGuardEntered()) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); } function _nonReentrantAfter() private { REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false); } /** * @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) { return REENTRANCY_GUARD_STORAGE.asBoolean().tload(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.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 ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * 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; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 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) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { 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) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { 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) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol) // This file was procedurally generated from scripts/generate/templates/TransientSlot.js. pragma solidity ^0.8.24; /** * @dev Library for reading and writing value-types to specific transient storage slots. * * Transient slots are often used to store temporary values that are removed after the current transaction. * This library helps with reading and writing to such slots without the need for inline assembly. * * * Example reading and writing values using transient storage: * ```solidity * contract Lock { * using TransientSlot for *; * * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; * * modifier locked() { * require(!_LOCK_SLOT.asBoolean().tload()); * * _LOCK_SLOT.asBoolean().tstore(true); * _; * _LOCK_SLOT.asBoolean().tstore(false); * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library TransientSlot { /** * @dev UDVT that represent a slot holding a address. */ type AddressSlot is bytes32; /** * @dev Cast an arbitrary slot to a AddressSlot. */ function asAddress(bytes32 slot) internal pure returns (AddressSlot) { return AddressSlot.wrap(slot); } /** * @dev UDVT that represent a slot holding a bool. */ type BooleanSlot is bytes32; /** * @dev Cast an arbitrary slot to a BooleanSlot. */ function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) { return BooleanSlot.wrap(slot); } /** * @dev UDVT that represent a slot holding a bytes32. */ type Bytes32Slot is bytes32; /** * @dev Cast an arbitrary slot to a Bytes32Slot. */ function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) { return Bytes32Slot.wrap(slot); } /** * @dev UDVT that represent a slot holding a uint256. */ type Uint256Slot is bytes32; /** * @dev Cast an arbitrary slot to a Uint256Slot. */ function asUint256(bytes32 slot) internal pure returns (Uint256Slot) { return Uint256Slot.wrap(slot); } /** * @dev UDVT that represent a slot holding a int256. */ type Int256Slot is bytes32; /** * @dev Cast an arbitrary slot to a Int256Slot. */ function asInt256(bytes32 slot) internal pure returns (Int256Slot) { return Int256Slot.wrap(slot); } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(AddressSlot slot) internal view returns (address value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(AddressSlot slot, address value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(BooleanSlot slot) internal view returns (bool value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(BooleanSlot slot, bool value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Bytes32Slot slot) internal view returns (bytes32 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Bytes32Slot slot, bytes32 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Uint256Slot slot) internal view returns (uint256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Uint256Slot slot, uint256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Int256Slot slot) internal view returns (int256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Int256Slot slot, int256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {BookId} from "../libraries/BookId.sol"; import {Currency} from "../libraries/Currency.sol"; import {OrderId} from "../libraries/OrderId.sol"; import {Tick} from "../libraries/Tick.sol"; import {FeePolicy} from "../libraries/FeePolicy.sol"; import {IERC721Permit} from "./IERC721Permit.sol"; import {IHooks} from "./IHooks.sol"; /** * @title IBookManager * @notice The interface for the BookManager contract */ interface IBookManager is IERC721Metadata, IERC721Permit { error InvalidUnitSize(); error InvalidFeePolicy(); error InvalidProvider(address provider); error LockedBy(address locker, address hook); error CurrencyNotSettled(); /** * @notice Event emitted when a new book is opened * @param id The book id * @param base The base currency * @param quote The quote currency * @param unitSize The unit size of the book * @param makerPolicy The maker fee policy * @param takerPolicy The taker fee policy * @param hooks The hooks contract */ event Open( BookId indexed id, Currency indexed base, Currency indexed quote, uint64 unitSize, FeePolicy makerPolicy, FeePolicy takerPolicy, IHooks hooks ); /** * @notice Event emitted when a new order is made * @param bookId The book id * @param user The user address * @param tick The order tick * @param orderIndex The order index * @param unit The order unit * @param provider The provider address */ event Make( BookId indexed bookId, address indexed user, Tick tick, uint256 orderIndex, uint64 unit, address provider ); /** * @notice Event emitted when an order is taken * @param bookId The book id * @param user The user address * @param tick The order tick * @param unit The order unit */ event Take(BookId indexed bookId, address indexed user, Tick tick, uint64 unit); /** * @notice Event emitted when an order is canceled * @param orderId The order id * @param unit The canceled unit */ event Cancel(OrderId indexed orderId, uint64 unit); /** * @notice Event emitted when an order is claimed * @param orderId The order id * @param unit The claimed unit */ event Claim(OrderId indexed orderId, uint64 unit); /** * @notice Event emitted when a provider is whitelisted * @param provider The provider address */ event Whitelist(address indexed provider); /** * @notice Event emitted when a provider is delisted * @param provider The provider address */ event Delist(address indexed provider); /** * @notice Event emitted when a provider collects fees * @param provider The provider address * @param recipient The recipient address * @param currency The currency * @param amount The collected amount */ event Collect(address indexed provider, address indexed recipient, Currency indexed currency, uint256 amount); /** * @notice Event emitted when new default provider is set * @param newDefaultProvider The new default provider address */ event SetDefaultProvider(address indexed newDefaultProvider); /** * @notice This structure represents a unique identifier for a book in the BookManager. * @param base The base currency of the book * @param unitSize The unit size of the book * @param quote The quote currency of the book * @param makerPolicy The maker fee policy of the book * @param hooks The hooks contract of the book * @param takerPolicy The taker fee policy of the book */ struct BookKey { Currency base; uint64 unitSize; Currency quote; FeePolicy makerPolicy; IHooks hooks; FeePolicy takerPolicy; } /** * @notice Returns the base URI * @return The base URI */ function baseURI() external view returns (string memory); /** * @notice Returns the contract URI * @return The contract URI */ function contractURI() external view returns (string memory); /** * @notice Returns the default provider * @return The default provider */ function defaultProvider() external view returns (address); /** * @notice Returns the total reserves of a given currency * @param currency The currency in question * @return The total reserves amount */ function reservesOf(Currency currency) external view returns (uint256); /** * @notice Checks if a provider is whitelisted * @param provider The address of the provider * @return True if the provider is whitelisted, false otherwise */ function isWhitelisted(address provider) external view returns (bool); /** * @notice Verifies if an owner has authorized a spender for a token * @param owner The address of the token owner * @param spender The address of the spender * @param tokenId The token ID */ function checkAuthorized(address owner, address spender, uint256 tokenId) external view; /** * @notice Calculates the amount owed to a provider in a given currency * @param provider The provider's address * @param currency The currency in question * @return The owed amount */ function tokenOwed(address provider, Currency currency) external view returns (uint256); /** * @notice Calculates the currency balance changes for a given locker * @param locker The address of the locker * @param currency The currency in question * @return The net change in currency balance */ function getCurrencyDelta(address locker, Currency currency) external view returns (int256); /** * @notice Retrieves the book key for a given book ID * @param id The book ID * @return The book key */ function getBookKey(BookId id) external view returns (BookKey memory); /** * @notice This structure represents a current status for an order in the BookManager. * @param provider The provider of the order * @param open The open unit of the order * @param claimable The claimable unit of the order */ struct OrderInfo { address provider; uint64 open; uint64 claimable; } /** * @notice Provides information about an order * @param id The order ID * @return Order information including provider, open status, and claimable unit */ function getOrder(OrderId id) external view returns (OrderInfo memory); /** * @notice Retrieves the locker and caller addresses for a given lock * @param i The index of the lock * @return locker The locker's address * @return lockCaller The caller's address */ function getLock(uint256 i) external view returns (address locker, address lockCaller); /** * @notice Provides the lock data * @return The lock data including necessary numeric values */ function getLockData() external view returns (uint128, uint128); /** * @notice Returns the depth of a given book ID and tick * @param id The book ID * @param tick The tick * @return The depth of the tick */ function getDepth(BookId id, Tick tick) external view returns (uint64); /** * @notice Retrieves the highest tick for a given book ID * @param id The book ID * @return tick The highest tick */ function getHighest(BookId id) external view returns (Tick tick); /** * @notice Finds the maximum tick less than a specified tick in a book * @dev Returns `Tick.wrap(type(int24).min)` if the specified tick is the lowest * @param id The book ID * @param tick The specified tick * @return The next lower tick */ function maxLessThan(BookId id, Tick tick) external view returns (Tick); /** * @notice Checks if a book is opened * @param id The book ID * @return True if the book is opened, false otherwise */ function isOpened(BookId id) external view returns (bool); /** * @notice Checks if a book is empty * @param id The book ID * @return True if the book is empty, false otherwise */ function isEmpty(BookId id) external view returns (bool); /** * @notice Encodes a BookKey into a BookId * @param key The BookKey to encode * @return The encoded BookId */ function encodeBookKey(BookKey calldata key) external pure returns (BookId); /** * @notice Loads a value from a specific storage slot * @param slot The storage slot * @return The value in the slot */ function load(bytes32 slot) external view returns (bytes32); /** * @notice Loads a sequence of values starting from a specific slot * @param startSlot The starting slot * @param nSlot The number of slots to load * @return The sequence of values */ function load(bytes32 startSlot, uint256 nSlot) external view returns (bytes memory); /** * @notice Opens a new book * @param key The book key * @param hookData The hook data */ function open(BookKey calldata key, bytes calldata hookData) external; /** * @notice Locks a book manager function * @param locker The locker address * @param data The lock data * @return The lock return data */ function lock(address locker, bytes calldata data) external returns (bytes memory); /** * @notice This structure represents the parameters for making an order. * @param key The book key for the order * @param tick The tick for the order * @param unit The unit for the order. Times key.unitSize to get actual bid amount. * @param provider The provider for the order. The limit order service provider address to collect fees. */ struct MakeParams { BookKey key; Tick tick; uint64 unit; address provider; } /** * @notice Make a limit order * @param params The order parameters * @param hookData The hook data * @return id The order id. Returns 0 if the order is not settled * @return quoteAmount The amount of quote currency to be paid */ function make(MakeParams calldata params, bytes calldata hookData) external returns (OrderId id, uint256 quoteAmount); /** * @notice This structure represents the parameters for taking orders in the specified tick. * @param key The book key for the order * @param tick The tick for the order * @param maxUnit The max unit to take */ struct TakeParams { BookKey key; Tick tick; uint64 maxUnit; } /** * @notice Take a limit order at specific tick * @param params The order parameters * @param hookData The hook data * @return quoteAmount The amount of quote currency to be received * @return baseAmount The amount of base currency to be paid */ function take(TakeParams calldata params, bytes calldata hookData) external returns (uint256 quoteAmount, uint256 baseAmount); /** * @notice This structure represents the parameters for canceling an order. * @param id The order id for the order * @param toUnit The remaining open unit for the order after cancellation. Must not exceed the current open unit. */ struct CancelParams { OrderId id; uint64 toUnit; } /** * @notice Cancel a limit order * @param params The order parameters * @param hookData The hook data * @return canceledAmount The amount of quote currency canceled */ function cancel(CancelParams calldata params, bytes calldata hookData) external returns (uint256 canceledAmount); /** * @notice Claims an order * @param id The order ID * @param hookData The hook data * @return claimedAmount The amount claimed */ function claim(OrderId id, bytes calldata hookData) external returns (uint256 claimedAmount); /** * @notice Collects fees from a provider * @param recipient The recipient address * @param currency The currency * @return The collected amount */ function collect(address recipient, Currency currency) external returns (uint256); /** * @notice Withdraws a currency * @param currency The currency * @param to The recipient address * @param amount The amount */ function withdraw(Currency currency, address to, uint256 amount) external; /** * @notice Settles a currency * @param currency The currency * @return The settled amount */ function settle(Currency currency) external payable returns (uint256); /** * @notice Whitelists a provider * @param provider The provider address */ function whitelist(address provider) external; /** * @notice Delists a provider * @param provider The provider address */ function delist(address provider) external; /** * @notice Sets the default provider * @param newDefaultProvider The new default provider address */ function setDefaultProvider(address newDefaultProvider) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; /** * @title IERC721Permit * @notice An interface for the ERC721 permit extension */ interface IERC721Permit is IERC721 { error InvalidSignature(); error PermitExpired(); /** * @notice The EIP-712 typehash for the permit struct used by the contract */ function PERMIT_TYPEHASH() external pure returns (bytes32); /** * @notice The EIP-712 domain separator for this contract */ function DOMAIN_SEPARATOR() external view returns (bytes32); /** * @notice Approve the spender to transfer the given tokenId * @param spender The address to approve * @param tokenId The tokenId to approve * @param deadline The deadline for the signature * @param v The recovery id of the signature * @param r The r value of the signature * @param s The s value of the signature */ function permit(address spender, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @notice Get the current nonce for a token * @param tokenId The tokenId to get the nonce for * @return The current nonce */ function nonces(uint256 tokenId) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IBookManager} from "./IBookManager.sol"; import {OrderId} from "../libraries/OrderId.sol"; /** * @title IHooks * @notice Interface for the hooks contract */ interface IHooks { /** * @notice Hook called before opening a new book * @param sender The sender of the open transaction * @param key The key of the book being opened * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeOpen(address sender, IBookManager.BookKey calldata key, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after opening a new book * @param sender The sender of the open transaction * @param key The key of the book being opened * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterOpen(address sender, IBookManager.BookKey calldata key, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called before making a new order * @param sender The sender of the make transaction * @param params The parameters of the make transaction * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeMake(address sender, IBookManager.MakeParams calldata params, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after making a new order * @param sender The sender of the make transaction * @param params The parameters of the make transaction * @param orderId The id of the order that was made * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterMake( address sender, IBookManager.MakeParams calldata params, OrderId orderId, bytes calldata hookData ) external returns (bytes4); /** * @notice Hook called before taking an order * @param sender The sender of the take transaction * @param params The parameters of the take transaction * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeTake(address sender, IBookManager.TakeParams calldata params, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after taking an order * @param sender The sender of the take transaction * @param params The parameters of the take transaction * @param takenUnit The unit that was taken * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterTake( address sender, IBookManager.TakeParams calldata params, uint64 takenUnit, bytes calldata hookData ) external returns (bytes4); /** * @notice Hook called before canceling an order * @param sender The sender of the cancel transaction * @param params The parameters of the cancel transaction * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeCancel(address sender, IBookManager.CancelParams calldata params, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after canceling an order * @param sender The sender of the cancel transaction * @param params The parameters of the cancel transaction * @param canceledUnit The unit that was canceled * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterCancel( address sender, IBookManager.CancelParams calldata params, uint64 canceledUnit, bytes calldata hookData ) external returns (bytes4); /** * @notice Hook called before claiming an order * @param sender The sender of the claim transaction * @param orderId The id of the order being claimed * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeClaim(address sender, OrderId orderId, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after claiming an order * @param sender The sender of the claim transaction * @param orderId The id of the order being claimed * @param claimedUnit The unit that was claimed * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterClaim(address sender, OrderId orderId, uint64 claimedUnit, bytes calldata hookData) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ILocker * @notice Interface for the locker contract */ interface ILocker { /** * @notice Called by the book manager on `msg.sender` when a lock is acquired * @param data The data that was passed to the call to lock * @return Any data that you want to be returned from the lock call */ function lockAcquired(address lockCaller, bytes calldata data) external returns (bytes memory); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {IBookManager} from "../interfaces/IBookManager.sol"; type BookId is uint192; library BookIdLibrary { function toId(IBookManager.BookKey memory bookKey) internal pure returns (BookId id) { bytes32 hash = keccak256(abi.encode(bookKey)); assembly { id := and(hash, 0xffffffffffffffffffffffffffffffffffffffffffffffff) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; type Currency is address; /// @title CurrencyLibrary /// @dev This library allows for transferring and holding native tokens and ERC20 tokens library CurrencyLibrary { using CurrencyLibrary for Currency; /// @notice Thrown when a native transfer fails error NativeTransferFailed(); /// @notice Thrown when an ERC20 transfer fails error ERC20TransferFailed(); Currency public constant NATIVE = Currency.wrap(address(0)); function transfer(Currency currency, address to, uint256 amount) internal { // implementation from // https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol bool success; if (currency.isNative()) { assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } if (!success) revert NativeTransferFailed(); } else { assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), currency, 0, freeMemoryPointer, 68, 0, 32) ) } if (!success) revert ERC20TransferFailed(); } } function balanceOfSelf(Currency currency) internal view returns (uint256) { if (currency.isNative()) return address(this).balance; else return IERC20(Currency.unwrap(currency)).balanceOf(address(this)); } function equals(Currency currency, Currency other) internal pure returns (bool) { return Currency.unwrap(currency) == Currency.unwrap(other); } function isNative(Currency currency) internal pure returns (bool) { return Currency.unwrap(currency) == Currency.unwrap(NATIVE); } function toId(Currency currency) internal pure returns (uint256) { return uint160(Currency.unwrap(currency)); } function fromId(uint256 id) internal pure returns (Currency) { return Currency.wrap(address(uint160(id))); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {Math} from "./Math.sol"; type FeePolicy is uint24; library FeePolicyLibrary { uint256 internal constant RATE_PRECISION = 10 ** 6; int256 internal constant MAX_FEE_RATE = 500000; int256 internal constant MIN_FEE_RATE = -500000; uint256 internal constant RATE_MASK = 0x7fffff; // 23 bits error InvalidFeePolicy(); function encode(bool usesQuote_, int24 rate_) internal pure returns (FeePolicy feePolicy) { if (rate_ > MAX_FEE_RATE || rate_ < MIN_FEE_RATE) { revert InvalidFeePolicy(); } uint256 mask = usesQuote_ ? 1 << 23 : 0; assembly { feePolicy := or(mask, add(and(rate_, 0xffffff), MAX_FEE_RATE)) } } function isValid(FeePolicy self) internal pure returns (bool) { int24 r = rate(self); return !(r > MAX_FEE_RATE || r < MIN_FEE_RATE); } function usesQuote(FeePolicy self) internal pure returns (bool f) { assembly { f := shr(23, self) } } function rate(FeePolicy self) internal pure returns (int24 r) { assembly { r := sub(and(self, RATE_MASK), MAX_FEE_RATE) } } function calculateFee(FeePolicy self, uint256 amount, bool reverseRounding) internal pure returns (int256 fee) { int24 r = rate(self); bool positive = r > 0; uint256 absRate; unchecked { absRate = uint256(uint24(positive ? r : -r)); } // @dev absFee must be less than type(int256).max uint256 absFee = Math.divide(amount * absRate, RATE_PRECISION, reverseRounding ? !positive : positive); fee = positive ? int256(absFee) : -int256(absFee); } function calculateOriginalAmount(FeePolicy self, uint256 amount, bool reverseFee) internal pure returns (uint256 originalAmount) { int24 r = rate(self); uint256 divider; assembly { if reverseFee { r := sub(0, r) } divider := add(RATE_PRECISION, r) } originalAmount = Math.divide(amount * RATE_PRECISION, divider, reverseFee); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; library Math { function divide(uint256 a, uint256 b, bool roundingUp) internal pure returns (uint256 ret) { // In the OrderBook contract code, b is never zero. assembly { ret := add(div(a, b), and(gt(mod(a, b), 0), roundingUp)) } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Base conversion: mul `2**96 / (5**18 * 2**192)`. r := sdiv(p, 302231454903657293676544000000000000000000) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {Tick} from "./Tick.sol"; import {BookId} from "./BookId.sol"; type OrderId is uint256; library OrderIdLibrary { /** * @dev Encode the order id. * @param bookId The book id. * @param tick The tick. * @param index The index. * @return id The order id. */ function encode(BookId bookId, Tick tick, uint40 index) internal pure returns (OrderId id) { // @dev If we just use tick at the assembly code, the code will convert tick into bytes32. // e.g. When index == -2, the shifted value( shl(40, tick) ) will be // 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000 instead of 0xfffffffe0000000000 // Therefore, we have to safely cast tick into uint256 first. uint256 _tick = uint256(uint24(Tick.unwrap(tick))); assembly { id := add(index, add(shl(40, _tick), shl(64, bookId))) } } function decode(OrderId id) internal pure returns (BookId bookId, Tick tick, uint40 index) { assembly { bookId := shr(64, id) tick := and(shr(40, id), 0xffffff) index := and(id, 0xffffffffff) } } function getBookId(OrderId id) internal pure returns (BookId bookId) { assembly { bookId := shr(64, id) } } function getTick(OrderId id) internal pure returns (Tick tick) { assembly { tick := and(shr(40, id), 0xffffff) } } function getIndex(OrderId id) internal pure returns (uint40 index) { assembly { index := and(id, 0xffffffffff) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {Math} from "./Math.sol"; type Tick is int24; library TickLibrary { using Math for *; using TickLibrary for Tick; error InvalidTick(); error InvalidPrice(); error TickOverflow(); int24 internal constant MAX_TICK = 2 ** 19 - 1; int24 internal constant MIN_TICK = -MAX_TICK; uint256 internal constant MIN_PRICE = 1350587; uint256 internal constant MAX_PRICE = 4647684107270898330752324302845848816923571339324334; uint256 private constant _R0 = 0xfff97272373d413259a46990; uint256 private constant _R1 = 0xfff2e50f5f656932ef12357c; uint256 private constant _R2 = 0xffe5caca7e10e4e61c3624ea; uint256 private constant _R3 = 0xffcb9843d60f6159c9db5883; uint256 private constant _R4 = 0xff973b41fa98c081472e6896; uint256 private constant _R5 = 0xff2ea16466c96a3843ec78b3; uint256 private constant _R6 = 0xfe5dee046a99a2a811c461f1; uint256 private constant _R7 = 0xfcbe86c7900a88aedcffc83b; uint256 private constant _R8 = 0xf987a7253ac413176f2b074c; uint256 private constant _R9 = 0xf3392b0822b70005940c7a39; uint256 private constant _R10 = 0xe7159475a2c29b7443b29c7f; uint256 private constant _R11 = 0xd097f3bdfd2022b8845ad8f7; uint256 private constant _R12 = 0xa9f746462d870fdf8a65dc1f; uint256 private constant _R13 = 0x70d869a156d2a1b890bb3df6; uint256 private constant _R14 = 0x31be135f97d08fd981231505; uint256 private constant _R15 = 0x9aa508b5b7a84e1c677de54; uint256 private constant _R16 = 0x5d6af8dedb81196699c329; uint256 private constant _R17 = 0x2216e584f5fa1ea92604; uint256 private constant _R18 = 0x48a170391f7dc42; uint256 private constant _R19 = 0x149b34; function validateTick(Tick tick) internal pure { if (Tick.unwrap(tick) > MAX_TICK || Tick.unwrap(tick) < MIN_TICK) revert InvalidTick(); } modifier validatePrice(uint256 price) { if (price > MAX_PRICE || price < MIN_PRICE) revert InvalidPrice(); _; } function fromPrice(uint256 price) internal pure validatePrice(price) returns (Tick) { unchecked { int24 tick = int24((int256(price).lnWad() * 42951820407860) / 2 ** 128); if (toPrice(Tick.wrap(tick)) > price) return Tick.wrap(tick - 1); return Tick.wrap(tick); } } function toPrice(Tick tick) internal pure returns (uint256 price) { validateTick(tick); int24 tickValue = Tick.unwrap(tick); uint256 absTick = uint24(tickValue < 0 ? -tickValue : tickValue); unchecked { if (absTick & 0x1 != 0) price = _R0; else price = 1 << 96; if (absTick & 0x2 != 0) price = (price * _R1) >> 96; if (absTick & 0x4 != 0) price = (price * _R2) >> 96; if (absTick & 0x8 != 0) price = (price * _R3) >> 96; if (absTick & 0x10 != 0) price = (price * _R4) >> 96; if (absTick & 0x20 != 0) price = (price * _R5) >> 96; if (absTick & 0x40 != 0) price = (price * _R6) >> 96; if (absTick & 0x80 != 0) price = (price * _R7) >> 96; if (absTick & 0x100 != 0) price = (price * _R8) >> 96; if (absTick & 0x200 != 0) price = (price * _R9) >> 96; if (absTick & 0x400 != 0) price = (price * _R10) >> 96; if (absTick & 0x800 != 0) price = (price * _R11) >> 96; if (absTick & 0x1000 != 0) price = (price * _R12) >> 96; if (absTick & 0x2000 != 0) price = (price * _R13) >> 96; if (absTick & 0x4000 != 0) price = (price * _R14) >> 96; if (absTick & 0x8000 != 0) price = (price * _R15) >> 96; if (absTick & 0x10000 != 0) price = (price * _R16) >> 96; if (absTick & 0x20000 != 0) price = (price * _R17) >> 96; if (absTick & 0x40000 != 0) price = (price * _R18) >> 96; } if (tickValue > 0) price = 0x1000000000000000000000000000000000000000000000000 / price; } function gt(Tick a, Tick b) internal pure returns (bool) { return Tick.unwrap(a) > Tick.unwrap(b); } function baseToQuote(Tick tick, uint256 base, bool roundingUp) internal pure returns (uint256) { return Math.divide((base * tick.toPrice()), 1 << 96, roundingUp); } function quoteToBase(Tick tick, uint256 quote, bool roundingUp) internal pure returns (uint256) { // @dev quote = unit(uint64) * unitSize(uint64) < 2^96 // We don't need to check overflow here return Math.divide(quote << 96, tick.toPrice(), roundingUp); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Minimalist and gas efficient standard ERC6909 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC6909.sol) abstract contract ERC6909 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OperatorSet(address indexed owner, address indexed operator, bool approved); event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); event Transfer(address caller, address indexed from, address indexed to, uint256 indexed id, uint256 amount); /*////////////////////////////////////////////////////////////// ERC6909 STORAGE //////////////////////////////////////////////////////////////*/ mapping(address => mapping(address => bool)) public isOperator; mapping(address => mapping(uint256 => uint256)) public balanceOf; mapping(address => mapping(address => mapping(uint256 => uint256))) public allowance; /*////////////////////////////////////////////////////////////// ERC6909 LOGIC //////////////////////////////////////////////////////////////*/ function transfer( address receiver, uint256 id, uint256 amount ) public virtual returns (bool) { balanceOf[msg.sender][id] -= amount; balanceOf[receiver][id] += amount; emit Transfer(msg.sender, msg.sender, receiver, id, amount); return true; } function transferFrom( address sender, address receiver, uint256 id, uint256 amount ) public virtual returns (bool) { if (msg.sender != sender && !isOperator[sender][msg.sender]) { uint256 allowed = allowance[sender][msg.sender][id]; if (allowed != type(uint256).max) allowance[sender][msg.sender][id] = allowed - amount; } balanceOf[sender][id] -= amount; balanceOf[receiver][id] += amount; emit Transfer(msg.sender, sender, receiver, id, amount); return true; } function approve( address spender, uint256 id, uint256 amount ) public virtual returns (bool) { allowance[msg.sender][spender][id] = amount; emit Approval(msg.sender, spender, id, amount); return true; } function setOperator(address operator, bool approved) public virtual returns (bool) { isOperator[msg.sender][operator] = approved; emit OperatorSet(msg.sender, operator, approved); return true; } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x0f632fb3; // ERC165 Interface ID for ERC6909 } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint( address receiver, uint256 id, uint256 amount ) internal virtual { balanceOf[receiver][id] += amount; emit Transfer(msg.sender, address(0), receiver, id, amount); } function _burn( address sender, uint256 id, uint256 amount ) internal virtual { balanceOf[sender][id] -= amount; emit Transfer(msg.sender, sender, address(0), id, amount); } }
// 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: GPL-2.0-or-later pragma solidity ^0.8.0; import {IBookManager} from "clober-dex/v2-core/interfaces/IBookManager.sol"; import {BookId} from "clober-dex/v2-core/libraries/BookId.sol"; import {OrderId} from "clober-dex/v2-core/libraries/OrderId.sol"; import {Currency} from "clober-dex/v2-core/libraries/Currency.sol"; import {IStrategy} from "./IStrategy.sol"; interface ILiquidityVault { struct Pool { BookId bookIdA; BookId bookIdB; IStrategy strategy; uint256 reserveA; uint256 reserveB; OrderId[] orderListA; OrderId[] orderListB; } error InvalidRate(); error NotSelf(); error InvalidHook(); error InvalidStrategy(); error InvalidBookPair(); error AlreadyOpened(); error InvalidLockAcquiredSender(); error InvalidLockCaller(); error LockFailure(); error InvalidAmount(); error InvalidValue(); error Slippage(); event Open(bytes32 indexed key, BookId indexed bookIdA, BookId indexed bookIdB, bytes32 salt, address strategy); event Mint(address indexed user, bytes32 indexed key, uint256 amountA, uint256 amountB, uint256 lpAmount); event Burn( address indexed user, bytes32 indexed key, uint256 lpAmount, uint256 amountA, uint256 amountB, uint256 feeA, uint256 feeB ); event Rebalance(bytes32 indexed key); event Claim(bytes32 indexed key, uint256 claimedAmountA, uint256 claimedAmountB); event Cancel(bytes32 indexed key, uint256 canceledAmountA, uint256 canceledAmountB); event Collect(Currency indexed currency, address indexed to, uint256 amount); struct Liquidity { uint256 reserve; uint256 claimable; uint256 cancelable; } /// @notice Retrieves the burn fee rate. /// @return The burn fee rate. function burnFeeRate() external view returns (uint256); /// @notice Returns the amount of pending fees for a given currency that can be collected /// @param currency The currency to check pending fees for /// @return The total amount of uncollected fees in the specified currency function fees(Currency currency) external view returns (uint256); /// @notice Retrieves the book pair for a specified book ID. /// @param bookId The book ID. /// @return The book pair. function bookPair(BookId bookId) external view returns (BookId); /// @notice Retrieves the pool for a specified key. /// @param key The key of the pool. /// @return The pool. function getPool(bytes32 key) external view returns (Pool memory); /// @notice Retrieves the book pairs for a specified key. /// @param key The key of the pool. /// @return bookIdA The book ID for the first book. /// @return bookIdB The book ID for the second book. function getBookPairs(bytes32 key) external view returns (BookId bookIdA, BookId bookIdB); /// @notice Retrieves the liquidity for a specified key. /// @param key The key of the pool. /// @return liquidityA The liquidity for the first token. /// @return liquidityB The liquidity for the second token. function getLiquidity(bytes32 key) external view returns (Liquidity memory liquidityA, Liquidity memory liquidityB); /// @notice Opens a new pool with the specified parameters. /// @param bookKeyA The book key for the first book. /// @param bookKeyB The book key for the second book. /// @param salt The salt value. /// @param strategy The address of the strategy. /// @return key The key of the opened pool. function open( IBookManager.BookKey calldata bookKeyA, IBookManager.BookKey calldata bookKeyB, bytes32 salt, address strategy ) external returns (bytes32 key); /// @notice Mints liquidity for the specified key. /// @param key The key of the pool. /// @param amountA The amount of the first token. /// @param amountB The amount of the second token. /// @param minLpAmount The minimum amount of liquidity tokens to mint. /// @return The amount of liquidity tokens minted. function mint(bytes32 key, uint256 amountA, uint256 amountB, uint256 minLpAmount) external payable returns (uint256); /// @notice Burns liquidity for the specified key. /// @param key The key of the pool. /// @param amount The amount of liquidity tokens to burn. /// @param minAmountA The amount of the first token to receive. /// @param minAmountB The minimum amount of the second token to receive. /// @return The amounts of the first and second tokens to receive. function burn(bytes32 key, uint256 amount, uint256 minAmountA, uint256 minAmountB) external returns (uint256, uint256); /// @notice Rebalances the pool for the specified key. /// @param key The key of the pool. function rebalance(bytes32 key) external; /// @notice Collects the pending fees for a given currency. /// @param currency The currency to collect fees for. /// @param to The address to send the collected fees to. /// @dev Only the owner can collect fees. function collect(Currency currency, address to) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {BookId} from "clober-dex/v2-core/libraries/BookId.sol"; import {Tick} from "clober-dex/v2-core/libraries/Tick.sol"; interface IStrategy { struct Order { Tick tick; uint64 rawAmount; } /// @notice Retrieves the orders for a specified key. /// @param key The key of the pool. /// @return ordersA The orders for the first token. /// @return ordersB The orders for the second token. /// @dev Clears pool orders if an error occurs and retains current orders if the list is empty. function computeOrders(bytes32 key) external view returns (Order[] memory ordersA, Order[] memory ordersB); /// @notice Hook that is called after minting. /// @param sender The address of the sender. /// @param key The key of the pool. /// @param mintAmount The amount minted. /// @param lastTotalSupply The total supply before minting. function mintHook(address sender, bytes32 key, uint256 mintAmount, uint256 lastTotalSupply) external; /// @notice Hook that is called after burning. /// @param sender The address of the sender. /// @param key The key of the pool. /// @param burnAmount The amount burned. /// @param lastTotalSupply The total supply before burning. function burnHook(address sender, bytes32 key, uint256 burnAmount, uint256 lastTotalSupply) external; /// @notice Hook that is called after rebalancing. /// @param sender The address of the sender. /// @param key The key of the pool. /// @param liquidityA The liquidity orders for the first token. /// @param liquidityB The liquidity orders for the second token. /// @param amountA The amount of the first token. /// @param amountB The amount of the second token. function rebalanceHook( address sender, bytes32 key, Order[] memory liquidityA, Order[] memory liquidityB, uint256 amountA, uint256 amountB ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {ERC6909} from "solmate/tokens/ERC6909.sol"; abstract contract ERC6909Supply is ERC6909 { mapping(uint256 => uint256) public totalSupply; function _mint(address receiver, uint256 id, uint256 amount) internal virtual override { super._mint(receiver, id, amount); totalSupply[id] += amount; } function _burn(address sender, uint256 id, uint256 amount) internal virtual override { super._burn(sender, id, amount); totalSupply[id] -= amount; } }
{ "evmVersion": "cancun", "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IBookManager","name":"bookManager_","type":"address"},{"internalType":"uint256","name":"burnFeeRate_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"AlreadyOpened","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"ERC20TransferFailed","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidBookPair","type":"error"},{"inputs":[],"name":"InvalidHook","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidLockAcquiredSender","type":"error"},{"inputs":[],"name":"InvalidLockCaller","type":"error"},{"inputs":[],"name":"InvalidRate","type":"error"},{"inputs":[],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"InvalidTick","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"LockFailure","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotSelf","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"Slippage","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"lpAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountB","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeB","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"canceledAmountA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"canceledAmountB","type":"uint256"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"claimedAmountA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimedAmountB","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"Currency","name":"currency","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Collect","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountB","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpAmount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"BookId","name":"bookIdA","type":"uint192"},{"indexed":true,"internalType":"BookId","name":"bookIdB","type":"uint192"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"},{"indexed":false,"internalType":"address","name":"strategy","type":"address"}],"name":"Open","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"OperatorSet","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"Rebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"RATE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"burnAmount","type":"uint256"}],"name":"_burn","outputs":[{"internalType":"uint256","name":"withdrawalA","type":"uint256"},{"internalType":"uint256","name":"withdrawalB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"Currency","name":"base","type":"address"},{"internalType":"uint64","name":"unitSize","type":"uint64"},{"internalType":"Currency","name":"quote","type":"address"},{"internalType":"FeePolicy","name":"makerPolicy","type":"uint24"},{"internalType":"contract IHooks","name":"hooks","type":"address"},{"internalType":"FeePolicy","name":"takerPolicy","type":"uint24"}],"internalType":"struct IBookManager.BookKey","name":"bookKeyA","type":"tuple"},{"components":[{"internalType":"Currency","name":"base","type":"address"},{"internalType":"uint64","name":"unitSize","type":"uint64"},{"internalType":"Currency","name":"quote","type":"address"},{"internalType":"FeePolicy","name":"makerPolicy","type":"uint24"},{"internalType":"contract IHooks","name":"hooks","type":"address"},{"internalType":"FeePolicy","name":"takerPolicy","type":"uint24"}],"internalType":"struct IBookManager.BookKey","name":"bookKeyB","type":"tuple"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"strategy","type":"address"}],"name":"_open","outputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"_rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bookManager","outputs":[{"internalType":"contract IBookManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"BookId","name":"","type":"uint192"}],"name":"bookPair","outputs":[{"internalType":"BookId","name":"","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountA","type":"uint256"},{"internalType":"uint256","name":"minAmountB","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"withdrawalA","type":"uint256"},{"internalType":"uint256","name":"withdrawalB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"collect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"Currency","name":"","type":"address"}],"name":"fees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBookPairs","outputs":[{"internalType":"BookId","name":"","type":"uint192"},{"internalType":"BookId","name":"","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"reserve","type":"uint256"},{"internalType":"uint256","name":"claimable","type":"uint256"},{"internalType":"uint256","name":"cancelable","type":"uint256"}],"internalType":"struct ILiquidityVault.Liquidity","name":"liquidityA","type":"tuple"},{"components":[{"internalType":"uint256","name":"reserve","type":"uint256"},{"internalType":"uint256","name":"claimable","type":"uint256"},{"internalType":"uint256","name":"cancelable","type":"uint256"}],"internalType":"struct ILiquidityVault.Liquidity","name":"liquidityB","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getPool","outputs":[{"components":[{"internalType":"BookId","name":"bookIdA","type":"uint192"},{"internalType":"BookId","name":"bookIdB","type":"uint192"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"},{"internalType":"OrderId[]","name":"orderListA","type":"uint256[]"},{"internalType":"OrderId[]","name":"orderListB","type":"uint256[]"}],"internalType":"struct ILiquidityVault.Pool","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lockCaller","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"lockAcquired","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"minLpAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"Currency","name":"base","type":"address"},{"internalType":"uint64","name":"unitSize","type":"uint64"},{"internalType":"Currency","name":"quote","type":"address"},{"internalType":"FeePolicy","name":"makerPolicy","type":"uint24"},{"internalType":"contract IHooks","name":"hooks","type":"address"},{"internalType":"FeePolicy","name":"takerPolicy","type":"uint24"}],"internalType":"struct IBookManager.BookKey","name":"bookKeyA","type":"tuple"},{"components":[{"internalType":"Currency","name":"base","type":"address"},{"internalType":"uint64","name":"unitSize","type":"uint64"},{"internalType":"Currency","name":"quote","type":"address"},{"internalType":"FeePolicy","name":"makerPolicy","type":"uint24"},{"internalType":"contract IHooks","name":"hooks","type":"address"},{"internalType":"FeePolicy","name":"takerPolicy","type":"uint24"}],"internalType":"struct IBookManager.BookKey","name":"bookKeyB","type":"tuple"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"strategy","type":"address"}],"name":"open","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","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":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e060405230608052348015610013575f80fd5b50604051615481380380615481833981016040819052610032916101c0565b338061005757604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b610060816100b9565b50620f4240831061008457604051636a43f8d160e01b815260040160405180910390fd5b6001600160a01b03841660a05260c083905260096100a283826102ca565b50600a6100af82826102ca565b5050505050610389565b600180546001600160a01b03191690556100d2816100d5565b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112610147575f80fd5b81516001600160401b038082111561016157610161610124565b604051601f8301601f19908116603f0116810190828211818310171561018957610189610124565b816040528381528660208588010111156101a1575f80fd5b8360208701602083015e5f602085830101528094505050505092915050565b5f805f80608085870312156101d3575f80fd5b84516001600160a01b03811681146101e9575f80fd5b6020860151604087015191955093506001600160401b038082111561020c575f80fd5b61021888838901610138565b9350606087015191508082111561022d575f80fd5b5061023a87828801610138565b91505092959194509250565b600181811c9082168061025a57607f821691505b60208210810361027857634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156102c557805f5260205f20601f840160051c810160208510156102a35750805b601f840160051c820191505b818110156102c2575f81556001016102af565b50505b505050565b81516001600160401b038111156102e3576102e3610124565b6102f7816102f18454610246565b8461027e565b602080601f83116001811461032a575f84156103135750858301515b5f19600386901b1c1916600185901b178555610381565b5f85815260208120601f198616915b8281101561035857888601518255948401946001909101908401610339565b508582101561037557878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b60805160a05160c05161500a6104775f395f81816104b801528181612095015261214301525f81816104090152818161093a015281816109d401528181610dae01528181611363015281816114430152818161159601528181611a4301528181611acf01528181611b5001528181611bdc01528181611f1f01528181612347015281816126c9015281816127df01528181612b0501528181612bb201528181612c6c01528181612ce301528181612d3b01528181612e03015281816134bc0152818161369401528181613774015261380901525f81816131b9015281816131e20152613365015261500a5ff3fe608060405260043610610279575f3560e01c806379ba50971161014b578063c4d66de8116100c6578063f3cbc88c1161007c578063fa6793d511610062578063fa6793d5146107fc578063faaebd2114610829578063fe99049a14610854575f80fd5b8063f3cbc88c146107b1578063f6c00927146107d0575f80fd5b8063e27ff0ad116100ac578063e27ff0ad14610756578063e30c397814610775578063f2fde38b14610792575f80fd5b8063c4d66de8146106d7578063c630ed7d146106f6575f80fd5b8063a12ef25e1161011b578063ad3cb1cc11610101578063ad3cb1cc1461062b578063b6363cf214610673578063bd85b039146106ac575f80fd5b8063a12ef25e146105ed578063a1d5f1311461060c575f80fd5b806379ba50971461055d5780638da5cb5b1461057157806395d89b411461058d578063998ff4ef146105a1575f80fd5b80632b3ba681116101f5578063509bf42a116101ab578063558a729711610191578063558a7297146104ee578063598af9e71461050d578063715018a614610549575f80fd5b8063509bf42a146104a757806352d1902d146104da575f80fd5b80633f47e662116101db5780633f47e66214610443578063426a8493146104755780634f1ef28614610494575f80fd5b80632b3ba681146103e25780633f322bc9146103f8575f80fd5b8063095bcdb61161024a5780630a31b953116102305780630a31b9531461037057806315c7afb4146103a45780631b022ec8146103c3575f80fd5b8063095bcdb61461033e57806309cb66c41461035d575f80fd5b8062fdd58e1461028457806301ffc9a7146102cd578063022dd4ef146102fc57806306fdde031461031d575f80fd5b3661028057005b5f80fd5b34801561028f575f80fd5b506102ba61029e366004614164565b600360209081525f928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b3480156102d8575f80fd5b506102ec6102e736600461418e565b610873565b60405190151581526020016102c4565b348015610307575f80fd5b5061031b6103163660046141b5565b6108db565b005b348015610328575f80fd5b50610331610c2f565b6040516102c491906141fa565b348015610349575f80fd5b506102ec61035836600461420c565b610cbb565b6102ba61036b36600461423e565b610d75565b34801561037b575f80fd5b5061038f61038a36600461423e565b6112d5565b604080519283526020830191909152016102c4565b3480156103af575f80fd5b506103316103be36600461426d565b611436565b3480156103ce575f80fd5b5061031b6103dd3660046141b5565b61158c565b3480156103ed575f80fd5b506102ba620f424081565b348015610403575f80fd5b5061042b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102c4565b34801561044e575f80fd5b5061046361045d3660046141b5565b50601290565b60405160ff90911681526020016102c4565b348015610480575f80fd5b506102ec61048f36600461420c565b611670565b61031b6104a23660046143a3565b6116d4565b3480156104b2575f80fd5b506102ba7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e5575f80fd5b506102ba6116f3565b3480156104f9575f80fd5b506102ec61050836600461443d565b611721565b348015610518575f80fd5b506102ba610527366004614474565b600460209081525f938452604080852082529284528284209052825290205481565b348015610554575f80fd5b5061031b611790565b348015610568575f80fd5b5061031b6117a3565b34801561057c575f80fd5b505f546001600160a01b031661042b565b348015610598575f80fd5b506103316117e9565b3480156105ac575f80fd5b506105d56105bb3660046144b2565b60076020525f90815260409020546001600160c01b031681565b6040516001600160c01b0390911681526020016102c4565b3480156105f8575f80fd5b5061031b6106073660046144d8565b6117f6565b348015610617575f80fd5b506102ba61062636600461451a565b611878565b348015610636575f80fd5b506103316040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b34801561067e575f80fd5b506102ec61068d3660046144d8565b600260209081525f928352604080842090915290825290205460ff1681565b3480156106b7575f80fd5b506102ba6106c63660046141b5565b60056020525f908152604090205481565b3480156106e2575f80fd5b5061031b6106f136600461456b565b611d7c565b348015610701575f80fd5b506107366107103660046141b5565b5f90815260066020526040902080546001909101546001600160c01b0391821692911690565b604080516001600160c01b039384168152929091166020830152016102c4565b348015610761575f80fd5b5061038f610770366004614586565b611eb6565b348015610780575f80fd5b506001546001600160a01b031661042b565b34801561079d575f80fd5b5061031b6107ac36600461456b565b6122cc565b3480156107bc575f80fd5b506102ba6107cb36600461451a565b61233c565b3480156107db575f80fd5b506107ef6107ea3660046141b5565b612439565b6040516102c491906145e4565b348015610807575f80fd5b5061081b6108163660046141b5565b61259a565b6040516102c4929190614665565b348015610834575f80fd5b506102ba61084336600461456b565b60086020525f908152604090205481565b34801561085f575f80fd5b506102ec61086e36600461469e565b6128c3565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614806108d557507f0f632fb3000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b3330146108fb576040516314e1dbf760e11b815260040160405180910390fd5b5f81815260066020526040808220600381015460048083015483549451639b22917d60e01b81526001600160c01b0390951691850191909152919390927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015610987573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ab9190614706565b6001850154604051639b22917d60e01b81526001600160c01b0390911660048201529091505f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015610a21573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a459190614706565b60028601546040517f3b93fabc000000000000000000000000000000000000000000000000000000008152600481018990529192506001600160a01b031690633b93fabc906024015f60405180830381865afa925050508015610ac957506040513d5f823e601f3d908101601f19168201604052610ac69190810190614847565b60015b610b0357610ada8686600180612a34565b610ae8826040015185612ae4565b60038601558151610af99084612ae4565b6004860155610c26565b8151158015610b1157508051155b15610b20575050505050505050565b610b2d8888600180612a34565b5f610b3c85848a600501612dc4565b90505f610b4d85848b600601612dc4565b9050610b5d866040015189612ae4565b60038a01558551610b6e9088612ae4565b6004808b019190915560028a01546040517f4424d7f50000000000000000000000000000000000000000000000000000000081526001600160a01b0390911691634424d7f591610bca9133918f918a918a918a918a91016148ee565b5f604051808303815f87803b158015610be1575f80fd5b505af1158015610bf3573d5f803e3d5ffd5b50506040518c92507f37f8042257f6b4d65b9614deb7792e5b374db2fdcd1983bf8a1247a8a788af5c91505f90a2505050505b50505050505b50565b60098054610c3c9061493d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c689061493d565b8015610cb35780601f10610c8a57610100808354040283529160200191610cb3565b820191905f5260205f20905b815481529060010190602001808311610c9657829003601f168201915b505050505081565b335f908152600360209081526040808320858452909152812080548391908390610ce6908490614983565b90915550506001600160a01b0384165f90815260036020908152604080832086845290915281208054849290610d1d908490614996565b909155505060408051338082526020820185905285926001600160a01b038816927f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac72885991015b60405180910390a45060015b9392505050565b5f610d7e612f33565b5f8581526006602052604080822080549151639b22917d60e01b81526001600160c01b03909216600483015291907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015610dfb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e1f9190614706565b5f88815260056020526040812054919250819003610fdc57861580610e42575085155b15610e79576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201515f906001600160a01b031615610f0d5782604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ece573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef291906149a9565b610efd9060126149c9565b610f0890600a614ac2565b610f10565b60015b83519091505f906001600160a01b031615610fa357835f01516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8891906149a9565b610f939060126149c9565b610f9e90600a614ac2565b610fa6565b60015b90505f610fb3838b614ad0565b90505f610fc0838b614ad0565b9050808211610fcf5780610fd1565b815b9750505050506110de565b5f80610fe78a61259a565b915091505f82604001518360200151845f01516110049190614996565b61100e9190614996565b90505f82604001518360200151845f01516110299190614996565b6110339190614996565b905081158015611041575080155b15611054575f9950899a508a97506110d9565b815f03611070576110668a8683612fb9565b97505f9a506110d9565b805f0361108c576110828b8684612fb9565b97505f99506110d9565b5f6110988c8785612fb9565b90505f6110a68c8885612fb9565b9050808211156110c5578099506110be848b89612fd4565b9c506110d6565b8199506110d3838b89612fd4565b9b505b50505b505050505b848410156110ff576040516307dd37f760e41b815260040160405180910390fd5b604082015134906001600160a01b031661113c578734101561113457604051632a9ffab760e21b815260040160405180910390fd5b879003611156565b6040830151611156906001600160a01b031633308b612ff7565b82516001600160a01b031661118e578634101561118657604051632a9ffab760e21b815260040160405180910390fd5b8690036111a5565b82516111a5906001600160a01b031633308a612ff7565b87846003015f8282546111b89190614996565b9250508190555086846004015f8282546111d29190614996565b909155506111e39050338a87613070565b80156111f4576111f45f33836130a2565b6040805189815260208101899052908101869052899033907f1d43dbd7e59f8c9371169f5c49c01e100227d9ee5f5fe54665cf10e35042bb729060600160405180910390a360028401546040517fa3a36f55000000000000000000000000000000000000000000000000000000008152336004820152602481018b905260448101879052606481018490526001600160a01b039091169063a3a36f55906084015f604051808303815f87803b1580156112ab575f80fd5b505af11580156112bd573d5f803e3d5ffd5b50505050505050506112cd613184565b949350505050565b5f806112df612f33565b6040805160248101889052336044820152606480820188905282518083039091018152608490910182526020810180516001600160e01b03167fe27ff0ad0000000000000000000000000000000000000000000000000000000017905290517f9ca179980000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691639ca17998916113a0913091600401614ae7565b5f604051808303815f875af11580156113bb573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113e29190810190614b08565b8060200190518101906113f59190614b7d565b90925090508382108061140757508281105b15611425576040516307dd37f760e41b815260040160405180910390fd5b61142d613184565b94509492505050565b6060336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461149a576040517f4bd37f4300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841630146114dc576040517f66a7598c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80306001600160a01b031685856040516114f8929190614b9f565b5f604051808303815f865af19150503d805f8114611531576040519150601f19603f3d011682016040523d82523d5f602084013e611536565b606091505b5091509150811561154a579150610d6e9050565b80515f03611584576040517fa40afa3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160208201fd5b611594612f33565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639ca179983063022dd4ef60e01b846040516024016115df91815260200190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b90921682526116259291600401614ae7565b5f604051808303815f875af1158015611640573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526116679190810190614b08565b50610c2c613184565b335f8181526004602090815260408083206001600160a01b03881680855290835281842087855290925280832085905551919285927fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a790610d629087815260200190565b6116dc6131ae565b6116e582613265565b6116ef828261326d565b5050565b5f6116fc61335a565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b335f8181526002602090815260408083206001600160a01b038716808552908352818420805460ff191687151590811790915591519182529293917fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267910160405180910390a350600192915050565b6117986133a3565b6117a15f6133cf565b565b60015433906001600160a01b031681146117e05760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b610c2c816133cf565b600a8054610c3c9061493d565b6117fe6133a3565b6001600160a01b0382165f8181526008602052604081208054919055906118269083836130a2565b816001600160a01b0316836001600160a01b03167f1314fd112a381beea61539dbd21ec04afcff2662ac7d1b83273aade1f53d1b978360405161186b91815260200190565b60405180910390a3505050565b5f333014611899576040516314e1dbf760e11b815260040160405180910390fd5b6118ca6118a9602086018661456b565b6118b9606088016040890161456b565b6001600160a01b0391821691161490565b80156118f157506118f16118e4606086016040870161456b565b6118b9602088018861456b565b158061190857506119086118a9602087018761456b565b1561193f576040517f27a4015200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61195060a087016080880161456b565b6001600160a01b031614158061197e57505f61197260a086016080870161456b565b6001600160a01b031614155b156119b5576040517f9c9d882300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166119f5576040517f4e236e9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611a0d611a0836889003880188614bae565b6133e8565b90505f611a22611a0836889003880188614bae565b604051632ad7b51960e11b81526001600160c01b03841660048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906355af6a3290602401602060405180830381865afa158015611a90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ab49190614c2d565b611b325760405163fefc7c5160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fefc7c5190611b04908a90600401614ce7565b5f604051808303815f87803b158015611b1b575f80fd5b505af1158015611b2d573d5f803e3d5ffd5b505050505b604051632ad7b51960e11b81526001600160c01b03821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906355af6a3290602401602060405180830381865afa158015611b9d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc19190614c2d565b611c3f5760405163fefc7c5160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fefc7c5190611c11908990600401614ce7565b5f604051808303815f87803b158015611c28575f80fd5b505af1158015611c3a573d5f803e3d5ffd5b505050505b611c4a828287613423565b5f818152600660205260409020600201549093506001600160a01b031615611c9e576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f83815260066020908152604080832080546001600160c01b038781167fffffffffffffffff0000000000000000000000000000000000000000000000009283168117845560018401805492891692841683179055600290930180546001600160a01b038c166001600160a01b03199091168117909155838752600786528487208054841683179055818752958490208054909216831790915582518a8152938401949094529186917f66d8f0c63665a9bd1357e5d422d5f538805b225f260974cb408a66635040ec6c910160405180910390a45050949350505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015611dc65750825b90505f8267ffffffffffffffff166001148015611de25750303b155b905081158015611df0575080155b15611e27576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff191660011785558315611e5b57845468ff00000000000000001916680100000000000000001785555b611e64866133cf565b8315610c2657845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a1505050505050565b5f80333014611ed8576040516314e1dbf760e11b815260040160405180910390fd5b5f858152600660209081526040808320600590925290912054611efc86888761348f565b8154604051639b22917d60e01b81526001600160c01b0390911660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015611f6c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f909190614706565b9050611f9e88848885612a34565b611fb081604001518460030154612ae4565b600384015580516004840154611fc69190612ae4565b60048401555f80611fd68a61259a565b91509150838883604001518460200151855f0151611ff49190614996565b611ffe9190614996565b6120089190614ad0565b6120129190614d08565b9650838882604001518360200151845f015161202e9190614996565b6120389190614996565b6120429190614ad0565b61204c9190614d08565b955086856003015f8282546120619190614983565b9250508190555085856004015f82825461207b9190614983565b909155505f905080881561213157620f42406001816120ba7f00000000000000000000000000000000000000000000000000000000000000008d614ad0565b6120c49190614996565b6120ce9190614983565b6120d89190614d08565b91506120e4828a614983565b6040860151909950612100906001600160a01b03168c8b6130a2565b6040808601516001600160a01b03165f9081526008602052908120805484929061212b908490614996565b90915550505b87156121d957620f42406001816121687f00000000000000000000000000000000000000000000000000000000000000008c614ad0565b6121729190614996565b61217c9190614983565b6121869190614d08565b90506121928189614983565b85519098506121ab906001600160a01b03168c8a6130a2565b84516001600160a01b03165f90815260086020526040812080548392906121d3908490614996565b90915550505b604080518b8152602081018b905290810189905260608101839052608081018290528c906001600160a01b038d16907f7825ad5cf3aafe81da61bbb75737444e6d77278cb110bb9bfa3ee809f1fb64b99060a00160405180910390a360028701546040517fdb7c74b6000000000000000000000000000000000000000000000000000000008152336004820152602481018e9052604481018c9052606481018890526001600160a01b039091169063db7c74b6906084015f604051808303815f87803b1580156122a7575f80fd5b505af11580156122b9573d5f803e3d5ffd5b5050505050505050505050935093915050565b6122d46133a3565b600180546001600160a01b0383166001600160a01b031990911681179091556123045f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f612345612f33565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639ca179983063a1d5f13160e01b888888886040516024016123949493929190614d27565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b90921682526123da9291600401614ae7565b5f604051808303815f875af11580156123f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261241c9190810190614b08565b80602001905181019061242f9190614d63565b90506112cd613184565b61248f6040518060e001604052805f6001600160c01b031681526020015f6001600160c01b031681526020015f6001600160a01b031681526020015f81526020015f815260200160608152602001606081525090565b5f82815260066020908152604091829020825160e08101845281546001600160c01b0390811682526001830154168184015260028201546001600160a01b03168185015260038201546060820152600482015460808201526005820180548551818602810186019096528086529194929360a0860193929083018282801561253457602002820191905f5260205f20905b815481526020019060010190808311612520575b505050505081526020016006820180548060200260200160405190810160405280929190818152602001828054801561258a57602002820191905f5260205f20905b815481526020019060010190808311612576575b5050505050815250509050919050565b6125bb60405180606001604052805f81526020015f81526020015f81525090565b6125dc60405180606001604052805f81526020015f81526020015f81525090565b5f838152600660209081526040808320600381015486526004810154855260058101805483518186028101860190945280845291949390919083018282801561264257602002820191905f5260205f20905b81548152602001906001019080831161262e575b505050505090505f8260060180548060200260200160405190810160405280929190818152602001828054801561269657602002820191905f5260205f20905b815481526020019060010190808311612682575b505050505090505f825111156127b2578254604051639b22917d60e01b81526001600160c01b0390911660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015612716573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061273a9190614706565b90505f5b83518110156127af575f806127758460600151856020015188868151811061276857612768614d7a565b60200260200101516134b7565b91509150818960400181815161278b9190614996565b9052506020880180518291906127a2908390614996565b905250505060010161273e565b50505b8051156128bb576001830154604051639b22917d60e01b81526001600160c01b0390911660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa15801561282c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128509190614706565b90505f5b82518110156128b8575f8061287e8460600151856020015187868151811061276857612768614d7a565b9150915080896020018181516128949190614996565b9052506040880180518391906128ab908390614996565b9052505050600101612854565b50505b505050915091565b5f336001600160a01b0386161480159061290057506001600160a01b0385165f90815260026020908152604080832033845290915290205460ff16155b15612970576001600160a01b0385165f90815260046020908152604080832033845282528083208684529091529020545f19811461296e576129428382614983565b6001600160a01b0387165f90815260046020908152604080832033845282528083208884529091529020555b505b6001600160a01b0385165f908152600360209081526040808320868452909152812080548492906129a2908490614983565b90915550506001600160a01b0384165f908152600360209081526040808320868452909152812080548492906129d9908490614996565b9091555050604080513381526020810184905284916001600160a01b0380881692908916917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a4506001949350505050565b5f80612a44856005018585613616565b915091505f80612a58876006018787613616565b91509150877f1c29b938e5c165e4f17dcbaf854af84a6c529c3f0face137b12bda74606cca9e8285604051612a97929190918252602082015260400190565b60405180910390a2604080518581526020810184905289917f5721685080049ebad55f69ed0f4bf84a11d57cd2050e67986deab2323a9b2103910160405180910390a25050505050505050565b604051636a256b2960e01b81526001600160a01b0383811660048301525f917f000000000000000000000000000000000000000000000000000000000000000090911690636a256b29906024016020604051808303815f875af1158015612b4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b719190614d63565b506040517f9611cf6c0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384811660248301525f917f000000000000000000000000000000000000000000000000000000000000000090911690639611cf6c90604401602060405180830381865afa158015612bf9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c1d9190614d63565b90505f811315612cd6576040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152306024830152604482018390527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed12906064015f604051808303815f87803b158015612cad575f80fd5b505af1158015612cbf573d5f803e3d5ffd5b505050508083612ccf9190614996565b9250612dbc565b5f811215612dbc57612d1c7f0000000000000000000000000000000000000000000000000000000000000000612d0b83614d8e565b6001600160a01b03871691906130a2565b604051636a256b2960e01b81526001600160a01b0385811660048301527f00000000000000000000000000000000000000000000000000000000000000001690636a256b29906024016020604051808303815f875af1158015612d81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612da59190614d63565b50612daf81614d8e565b612db99084614983565b92505b509092915050565b5f805b8351811015612f2b57838181518110612de257612de2614d7a565b60200260200101516020015167ffffffffffffffff165f0315612f23575f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631dbef48860405180608001604052808a8152602001898781518110612e5357612e53614d7a565b60200260200101515f015160020b8152602001898781518110612e7857612e78614d7a565b60200260200101516020015167ffffffffffffffff1681526020015f6001600160a01b03168152506040518263ffffffff1660e01b8152600401612ebc9190614dc4565b60408051808303815f875af1158015612ed7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612efb9190614b7d565b9092509050612f0a8185614996565b85546001810187555f8781526020902001929092555091505b600101612dc7565b509392505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15612f8c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117a160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b9061392f565b5f825f190484118302158202612fcd575f80fd5b5091020490565b5f825f190484118302158202612fe8575f80fd5b50910281810615159190040190565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03167f23b872dd0000000000000000000000000000000000000000000000000000000017905261306a908590613936565b50505050565b61307b8383836139bb565b5f8281526005602052604081208054839290613098908490614996565b9091555050505050565b5f6001600160a01b0384166130f7575f805f8085875af19050806130f2576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61306a565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f51141617169150508061306a576040517ff27f64e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00612fb3565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061324757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661323b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b156117a15760405163703e46dd60e11b815260040160405180910390fd5b610c2c6133a3565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156132c7575060408051601f3d908101601f191682019092526132c491810190614d63565b60015b6132ef57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016117d7565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc811461334b576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016117d7565b6133558383613a40565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117a15760405163703e46dd60e11b815260040160405180910390fd5b5f546001600160a01b031633146117a15760405163118cdaa760e01b81523360048201526024016117d7565b600180546001600160a01b0319169055610c2c81613a95565b5f80826040516020016133fb9190614e7a565b60408051601f1981840301815291905280516020909101206001600160c01b03169392505050565b5f826001600160c01b0316846001600160c01b03161115613442579192915b6040805167ffffffffffffffff1986831b811660208301529185901b9091166038820152605081018390526070016040516020818303038152906040528051906020012090509392505050565b61349a838383613ae4565b5f8281526005602052604081208054839290613098908490614983565b5f805f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d09ef241856040518263ffffffff1660e01b815260040161350891815260200190565b606060405180830381865afa158015613523573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135479190614ee1565b90508467ffffffffffffffff16816020015167ffffffffffffffff1661356d9190614ad0565b92506135b08567ffffffffffffffff16826040015167ffffffffffffffff166135969190614ad0565b5f6135a68760281c62ffffff1690565b60020b9190613b60565b91506135c18662ffffff1660171c90565b156135ec575f6135d862ffffff8816856001613b82565b90506135e48185614f51565b93505061360d565b5f6135fd62ffffff88168483613b82565b90506136098184614f78565b9250505b50935093915050565b5f805f8580548060200260200160405190810160405280929190818152602001828054801561366257602002820191905f5260205f20905b81548152602001906001019080831161364e575b505050505090505f5b815181101561391c575f82828151811061368757613687614d7a565b602002602001015190505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d09ef241836040518263ffffffff1660e01b81526004016136e091815260200190565b606060405180830381865afa1580156136fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061371f9190614ee1565b604081015190915067ffffffffffffffff16156137f357604080517f38926b6d0000000000000000000000000000000000000000000000000000000081526004810184905260248101919091525f60448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906338926b6d906064016020604051808303815f875af11580156137c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137e69190614d63565b6137f09086614996565b94505b602081015167ffffffffffffffff1615613912577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166314d6a9eb604051806040016040528085815260200161387f8b8d8d6138579190614983565b876020015167ffffffffffffffff166138709190614ad0565b61387a9190614d08565b613c02565b67ffffffffffffffff9081169091526040516001600160e01b031960e085901b16815282516004820152602090920151166024820152606060448201525f60648201526084016020604051808303815f875af11580156138e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139059190614d63565b61390f9087614996565b95505b505060010161366b565b5084840361360d57505f90945593915050565b80825d5050565b5f8060205f8451602086015f885af180613955576040513d5f823e3d81fd5b50505f513d9150811561396c578060011415613979565b6001600160a01b0384163b155b1561306a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117d7565b6001600160a01b0383165f908152600360209081526040808320858452909152812080548392906139ed908490614996565b9091555050604080513381526020810183905283916001600160a01b038616915f917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac72885991015b60405180910390a4505050565b613a4982613c55565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115613a8d576133558282613ccb565b6116ef613d3d565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0383165f90815260036020908152604080832085845290915281208054839290613b16908490614983565b9091555050604080513381526020810183905283915f916001600160a01b038716917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac7288599101613a33565b5f6112cd606084901b613b758660020b613d75565b8082061515851691040190565b5f6207a11f19627fffff851601600281900b82128281613ba457825f03613ba6565b825b62ffffff1690505f613bdf613bbb8389614ad0565b620f424088613bd1578581830615151691040190565b808206151586151691040190565b905082613bf457613bef81614d8e565b613bf6565b805b98975050505050505050565b5f67ffffffffffffffff821115613c5157604080517f6dfcc6500000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044016117d7565b5090565b806001600160a01b03163b5f03613c8a57604051634c9c8ce360e01b81526001600160a01b03821660048201526024016117d7565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b031684604051613ce79190614f9e565b5f60405180830381855af49150503d805f8114613d1f576040519150601f19603f3d011682016040523d82523d5f602084013e613d24565b606091505b5091509150613d3485838361403d565b95945050505050565b34156117a1576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613d7f826140b2565b815f600282900b8113613d925781613d9b565b613d9b82614fb4565b62ffffff8116915060011615613dbf576bfff97272373d413259a469909250613dd0565b6c0100000000000000000000000092505b6002811615613def5760606bfff2e50f5f656932ef12357c8402901c92505b6004811615613e0e5760606bffe5caca7e10e4e61c3624ea8402901c92505b6008811615613e2d5760606bffcb9843d60f6159c9db58838402901c92505b6010811615613e4c5760606bff973b41fa98c081472e68968402901c92505b6020811615613e6b5760606bff2ea16466c96a3843ec78b38402901c92505b6040811615613e8a5760606bfe5dee046a99a2a811c461f18402901c92505b6080811615613ea95760606bfcbe86c7900a88aedcffc83b8402901c92505b610100811615613ec95760606bf987a7253ac413176f2b074c8402901c92505b610200811615613ee95760606bf3392b0822b70005940c7a398402901c92505b610400811615613f095760606be7159475a2c29b7443b29c7f8402901c92505b610800811615613f295760606bd097f3bdfd2022b8845ad8f78402901c92505b611000811615613f495760606ba9f746462d870fdf8a65dc1f8402901c92505b612000811615613f695760606b70d869a156d2a1b890bb3df68402901c92505b614000811615613f895760606b31be135f97d08fd9812315058402901c92505b618000811615613fa95760606b09aa508b5b7a84e1c677de548402901c92505b62010000811615613fc95760606a5d6af8dedb81196699c3298402901c92505b62020000811615613fe8576060692216e584f5fa1ea926048402901c92505b6204000081161561400557606067048a170391f7dc428402901c92505b5f8260020b131561403657614033837801000000000000000000000000000000000000000000000000614d08565b92505b5050919050565b6060826140525761404d8261410e565b610d6e565b815115801561406957506001600160a01b0384163b155b156140ab576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117d7565b5080610d6e565b6207ffff600282900b13806140d757506140ce6207ffff614fb4565b60020b8160020b125b15610c2c576040517fce8ef7fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80511561411e5780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381168114610c2c575f80fd5b5f8060408385031215614175575f80fd5b823561418081614150565b946020939093013593505050565b5f6020828403121561419e575f80fd5b81356001600160e01b031981168114610d6e575f80fd5b5f602082840312156141c5575f80fd5b5035919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610d6e60208301846141cc565b5f805f6060848603121561421e575f80fd5b833561422981614150565b95602085013595506040909401359392505050565b5f805f8060808587031215614251575f80fd5b5050823594602084013594506040840135936060013592509050565b5f805f6040848603121561427f575f80fd5b833561428a81614150565b9250602084013567ffffffffffffffff808211156142a6575f80fd5b818601915086601f8301126142b9575f80fd5b8135818111156142c7575f80fd5b8760208285010111156142d8575f80fd5b6020830194508093505050509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715614322576143226142eb565b60405290565b6040805190810167ffffffffffffffff81118282101715614322576143226142eb565b604051601f8201601f1916810167ffffffffffffffff81118282101715614374576143746142eb565b604052919050565b5f67ffffffffffffffff821115614395576143956142eb565b50601f01601f191660200190565b5f80604083850312156143b4575f80fd5b82356143bf81614150565b9150602083013567ffffffffffffffff8111156143da575f80fd5b8301601f810185136143ea575f80fd5b80356143fd6143f88261437c565b61434b565b818152866020838501011115614411575f80fd5b816020840160208301375f602083830101528093505050509250929050565b8015158114610c2c575f80fd5b5f806040838503121561444e575f80fd5b823561445981614150565b9150602083013561446981614430565b809150509250929050565b5f805f60608486031215614486575f80fd5b833561449181614150565b925060208401356144a181614150565b929592945050506040919091013590565b5f602082840312156144c2575f80fd5b81356001600160c01b0381168114610d6e575f80fd5b5f80604083850312156144e9575f80fd5b82356144f481614150565b9150602083013561446981614150565b5f60c08284031215614514575f80fd5b50919050565b5f805f806101c0858703121561452e575f80fd5b6145388686614504565b93506145478660c08701614504565b925061018085013591506101a085013561456081614150565b939692955090935050565b5f6020828403121561457b575f80fd5b8135610d6e81614150565b5f805f60608486031215614598575f80fd5b8335925060208401356144a181614150565b5f815180845260208085019450602084015f5b838110156145d9578151875295820195908201906001016145bd565b509495945050505050565b602081525f6001600160c01b03808451166020840152806020850151166040840152506001600160a01b03604084015116606083015260608301516080830152608083015160a083015260a083015160e060c08401526146486101008401826145aa565b905060c0840151601f198483030160e0850152613d3482826145aa565b8251815260208084015181830152604080850151818401528351606084015290830151608083015282015160a082015260c08101610d6e565b5f805f80608085870312156146b1575f80fd5b84356146bc81614150565b935060208501356146cc81614150565b93969395505050506040820135916060013590565b67ffffffffffffffff81168114610c2c575f80fd5b62ffffff81168114610c2c575f80fd5b5f60c08284031215614716575f80fd5b61471e6142ff565b825161472981614150565b81526020830151614739816146e1565b6020820152604083015161474c81614150565b6040820152606083015161475f816146f6565b6060820152608083015161477281614150565b608082015260a0830151614785816146f6565b60a08201529392505050565b5f82601f8301126147a0575f80fd5b8151602067ffffffffffffffff8211156147bc576147bc6142eb565b6147ca818360051b0161434b565b82815260069290921b840181019181810190868411156147e8575f80fd5b8286015b8481101561483c5760408189031215614803575f80fd5b61480b614328565b81518060020b811461481b575f80fd5b81528185015161482a816146e1565b818601528352918301916040016147ec565b509695505050505050565b5f8060408385031215614858575f80fd5b825167ffffffffffffffff8082111561486f575f80fd5b61487b86838701614791565b93506020850151915080821115614890575f80fd5b5061489d85828601614791565b9150509250929050565b5f815180845260208085019450602084015f5b838110156145d9578151805160020b885283015167ffffffffffffffff1683880152604090960195908201906001016148ba565b6001600160a01b038716815285602082015260c060408201525f61491560c08301876148a7565b828103606084015261492781876148a7565b6080840195909552505060a00152949350505050565b600181811c9082168061495157607f821691505b60208210810361451457634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b818103818111156108d5576108d561496f565b808201808211156108d5576108d561496f565b5f602082840312156149b9575f80fd5b815160ff81168114610d6e575f80fd5b60ff82811682821603908111156108d5576108d561496f565b600181815b80851115614a1c57815f1904821115614a0257614a0261496f565b80851615614a0f57918102915b93841c93908002906149e7565b509250929050565b5f82614a32575060016108d5565b81614a3e57505f6108d5565b8160018114614a545760028114614a5e57614a7a565b60019150506108d5565b60ff841115614a6f57614a6f61496f565b50506001821b6108d5565b5060208310610133831016604e8410600b8410161715614a9d575081810a6108d5565b614aa783836149e2565b805f1904821115614aba57614aba61496f565b029392505050565b5f610d6e60ff841683614a24565b80820281158282048414176108d5576108d561496f565b6001600160a01b0383168152604060208201525f6112cd60408301846141cc565b5f60208284031215614b18575f80fd5b815167ffffffffffffffff811115614b2e575f80fd5b8201601f81018413614b3e575f80fd5b8051614b4c6143f88261437c565b818152856020838501011115614b60575f80fd5b8160208401602083015e5f91810160200191909152949350505050565b5f8060408385031215614b8e575f80fd5b505080516020909101519092909150565b818382375f9101908152919050565b5f60c08284031215614bbe575f80fd5b614bc66142ff565b8235614bd181614150565b81526020830135614be1816146e1565b60208201526040830135614bf481614150565b60408201526060830135614c07816146f6565b60608201526080830135614c1a81614150565b608082015260a0830135614785816146f6565b5f60208284031215614c3d575f80fd5b8151610d6e81614430565b8035614c5381614150565b6001600160a01b039081168352602082013590614c6f826146e1565b67ffffffffffffffff8216602085015260408301359150614c8f82614150565b9081166040840152606082013590614ca6826146f6565b62ffffff9182166060850152608083013591614cc183614150565b918116608085015260a083013591614cd8836146f6565b80831660a08601525050505050565b614cf18183614c48565b60e060c082018190525f9082015261010001919050565b5f82614d2257634e487b7160e01b5f52601260045260245ffd5b500490565b6101c08101614d368287614c48565b614d4360c0830186614c48565b836101808301526001600160a01b0383166101a083015295945050505050565b5f60208284031215614d73575f80fd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b5f7f80000000000000000000000000000000000000000000000000000000000000008203614dbe57614dbe61496f565b505f0390565b5f610140614e2c8385516001600160a01b0380825116835267ffffffffffffffff6020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b602084015160020b60c0840152604084015167ffffffffffffffff1660e08401526060909301516001600160a01b03166101008301525061012081018290525f918101919091526101600190565b60c081016108d582846001600160a01b0380825116835267ffffffffffffffff6020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b5f60608284031215614ef1575f80fd5b6040516060810181811067ffffffffffffffff82111715614f1457614f146142eb565b6040528251614f2281614150565b81526020830151614f32816146e1565b60208201526040830151614f45816146e1565b60408201529392505050565b8082018281125f831280158216821582161715614f7057614f7061496f565b505092915050565b8181035f831280158383131683831282161715614f9757614f9761496f565b5092915050565b5f82518060208501845e5f920191825250919050565b5f8160020b627fffff198103614fcc57614fcc61496f565b5f039291505056fea2646970667358221220db8f007ed5632b261c40bb9678348ad618c17b5fe71a527e8852b2d458894ca564736f6c63430008190033000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6360000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001c536f6e6963204d61726b6574204c6971756964697479205661756c74000000000000000000000000000000000000000000000000000000000000000000000003534c560000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405260043610610279575f3560e01c806379ba50971161014b578063c4d66de8116100c6578063f3cbc88c1161007c578063fa6793d511610062578063fa6793d5146107fc578063faaebd2114610829578063fe99049a14610854575f80fd5b8063f3cbc88c146107b1578063f6c00927146107d0575f80fd5b8063e27ff0ad116100ac578063e27ff0ad14610756578063e30c397814610775578063f2fde38b14610792575f80fd5b8063c4d66de8146106d7578063c630ed7d146106f6575f80fd5b8063a12ef25e1161011b578063ad3cb1cc11610101578063ad3cb1cc1461062b578063b6363cf214610673578063bd85b039146106ac575f80fd5b8063a12ef25e146105ed578063a1d5f1311461060c575f80fd5b806379ba50971461055d5780638da5cb5b1461057157806395d89b411461058d578063998ff4ef146105a1575f80fd5b80632b3ba681116101f5578063509bf42a116101ab578063558a729711610191578063558a7297146104ee578063598af9e71461050d578063715018a614610549575f80fd5b8063509bf42a146104a757806352d1902d146104da575f80fd5b80633f47e662116101db5780633f47e66214610443578063426a8493146104755780634f1ef28614610494575f80fd5b80632b3ba681146103e25780633f322bc9146103f8575f80fd5b8063095bcdb61161024a5780630a31b953116102305780630a31b9531461037057806315c7afb4146103a45780631b022ec8146103c3575f80fd5b8063095bcdb61461033e57806309cb66c41461035d575f80fd5b8062fdd58e1461028457806301ffc9a7146102cd578063022dd4ef146102fc57806306fdde031461031d575f80fd5b3661028057005b5f80fd5b34801561028f575f80fd5b506102ba61029e366004614164565b600360209081525f928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b3480156102d8575f80fd5b506102ec6102e736600461418e565b610873565b60405190151581526020016102c4565b348015610307575f80fd5b5061031b6103163660046141b5565b6108db565b005b348015610328575f80fd5b50610331610c2f565b6040516102c491906141fa565b348015610349575f80fd5b506102ec61035836600461420c565b610cbb565b6102ba61036b36600461423e565b610d75565b34801561037b575f80fd5b5061038f61038a36600461423e565b6112d5565b604080519283526020830191909152016102c4565b3480156103af575f80fd5b506103316103be36600461426d565b611436565b3480156103ce575f80fd5b5061031b6103dd3660046141b5565b61158c565b3480156103ed575f80fd5b506102ba620f424081565b348015610403575f80fd5b5061042b7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63681565b6040516001600160a01b0390911681526020016102c4565b34801561044e575f80fd5b5061046361045d3660046141b5565b50601290565b60405160ff90911681526020016102c4565b348015610480575f80fd5b506102ec61048f36600461420c565b611670565b61031b6104a23660046143a3565b6116d4565b3480156104b2575f80fd5b506102ba7f000000000000000000000000000000000000000000000000000000000000006481565b3480156104e5575f80fd5b506102ba6116f3565b3480156104f9575f80fd5b506102ec61050836600461443d565b611721565b348015610518575f80fd5b506102ba610527366004614474565b600460209081525f938452604080852082529284528284209052825290205481565b348015610554575f80fd5b5061031b611790565b348015610568575f80fd5b5061031b6117a3565b34801561057c575f80fd5b505f546001600160a01b031661042b565b348015610598575f80fd5b506103316117e9565b3480156105ac575f80fd5b506105d56105bb3660046144b2565b60076020525f90815260409020546001600160c01b031681565b6040516001600160c01b0390911681526020016102c4565b3480156105f8575f80fd5b5061031b6106073660046144d8565b6117f6565b348015610617575f80fd5b506102ba61062636600461451a565b611878565b348015610636575f80fd5b506103316040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b34801561067e575f80fd5b506102ec61068d3660046144d8565b600260209081525f928352604080842090915290825290205460ff1681565b3480156106b7575f80fd5b506102ba6106c63660046141b5565b60056020525f908152604090205481565b3480156106e2575f80fd5b5061031b6106f136600461456b565b611d7c565b348015610701575f80fd5b506107366107103660046141b5565b5f90815260066020526040902080546001909101546001600160c01b0391821692911690565b604080516001600160c01b039384168152929091166020830152016102c4565b348015610761575f80fd5b5061038f610770366004614586565b611eb6565b348015610780575f80fd5b506001546001600160a01b031661042b565b34801561079d575f80fd5b5061031b6107ac36600461456b565b6122cc565b3480156107bc575f80fd5b506102ba6107cb36600461451a565b61233c565b3480156107db575f80fd5b506107ef6107ea3660046141b5565b612439565b6040516102c491906145e4565b348015610807575f80fd5b5061081b6108163660046141b5565b61259a565b6040516102c4929190614665565b348015610834575f80fd5b506102ba61084336600461456b565b60086020525f908152604090205481565b34801561085f575f80fd5b506102ec61086e36600461469e565b6128c3565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614806108d557507f0f632fb3000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b3330146108fb576040516314e1dbf760e11b815260040160405180910390fd5b5f81815260066020526040808220600381015460048083015483549451639b22917d60e01b81526001600160c01b0390951691850191909152919390927f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015610987573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ab9190614706565b6001850154604051639b22917d60e01b81526001600160c01b0390911660048201529091505f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015610a21573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a459190614706565b60028601546040517f3b93fabc000000000000000000000000000000000000000000000000000000008152600481018990529192506001600160a01b031690633b93fabc906024015f60405180830381865afa925050508015610ac957506040513d5f823e601f3d908101601f19168201604052610ac69190810190614847565b60015b610b0357610ada8686600180612a34565b610ae8826040015185612ae4565b60038601558151610af99084612ae4565b6004860155610c26565b8151158015610b1157508051155b15610b20575050505050505050565b610b2d8888600180612a34565b5f610b3c85848a600501612dc4565b90505f610b4d85848b600601612dc4565b9050610b5d866040015189612ae4565b60038a01558551610b6e9088612ae4565b6004808b019190915560028a01546040517f4424d7f50000000000000000000000000000000000000000000000000000000081526001600160a01b0390911691634424d7f591610bca9133918f918a918a918a918a91016148ee565b5f604051808303815f87803b158015610be1575f80fd5b505af1158015610bf3573d5f803e3d5ffd5b50506040518c92507f37f8042257f6b4d65b9614deb7792e5b374db2fdcd1983bf8a1247a8a788af5c91505f90a2505050505b50505050505b50565b60098054610c3c9061493d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c689061493d565b8015610cb35780601f10610c8a57610100808354040283529160200191610cb3565b820191905f5260205f20905b815481529060010190602001808311610c9657829003601f168201915b505050505081565b335f908152600360209081526040808320858452909152812080548391908390610ce6908490614983565b90915550506001600160a01b0384165f90815260036020908152604080832086845290915281208054849290610d1d908490614996565b909155505060408051338082526020820185905285926001600160a01b038816927f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac72885991015b60405180910390a45060015b9392505050565b5f610d7e612f33565b5f8581526006602052604080822080549151639b22917d60e01b81526001600160c01b03909216600483015291907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015610dfb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e1f9190614706565b5f88815260056020526040812054919250819003610fdc57861580610e42575085155b15610e79576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201515f906001600160a01b031615610f0d5782604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ece573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef291906149a9565b610efd9060126149c9565b610f0890600a614ac2565b610f10565b60015b83519091505f906001600160a01b031615610fa357835f01516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8891906149a9565b610f939060126149c9565b610f9e90600a614ac2565b610fa6565b60015b90505f610fb3838b614ad0565b90505f610fc0838b614ad0565b9050808211610fcf5780610fd1565b815b9750505050506110de565b5f80610fe78a61259a565b915091505f82604001518360200151845f01516110049190614996565b61100e9190614996565b90505f82604001518360200151845f01516110299190614996565b6110339190614996565b905081158015611041575080155b15611054575f9950899a508a97506110d9565b815f03611070576110668a8683612fb9565b97505f9a506110d9565b805f0361108c576110828b8684612fb9565b97505f99506110d9565b5f6110988c8785612fb9565b90505f6110a68c8885612fb9565b9050808211156110c5578099506110be848b89612fd4565b9c506110d6565b8199506110d3838b89612fd4565b9b505b50505b505050505b848410156110ff576040516307dd37f760e41b815260040160405180910390fd5b604082015134906001600160a01b031661113c578734101561113457604051632a9ffab760e21b815260040160405180910390fd5b879003611156565b6040830151611156906001600160a01b031633308b612ff7565b82516001600160a01b031661118e578634101561118657604051632a9ffab760e21b815260040160405180910390fd5b8690036111a5565b82516111a5906001600160a01b031633308a612ff7565b87846003015f8282546111b89190614996565b9250508190555086846004015f8282546111d29190614996565b909155506111e39050338a87613070565b80156111f4576111f45f33836130a2565b6040805189815260208101899052908101869052899033907f1d43dbd7e59f8c9371169f5c49c01e100227d9ee5f5fe54665cf10e35042bb729060600160405180910390a360028401546040517fa3a36f55000000000000000000000000000000000000000000000000000000008152336004820152602481018b905260448101879052606481018490526001600160a01b039091169063a3a36f55906084015f604051808303815f87803b1580156112ab575f80fd5b505af11580156112bd573d5f803e3d5ffd5b50505050505050506112cd613184565b949350505050565b5f806112df612f33565b6040805160248101889052336044820152606480820188905282518083039091018152608490910182526020810180516001600160e01b03167fe27ff0ad0000000000000000000000000000000000000000000000000000000017905290517f9ca179980000000000000000000000000000000000000000000000000000000081527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031691639ca17998916113a0913091600401614ae7565b5f604051808303815f875af11580156113bb573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113e29190810190614b08565b8060200190518101906113f59190614b7d565b90925090508382108061140757508281105b15611425576040516307dd37f760e41b815260040160405180910390fd5b61142d613184565b94509492505050565b6060336001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636161461149a576040517f4bd37f4300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841630146114dc576040517f66a7598c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80306001600160a01b031685856040516114f8929190614b9f565b5f604051808303815f865af19150503d805f8114611531576040519150601f19603f3d011682016040523d82523d5f602084013e611536565b606091505b5091509150811561154a579150610d6e9050565b80515f03611584576040517fa40afa3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160208201fd5b611594612f33565b7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316639ca179983063022dd4ef60e01b846040516024016115df91815260200190565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b90921682526116259291600401614ae7565b5f604051808303815f875af1158015611640573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526116679190810190614b08565b50610c2c613184565b335f8181526004602090815260408083206001600160a01b03881680855290835281842087855290925280832085905551919285927fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a790610d629087815260200190565b6116dc6131ae565b6116e582613265565b6116ef828261326d565b5050565b5f6116fc61335a565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b335f8181526002602090815260408083206001600160a01b038716808552908352818420805460ff191687151590811790915591519182529293917fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267910160405180910390a350600192915050565b6117986133a3565b6117a15f6133cf565b565b60015433906001600160a01b031681146117e05760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b610c2c816133cf565b600a8054610c3c9061493d565b6117fe6133a3565b6001600160a01b0382165f8181526008602052604081208054919055906118269083836130a2565b816001600160a01b0316836001600160a01b03167f1314fd112a381beea61539dbd21ec04afcff2662ac7d1b83273aade1f53d1b978360405161186b91815260200190565b60405180910390a3505050565b5f333014611899576040516314e1dbf760e11b815260040160405180910390fd5b6118ca6118a9602086018661456b565b6118b9606088016040890161456b565b6001600160a01b0391821691161490565b80156118f157506118f16118e4606086016040870161456b565b6118b9602088018861456b565b158061190857506119086118a9602087018761456b565b1561193f576040517f27a4015200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61195060a087016080880161456b565b6001600160a01b031614158061197e57505f61197260a086016080870161456b565b6001600160a01b031614155b156119b5576040517f9c9d882300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166119f5576040517f4e236e9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611a0d611a0836889003880188614bae565b6133e8565b90505f611a22611a0836889003880188614bae565b604051632ad7b51960e11b81526001600160c01b03841660048201529091507f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316906355af6a3290602401602060405180830381865afa158015611a90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ab49190614c2d565b611b325760405163fefc7c5160e01b81526001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169063fefc7c5190611b04908a90600401614ce7565b5f604051808303815f87803b158015611b1b575f80fd5b505af1158015611b2d573d5f803e3d5ffd5b505050505b604051632ad7b51960e11b81526001600160c01b03821660048201527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316906355af6a3290602401602060405180830381865afa158015611b9d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc19190614c2d565b611c3f5760405163fefc7c5160e01b81526001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169063fefc7c5190611c11908990600401614ce7565b5f604051808303815f87803b158015611c28575f80fd5b505af1158015611c3a573d5f803e3d5ffd5b505050505b611c4a828287613423565b5f818152600660205260409020600201549093506001600160a01b031615611c9e576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f83815260066020908152604080832080546001600160c01b038781167fffffffffffffffff0000000000000000000000000000000000000000000000009283168117845560018401805492891692841683179055600290930180546001600160a01b038c166001600160a01b03199091168117909155838752600786528487208054841683179055818752958490208054909216831790915582518a8152938401949094529186917f66d8f0c63665a9bd1357e5d422d5f538805b225f260974cb408a66635040ec6c910160405180910390a45050949350505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015611dc65750825b90505f8267ffffffffffffffff166001148015611de25750303b155b905081158015611df0575080155b15611e27576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff191660011785558315611e5b57845468ff00000000000000001916680100000000000000001785555b611e64866133cf565b8315610c2657845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a1505050505050565b5f80333014611ed8576040516314e1dbf760e11b815260040160405180910390fd5b5f858152600660209081526040808320600590925290912054611efc86888761348f565b8154604051639b22917d60e01b81526001600160c01b0390911660048201525f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015611f6c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f909190614706565b9050611f9e88848885612a34565b611fb081604001518460030154612ae4565b600384015580516004840154611fc69190612ae4565b60048401555f80611fd68a61259a565b91509150838883604001518460200151855f0151611ff49190614996565b611ffe9190614996565b6120089190614ad0565b6120129190614d08565b9650838882604001518360200151845f015161202e9190614996565b6120389190614996565b6120429190614ad0565b61204c9190614d08565b955086856003015f8282546120619190614983565b9250508190555085856004015f82825461207b9190614983565b909155505f905080881561213157620f42406001816120ba7f00000000000000000000000000000000000000000000000000000000000000648d614ad0565b6120c49190614996565b6120ce9190614983565b6120d89190614d08565b91506120e4828a614983565b6040860151909950612100906001600160a01b03168c8b6130a2565b6040808601516001600160a01b03165f9081526008602052908120805484929061212b908490614996565b90915550505b87156121d957620f42406001816121687f00000000000000000000000000000000000000000000000000000000000000648c614ad0565b6121729190614996565b61217c9190614983565b6121869190614d08565b90506121928189614983565b85519098506121ab906001600160a01b03168c8a6130a2565b84516001600160a01b03165f90815260086020526040812080548392906121d3908490614996565b90915550505b604080518b8152602081018b905290810189905260608101839052608081018290528c906001600160a01b038d16907f7825ad5cf3aafe81da61bbb75737444e6d77278cb110bb9bfa3ee809f1fb64b99060a00160405180910390a360028701546040517fdb7c74b6000000000000000000000000000000000000000000000000000000008152336004820152602481018e9052604481018c9052606481018890526001600160a01b039091169063db7c74b6906084015f604051808303815f87803b1580156122a7575f80fd5b505af11580156122b9573d5f803e3d5ffd5b5050505050505050505050935093915050565b6122d46133a3565b600180546001600160a01b0383166001600160a01b031990911681179091556123045f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f612345612f33565b7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316639ca179983063a1d5f13160e01b888888886040516024016123949493929190614d27565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b90921682526123da9291600401614ae7565b5f604051808303815f875af11580156123f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261241c9190810190614b08565b80602001905181019061242f9190614d63565b90506112cd613184565b61248f6040518060e001604052805f6001600160c01b031681526020015f6001600160c01b031681526020015f6001600160a01b031681526020015f81526020015f815260200160608152602001606081525090565b5f82815260066020908152604091829020825160e08101845281546001600160c01b0390811682526001830154168184015260028201546001600160a01b03168185015260038201546060820152600482015460808201526005820180548551818602810186019096528086529194929360a0860193929083018282801561253457602002820191905f5260205f20905b815481526020019060010190808311612520575b505050505081526020016006820180548060200260200160405190810160405280929190818152602001828054801561258a57602002820191905f5260205f20905b815481526020019060010190808311612576575b5050505050815250509050919050565b6125bb60405180606001604052805f81526020015f81526020015f81525090565b6125dc60405180606001604052805f81526020015f81526020015f81525090565b5f838152600660209081526040808320600381015486526004810154855260058101805483518186028101860190945280845291949390919083018282801561264257602002820191905f5260205f20905b81548152602001906001019080831161262e575b505050505090505f8260060180548060200260200160405190810160405280929190818152602001828054801561269657602002820191905f5260205f20905b815481526020019060010190808311612682575b505050505090505f825111156127b2578254604051639b22917d60e01b81526001600160c01b0390911660048201525f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015612716573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061273a9190614706565b90505f5b83518110156127af575f806127758460600151856020015188868151811061276857612768614d7a565b60200260200101516134b7565b91509150818960400181815161278b9190614996565b9052506020880180518291906127a2908390614996565b905250505060010161273e565b50505b8051156128bb576001830154604051639b22917d60e01b81526001600160c01b0390911660048201525f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa15801561282c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128509190614706565b90505f5b82518110156128b8575f8061287e8460600151856020015187868151811061276857612768614d7a565b9150915080896020018181516128949190614996565b9052506040880180518391906128ab908390614996565b9052505050600101612854565b50505b505050915091565b5f336001600160a01b0386161480159061290057506001600160a01b0385165f90815260026020908152604080832033845290915290205460ff16155b15612970576001600160a01b0385165f90815260046020908152604080832033845282528083208684529091529020545f19811461296e576129428382614983565b6001600160a01b0387165f90815260046020908152604080832033845282528083208884529091529020555b505b6001600160a01b0385165f908152600360209081526040808320868452909152812080548492906129a2908490614983565b90915550506001600160a01b0384165f908152600360209081526040808320868452909152812080548492906129d9908490614996565b9091555050604080513381526020810184905284916001600160a01b0380881692908916917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a4506001949350505050565b5f80612a44856005018585613616565b915091505f80612a58876006018787613616565b91509150877f1c29b938e5c165e4f17dcbaf854af84a6c529c3f0face137b12bda74606cca9e8285604051612a97929190918252602082015260400190565b60405180910390a2604080518581526020810184905289917f5721685080049ebad55f69ed0f4bf84a11d57cd2050e67986deab2323a9b2103910160405180910390a25050505050505050565b604051636a256b2960e01b81526001600160a01b0383811660048301525f917f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63690911690636a256b29906024016020604051808303815f875af1158015612b4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b719190614d63565b506040517f9611cf6c0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384811660248301525f917f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63690911690639611cf6c90604401602060405180830381865afa158015612bf9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c1d9190614d63565b90505f811315612cd6576040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152306024830152604482018390527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169063d9caed12906064015f604051808303815f87803b158015612cad575f80fd5b505af1158015612cbf573d5f803e3d5ffd5b505050508083612ccf9190614996565b9250612dbc565b5f811215612dbc57612d1c7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636612d0b83614d8e565b6001600160a01b03871691906130a2565b604051636a256b2960e01b81526001600160a01b0385811660048301527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690636a256b29906024016020604051808303815f875af1158015612d81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612da59190614d63565b50612daf81614d8e565b612db99084614983565b92505b509092915050565b5f805b8351811015612f2b57838181518110612de257612de2614d7a565b60200260200101516020015167ffffffffffffffff165f0315612f23575f807f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316631dbef48860405180608001604052808a8152602001898781518110612e5357612e53614d7a565b60200260200101515f015160020b8152602001898781518110612e7857612e78614d7a565b60200260200101516020015167ffffffffffffffff1681526020015f6001600160a01b03168152506040518263ffffffff1660e01b8152600401612ebc9190614dc4565b60408051808303815f875af1158015612ed7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612efb9190614b7d565b9092509050612f0a8185614996565b85546001810187555f8781526020902001929092555091505b600101612dc7565b509392505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15612f8c576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117a160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b9061392f565b5f825f190484118302158202612fcd575f80fd5b5091020490565b5f825f190484118302158202612fe8575f80fd5b50910281810615159190040190565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03167f23b872dd0000000000000000000000000000000000000000000000000000000017905261306a908590613936565b50505050565b61307b8383836139bb565b5f8281526005602052604081208054839290613098908490614996565b9091555050505050565b5f6001600160a01b0384166130f7575f805f8085875af19050806130f2576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61306a565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f51141617169150508061306a576040517ff27f64e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00612fb3565b306001600160a01b037f0000000000000000000000009bb7d556a4eb463b213135df3184303cbdd52e1d16148061324757507f0000000000000000000000009bb7d556a4eb463b213135df3184303cbdd52e1d6001600160a01b031661323b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b156117a15760405163703e46dd60e11b815260040160405180910390fd5b610c2c6133a3565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156132c7575060408051601f3d908101601f191682019092526132c491810190614d63565b60015b6132ef57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016117d7565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc811461334b576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016117d7565b6133558383613a40565b505050565b306001600160a01b037f0000000000000000000000009bb7d556a4eb463b213135df3184303cbdd52e1d16146117a15760405163703e46dd60e11b815260040160405180910390fd5b5f546001600160a01b031633146117a15760405163118cdaa760e01b81523360048201526024016117d7565b600180546001600160a01b0319169055610c2c81613a95565b5f80826040516020016133fb9190614e7a565b60408051601f1981840301815291905280516020909101206001600160c01b03169392505050565b5f826001600160c01b0316846001600160c01b03161115613442579192915b6040805167ffffffffffffffff1986831b811660208301529185901b9091166038820152605081018390526070016040516020818303038152906040528051906020012090509392505050565b61349a838383613ae4565b5f8281526005602052604081208054839290613098908490614983565b5f805f7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031663d09ef241856040518263ffffffff1660e01b815260040161350891815260200190565b606060405180830381865afa158015613523573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135479190614ee1565b90508467ffffffffffffffff16816020015167ffffffffffffffff1661356d9190614ad0565b92506135b08567ffffffffffffffff16826040015167ffffffffffffffff166135969190614ad0565b5f6135a68760281c62ffffff1690565b60020b9190613b60565b91506135c18662ffffff1660171c90565b156135ec575f6135d862ffffff8816856001613b82565b90506135e48185614f51565b93505061360d565b5f6135fd62ffffff88168483613b82565b90506136098184614f78565b9250505b50935093915050565b5f805f8580548060200260200160405190810160405280929190818152602001828054801561366257602002820191905f5260205f20905b81548152602001906001019080831161364e575b505050505090505f5b815181101561391c575f82828151811061368757613687614d7a565b602002602001015190505f7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031663d09ef241836040518263ffffffff1660e01b81526004016136e091815260200190565b606060405180830381865afa1580156136fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061371f9190614ee1565b604081015190915067ffffffffffffffff16156137f357604080517f38926b6d0000000000000000000000000000000000000000000000000000000081526004810184905260248101919091525f60448201527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316906338926b6d906064016020604051808303815f875af11580156137c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137e69190614d63565b6137f09086614996565b94505b602081015167ffffffffffffffff1615613912577f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b03166314d6a9eb604051806040016040528085815260200161387f8b8d8d6138579190614983565b876020015167ffffffffffffffff166138709190614ad0565b61387a9190614d08565b613c02565b67ffffffffffffffff9081169091526040516001600160e01b031960e085901b16815282516004820152602090920151166024820152606060448201525f60648201526084016020604051808303815f875af11580156138e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139059190614d63565b61390f9087614996565b95505b505060010161366b565b5084840361360d57505f90945593915050565b80825d5050565b5f8060205f8451602086015f885af180613955576040513d5f823e3d81fd5b50505f513d9150811561396c578060011415613979565b6001600160a01b0384163b155b1561306a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117d7565b6001600160a01b0383165f908152600360209081526040808320858452909152812080548392906139ed908490614996565b9091555050604080513381526020810183905283916001600160a01b038616915f917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac72885991015b60405180910390a4505050565b613a4982613c55565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115613a8d576133558282613ccb565b6116ef613d3d565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0383165f90815260036020908152604080832085845290915281208054839290613b16908490614983565b9091555050604080513381526020810183905283915f916001600160a01b038716917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac7288599101613a33565b5f6112cd606084901b613b758660020b613d75565b8082061515851691040190565b5f6207a11f19627fffff851601600281900b82128281613ba457825f03613ba6565b825b62ffffff1690505f613bdf613bbb8389614ad0565b620f424088613bd1578581830615151691040190565b808206151586151691040190565b905082613bf457613bef81614d8e565b613bf6565b805b98975050505050505050565b5f67ffffffffffffffff821115613c5157604080517f6dfcc6500000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044016117d7565b5090565b806001600160a01b03163b5f03613c8a57604051634c9c8ce360e01b81526001600160a01b03821660048201526024016117d7565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b031684604051613ce79190614f9e565b5f60405180830381855af49150503d805f8114613d1f576040519150601f19603f3d011682016040523d82523d5f602084013e613d24565b606091505b5091509150613d3485838361403d565b95945050505050565b34156117a1576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613d7f826140b2565b815f600282900b8113613d925781613d9b565b613d9b82614fb4565b62ffffff8116915060011615613dbf576bfff97272373d413259a469909250613dd0565b6c0100000000000000000000000092505b6002811615613def5760606bfff2e50f5f656932ef12357c8402901c92505b6004811615613e0e5760606bffe5caca7e10e4e61c3624ea8402901c92505b6008811615613e2d5760606bffcb9843d60f6159c9db58838402901c92505b6010811615613e4c5760606bff973b41fa98c081472e68968402901c92505b6020811615613e6b5760606bff2ea16466c96a3843ec78b38402901c92505b6040811615613e8a5760606bfe5dee046a99a2a811c461f18402901c92505b6080811615613ea95760606bfcbe86c7900a88aedcffc83b8402901c92505b610100811615613ec95760606bf987a7253ac413176f2b074c8402901c92505b610200811615613ee95760606bf3392b0822b70005940c7a398402901c92505b610400811615613f095760606be7159475a2c29b7443b29c7f8402901c92505b610800811615613f295760606bd097f3bdfd2022b8845ad8f78402901c92505b611000811615613f495760606ba9f746462d870fdf8a65dc1f8402901c92505b612000811615613f695760606b70d869a156d2a1b890bb3df68402901c92505b614000811615613f895760606b31be135f97d08fd9812315058402901c92505b618000811615613fa95760606b09aa508b5b7a84e1c677de548402901c92505b62010000811615613fc95760606a5d6af8dedb81196699c3298402901c92505b62020000811615613fe8576060692216e584f5fa1ea926048402901c92505b6204000081161561400557606067048a170391f7dc428402901c92505b5f8260020b131561403657614033837801000000000000000000000000000000000000000000000000614d08565b92505b5050919050565b6060826140525761404d8261410e565b610d6e565b815115801561406957506001600160a01b0384163b155b156140ab576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117d7565b5080610d6e565b6207ffff600282900b13806140d757506140ce6207ffff614fb4565b60020b8160020b125b15610c2c576040517fce8ef7fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80511561411e5780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381168114610c2c575f80fd5b5f8060408385031215614175575f80fd5b823561418081614150565b946020939093013593505050565b5f6020828403121561419e575f80fd5b81356001600160e01b031981168114610d6e575f80fd5b5f602082840312156141c5575f80fd5b5035919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610d6e60208301846141cc565b5f805f6060848603121561421e575f80fd5b833561422981614150565b95602085013595506040909401359392505050565b5f805f8060808587031215614251575f80fd5b5050823594602084013594506040840135936060013592509050565b5f805f6040848603121561427f575f80fd5b833561428a81614150565b9250602084013567ffffffffffffffff808211156142a6575f80fd5b818601915086601f8301126142b9575f80fd5b8135818111156142c7575f80fd5b8760208285010111156142d8575f80fd5b6020830194508093505050509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715614322576143226142eb565b60405290565b6040805190810167ffffffffffffffff81118282101715614322576143226142eb565b604051601f8201601f1916810167ffffffffffffffff81118282101715614374576143746142eb565b604052919050565b5f67ffffffffffffffff821115614395576143956142eb565b50601f01601f191660200190565b5f80604083850312156143b4575f80fd5b82356143bf81614150565b9150602083013567ffffffffffffffff8111156143da575f80fd5b8301601f810185136143ea575f80fd5b80356143fd6143f88261437c565b61434b565b818152866020838501011115614411575f80fd5b816020840160208301375f602083830101528093505050509250929050565b8015158114610c2c575f80fd5b5f806040838503121561444e575f80fd5b823561445981614150565b9150602083013561446981614430565b809150509250929050565b5f805f60608486031215614486575f80fd5b833561449181614150565b925060208401356144a181614150565b929592945050506040919091013590565b5f602082840312156144c2575f80fd5b81356001600160c01b0381168114610d6e575f80fd5b5f80604083850312156144e9575f80fd5b82356144f481614150565b9150602083013561446981614150565b5f60c08284031215614514575f80fd5b50919050565b5f805f806101c0858703121561452e575f80fd5b6145388686614504565b93506145478660c08701614504565b925061018085013591506101a085013561456081614150565b939692955090935050565b5f6020828403121561457b575f80fd5b8135610d6e81614150565b5f805f60608486031215614598575f80fd5b8335925060208401356144a181614150565b5f815180845260208085019450602084015f5b838110156145d9578151875295820195908201906001016145bd565b509495945050505050565b602081525f6001600160c01b03808451166020840152806020850151166040840152506001600160a01b03604084015116606083015260608301516080830152608083015160a083015260a083015160e060c08401526146486101008401826145aa565b905060c0840151601f198483030160e0850152613d3482826145aa565b8251815260208084015181830152604080850151818401528351606084015290830151608083015282015160a082015260c08101610d6e565b5f805f80608085870312156146b1575f80fd5b84356146bc81614150565b935060208501356146cc81614150565b93969395505050506040820135916060013590565b67ffffffffffffffff81168114610c2c575f80fd5b62ffffff81168114610c2c575f80fd5b5f60c08284031215614716575f80fd5b61471e6142ff565b825161472981614150565b81526020830151614739816146e1565b6020820152604083015161474c81614150565b6040820152606083015161475f816146f6565b6060820152608083015161477281614150565b608082015260a0830151614785816146f6565b60a08201529392505050565b5f82601f8301126147a0575f80fd5b8151602067ffffffffffffffff8211156147bc576147bc6142eb565b6147ca818360051b0161434b565b82815260069290921b840181019181810190868411156147e8575f80fd5b8286015b8481101561483c5760408189031215614803575f80fd5b61480b614328565b81518060020b811461481b575f80fd5b81528185015161482a816146e1565b818601528352918301916040016147ec565b509695505050505050565b5f8060408385031215614858575f80fd5b825167ffffffffffffffff8082111561486f575f80fd5b61487b86838701614791565b93506020850151915080821115614890575f80fd5b5061489d85828601614791565b9150509250929050565b5f815180845260208085019450602084015f5b838110156145d9578151805160020b885283015167ffffffffffffffff1683880152604090960195908201906001016148ba565b6001600160a01b038716815285602082015260c060408201525f61491560c08301876148a7565b828103606084015261492781876148a7565b6080840195909552505060a00152949350505050565b600181811c9082168061495157607f821691505b60208210810361451457634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b818103818111156108d5576108d561496f565b808201808211156108d5576108d561496f565b5f602082840312156149b9575f80fd5b815160ff81168114610d6e575f80fd5b60ff82811682821603908111156108d5576108d561496f565b600181815b80851115614a1c57815f1904821115614a0257614a0261496f565b80851615614a0f57918102915b93841c93908002906149e7565b509250929050565b5f82614a32575060016108d5565b81614a3e57505f6108d5565b8160018114614a545760028114614a5e57614a7a565b60019150506108d5565b60ff841115614a6f57614a6f61496f565b50506001821b6108d5565b5060208310610133831016604e8410600b8410161715614a9d575081810a6108d5565b614aa783836149e2565b805f1904821115614aba57614aba61496f565b029392505050565b5f610d6e60ff841683614a24565b80820281158282048414176108d5576108d561496f565b6001600160a01b0383168152604060208201525f6112cd60408301846141cc565b5f60208284031215614b18575f80fd5b815167ffffffffffffffff811115614b2e575f80fd5b8201601f81018413614b3e575f80fd5b8051614b4c6143f88261437c565b818152856020838501011115614b60575f80fd5b8160208401602083015e5f91810160200191909152949350505050565b5f8060408385031215614b8e575f80fd5b505080516020909101519092909150565b818382375f9101908152919050565b5f60c08284031215614bbe575f80fd5b614bc66142ff565b8235614bd181614150565b81526020830135614be1816146e1565b60208201526040830135614bf481614150565b60408201526060830135614c07816146f6565b60608201526080830135614c1a81614150565b608082015260a0830135614785816146f6565b5f60208284031215614c3d575f80fd5b8151610d6e81614430565b8035614c5381614150565b6001600160a01b039081168352602082013590614c6f826146e1565b67ffffffffffffffff8216602085015260408301359150614c8f82614150565b9081166040840152606082013590614ca6826146f6565b62ffffff9182166060850152608083013591614cc183614150565b918116608085015260a083013591614cd8836146f6565b80831660a08601525050505050565b614cf18183614c48565b60e060c082018190525f9082015261010001919050565b5f82614d2257634e487b7160e01b5f52601260045260245ffd5b500490565b6101c08101614d368287614c48565b614d4360c0830186614c48565b836101808301526001600160a01b0383166101a083015295945050505050565b5f60208284031215614d73575f80fd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b5f7f80000000000000000000000000000000000000000000000000000000000000008203614dbe57614dbe61496f565b505f0390565b5f610140614e2c8385516001600160a01b0380825116835267ffffffffffffffff6020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b602084015160020b60c0840152604084015167ffffffffffffffff1660e08401526060909301516001600160a01b03166101008301525061012081018290525f918101919091526101600190565b60c081016108d582846001600160a01b0380825116835267ffffffffffffffff6020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b5f60608284031215614ef1575f80fd5b6040516060810181811067ffffffffffffffff82111715614f1457614f146142eb565b6040528251614f2281614150565b81526020830151614f32816146e1565b60208201526040830151614f45816146e1565b60408201529392505050565b8082018281125f831280158216821582161715614f7057614f7061496f565b505092915050565b8181035f831280158383131683831282161715614f9757614f9761496f565b5092915050565b5f82518060208501845e5f920191825250919050565b5f8160020b627fffff198103614fcc57614fcc61496f565b5f039291505056fea2646970667358221220db8f007ed5632b261c40bb9678348ad618c17b5fe71a527e8852b2d458894ca564736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6360000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001c536f6e6963204d61726b6574204c6971756964697479205661756c74000000000000000000000000000000000000000000000000000000000000000000000003534c560000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : bookManager_ (address): 0xD4aD5Ed9E1436904624b6dB8B1BE31f36317C636
Arg [1] : burnFeeRate_ (uint256): 100
Arg [2] : name_ (string): Sonic Market Liquidity Vault
Arg [3] : symbol_ (string): SLV
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [4] : 000000000000000000000000000000000000000000000000000000000000001c
Arg [5] : 536f6e6963204d61726b6574204c6971756964697479205661756c7400000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [7] : 534c560000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.