Source Code
Overview
S Balance
S Value
$0.00Latest 25 from a total of 1,172 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Cancel | 18917984 | 292 days ago | IN | 0 S | 0.02083525 | ||||
| Make | 18760427 | 292 days ago | IN | 0 S | 0.01967069 | ||||
| Make | 18760372 | 292 days ago | IN | 0 S | 0.01967069 | ||||
| Make | 18760297 | 292 days ago | IN | 0 S | 0.02014628 | ||||
| Make | 18760205 | 292 days ago | IN | 0 S | 0.02494279 | ||||
| Open | 18760105 | 292 days ago | IN | 0 S | 0.00997692 | ||||
| Make | 18065438 | 296 days ago | IN | 0 S | 0.01993263 | ||||
| Open | 18065378 | 296 days ago | IN | 0 S | 0.00622346 | ||||
| Make | 17049264 | 300 days ago | IN | 0 S | 0.01505398 | ||||
| Claim | 16762289 | 302 days ago | IN | 0 S | 0.00702652 | ||||
| Cancel | 16626203 | 302 days ago | IN | 0 S | 0.00840118 | ||||
| Make | 16608920 | 302 days ago | IN | 0 S | 0.02001213 | ||||
| Cancel | 16575728 | 303 days ago | IN | 0 S | 0.00840118 | ||||
| Cancel | 16575688 | 303 days ago | IN | 0 S | 0.00866523 | ||||
| Cancel | 16231930 | 304 days ago | IN | 0 S | 0.00956376 | ||||
| Make | 16231714 | 304 days ago | IN | 0 S | 0.02215067 | ||||
| Cancel | 15104379 | 309 days ago | IN | 0 S | 0.00847175 | ||||
| Cancel | 15008810 | 310 days ago | IN | 0 S | 0.00704311 | ||||
| Cancel | 15008772 | 310 days ago | IN | 0 S | 0.00746331 | ||||
| Make | 14295660 | 313 days ago | IN | 0 S | 0.02041209 | ||||
| Open | 14295575 | 313 days ago | IN | 0 S | 0.00622466 | ||||
| Cancel | 14218377 | 314 days ago | IN | 0 S | 0.0154519 | ||||
| Cancel | 14206978 | 314 days ago | IN | 0 S | 0.0089519 | ||||
| Cancel | 14206596 | 314 days ago | IN | 0 S | 0.010173 | ||||
| Cancel | 13986731 | 315 days ago | IN | 0 S | 0.01318627 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 36774507 | 207 days ago | 0.0000026 S | ||||
| 36774507 | 207 days ago | 3.99999739 S | ||||
| 36774507 | 207 days ago | 4 S | ||||
| 36763168 | 207 days ago | 0.00000148 S | ||||
| 36763168 | 207 days ago | 6.96999851 S | ||||
| 36763168 | 207 days ago | 6.97 S | ||||
| 36762744 | 207 days ago | 0.00000065 S | ||||
| 36762744 | 207 days ago | 819.99999934 S | ||||
| 36762744 | 207 days ago | 820 S | ||||
| 32614967 | 231 days ago | 0.00000214 S | ||||
| 32614967 | 231 days ago | 0.00999785 S | ||||
| 32614967 | 231 days ago | 0.01 S | ||||
| 32611540 | 231 days ago | 0.00000189 S | ||||
| 32611540 | 231 days ago | 0.0099981 S | ||||
| 32611540 | 231 days ago | 0.01 S | ||||
| 32583387 | 231 days ago | 0.00000189 S | ||||
| 32583387 | 231 days ago | 0.0099981 S | ||||
| 32583387 | 231 days ago | 0.01 S | ||||
| 32374309 | 232 days ago | 0.00000189 S | ||||
| 32374309 | 232 days ago | 0.0099981 S | ||||
| 32374309 | 232 days ago | 0.01 S | ||||
| 31324649 | 237 days ago | 0.00000243 S | ||||
| 31324649 | 237 days ago | 0.00099756 S | ||||
| 31324649 | 237 days ago | 0.001 S | ||||
| 30848322 | 239 days ago | 0.00000189 S |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Controller
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 {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {ILocker} from "core/interfaces/ILocker.sol";
import {IBookManager} from "core/interfaces/IBookManager.sol";
import {IERC721Permit} from "core/interfaces/IERC721Permit.sol";
import {Math} from "core/libraries/Math.sol";
import {BookId, BookIdLibrary} from "core/libraries/BookId.sol";
import {OrderId, OrderIdLibrary} from "core/libraries/OrderId.sol";
import {Currency, CurrencyLibrary} from "core/libraries/Currency.sol";
import {FeePolicy, FeePolicyLibrary} from "core/libraries/FeePolicy.sol";
import {Tick, TickLibrary} from "core/libraries/Tick.sol";
import {OrderId, OrderIdLibrary} from "core/libraries/OrderId.sol";
import {IController} from "./interfaces/IController.sol";
import {ReentrancyGuard} from "./libraries/ReentrancyGuard.sol";
contract Controller is IController, ILocker, ReentrancyGuard {
using TickLibrary for *;
using OrderIdLibrary for OrderId;
using BookIdLibrary for IBookManager.BookKey;
using SafeERC20 for IERC20;
using SafeCast for uint256;
using Math for uint256;
using CurrencyLibrary for Currency;
using FeePolicyLibrary for FeePolicy;
IBookManager public immutable bookManager;
constructor(address bookManager_) {
bookManager = IBookManager(bookManager_);
}
modifier checkDeadline(uint64 deadline) {
if (block.timestamp > deadline) revert Deadline();
_;
}
modifier permitERC20(ERC20PermitParams[] calldata permitParamsList) {
_permitERC20(permitParamsList);
_;
}
function getDepth(BookId id, Tick tick) external view returns (uint256) {
return uint256(bookManager.getDepth(id, tick)) * bookManager.getBookKey(id).unitSize;
}
function getHighestPrice(BookId id) external view returns (uint256) {
return bookManager.getHighest(id).toPrice();
}
function getOrder(OrderId orderId)
external
view
returns (address provider, uint256 price, uint256 openAmount, uint256 claimableAmount)
{
(BookId bookId, Tick tick,) = orderId.decode();
IBookManager.BookKey memory key = bookManager.getBookKey(bookId);
uint256 unitSize = key.unitSize;
price = tick.toPrice();
IBookManager.OrderInfo memory orderInfo = bookManager.getOrder(orderId);
provider = orderInfo.provider;
openAmount = unitSize * orderInfo.open;
FeePolicy makerPolicy = key.makerPolicy;
claimableAmount = tick.quoteToBase(unitSize * orderInfo.claimable, false);
if (!makerPolicy.usesQuote()) {
int256 fee = makerPolicy.calculateFee(claimableAmount, false);
claimableAmount = fee > 0 ? claimableAmount - uint256(fee) : claimableAmount + uint256(-fee);
}
}
function fromPrice(uint256 price) external pure returns (Tick) {
return price.fromPrice();
}
function toPrice(Tick tick) external pure returns (uint256) {
return tick.toPrice();
}
function lockAcquired(address sender, bytes memory data) external nonReentrant returns (bytes memory returnData) {
if (msg.sender != address(bookManager) || sender != address(this)) revert InvalidAccess();
(address user, Action[] memory actionList, bytes[] memory orderParamsList, address[] memory tokensToSettle) =
abi.decode(data, (address, Action[], bytes[], address[]));
uint256 length = actionList.length;
OrderId[] memory ids = new OrderId[](length);
uint256 orderIdIndex;
for (uint256 i = 0; i < length; ++i) {
Action action = actionList[i];
if (action == Action.OPEN) {
_open(abi.decode(orderParamsList[i], (OpenBookParams)));
} else if (action == Action.MAKE) {
OrderId id = _make(abi.decode(orderParamsList[i], (MakeOrderParams)));
if (OrderId.unwrap(id) != 0) {
bookManager.transferFrom(address(this), user, OrderId.unwrap(id));
ids[orderIdIndex++] = id;
}
} else if (action == Action.LIMIT) {
OrderId id = _limit(abi.decode(orderParamsList[i], (LimitOrderParams)));
if (OrderId.unwrap(id) != 0) {
bookManager.transferFrom(address(this), user, OrderId.unwrap(id));
ids[orderIdIndex++] = id;
}
} else if (action == Action.TAKE) {
_take(abi.decode(orderParamsList[i], (TakeOrderParams)));
} else if (action == Action.SPEND) {
_spend(abi.decode(orderParamsList[i], (SpendOrderParams)));
} else if (action == Action.CLAIM) {
ClaimOrderParams memory claimOrderParams = abi.decode(orderParamsList[i], (ClaimOrderParams));
if (_isValidOrderId(claimOrderParams.id, user)) _claim(claimOrderParams);
} else if (action == Action.CANCEL) {
CancelOrderParams memory cancelOrderParams = abi.decode(orderParamsList[i], (CancelOrderParams));
if (_isValidOrderId(cancelOrderParams.id, user)) _cancel(cancelOrderParams);
} else {
revert InvalidAction();
}
}
_settleTokens(user, tokensToSettle);
assembly {
mstore(ids, orderIdIndex)
}
returnData = abi.encode(ids);
}
function _isValidOrderId(OrderId orderId, address user) internal view returns (bool) {
uint256 id = OrderId.unwrap(orderId);
try bookManager.ownerOf(id) returns (address owner) {
try bookManager.checkAuthorized(owner, user, id) {
return true;
} catch {
return false;
}
} catch {
return false;
}
}
function execute(
Action[] calldata actionList,
bytes[] calldata paramsDataList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata erc20PermitParamsList,
ERC721PermitParams[] calldata erc721PermitParamsList,
uint64 deadline
) external payable checkDeadline(deadline) returns (OrderId[] memory ids) {
if (actionList.length != paramsDataList.length) revert InvalidLength();
_permitERC20(erc20PermitParamsList);
_permitERC721(erc721PermitParamsList);
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bytes memory result = bookManager.lock(address(this), lockData);
if (result.length != 0) {
(ids) = abi.decode(result, (OrderId[]));
}
return ids;
}
function open(OpenBookParams[] calldata openBookParamsList, uint64 deadline) external checkDeadline(deadline) {
uint256 length = openBookParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.OPEN;
paramsDataList[i] = abi.encode(openBookParamsList[i]);
}
address[] memory tokensToSettle;
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bookManager.lock(address(this), lockData);
}
function limit(
LimitOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable checkDeadline(deadline) permitERC20(permitParamsList) returns (OrderId[] memory ids) {
uint256 length = orderParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.LIMIT;
paramsDataList[i] = abi.encode(orderParamsList[i]);
}
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bytes memory result = bookManager.lock(address(this), lockData);
(ids) = abi.decode(result, (OrderId[]));
}
function make(
MakeOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable checkDeadline(deadline) permitERC20(permitParamsList) returns (OrderId[] memory ids) {
uint256 length = orderParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.MAKE;
paramsDataList[i] = abi.encode(orderParamsList[i]);
}
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bytes memory result = bookManager.lock(address(this), lockData);
(ids) = abi.decode(result, (OrderId[]));
}
function take(
TakeOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable checkDeadline(deadline) permitERC20(permitParamsList) {
uint256 length = orderParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.TAKE;
paramsDataList[i] = abi.encode(orderParamsList[i]);
}
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bookManager.lock(address(this), lockData);
}
function spend(
SpendOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable checkDeadline(deadline) permitERC20(permitParamsList) {
uint256 length = orderParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.SPEND;
paramsDataList[i] = abi.encode(orderParamsList[i]);
}
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bookManager.lock(address(this), lockData);
}
function claim(
ClaimOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC721PermitParams[] calldata permitParamsList,
uint64 deadline
) external checkDeadline(deadline) {
_permitERC721(permitParamsList);
uint256 length = orderParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.CLAIM;
paramsDataList[i] = abi.encode(orderParamsList[i]);
}
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bookManager.lock(address(this), lockData);
}
function cancel(
CancelOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC721PermitParams[] calldata permitParamsList,
uint64 deadline
) external checkDeadline(deadline) {
_permitERC721(permitParamsList);
uint256 length = orderParamsList.length;
Action[] memory actionList = new Action[](length);
bytes[] memory paramsDataList = new bytes[](length);
for (uint256 i = 0; i < length; ++i) {
actionList[i] = Action.CANCEL;
paramsDataList[i] = abi.encode(orderParamsList[i]);
}
bytes memory lockData = abi.encode(msg.sender, actionList, paramsDataList, tokensToSettle);
bookManager.lock(address(this), lockData);
}
function _open(OpenBookParams memory params) internal {
bookManager.open(params.key, params.hookData);
}
function _make(MakeOrderParams memory params) internal returns (OrderId id) {
IBookManager.BookKey memory key = bookManager.getBookKey(params.id);
uint256 quoteAmount = params.quoteAmount;
if (key.makerPolicy.usesQuote()) {
quoteAmount = key.makerPolicy.calculateOriginalAmount(quoteAmount, false);
}
uint64 unit = (quoteAmount / key.unitSize).toUint64();
if (unit > 0) {
(id,) = bookManager.make(
IBookManager.MakeParams({key: key, tick: params.tick, unit: unit, provider: address(0)}),
params.hookData
);
}
return id;
}
function _limit(LimitOrderParams memory params) internal returns (OrderId id) {
(bool isQuoteRemained, uint256 spentQuoteAmount) = _spend(
SpendOrderParams({
id: params.takeBookId,
limitPrice: params.limitPrice,
baseAmount: params.quoteAmount,
minQuoteAmount: 0,
hookData: params.takeHookData
})
);
params.quoteAmount -= spentQuoteAmount;
if (isQuoteRemained) {
id = _make(
MakeOrderParams({
id: params.makeBookId,
quoteAmount: params.quoteAmount,
tick: params.tick,
hookData: params.makeHookData
})
);
}
}
function _take(TakeOrderParams memory params)
internal
returns (uint256 takenQuoteAmount, uint256 spentBaseAmount)
{
IBookManager.BookKey memory key = bookManager.getBookKey(params.id);
while (params.quoteAmount > takenQuoteAmount && !bookManager.isEmpty(params.id)) {
Tick tick = bookManager.getHighest(params.id);
if (params.limitPrice > tick.toPrice()) break;
uint256 maxAmount;
unchecked {
if (key.takerPolicy.usesQuote()) {
maxAmount = key.takerPolicy.calculateOriginalAmount(params.quoteAmount - takenQuoteAmount, true);
} else {
maxAmount = params.quoteAmount - takenQuoteAmount;
}
}
maxAmount = maxAmount.divide(key.unitSize, true);
if (maxAmount == 0) break;
(uint256 quoteAmount, uint256 baseAmount) = bookManager.take(
IBookManager.TakeParams({key: key, tick: tick, maxUnit: maxAmount.toUint64()}), params.hookData
);
if (quoteAmount == 0) break;
takenQuoteAmount += quoteAmount;
spentBaseAmount += baseAmount;
}
if (params.maxBaseAmount < spentBaseAmount) revert ControllerSlippage();
}
function _spend(SpendOrderParams memory params) internal returns (bool isBaseRemained, uint256 spentBaseAmount) {
uint256 takenQuoteAmount;
IBookManager.BookKey memory key = bookManager.getBookKey(params.id);
while (spentBaseAmount < params.baseAmount) {
if (bookManager.isEmpty(params.id)) {
isBaseRemained = true;
break;
}
Tick tick = bookManager.getHighest(params.id);
if (params.limitPrice > tick.toPrice()) {
isBaseRemained = true;
break;
}
uint256 maxAmount;
unchecked {
if (key.takerPolicy.usesQuote()) {
maxAmount = params.baseAmount - spentBaseAmount;
} else {
maxAmount = key.takerPolicy.calculateOriginalAmount(params.baseAmount - spentBaseAmount, false);
}
}
maxAmount = tick.baseToQuote(maxAmount, false) / key.unitSize;
if (maxAmount == 0) break;
(uint256 quoteAmount, uint256 baseAmount) = bookManager.take(
IBookManager.TakeParams({key: key, tick: tick, maxUnit: maxAmount.toUint64()}), params.hookData
);
if (baseAmount == 0) break;
takenQuoteAmount += quoteAmount;
spentBaseAmount += baseAmount;
}
if (params.minQuoteAmount > takenQuoteAmount) revert ControllerSlippage();
}
function _claim(ClaimOrderParams memory params) internal {
bookManager.claim(params.id, params.hookData);
}
function _cancel(CancelOrderParams memory params) internal {
IBookManager.BookKey memory key = bookManager.getBookKey(params.id.getBookId());
try bookManager.cancel(
IBookManager.CancelParams({id: params.id, toUnit: (params.leftQuoteAmount / key.unitSize).toUint64()}),
params.hookData
) {} catch {}
}
function _settleTokens(address user, address[] memory tokensToSettle) internal {
Currency native = CurrencyLibrary.NATIVE;
int256 currencyDelta = bookManager.getCurrencyDelta(address(this), native);
if (currencyDelta < 0) {
native.transfer(address(bookManager), uint256(-currencyDelta));
bookManager.settle(native);
}
currencyDelta = bookManager.getCurrencyDelta(address(this), native);
if (currencyDelta > 0) {
bookManager.withdraw(native, user, uint256(currencyDelta));
}
uint256 length = tokensToSettle.length;
for (uint256 i = 0; i < length; ++i) {
Currency currency = Currency.wrap(tokensToSettle[i]);
currencyDelta = bookManager.getCurrencyDelta(address(this), currency);
if (currencyDelta < 0) {
IERC20(tokensToSettle[i]).safeTransferFrom(user, address(bookManager), uint256(-currencyDelta));
bookManager.settle(currency);
}
currencyDelta = bookManager.getCurrencyDelta(address(this), currency);
if (currencyDelta > 0) {
bookManager.withdraw(Currency.wrap(tokensToSettle[i]), user, uint256(currencyDelta));
}
uint256 balance = IERC20(tokensToSettle[i]).balanceOf(address(this));
if (balance > 0) {
IERC20(tokensToSettle[i]).transfer(user, balance);
}
}
if (address(this).balance > 0) native.transfer(user, address(this).balance);
}
function _permitERC20(ERC20PermitParams[] calldata permitParamsList) internal {
for (uint256 i = 0; i < permitParamsList.length; ++i) {
ERC20PermitParams memory permitParams = permitParamsList[i];
if (permitParams.signature.deadline > 0) {
try IERC20Permit(permitParams.token).permit(
msg.sender,
address(this),
permitParams.permitAmount,
permitParams.signature.deadline,
permitParams.signature.v,
permitParams.signature.r,
permitParams.signature.s
) {} catch {}
}
}
}
function _permitERC721(ERC721PermitParams[] calldata permitParamsList) internal {
for (uint256 i = 0; i < permitParamsList.length; ++i) {
PermitSignature memory signature = permitParamsList[i].signature;
if (signature.deadline > 0) {
try IERC721Permit(address(bookManager)).permit(
address(this),
permitParamsList[i].tokenId,
signature.deadline,
signature.v,
signature.r,
signature.s
) {} catch {}
}
}
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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/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) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.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 {
using Address for address;
/**
* @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.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev 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).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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.0.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.0.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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
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.
*/
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();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/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) {
/// @solidity memory-safe-assembly
assembly {
u := iszero(iszero(b))
}
}
}// 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;
import {OrderId} from "core/libraries/OrderId.sol";
import {BookId} from "core/libraries/BookId.sol";
import {Tick} from "core/libraries/Tick.sol";
import {IBookManager} from "core/interfaces/IBookManager.sol";
/**
* @title IController
* @notice Interface for the controller contract
*/
interface IController {
// Error messages
error InvalidAccess();
error InvalidLength();
error Deadline();
error ControllerSlippage();
error InvalidAction();
/**
* @notice Enum for the different actions that can be performed
*/
enum Action {
OPEN,
MAKE,
LIMIT,
TAKE,
SPEND,
CLAIM,
CANCEL
}
/**
* @notice Struct for the parameters of the ERC20 permit
*/
struct ERC20PermitParams {
address token;
uint256 permitAmount;
PermitSignature signature;
}
/**
* @notice Struct for the parameters of the ERC721 permit
*/
struct ERC721PermitParams {
uint256 tokenId;
PermitSignature signature;
}
/**
* @notice Struct for the signature of the permit
*/
struct PermitSignature {
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
/**
* @notice Struct for the parameters of the open book action
*/
struct OpenBookParams {
IBookManager.BookKey key;
bytes hookData;
}
/**
* @notice Struct for the parameters of the make order action
*/
struct MakeOrderParams {
BookId id;
Tick tick;
uint256 quoteAmount;
bytes hookData;
}
/**
* @notice Struct for the parameters of the limit order action
*/
struct LimitOrderParams {
BookId takeBookId;
BookId makeBookId;
uint256 limitPrice;
Tick tick;
uint256 quoteAmount;
bytes takeHookData;
bytes makeHookData;
}
/**
* @notice Struct for the parameters of the take order action
*/
struct TakeOrderParams {
BookId id;
uint256 limitPrice;
uint256 quoteAmount;
uint256 maxBaseAmount;
bytes hookData;
}
/**
* @notice Struct for the parameters of the spend order action
*/
struct SpendOrderParams {
BookId id;
uint256 limitPrice;
uint256 baseAmount;
uint256 minQuoteAmount;
bytes hookData;
}
/**
* @notice Struct for the parameters of the claim order action
*/
struct ClaimOrderParams {
OrderId id;
bytes hookData;
}
/**
* @notice Struct for the parameters of the cancel order action
*/
struct CancelOrderParams {
OrderId id;
uint256 leftQuoteAmount;
bytes hookData;
}
/**
* @notice Returns the book manager
* @return The instance of the book manager
*/
function bookManager() external view returns (IBookManager);
/**
* @notice Opens a book
* @param openBookParamsList The parameters of the open book action
* @param deadline The deadline for the action
*/
function open(OpenBookParams[] calldata openBookParamsList, uint64 deadline) external;
/**
* @notice Returns the depth of a book
* @param id The id of the book
* @param tick The tick of the book
* @return The depth of the book in quote amount
*/
function getDepth(BookId id, Tick tick) external view returns (uint256);
/**
* @notice Returns the highest price of a book
* @param id The id of the book
* @return The highest price of the book with 2**96 precision
*/
function getHighestPrice(BookId id) external view returns (uint256);
/**
* @notice Returns the details of an order
* @param orderId The id of the order
* @return provider The provider of the order
* @return price The price of the order with 2**96 precision
* @return openAmount The open quote amount of the order
* @return claimableAmount The claimable base amount of the order
*/
function getOrder(OrderId orderId)
external
view
returns (address provider, uint256 price, uint256 openAmount, uint256 claimableAmount);
/**
* @notice Converts a price to a tick
* @param price The price to convert
* @return The tick
*/
function fromPrice(uint256 price) external pure returns (Tick);
/**
* @notice Converts a tick to a price
* @param tick The tick to convert
* @return The price with 2**96 precision
*/
function toPrice(Tick tick) external pure returns (uint256);
/**
* @notice Executes a list of actions
* @dev IMPORTANT: The caller must provide `tokensToSettle` to receive appropriate tokens after execution.
* @param actionList The list of actions to execute
* @param paramsDataList The parameters of the actions
* @param tokensToSettle The tokens to settle
* @param erc20PermitParamsList The parameters of the ERC20 permits
* @param erc721PermitParamsList The parameters of the ERC721 permits
* @param deadline The deadline for the actions
* @return ids The ids of the orders
*/
function execute(
Action[] calldata actionList,
bytes[] calldata paramsDataList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata erc20PermitParamsList,
ERC721PermitParams[] calldata erc721PermitParamsList,
uint64 deadline
) external payable returns (OrderId[] memory ids);
/**
* @notice Makes a list of orders
* @dev IMPORTANT: The caller must provide `tokensToSettle` to receive appropriate tokens after execution.
* @param orderParamsList The list of actions to make
* @param tokensToSettle The tokens to settle
* @param permitParamsList The parameters of the permits
* @param deadline The deadline for the actions
* @return ids The ids of the orders
*/
function make(
MakeOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable returns (OrderId[] memory ids);
/**
* @notice Takes a list of orders
* @dev IMPORTANT: The caller must provide `tokensToSettle` to receive appropriate tokens after execution.
* @param orderParamsList The list of actions to take
* @param tokensToSettle The tokens to settle
* @param permitParamsList The parameters of the permits
* @param deadline The deadline for the actions
*/
function take(
TakeOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable;
/**
* @notice Spends to take a list of orders
* @dev IMPORTANT: The caller must provide `tokensToSettle` to receive appropriate tokens after execution.
* @param orderParamsList The list of actions to spend
* @param tokensToSettle The tokens to settle
* @param permitParamsList The parameters of the permits
* @param deadline The deadline for the actions
*/
function spend(
SpendOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC20PermitParams[] calldata permitParamsList,
uint64 deadline
) external payable;
/**
* @notice Claims a list of orders
* @dev IMPORTANT: The caller must provide `tokensToSettle` to receive appropriate tokens after execution.
* @param orderParamsList The list of actions to claim
* @param tokensToSettle The tokens to settle
* @param permitParamsList The parameters of the permits
* @param deadline The deadline for the actions
*/
function claim(
ClaimOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC721PermitParams[] calldata permitParamsList,
uint64 deadline
) external;
/**
* @notice Cancels a list of orders
* @dev IMPORTANT: The caller must provide `tokensToSettle` to receive appropriate tokens after execution.
* @param orderParamsList The list of actions to cancel
* @param tokensToSettle The tokens to settle
* @param permitParamsList The parameters of the permits
* @param deadline The deadline for the actions
*/
function cancel(
CancelOrderParams[] calldata orderParamsList,
address[] calldata tokensToSettle,
ERC721PermitParams[] calldata permitParamsList,
uint64 deadline
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.24;
abstract contract ReentrancyGuard {
// uint256(keccak256("ReentrancyGuard")) - 1
uint256 internal constant REENTRANCY_GUARD_SLOT = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4;
error ReentrancyGuardReentrantCall();
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
assembly {
// Any calls to nonReentrant after this point will fail
tstore(REENTRANCY_GUARD_SLOT, 1)
}
}
function _nonReentrantAfter() private {
assembly {
tstore(REENTRANCY_GUARD_SLOT, 0)
}
}
function _reentrancyGuardEntered() internal view returns (bool isEntered) {
assembly {
isEntered := tload(REENTRANCY_GUARD_SLOT)
}
}
}{
"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":"address","name":"bookManager_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"ControllerSlippage","type":"error"},{"inputs":[],"name":"Deadline","type":"error"},{"inputs":[],"name":"ERC20TransferFailed","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAccess","type":"error"},{"inputs":[],"name":"InvalidAction","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"InvalidTick","type":"error"},{"inputs":[],"name":"NativeTransferFailed","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":"bookManager","outputs":[{"internalType":"contract IBookManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"OrderId","name":"id","type":"uint256"},{"internalType":"uint256","name":"leftQuoteAmount","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"internalType":"struct IController.CancelOrderParams[]","name":"orderParamsList","type":"tuple[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC721PermitParams[]","name":"permitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"OrderId","name":"id","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"internalType":"struct IController.ClaimOrderParams[]","name":"orderParamsList","type":"tuple[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC721PermitParams[]","name":"permitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IController.Action[]","name":"actionList","type":"uint8[]"},{"internalType":"bytes[]","name":"paramsDataList","type":"bytes[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC20PermitParams[]","name":"erc20PermitParamsList","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC721PermitParams[]","name":"erc721PermitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"execute","outputs":[{"internalType":"OrderId[]","name":"ids","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"fromPrice","outputs":[{"internalType":"Tick","name":"","type":"int24"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"BookId","name":"id","type":"uint192"},{"internalType":"Tick","name":"tick","type":"int24"}],"name":"getDepth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"BookId","name":"id","type":"uint192"}],"name":"getHighestPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"OrderId","name":"orderId","type":"uint256"}],"name":"getOrder","outputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"openAmount","type":"uint256"},{"internalType":"uint256","name":"claimableAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"BookId","name":"takeBookId","type":"uint192"},{"internalType":"BookId","name":"makeBookId","type":"uint192"},{"internalType":"uint256","name":"limitPrice","type":"uint256"},{"internalType":"Tick","name":"tick","type":"int24"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"bytes","name":"takeHookData","type":"bytes"},{"internalType":"bytes","name":"makeHookData","type":"bytes"}],"internalType":"struct IController.LimitOrderParams[]","name":"orderParamsList","type":"tuple[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC20PermitParams[]","name":"permitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"limit","outputs":[{"internalType":"OrderId[]","name":"ids","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"lockAcquired","outputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"BookId","name":"id","type":"uint192"},{"internalType":"Tick","name":"tick","type":"int24"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"internalType":"struct IController.MakeOrderParams[]","name":"orderParamsList","type":"tuple[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC20PermitParams[]","name":"permitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"make","outputs":[{"internalType":"OrderId[]","name":"ids","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"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":"key","type":"tuple"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"internalType":"struct IController.OpenBookParams[]","name":"openBookParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"open","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"BookId","name":"id","type":"uint192"},{"internalType":"uint256","name":"limitPrice","type":"uint256"},{"internalType":"uint256","name":"baseAmount","type":"uint256"},{"internalType":"uint256","name":"minQuoteAmount","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"internalType":"struct IController.SpendOrderParams[]","name":"orderParamsList","type":"tuple[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC20PermitParams[]","name":"permitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"spend","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"BookId","name":"id","type":"uint192"},{"internalType":"uint256","name":"limitPrice","type":"uint256"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"uint256","name":"maxBaseAmount","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"internalType":"struct IController.TakeOrderParams[]","name":"orderParamsList","type":"tuple[]"},{"internalType":"address[]","name":"tokensToSettle","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"permitAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IController.PermitSignature","name":"signature","type":"tuple"}],"internalType":"struct IController.ERC20PermitParams[]","name":"permitParamsList","type":"tuple[]"},{"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"take","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"Tick","name":"tick","type":"int24"}],"name":"toPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a0604052348015600e575f80fd5b50604051615815380380615815833981016040819052602b91603b565b6001600160a01b03166080526066565b5f60208284031215604a575f80fd5b81516001600160a01b0381168114605f575f80fd5b9392505050565b60805161568661018f5f395f818161017a015281816104e6015281816105850152818161076901528181610a5801528181610ae901528181610bb301528181610d0e01528181610f81015281816111e6015281816115a3015281816117eb015281816118ae01528181611d0a01528181611d9201528181611e7201528181612025015281816120c80152818161216301528181612270015281816123be01528181612457015281816124f9015281816126160152818161276701528181612826015281816128c701528181612941015281816129fd01528181612af801528181612b7001528181612bc801528181612c5901528181612d1301528181612dbd01528181612e3801528181612eb201528181612f4301528181612fb801526135b301526156865ff3fe6080604052600436106100e7575f3560e01c80637658ab0511610087578063a183a10411610057578063a183a10414610295578063c0e8e89a146102b4578063d09ef241146102c7578063fe81574614610310575f80fd5b80637658ab05146102245780637d773110146102445780638feb85b714610257578063a04c796b14610276575f80fd5b80633f322bc9116100c25780633f322bc91461016957806341a8bb88146101b4578063483f9f2f146101d35780635083585814610205575f80fd5b806309ae2c13146100f257806315c7afb4146101075780631ae45a121461013c575f80fd5b366100ee57005b5f80fd5b610105610100366004613e30565b610323565b005b348015610112575f80fd5b50610126610121366004613fe1565b610570565b604051610133919061409b565b60405180910390f35b348015610147575f80fd5b5061015b6101563660046140c1565b610a2c565b604051908152602001610133565b348015610174575f80fd5b5061019c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610133565b3480156101bf575f80fd5b5061015b6101ce3660046140f5565b610ac9565b3480156101de575f80fd5b506101f26101ed36600461412c565b610c36565b60405160029190910b8152602001610133565b348015610210575f80fd5b5061015b61021f366004614143565b610c40565b61023761023236600461419e565b610c4d565b6040516101339190614292565b610237610252366004613e30565b610dba565b348015610262575f80fd5b506101056102713660046142d5565b611025565b348015610281575f80fd5b506101056102903660046142d5565b61126e565b3480156102a0575f80fd5b506101056102af366004614356565b6113ed565b6101056102c2366004613e30565b611628565b3480156102d2575f80fd5b506102e66102e136600461412c565b6117a9565b604080516001600160a01b0390951685526020850193909352918301526060820152608001610133565b61023761031e366004613e30565b6119ca565b80806001600160401b031642111561034e5760405163637910d560e11b815260040160405180910390fd5b838361035a8282611b4d565b885f816001600160401b0381111561037457610374613ee9565b60405190808252806020026020018201604052801561039d578160200160208202803683370190505b5090505f826001600160401b038111156103b9576103b9613ee9565b6040519080825280602002602001820160405280156103ec57816020015b60608152602001906001900390816103d75790505b5090505f5b838110156104a457600383828151811061040d5761040d6143a8565b60200260200101906006811115610426576104266143bc565b90816006811115610439576104396143bc565b9052508d8d8281811061044e5761044e6143a8565b905060200281019061046091906143d0565b60405160200161047091906144b9565b604051602081830303815290604052828281518110610491576104916143a8565b60209081029190910101526001016103f1565b505f3383838e8e6040516020016104bf9594939291906145c4565b60408051601f19818403018152908290526313942f3360e31b825291506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ca179989061051d903090859060040161460c565b5f604051808303815f875af1158015610538573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261055f919081019061467a565b505050505050505050505050505050565b606061057a611c54565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415806105bb57506001600160a01b0383163014155b156105f2576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f808580602001905181019061060a91906147c3565b8251939750919550935091505f816001600160401b0381111561062f5761062f613ee9565b604051908082528060200260200182016040528015610658578160200160208202803683370190505b5090505f805b838110156109e7575f878281518110610679576106796143a8565b602002602001015190505f6006811115610695576106956143bc565b8160068111156106a7576106a76143bc565b036106e6576106e18783815181106106c1576106c16143a8565b60200260200101518060200190518101906106dc9190614976565b611cd3565b6109de565b60018160068111156106fa576106fa6143bc565b036107f2575f610735888481518110610715576107156143a8565b60200260200101518060200190518101906107309190614a05565b611d6d565b905080156107ec576040516323b872dd60e01b81523060048201526001600160a01b038b81166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064015f604051808303815f87803b1580156107aa575f80fd5b505af11580156107bc573d5f803e3d5ffd5b50505050808585806107cd90614ab0565b9650815181106107df576107df6143a8565b6020026020010181815250505b506109de565b6002816006811115610806576108066143bc565b03610841575f610735888481518110610821576108216143a8565b602002602001015180602001905181019061083c9190614ac8565b611f46565b6003816006811115610855576108556143bc565b036108965761088f87838151811061086f5761086f6143a8565b602002602001015180602001905181019061088a9190614c2e565b611ffe565b50506109de565b60048160068111156108aa576108aa6143bc565b036108e45761088f8783815181106108c4576108c46143a8565b60200260200101518060200190518101906108df9190614c2e565b61238d565b60058160068111156108f8576108f86143bc565b03610948575f878381518110610910576109106143a8565b602002602001015180602001905181019061092b9190614c5f565b905061093a815f01518b612734565b156107ec576107ec81612890565b600681600681111561095c5761095c6143bc565b036109ac575f878381518110610974576109746143a8565b602002602001015180602001905181019061098f9190614cb5565b905061099e815f01518b612734565b156107ec576107ec8161293e565b6040517f4a7f394f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060010161065e565b506109f28785612ad0565b80825281604051602001610a069190614292565b604051602081830303815290604052975050505050505050610a266131d9565b92915050565b60405163cdc92f2d60e01b81526001600160c01b03821660048201525f90610a26906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cdc92f2d90602401602060405180830381865afa158015610a9d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac19190614d30565b60020b6131fe565b604051639b22917d60e01b81526001600160c01b03831660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015610b36573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b5a9190614d4b565b602001516040517f41a8bb880000000000000000000000000000000000000000000000000000000081526001600160c01b0385166004820152600284900b60248201526001600160401b03909116906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906341a8bb8890604401602060405180830381865afa158015610bf8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c1c9190614d65565b6001600160401b0316610c2f9190614d80565b9392505050565b5f610a26826134bc565b5f610a268260020b6131fe565b606081806001600160401b0316421115610c7a5760405163637910d560e11b815260040160405180910390fd5b8b8a14610cb3576040517f947d5a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cbd8787611b4d565b610cc78585613571565b5f338e8e8e8e8e8e604051602001610ce59796959493929190614d97565b60408051601f19818403018152908290526313942f3360e31b825291505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ca1799890610d45903090869060040161460c565b5f604051808303815f875af1158015610d60573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d87919081019061467a565b905080515f14610da85780806020019051810190610da59190614e66565b93505b5050509b9a5050505050505050505050565b606081806001600160401b0316421115610de75760405163637910d560e11b815260040160405180910390fd5b8484610df38282611b4d565b895f816001600160401b03811115610e0d57610e0d613ee9565b604051908082528060200260200182016040528015610e36578160200160208202803683370190505b5090505f826001600160401b03811115610e5257610e52613ee9565b604051908082528060200260200182016040528015610e8557816020015b6060815260200190600190039081610e705790505b5090505f5b83811015610f3d576001838281518110610ea657610ea66143a8565b60200260200101906006811115610ebf57610ebf6143bc565b90816006811115610ed257610ed26143bc565b9052508e8e82818110610ee757610ee76143a8565b9050602002810190610ef99190614ef1565b604051602001610f099190614f05565b604051602081830303815290604052828281518110610f2a57610f2a6143a8565b6020908102919091010152600101610e8a565b505f3383838f8f604051602001610f589594939291906145c4565b60408051601f19818403018152908290526313942f3360e31b825291505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ca1799890610fb8903090869060040161460c565b5f604051808303815f875af1158015610fd3573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ffa919081019061467a565b9050808060200190518101906110109190614e66565b98505050505050505050979650505050505050565b80806001600160401b03164211156110505760405163637910d560e11b815260040160405180910390fd5b61105a8484613571565b865f816001600160401b0381111561107457611074613ee9565b60405190808252806020026020018201604052801561109d578160200160208202803683370190505b5090505f826001600160401b038111156110b9576110b9613ee9565b6040519080825280602002602001820160405280156110ec57816020015b60608152602001906001900390816110d75790505b5090505f5b838110156111a457600583828151811061110d5761110d6143a8565b60200260200101906006811115611126576111266143bc565b90816006811115611139576111396143bc565b9052508b8b8281811061114e5761114e6143a8565b90506020028101906111609190614f68565b6040516020016111709190614f7c565b604051602081830303815290604052828281518110611191576111916143a8565b60209081029190910101526001016110f1565b505f3383838c8c6040516020016111bf9594939291906145c4565b60408051601f19818403018152908290526313942f3360e31b825291506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ca179989061121d903090859060040161460c565b5f604051808303815f875af1158015611238573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261125f919081019061467a565b50505050505050505050505050565b80806001600160401b03164211156112995760405163637910d560e11b815260040160405180910390fd5b6112a38484613571565b865f816001600160401b038111156112bd576112bd613ee9565b6040519080825280602002602001820160405280156112e6578160200160208202803683370190505b5090505f826001600160401b0381111561130257611302613ee9565b60405190808252806020026020018201604052801561133557816020015b60608152602001906001900390816113205790505b5090505f5b838110156111a4576006838281518110611356576113566143a8565b6020026020010190600681111561136f5761136f6143bc565b90816006811115611382576113826143bc565b9052508b8b82818110611397576113976143a8565b90506020028101906113a99190614fa9565b6040516020016113b99190614fbd565b6040516020818303038152906040528282815181106113da576113da6143a8565b602090810291909101015260010161133a565b80806001600160401b03164211156114185760405163637910d560e11b815260040160405180910390fd5b825f816001600160401b0381111561143257611432613ee9565b60405190808252806020026020018201604052801561145b578160200160208202803683370190505b5090505f826001600160401b0381111561147757611477613ee9565b6040519080825280602002602001820160405280156114aa57816020015b60608152602001906001900390816114955790505b5090505f5b83811015611561575f8382815181106114ca576114ca6143a8565b602002602001019060068111156114e3576114e36143bc565b908160068111156114f6576114f66143bc565b90525087878281811061150b5761150b6143a8565b905060200281019061151d9190614ff4565b60405160200161152d919061501e565b60405160208183030381529060405282828151811061154e5761154e6143a8565b60209081029190910101526001016114af565b5060605f3384848460405160200161157c94939291906150e5565b60408051601f19818403018152908290526313942f3360e31b825291506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ca17998906115da903090859060040161460c565b5f604051808303815f875af11580156115f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261161c919081019061467a565b50505050505050505050565b80806001600160401b03164211156116535760405163637910d560e11b815260040160405180910390fd5b838361165f8282611b4d565b885f816001600160401b0381111561167957611679613ee9565b6040519080825280602002602001820160405280156116a2578160200160208202803683370190505b5090505f826001600160401b038111156116be576116be613ee9565b6040519080825280602002602001820160405280156116f157816020015b60608152602001906001900390816116dc5790505b5090505f5b838110156104a4576004838281518110611712576117126143a8565b6020026020010190600681111561172b5761172b6143bc565b9081600681111561173e5761173e6143bc565b9052508d8d82818110611753576117536143a8565b905060200281019061176591906143d0565b60405160200161177591906144b9565b604051602081830303815290604052828281518110611796576117966143a8565b60209081029190910101526001016116f6565b5f8080808080604087901c62ffffff602889901c16604051639b22917d60e01b81526001600160c01b038316600482015291935091505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639b22917d9060240160c060405180830381865afa158015611830573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118549190614d4b565b60208101519091506001600160401b0316611872600284900b6131fe565b6040517fd09ef241000000000000000000000000000000000000000000000000000000008152600481018b90529097505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d09ef24190602401606060405180830381865afa1580156118f3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119179190615163565b80516020820151909a50909150611937906001600160401b031683614d80565b60608401516040830151919850906119689061195c906001600160401b031685614d80565b600287900b905f6136a0565b96506119798162ffffff1660171c90565b6119bd575f61198e62ffffff831689836136ca565b90505f81136119af576119a0816151b5565b6119aa90896151eb565b6119b9565b6119b981896151fe565b9750505b5050505050509193509193565b606081806001600160401b03164211156119f75760405163637910d560e11b815260040160405180910390fd5b8484611a038282611b4d565b895f816001600160401b03811115611a1d57611a1d613ee9565b604051908082528060200260200182016040528015611a46578160200160208202803683370190505b5090505f826001600160401b03811115611a6257611a62613ee9565b604051908082528060200260200182016040528015611a9557816020015b6060815260200190600190039081611a805790505b5090505f5b83811015610f3d576002838281518110611ab657611ab66143a8565b60200260200101906006811115611acf57611acf6143bc565b90816006811115611ae257611ae26143bc565b9052508e8e82818110611af757611af76143a8565b9050602002810190611b099190614ff4565b604051602001611b199190615211565b604051602081830303815290604052828281518110611b3a57611b3a6143a8565b6020908102919091010152600101611a9a565b5f5b81811015611c4f575f838383818110611b6a57611b6a6143a8565b905060c00201803603810190611b80919061531b565b60408101515190915015611c465780516020808301516040808501518051938101518183015160609092015192517fd505accf0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810194909452606484019490945260ff909316608483015260a482019290925260c48101919091526001600160a01b039091169063d505accf9060e4015f604051808303815f87803b158015611c33575f80fd5b505af1925050508015611c44575060015b505b50600101611b4f565b505050565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45c15611cad576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45d565b805160208201516040517ffefc7c510000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263fefc7c5192611d3d92600401615357565b5f604051808303815f87803b158015611d54575f80fd5b505af1158015611d66573d5f803e3d5ffd5b5050505050565b8051604051639b22917d60e01b81526001600160c01b0390911660048201525f9081907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015611ddf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e039190614d4b565b90505f83604001519050611e20826060015162ffffff1660171c90565b15611e3d576060820151611e3a9062ffffff16825f61374a565b90505b5f611e5f83602001516001600160401b031683611e5a91906153e2565b613797565b90506001600160401b03811615611f3e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631dbef4886040518060800160405280868152602001886020015160020b8152602001846001600160401b031681526020015f6001600160a01b031681525087606001516040518363ffffffff1660e01b8152600401611efb929190615401565b60408051808303815f875af1158015611f16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f3a91906154af565b5093505b505050919050565b5f805f611f906040518060a00160405280865f01516001600160c01b0316815260200186604001518152602001866080015181526020015f81526020018660a0015181525061238d565b915091508084608001818151611fa691906151fe565b9052508115611ff757611ff4604051806080016040528086602001516001600160c01b03168152602001866060015160020b8152602001866080015181526020018660c00151815250611d6d565b92505b5050919050565b8051604051639b22917d60e01b81526001600160c01b0390911660048201525f90819081907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639b22917d9060240160c060405180830381865afa158015612072573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120969190614d4b565b90505b82846040015111801561213b5750835160405163fcc8fc9b60e01b81526001600160c01b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063fcc8fc9b90602401602060405180830381865afa158015612115573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213991906154d1565b155b1561236257835160405163cdc92f2d60e01b81526001600160c01b0390911660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cdc92f2d90602401602060405180830381865afa1580156121b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121d49190614d30565b90506121e28160020b6131fe565b856020015111156121f35750612362565b5f6122078360a0015162ffffff1660171c90565b15612238576122318587604001510360018560a0015162ffffff1661374a9092919063ffffffff16565b9050612242565b8486604001510390505b60208301516001600160401b03168082049082061515600116019050805f0361226c575050612362565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633b9500b060405180606001604052808881526020018760020b81526020016122c087613797565b6001600160401b03168152508a608001516040518363ffffffff1660e01b81526004016122ee9291906154f0565b60408051808303815f875af1158015612309573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061232d91906154af565b91509150815f036123415750505050612362565b61234b82886151eb565b965061235781876151eb565b955050505050612099565b818460600151101561238757604051630f271b5560e41b815260040160405180910390fd5b50915091565b8051604051639b22917d60e01b81526001600160c01b0390911660048201525f908190819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639b22917d9060240160c060405180830381865afa158015612403573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124279190614d4b565b90505b846040015183101561270857845160405163fcc8fc9b60e01b81526001600160c01b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063fcc8fc9b90602401602060405180830381865afa1580156124a4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124c891906154d1565b156124d65760019350612708565b845160405163cdc92f2d60e01b81526001600160c01b0390911660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cdc92f2d90602401602060405180830381865afa158015612546573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061256a9190614d30565b90506125788160020b6131fe565b8660200151111561258d576001945050612708565b5f6125a18360a0015162ffffff1660171c90565b156125b4578487604001510390506125db565b6125d8858860400151035f8560a0015162ffffff1661374a9092919063ffffffff16565b90505b60208301516001600160401b03166125f8600284900b835f6137ee565b61260291906153e2565b9050805f03612612575050612708565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633b9500b060405180606001604052808881526020018760020b815260200161266687613797565b6001600160401b03168152508b608001516040518363ffffffff1660e01b81526004016126949291906154f0565b60408051808303815f875af11580156126af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126d391906154af565b91509150805f036126e75750505050612708565b6126f182876151eb565b95506126fd81886151eb565b96505050505061242a565b818560600151111561272d57604051630f271b5560e41b815260040160405180910390fd5b5050915091565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018390525f9083907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa9250505080156127d2575060408051601f3d908101601f191682019092526127cf9181019061558a565b60015b6127df575f915050610a26565b6040517f2f584a6d0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301528581166024830152604482018490527f00000000000000000000000000000000000000000000000000000000000000001690632f584a6d906064015f6040518083038186803b158015612866575f80fd5b505afa925050508015612877575060015b612885575f92505050610a26565b600192505050610a26565b805160208201516040517f38926b6d0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926338926b6d926128fa926004016155a5565b6020604051808303815f875af1158015612916573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061293a91906155bd565b5050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639b22917d61297b845f015160401c90565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160c01b03909116600482015260240160c060405180830381865afa1580156129d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129f99190614d4b565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166314d6a9eb6040518060400160405280855f01518152602001612a5e85602001516001600160401b03168760200151611e5a91906153e2565b6001600160401b031681525084604001516040518363ffffffff1660e01b8152600401612a8c9291906155d4565b6020604051808303815f875af1925050508015612ac6575060408051601f3d908101601f19168201909252612ac3918101906155bd565b60015b1561293a57505050565b60405163258473db60e21b81523060048201525f602482018190529081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639611cf6c90604401602060405180830381865afa158015612b3d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b6191906155bd565b90505f811215612c3457612ba97f0000000000000000000000000000000000000000000000000000000000000000612b98836151b5565b6001600160a01b0385169190613830565b604051636a256b2960e01b81526001600160a01b0383811660048301527f00000000000000000000000000000000000000000000000000000000000000001690636a256b29906024016020604051808303815f875af1158015612c0e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c3291906155bd565b505b60405163258473db60e21b81523060048201526001600160a01b0383811660248301527f00000000000000000000000000000000000000000000000000000000000000001690639611cf6c90604401602060405180830381865afa158015612c9e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc291906155bd565b90505f811315612d6b576040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528581166024830152604482018390527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed12906064015f604051808303815f87803b158015612d54575f80fd5b505af1158015612d66573d5f803e3d5ffd5b505050505b82515f5b818110156131be575f858281518110612d8a57612d8a6143a8565b602090810291909101015160405163258473db60e21b81523060048201526001600160a01b0380831660248301529192507f000000000000000000000000000000000000000000000000000000000000000090911690639611cf6c90604401602060405180830381865afa158015612e04573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e2891906155bd565b93505f841215612f1e57612e93877f0000000000000000000000000000000000000000000000000000000000000000612e60876151b5565b898681518110612e7257612e726143a8565b60200260200101516001600160a01b03166138ff909392919063ffffffff16565b604051636a256b2960e01b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690636a256b29906024016020604051808303815f875af1158015612ef8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f1c91906155bd565b505b60405163258473db60e21b81523060048201526001600160a01b0382811660248301527f00000000000000000000000000000000000000000000000000000000000000001690639611cf6c90604401602060405180830381865afa158015612f88573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fac91906155bd565b93505f84131561307e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d9caed12878481518110612ff757612ff76143a8565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039182166004820152908a166024820152604481018790526064015f604051808303815f87803b158015613067575f80fd5b505af1158015613079573d5f803e3d5ffd5b505050505b5f868381518110613091576130916143a8565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156130f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061311c91906155bd565b905080156131b457868381518110613136576131366143a8565b602090810291909101015160405163a9059cbb60e01b81526001600160a01b038a81166004830152602482018490529091169063a9059cbb906044016020604051808303815f875af115801561318e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131b291906154d1565b505b5050600101612d6f565b504715611d6657611d666001600160a01b0384168647613830565b5f7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45d565b5f6132088261396e565b815f600282900b811361321b5781613224565b61322482615600565b62ffffff8116915060011615613248576bfff97272373d413259a469909250613259565b6c0100000000000000000000000092505b60028116156132785760606bfff2e50f5f656932ef12357c8402901c92505b60048116156132975760606bffe5caca7e10e4e61c3624ea8402901c92505b60088116156132b65760606bffcb9843d60f6159c9db58838402901c92505b60108116156132d55760606bff973b41fa98c081472e68968402901c92505b60208116156132f45760606bff2ea16466c96a3843ec78b38402901c92505b60408116156133135760606bfe5dee046a99a2a811c461f18402901c92505b60808116156133325760606bfcbe86c7900a88aedcffc83b8402901c92505b6101008116156133525760606bf987a7253ac413176f2b074c8402901c92505b6102008116156133725760606bf3392b0822b70005940c7a398402901c92505b6104008116156133925760606be7159475a2c29b7443b29c7f8402901c92505b6108008116156133b25760606bd097f3bdfd2022b8845ad8f78402901c92505b6110008116156133d25760606ba9f746462d870fdf8a65dc1f8402901c92505b6120008116156133f25760606b70d869a156d2a1b890bb3df68402901c92505b6140008116156134125760606b31be135f97d08fd9812315058402901c92505b6180008116156134325760606b09aa508b5b7a84e1c677de548402901c92505b620100008116156134525760606a5d6af8dedb81196699c3298402901c92505b62020000811615613471576060692216e584f5fa1ea926048402901c92505b6204000081161561348e57606067048a170391f7dc428402901c92505b5f8260020b1315611ff757611ff48378010000000000000000000000000000000000000000000000006153e2565b5f81750c6c1313451aab317fb9b67e11777e9a5a6ccdb2ebae8111806134e4575062149bbb81105b1561351a576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f700100000000000000000000000000000000613536856139cd565b6527107fff7434028161354b5761354b6153ce565b05905083613558826131fe565b1115613568575f1901915061356b565b91505b50919050565b5f5b81811015611c4f575f83838381811061358e5761358e6143a8565b905060a002016020018036038101906135a79190615620565b805190915015613697577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637ac2ff7b308686868181106135f3576135f36143a8565b865160208801516040808a015160608b015191517fffffffff0000000000000000000000000000000000000000000000000000000060e08b901b1681526001600160a01b03909816600489015260a090940295909501356024870152604486019190915260ff16606485015260848401525060a482015260c4015f604051808303815f87803b158015613684575f80fd5b505af1925050508015613695575060015b505b50600101613573565b5f6136c2606084901b6136b58660020b6131fe565b8082061515851691040190565b949350505050565b5f6207a11f19627fffff851601600281900b821282816136ec57825f036136ee565b825b62ffffff1690505f6137276137038389614d80565b620f424088613719578581830615151691040190565b808206151586151691040190565b90508261373c57613737816151b5565b61373e565b805b98975050505050505050565b5f6207a11f19627fffff85160181831561376457815f0391505b81620f424001905061378d620f42408661377e9190614d80565b82810615158616908390040190565b9695505050505050565b5f6001600160401b038211156137ea57604080517f6dfcc6500000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044015b60405180910390fd5b5090565b5f6136c26137fe8560020b6131fe565b6138089085614d80565b6bffffffffffffffffffffffff8116151584166c010000000000000000000000009091040190565b5f6001600160a01b038416613885575f805f8085875af1905080613880576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138f9565b60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f5114161716915050806138f9576040517ff27f64e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b1790526138f9908590613be6565b6207ffff600282900b1380613993575061398a6207ffff615600565b60020b8160020b125b156139ca576040517fce8ef7fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b6fffffffffffffffffffffffffffffffff811160071b81811c6001600160401b031060061b1781811c63ffffffff1060051b1781811c61ffff1060041b1781811c60ff1060031b175f8213613a2957631615e6385f526004601cfd5b7103782dace9d90000000000000000000000007ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be84841c1c601f161a90911891821b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d6c8c3f38e95a6b1ff2ab1c3b343619018302821d6d02384773bdf1ac5676facced60901901830290911d6cb9a025d814b29c212b8b1a07cd19019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029290037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302919091010590565b5f613bfa6001600160a01b03841683613c60565b905080515f14158015613c1e575080806020019051810190613c1c91906154d1565b155b15611c4f576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016137e1565b6060610c2f83835f845f80856001600160a01b03168486604051613c84919061563a565b5f6040518083038185875af1925050503d805f8114613cbe576040519150601f19603f3d011682016040523d82523d5f602084013e613cc3565b606091505b509150915061378d868383606082613ce357613cde82613d43565b610c2f565b8151158015613cfa57506001600160a01b0384163b155b15613d3c576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016137e1565b5080610c2f565b805115613d535780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8083601f840112613d95575f80fd5b5081356001600160401b03811115613dab575f80fd5b6020830191508360208260051b8501011115613dc5575f80fd5b9250929050565b5f8083601f840112613ddc575f80fd5b5081356001600160401b03811115613df2575f80fd5b60208301915083602060c083028501011115613dc5575f80fd5b6001600160401b03811681146139ca575f80fd5b8035613e2b81613e0c565b919050565b5f805f805f805f6080888a031215613e46575f80fd5b87356001600160401b0380821115613e5c575f80fd5b613e688b838c01613d85565b909950975060208a0135915080821115613e80575f80fd5b613e8c8b838c01613d85565b909750955060408a0135915080821115613ea4575f80fd5b50613eb18a828b01613dcc565b9094509250506060880135613ec581613e0c565b8091505092959891949750929550565b6001600160a01b03811681146139ca575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b0381118282101715613f1f57613f1f613ee9565b60405290565b604051608081016001600160401b0381118282101715613f1f57613f1f613ee9565b60405160e081016001600160401b0381118282101715613f1f57613f1f613ee9565b604051606081016001600160401b0381118282101715613f1f57613f1f613ee9565b604051601f8201601f191681016001600160401b0381118282101715613fb357613fb3613ee9565b604052919050565b5f6001600160401b03821115613fd357613fd3613ee9565b50601f01601f191660200190565b5f8060408385031215613ff2575f80fd5b8235613ffd81613ed5565b915060208301356001600160401b03811115614017575f80fd5b8301601f81018513614027575f80fd5b803561403a61403582613fbb565b613f8b565b81815286602083850101111561404e575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610c2f602083018461406d565b6001600160c01b03811681146139ca575f80fd5b5f602082840312156140d1575f80fd5b8135610c2f816140ad565b8060020b81146139ca575f80fd5b8035613e2b816140dc565b5f8060408385031215614106575f80fd5b8235614111816140ad565b91506020830135614121816140dc565b809150509250929050565b5f6020828403121561413c575f80fd5b5035919050565b5f60208284031215614153575f80fd5b8135610c2f816140dc565b5f8083601f84011261416e575f80fd5b5081356001600160401b03811115614184575f80fd5b60208301915083602060a083028501011115613dc5575f80fd5b5f805f805f805f805f805f60c08c8e0312156141b8575f80fd5b6001600160401b03808d3511156141cd575f80fd5b6141da8e8e358f01613d85565b909c509a5060208d01358110156141ef575f80fd5b6141ff8e60208f01358f01613d85565b909a50985060408d0135811015614214575f80fd5b6142248e60408f01358f01613d85565b909850965060608d0135811015614239575f80fd5b6142498e60608f01358f01613dcc565b909650945060808d013581101561425e575f80fd5b5061426f8d60808e01358e0161415e565b909350915061428060a08d01613e20565b90509295989b509295989b9093969950565b602080825282518282018190525f9190848201906040850190845b818110156142c9578351835292840192918401916001016142ad565b50909695505050505050565b5f805f805f805f6080888a0312156142eb575f80fd5b87356001600160401b0380821115614301575f80fd5b61430d8b838c01613d85565b909950975060208a0135915080821115614325575f80fd5b6143318b838c01613d85565b909750955060408a0135915080821115614349575f80fd5b50613eb18a828b0161415e565b5f805f60408486031215614368575f80fd5b83356001600160401b0381111561437d575f80fd5b61438986828701613d85565b909450925050602084013561439d81613e0c565b809150509250925092565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b5f8235609e198336030181126143e4575f80fd5b9190910192915050565b5f808335601e19843603018112614403575f80fd5b83016020810192503590506001600160401b03811115614421575f80fd5b803603821315613dc5575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8135614463816140ad565b6001600160c01b03811684525060208201356020840152604082013560408401526060820135606084015261449b60808301836143ee565b60a060808601526144b060a08601828461442f565b95945050505050565b602081525f610c2f6020830184614457565b5f600782106144e857634e487b7160e01b5f52602160045260245ffd5b50815260200190565b5f815180845260208085019450602084015f5b83811015614525576145178783516144cb565b965090820190600101614504565b509495945050505050565b5f8282518085526020808601955060208260051b840101602086015f5b8481101561457b57601f1986840301895261456983835161406d565b9884019892509083019060010161454d565b5090979650505050505050565b8183525f60208085019450825f5b858110156145255781356145a981613ed5565b6001600160a01b031687529582019590820190600101614596565b6001600160a01b0386168152608060208201525f6145e560808301876144f1565b82810360408401526145f78187614530565b9050828103606084015261373e818587614588565b6001600160a01b0383168152604060208201525f6136c2604083018461406d565b5f82601f83011261463c575f80fd5b815161464a61403582613fbb565b81815284602083860101111561465e575f80fd5b8160208501602083015e5f918101602001919091529392505050565b5f6020828403121561468a575f80fd5b81516001600160401b0381111561469f575f80fd5b6136c28482850161462d565b5f6001600160401b038211156146c3576146c3613ee9565b5060051b60200190565b600781106139ca575f80fd5b5f82601f8301126146e8575f80fd5b815160206146f8614035836146ab565b82815260059290921b84018101918181019086841115614716575f80fd5b8286015b848110156147535780516001600160401b03811115614737575f80fd5b6147458986838b010161462d565b84525091830191830161471a565b509695505050505050565b5f82601f83011261476d575f80fd5b8151602061477d614035836146ab565b8083825260208201915060208460051b87010193508684111561479e575f80fd5b602086015b848110156147535780516147b681613ed5565b83529183019183016147a3565b5f805f80608085870312156147d6575f80fd5b84516147e181613ed5565b809450506020808601516001600160401b03808211156147ff575f80fd5b818801915088601f830112614812575f80fd5b8151614820614035826146ab565b81815260059190911b8301840190848101908b83111561483e575f80fd5b938501935b82851015614865578451614856816146cd565b82529385019390850190614843565b60408b0151909850945050508083111561487d575f80fd5b61488989848a016146d9565b9450606088015192508083111561489e575f80fd5b50506148ac8782880161475e565b91505092959194509250565b62ffffff811681146139ca575f80fd5b5f60c082840312156148d8575f80fd5b60405160c081018181106001600160401b03821117156148fa576148fa613ee9565b8060405250809150825161490d81613ed5565b8152602083015161491d81613e0c565b6020820152604083015161493081613ed5565b60408201526060830151614943816148b8565b6060820152608083015161495681613ed5565b608082015260a0830151614969816148b8565b60a0919091015292915050565b5f60208284031215614986575f80fd5b81516001600160401b038082111561499c575f80fd5b9083019060e082860312156149af575f80fd5b6149b7613efd565b6149c186846148c8565b815260c0830151828111156149d4575f80fd5b6149e08782860161462d565b60208301525095945050505050565b8051613e2b816140ad565b8051613e2b816140dc565b5f60208284031215614a15575f80fd5b81516001600160401b0380821115614a2b575f80fd5b9083019060808286031215614a3e575f80fd5b614a46613f25565b8251614a51816140ad565b81526020830151614a61816140dc565b602082015260408381015190820152606083015182811115614a81575f80fd5b614a8d8782860161462d565b60608301525095945050505050565b634e487b7160e01b5f52601160045260245ffd5b5f60018201614ac157614ac1614a9c565b5060010190565b5f60208284031215614ad8575f80fd5b81516001600160401b0380821115614aee575f80fd5b9083019060e08286031215614b01575f80fd5b614b09613f47565b614b12836149ef565b8152614b20602084016149ef565b602082015260408301516040820152614b3b606084016149fa565b60608201526080830151608082015260a083015182811115614b5b575f80fd5b614b678782860161462d565b60a08301525060c083015182811115614b7e575f80fd5b614b8a8782860161462d565b60c08301525095945050505050565b5f60a08284031215614ba9575f80fd5b60405160a081016001600160401b038282108183111715614bcc57614bcc613ee9565b8160405282935084519150614be0826140ad565b8183526020850151602084015260408501516040840152606085015160608401526080850151915080821115614c14575f80fd5b50614c218582860161462d565b6080830152505092915050565b5f60208284031215614c3e575f80fd5b81516001600160401b03811115614c53575f80fd5b6136c284828501614b99565b5f60208284031215614c6f575f80fd5b81516001600160401b0380821115614c85575f80fd5b9083019060408286031215614c98575f80fd5b614ca0613efd565b825181526020830151828111156149d4575f80fd5b5f60208284031215614cc5575f80fd5b81516001600160401b0380821115614cdb575f80fd5b9083019060608286031215614cee575f80fd5b614cf6613f69565b8251815260208301516020820152604083015182811115614d15575f80fd5b614d218782860161462d565b60408301525095945050505050565b5f60208284031215614d40575f80fd5b8151610c2f816140dc565b5f60c08284031215614d5b575f80fd5b610c2f83836148c8565b5f60208284031215614d75575f80fd5b8151610c2f81613e0c565b8082028115828204841417610a2657610a26614a9c565b6001600160a01b0388168152608060208083018290529082018790525f90889060a08401835b8a811015614de9578335614dd0816146cd565b614dda83826144cb565b94840194925050600101614dbd565b5084810360408601528781528181019250600588901b81018201895f5b8a811015614e4057838303601f19018652614e21828d6143ee565b614e2c85828461442f565b978701979450505090840190600101614e06565b50508581036060870152614e5581888a614588565b9d9c50505050505050505050505050565b5f6020808385031215614e77575f80fd5b82516001600160401b03811115614e8c575f80fd5b8301601f81018513614e9c575f80fd5b8051614eaa614035826146ab565b81815260059190911b82018301908381019087831115614ec8575f80fd5b928401925b82841015614ee657835182529284019290840190614ecd565b979650505050505050565b5f8235607e198336030181126143e4575f80fd5b602081525f8235614f15816140ad565b6001600160c01b0381166020840152506020830135614f33816140dc565b8060020b60408401525060408301356060830152614f5460608401846143ee565b6080808501526144b060a08501828461442f565b5f8235603e198336030181126143e4575f80fd5b60208152813560208201525f614f9560208401846143ee565b6040808501526144b060608501828461442f565b5f8235605e198336030181126143e4575f80fd5b6020815281356020820152602082013560408201525f614fe060408401846143ee565b6060808501526144b060808501828461442f565b5f823560de198336030181126143e4575f80fd5b8035613e2b816148b8565b8035613e2b81613ed5565b602081525f823561502e81613ed5565b6001600160a01b0380821660208501526020850135915061504e82613e0c565b6001600160401b03821660408501526040850135915061506d82613ed5565b16606083810191909152830135615083816148b8565b62ffffff811660808401525061509b60808401615013565b6001600160a01b03811660a0840152506150b760a08401615008565b62ffffff811660c0840152506150d060c08401846143ee565b60e0808501526144b06101008501828461442f565b5f6001600160a01b03808716835260206080602085015261510960808501886144f1565b848103604086015261511b8188614530565b8581036060870152865180825260208089019350909101905f5b81811015615153578351861683529284019291840191600101615135565b50909a9950505050505050505050565b5f60608284031215615173575f80fd5b61517b613f69565b825161518681613ed5565b8152602083015161519681613e0c565b602082015260408301516151a981613e0c565b60408201529392505050565b5f7f800000000000000000000000000000000000000000000000000000000000000082036151e5576151e5614a9c565b505f0390565b80820180821115610a2657610a26614a9c565b81810381811115610a2657610a26614a9c565b602081525f8235615221816140ad565b6001600160c01b038116602084015250602083013561523f816140ad565b6001600160c01b03811660408401525060408301356060830152615265606084016140ea565b615274608084018260020b9052565b50608083013560a083015261528c60a08401846143ee565b60e060c08501526152a26101008501828461442f565b9150506152b260c08501856143ee565b848303601f190160e086015261378d83828461442f565b5f608082840312156152d9575f80fd5b6152e1613f25565b905081358152602082013560ff811681146152fa575f80fd5b80602083015250604082013560408201526060820135606082015292915050565b5f60c0828403121561532b575f80fd5b615333613f69565b823561533e81613ed5565b8152602083810135908201526151a984604085016152c9565b6153b981846001600160a01b038082511683526001600160401b036020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b60e060c08201525f6136c260e083018461406d565b634e487b7160e01b5f52601260045260245ffd5b5f826153fc57634e487b7160e01b5f52601260045260245ffd5b500490565b5f6101406154688386516001600160a01b038082511683526001600160401b036020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b602085015160020b60c08401526001600160401b0360408601511660e08401526001600160a01b03606086015116610100840152806101208401526144b08184018561406d565b5f80604083850312156154c0575f80fd5b505080516020909101519092909150565b5f602082840312156154e1575f80fd5b81518015158114610c2f575f80fd5b5f6101206155578386516001600160a01b038082511683526001600160401b036020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b602085015160020b60c08401526001600160401b0360408601511660e0840152806101008401526144b08184018561406d565b5f6020828403121561559a575f80fd5b8151610c2f81613ed5565b828152604060208201525f6136c2604083018461406d565b5f602082840312156155cd575f80fd5b5051919050565b825181526001600160401b036020840151166020820152606060408201525f6136c2606083018461406d565b5f8160020b627fffff19810361561857615618614a9c565b5f0392915050565b5f60808284031215615630575f80fd5b610c2f83836152c9565b5f82518060208501845e5f92019182525091905056fea2646970667358221220813d6c16471676c72a924a49e4565436a793d186a3a4ad314c6f893e8ecbf0f864736f6c63430008190033000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636
Deployed Bytecode
0x6080604052600436106100e7575f3560e01c80637658ab0511610087578063a183a10411610057578063a183a10414610295578063c0e8e89a146102b4578063d09ef241146102c7578063fe81574614610310575f80fd5b80637658ab05146102245780637d773110146102445780638feb85b714610257578063a04c796b14610276575f80fd5b80633f322bc9116100c25780633f322bc91461016957806341a8bb88146101b4578063483f9f2f146101d35780635083585814610205575f80fd5b806309ae2c13146100f257806315c7afb4146101075780631ae45a121461013c575f80fd5b366100ee57005b5f80fd5b610105610100366004613e30565b610323565b005b348015610112575f80fd5b50610126610121366004613fe1565b610570565b604051610133919061409b565b60405180910390f35b348015610147575f80fd5b5061015b6101563660046140c1565b610a2c565b604051908152602001610133565b348015610174575f80fd5b5061019c7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63681565b6040516001600160a01b039091168152602001610133565b3480156101bf575f80fd5b5061015b6101ce3660046140f5565b610ac9565b3480156101de575f80fd5b506101f26101ed36600461412c565b610c36565b60405160029190910b8152602001610133565b348015610210575f80fd5b5061015b61021f366004614143565b610c40565b61023761023236600461419e565b610c4d565b6040516101339190614292565b610237610252366004613e30565b610dba565b348015610262575f80fd5b506101056102713660046142d5565b611025565b348015610281575f80fd5b506101056102903660046142d5565b61126e565b3480156102a0575f80fd5b506101056102af366004614356565b6113ed565b6101056102c2366004613e30565b611628565b3480156102d2575f80fd5b506102e66102e136600461412c565b6117a9565b604080516001600160a01b0390951685526020850193909352918301526060820152608001610133565b61023761031e366004613e30565b6119ca565b80806001600160401b031642111561034e5760405163637910d560e11b815260040160405180910390fd5b838361035a8282611b4d565b885f816001600160401b0381111561037457610374613ee9565b60405190808252806020026020018201604052801561039d578160200160208202803683370190505b5090505f826001600160401b038111156103b9576103b9613ee9565b6040519080825280602002602001820160405280156103ec57816020015b60608152602001906001900390816103d75790505b5090505f5b838110156104a457600383828151811061040d5761040d6143a8565b60200260200101906006811115610426576104266143bc565b90816006811115610439576104396143bc565b9052508d8d8281811061044e5761044e6143a8565b905060200281019061046091906143d0565b60405160200161047091906144b9565b604051602081830303815290604052828281518110610491576104916143a8565b60209081029190910101526001016103f1565b505f3383838e8e6040516020016104bf9594939291906145c4565b60408051601f19818403018152908290526313942f3360e31b825291506001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639ca179989061051d903090859060040161460c565b5f604051808303815f875af1158015610538573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261055f919081019061467a565b505050505050505050505050505050565b606061057a611c54565b336001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636161415806105bb57506001600160a01b0383163014155b156105f2576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f808580602001905181019061060a91906147c3565b8251939750919550935091505f816001600160401b0381111561062f5761062f613ee9565b604051908082528060200260200182016040528015610658578160200160208202803683370190505b5090505f805b838110156109e7575f878281518110610679576106796143a8565b602002602001015190505f6006811115610695576106956143bc565b8160068111156106a7576106a76143bc565b036106e6576106e18783815181106106c1576106c16143a8565b60200260200101518060200190518101906106dc9190614976565b611cd3565b6109de565b60018160068111156106fa576106fa6143bc565b036107f2575f610735888481518110610715576107156143a8565b60200260200101518060200190518101906107309190614a05565b611d6d565b905080156107ec576040516323b872dd60e01b81523060048201526001600160a01b038b81166024830152604482018390527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63616906323b872dd906064015f604051808303815f87803b1580156107aa575f80fd5b505af11580156107bc573d5f803e3d5ffd5b50505050808585806107cd90614ab0565b9650815181106107df576107df6143a8565b6020026020010181815250505b506109de565b6002816006811115610806576108066143bc565b03610841575f610735888481518110610821576108216143a8565b602002602001015180602001905181019061083c9190614ac8565b611f46565b6003816006811115610855576108556143bc565b036108965761088f87838151811061086f5761086f6143a8565b602002602001015180602001905181019061088a9190614c2e565b611ffe565b50506109de565b60048160068111156108aa576108aa6143bc565b036108e45761088f8783815181106108c4576108c46143a8565b60200260200101518060200190518101906108df9190614c2e565b61238d565b60058160068111156108f8576108f86143bc565b03610948575f878381518110610910576109106143a8565b602002602001015180602001905181019061092b9190614c5f565b905061093a815f01518b612734565b156107ec576107ec81612890565b600681600681111561095c5761095c6143bc565b036109ac575f878381518110610974576109746143a8565b602002602001015180602001905181019061098f9190614cb5565b905061099e815f01518b612734565b156107ec576107ec8161293e565b6040517f4a7f394f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060010161065e565b506109f28785612ad0565b80825281604051602001610a069190614292565b604051602081830303815290604052975050505050505050610a266131d9565b92915050565b60405163cdc92f2d60e01b81526001600160c01b03821660048201525f90610a26906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169063cdc92f2d90602401602060405180830381865afa158015610a9d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac19190614d30565b60020b6131fe565b604051639b22917d60e01b81526001600160c01b03831660048201525f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015610b36573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b5a9190614d4b565b602001516040517f41a8bb880000000000000000000000000000000000000000000000000000000081526001600160c01b0385166004820152600284900b60248201526001600160401b03909116906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63616906341a8bb8890604401602060405180830381865afa158015610bf8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c1c9190614d65565b6001600160401b0316610c2f9190614d80565b9392505050565b5f610a26826134bc565b5f610a268260020b6131fe565b606081806001600160401b0316421115610c7a5760405163637910d560e11b815260040160405180910390fd5b8b8a14610cb3576040517f947d5a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cbd8787611b4d565b610cc78585613571565b5f338e8e8e8e8e8e604051602001610ce59796959493929190614d97565b60408051601f19818403018152908290526313942f3360e31b825291505f906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639ca1799890610d45903090869060040161460c565b5f604051808303815f875af1158015610d60573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d87919081019061467a565b905080515f14610da85780806020019051810190610da59190614e66565b93505b5050509b9a5050505050505050505050565b606081806001600160401b0316421115610de75760405163637910d560e11b815260040160405180910390fd5b8484610df38282611b4d565b895f816001600160401b03811115610e0d57610e0d613ee9565b604051908082528060200260200182016040528015610e36578160200160208202803683370190505b5090505f826001600160401b03811115610e5257610e52613ee9565b604051908082528060200260200182016040528015610e8557816020015b6060815260200190600190039081610e705790505b5090505f5b83811015610f3d576001838281518110610ea657610ea66143a8565b60200260200101906006811115610ebf57610ebf6143bc565b90816006811115610ed257610ed26143bc565b9052508e8e82818110610ee757610ee76143a8565b9050602002810190610ef99190614ef1565b604051602001610f099190614f05565b604051602081830303815290604052828281518110610f2a57610f2a6143a8565b6020908102919091010152600101610e8a565b505f3383838f8f604051602001610f589594939291906145c4565b60408051601f19818403018152908290526313942f3360e31b825291505f906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639ca1799890610fb8903090869060040161460c565b5f604051808303815f875af1158015610fd3573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ffa919081019061467a565b9050808060200190518101906110109190614e66565b98505050505050505050979650505050505050565b80806001600160401b03164211156110505760405163637910d560e11b815260040160405180910390fd5b61105a8484613571565b865f816001600160401b0381111561107457611074613ee9565b60405190808252806020026020018201604052801561109d578160200160208202803683370190505b5090505f826001600160401b038111156110b9576110b9613ee9565b6040519080825280602002602001820160405280156110ec57816020015b60608152602001906001900390816110d75790505b5090505f5b838110156111a457600583828151811061110d5761110d6143a8565b60200260200101906006811115611126576111266143bc565b90816006811115611139576111396143bc565b9052508b8b8281811061114e5761114e6143a8565b90506020028101906111609190614f68565b6040516020016111709190614f7c565b604051602081830303815290604052828281518110611191576111916143a8565b60209081029190910101526001016110f1565b505f3383838c8c6040516020016111bf9594939291906145c4565b60408051601f19818403018152908290526313942f3360e31b825291506001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639ca179989061121d903090859060040161460c565b5f604051808303815f875af1158015611238573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261125f919081019061467a565b50505050505050505050505050565b80806001600160401b03164211156112995760405163637910d560e11b815260040160405180910390fd5b6112a38484613571565b865f816001600160401b038111156112bd576112bd613ee9565b6040519080825280602002602001820160405280156112e6578160200160208202803683370190505b5090505f826001600160401b0381111561130257611302613ee9565b60405190808252806020026020018201604052801561133557816020015b60608152602001906001900390816113205790505b5090505f5b838110156111a4576006838281518110611356576113566143a8565b6020026020010190600681111561136f5761136f6143bc565b90816006811115611382576113826143bc565b9052508b8b82818110611397576113976143a8565b90506020028101906113a99190614fa9565b6040516020016113b99190614fbd565b6040516020818303038152906040528282815181106113da576113da6143a8565b602090810291909101015260010161133a565b80806001600160401b03164211156114185760405163637910d560e11b815260040160405180910390fd5b825f816001600160401b0381111561143257611432613ee9565b60405190808252806020026020018201604052801561145b578160200160208202803683370190505b5090505f826001600160401b0381111561147757611477613ee9565b6040519080825280602002602001820160405280156114aa57816020015b60608152602001906001900390816114955790505b5090505f5b83811015611561575f8382815181106114ca576114ca6143a8565b602002602001019060068111156114e3576114e36143bc565b908160068111156114f6576114f66143bc565b90525087878281811061150b5761150b6143a8565b905060200281019061151d9190614ff4565b60405160200161152d919061501e565b60405160208183030381529060405282828151811061154e5761154e6143a8565b60209081029190910101526001016114af565b5060605f3384848460405160200161157c94939291906150e5565b60408051601f19818403018152908290526313942f3360e31b825291506001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639ca17998906115da903090859060040161460c565b5f604051808303815f875af11580156115f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261161c919081019061467a565b50505050505050505050565b80806001600160401b03164211156116535760405163637910d560e11b815260040160405180910390fd5b838361165f8282611b4d565b885f816001600160401b0381111561167957611679613ee9565b6040519080825280602002602001820160405280156116a2578160200160208202803683370190505b5090505f826001600160401b038111156116be576116be613ee9565b6040519080825280602002602001820160405280156116f157816020015b60608152602001906001900390816116dc5790505b5090505f5b838110156104a4576004838281518110611712576117126143a8565b6020026020010190600681111561172b5761172b6143bc565b9081600681111561173e5761173e6143bc565b9052508d8d82818110611753576117536143a8565b905060200281019061176591906143d0565b60405160200161177591906144b9565b604051602081830303815290604052828281518110611796576117966143a8565b60209081029190910101526001016116f6565b5f8080808080604087901c62ffffff602889901c16604051639b22917d60e01b81526001600160c01b038316600482015291935091505f906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639b22917d9060240160c060405180830381865afa158015611830573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118549190614d4b565b60208101519091506001600160401b0316611872600284900b6131fe565b6040517fd09ef241000000000000000000000000000000000000000000000000000000008152600481018b90529097505f906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169063d09ef24190602401606060405180830381865afa1580156118f3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119179190615163565b80516020820151909a50909150611937906001600160401b031683614d80565b60608401516040830151919850906119689061195c906001600160401b031685614d80565b600287900b905f6136a0565b96506119798162ffffff1660171c90565b6119bd575f61198e62ffffff831689836136ca565b90505f81136119af576119a0816151b5565b6119aa90896151eb565b6119b9565b6119b981896151fe565b9750505b5050505050509193509193565b606081806001600160401b03164211156119f75760405163637910d560e11b815260040160405180910390fd5b8484611a038282611b4d565b895f816001600160401b03811115611a1d57611a1d613ee9565b604051908082528060200260200182016040528015611a46578160200160208202803683370190505b5090505f826001600160401b03811115611a6257611a62613ee9565b604051908082528060200260200182016040528015611a9557816020015b6060815260200190600190039081611a805790505b5090505f5b83811015610f3d576002838281518110611ab657611ab66143a8565b60200260200101906006811115611acf57611acf6143bc565b90816006811115611ae257611ae26143bc565b9052508e8e82818110611af757611af76143a8565b9050602002810190611b099190614ff4565b604051602001611b199190615211565b604051602081830303815290604052828281518110611b3a57611b3a6143a8565b6020908102919091010152600101611a9a565b5f5b81811015611c4f575f838383818110611b6a57611b6a6143a8565b905060c00201803603810190611b80919061531b565b60408101515190915015611c465780516020808301516040808501518051938101518183015160609092015192517fd505accf0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810194909452606484019490945260ff909316608483015260a482019290925260c48101919091526001600160a01b039091169063d505accf9060e4015f604051808303815f87803b158015611c33575f80fd5b505af1925050508015611c44575060015b505b50600101611b4f565b505050565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45c15611cad576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45d565b805160208201516040517ffefc7c510000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169263fefc7c5192611d3d92600401615357565b5f604051808303815f87803b158015611d54575f80fd5b505af1158015611d66573d5f803e3d5ffd5b5050505050565b8051604051639b22917d60e01b81526001600160c01b0390911660048201525f9081907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015611ddf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e039190614d4b565b90505f83604001519050611e20826060015162ffffff1660171c90565b15611e3d576060820151611e3a9062ffffff16825f61374a565b90505b5f611e5f83602001516001600160401b031683611e5a91906153e2565b613797565b90506001600160401b03811615611f3e577f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316631dbef4886040518060800160405280868152602001886020015160020b8152602001846001600160401b031681526020015f6001600160a01b031681525087606001516040518363ffffffff1660e01b8152600401611efb929190615401565b60408051808303815f875af1158015611f16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f3a91906154af565b5093505b505050919050565b5f805f611f906040518060a00160405280865f01516001600160c01b0316815260200186604001518152602001866080015181526020015f81526020018660a0015181525061238d565b915091508084608001818151611fa691906151fe565b9052508115611ff757611ff4604051806080016040528086602001516001600160c01b03168152602001866060015160020b8152602001866080015181526020018660c00151815250611d6d565b92505b5050919050565b8051604051639b22917d60e01b81526001600160c01b0390911660048201525f90819081907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690639b22917d9060240160c060405180830381865afa158015612072573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120969190614d4b565b90505b82846040015111801561213b5750835160405163fcc8fc9b60e01b81526001600160c01b0390911660048201527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b03169063fcc8fc9b90602401602060405180830381865afa158015612115573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213991906154d1565b155b1561236257835160405163cdc92f2d60e01b81526001600160c01b0390911660048201525f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b03169063cdc92f2d90602401602060405180830381865afa1580156121b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121d49190614d30565b90506121e28160020b6131fe565b856020015111156121f35750612362565b5f6122078360a0015162ffffff1660171c90565b15612238576122318587604001510360018560a0015162ffffff1661374a9092919063ffffffff16565b9050612242565b8486604001510390505b60208301516001600160401b03168082049082061515600116019050805f0361226c575050612362565b5f807f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316633b9500b060405180606001604052808881526020018760020b81526020016122c087613797565b6001600160401b03168152508a608001516040518363ffffffff1660e01b81526004016122ee9291906154f0565b60408051808303815f875af1158015612309573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061232d91906154af565b91509150815f036123415750505050612362565b61234b82886151eb565b965061235781876151eb565b955050505050612099565b818460600151101561238757604051630f271b5560e41b815260040160405180910390fd5b50915091565b8051604051639b22917d60e01b81526001600160c01b0390911660048201525f908190819081906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639b22917d9060240160c060405180830381865afa158015612403573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124279190614d4b565b90505b846040015183101561270857845160405163fcc8fc9b60e01b81526001600160c01b0390911660048201527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b03169063fcc8fc9b90602401602060405180830381865afa1580156124a4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124c891906154d1565b156124d65760019350612708565b845160405163cdc92f2d60e01b81526001600160c01b0390911660048201525f907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b03169063cdc92f2d90602401602060405180830381865afa158015612546573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061256a9190614d30565b90506125788160020b6131fe565b8660200151111561258d576001945050612708565b5f6125a18360a0015162ffffff1660171c90565b156125b4578487604001510390506125db565b6125d8858860400151035f8560a0015162ffffff1661374a9092919063ffffffff16565b90505b60208301516001600160401b03166125f8600284900b835f6137ee565b61260291906153e2565b9050805f03612612575050612708565b5f807f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316633b9500b060405180606001604052808881526020018760020b815260200161266687613797565b6001600160401b03168152508b608001516040518363ffffffff1660e01b81526004016126949291906154f0565b60408051808303815f875af11580156126af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126d391906154af565b91509150805f036126e75750505050612708565b6126f182876151eb565b95506126fd81886151eb565b96505050505061242a565b818560600151111561272d57604051630f271b5560e41b815260040160405180910390fd5b5050915091565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018390525f9083907f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031690636352211e90602401602060405180830381865afa9250505080156127d2575060408051601f3d908101601f191682019092526127cf9181019061558a565b60015b6127df575f915050610a26565b6040517f2f584a6d0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301528581166024830152604482018490527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690632f584a6d906064015f6040518083038186803b158015612866575f80fd5b505afa925050508015612877575060015b612885575f92505050610a26565b600192505050610a26565b805160208201516040517f38926b6d0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63616926338926b6d926128fa926004016155a5565b6020604051808303815f875af1158015612916573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061293a91906155bd565b5050565b5f7f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316639b22917d61297b845f015160401c90565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160c01b03909116600482015260240160c060405180830381865afa1580156129d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129f99190614d4b565b90507f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b03166314d6a9eb6040518060400160405280855f01518152602001612a5e85602001516001600160401b03168760200151611e5a91906153e2565b6001600160401b031681525084604001516040518363ffffffff1660e01b8152600401612a8c9291906155d4565b6020604051808303815f875af1925050508015612ac6575060408051601f3d908101601f19168201909252612ac3918101906155bd565b60015b1561293a57505050565b60405163258473db60e21b81523060048201525f602482018190529081906001600160a01b037f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639611cf6c90604401602060405180830381865afa158015612b3d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b6191906155bd565b90505f811215612c3457612ba97f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636612b98836151b5565b6001600160a01b0385169190613830565b604051636a256b2960e01b81526001600160a01b0383811660048301527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690636a256b29906024016020604051808303815f875af1158015612c0e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c3291906155bd565b505b60405163258473db60e21b81523060048201526001600160a01b0383811660248301527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639611cf6c90604401602060405180830381865afa158015612c9e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc291906155bd565b90505f811315612d6b576040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528581166024830152604482018390527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636169063d9caed12906064015f604051808303815f87803b158015612d54575f80fd5b505af1158015612d66573d5f803e3d5ffd5b505050505b82515f5b818110156131be575f858281518110612d8a57612d8a6143a8565b602090810291909101015160405163258473db60e21b81523060048201526001600160a01b0380831660248301529192507f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c63690911690639611cf6c90604401602060405180830381865afa158015612e04573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e2891906155bd565b93505f841215612f1e57612e93877f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636612e60876151b5565b898681518110612e7257612e726143a8565b60200260200101516001600160a01b03166138ff909392919063ffffffff16565b604051636a256b2960e01b81526001600160a01b0382811660048301527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690636a256b29906024016020604051808303815f875af1158015612ef8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f1c91906155bd565b505b60405163258473db60e21b81523060048201526001600160a01b0382811660248301527f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6361690639611cf6c90604401602060405180830381865afa158015612f88573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fac91906155bd565b93505f84131561307e577f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b031663d9caed12878481518110612ff757612ff76143a8565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039182166004820152908a166024820152604481018790526064015f604051808303815f87803b158015613067575f80fd5b505af1158015613079573d5f803e3d5ffd5b505050505b5f868381518110613091576130916143a8565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156130f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061311c91906155bd565b905080156131b457868381518110613136576131366143a8565b602090810291909101015160405163a9059cbb60e01b81526001600160a01b038a81166004830152602482018490529091169063a9059cbb906044016020604051808303815f875af115801561318e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131b291906154d1565b505b5050600101612d6f565b504715611d6657611d666001600160a01b0384168647613830565b5f7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45d565b5f6132088261396e565b815f600282900b811361321b5781613224565b61322482615600565b62ffffff8116915060011615613248576bfff97272373d413259a469909250613259565b6c0100000000000000000000000092505b60028116156132785760606bfff2e50f5f656932ef12357c8402901c92505b60048116156132975760606bffe5caca7e10e4e61c3624ea8402901c92505b60088116156132b65760606bffcb9843d60f6159c9db58838402901c92505b60108116156132d55760606bff973b41fa98c081472e68968402901c92505b60208116156132f45760606bff2ea16466c96a3843ec78b38402901c92505b60408116156133135760606bfe5dee046a99a2a811c461f18402901c92505b60808116156133325760606bfcbe86c7900a88aedcffc83b8402901c92505b6101008116156133525760606bf987a7253ac413176f2b074c8402901c92505b6102008116156133725760606bf3392b0822b70005940c7a398402901c92505b6104008116156133925760606be7159475a2c29b7443b29c7f8402901c92505b6108008116156133b25760606bd097f3bdfd2022b8845ad8f78402901c92505b6110008116156133d25760606ba9f746462d870fdf8a65dc1f8402901c92505b6120008116156133f25760606b70d869a156d2a1b890bb3df68402901c92505b6140008116156134125760606b31be135f97d08fd9812315058402901c92505b6180008116156134325760606b09aa508b5b7a84e1c677de548402901c92505b620100008116156134525760606a5d6af8dedb81196699c3298402901c92505b62020000811615613471576060692216e584f5fa1ea926048402901c92505b6204000081161561348e57606067048a170391f7dc428402901c92505b5f8260020b1315611ff757611ff48378010000000000000000000000000000000000000000000000006153e2565b5f81750c6c1313451aab317fb9b67e11777e9a5a6ccdb2ebae8111806134e4575062149bbb81105b1561351a576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f700100000000000000000000000000000000613536856139cd565b6527107fff7434028161354b5761354b6153ce565b05905083613558826131fe565b1115613568575f1901915061356b565b91505b50919050565b5f5b81811015611c4f575f83838381811061358e5761358e6143a8565b905060a002016020018036038101906135a79190615620565b805190915015613697577f000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c6366001600160a01b0316637ac2ff7b308686868181106135f3576135f36143a8565b865160208801516040808a015160608b015191517fffffffff0000000000000000000000000000000000000000000000000000000060e08b901b1681526001600160a01b03909816600489015260a090940295909501356024870152604486019190915260ff16606485015260848401525060a482015260c4015f604051808303815f87803b158015613684575f80fd5b505af1925050508015613695575060015b505b50600101613573565b5f6136c2606084901b6136b58660020b6131fe565b8082061515851691040190565b949350505050565b5f6207a11f19627fffff851601600281900b821282816136ec57825f036136ee565b825b62ffffff1690505f6137276137038389614d80565b620f424088613719578581830615151691040190565b808206151586151691040190565b90508261373c57613737816151b5565b61373e565b805b98975050505050505050565b5f6207a11f19627fffff85160181831561376457815f0391505b81620f424001905061378d620f42408661377e9190614d80565b82810615158616908390040190565b9695505050505050565b5f6001600160401b038211156137ea57604080517f6dfcc6500000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044015b60405180910390fd5b5090565b5f6136c26137fe8560020b6131fe565b6138089085614d80565b6bffffffffffffffffffffffff8116151584166c010000000000000000000000009091040190565b5f6001600160a01b038416613885575f805f8085875af1905080613880576040517ff4b3b1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138f9565b60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f5114161716915050806138f9576040517ff27f64e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b1790526138f9908590613be6565b6207ffff600282900b1380613993575061398a6207ffff615600565b60020b8160020b125b156139ca576040517fce8ef7fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b6fffffffffffffffffffffffffffffffff811160071b81811c6001600160401b031060061b1781811c63ffffffff1060051b1781811c61ffff1060041b1781811c60ff1060031b175f8213613a2957631615e6385f526004601cfd5b7103782dace9d90000000000000000000000007ff8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff6f8421084210842108cc6318c6db6d54be84841c1c601f161a90911891821b609f90811c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d6c8c3f38e95a6b1ff2ab1c3b343619018302821d6d02384773bdf1ac5676facced60901901830290911d6cb9a025d814b29c212b8b1a07cd19019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506029290037d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302919091010590565b5f613bfa6001600160a01b03841683613c60565b905080515f14158015613c1e575080806020019051810190613c1c91906154d1565b155b15611c4f576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016137e1565b6060610c2f83835f845f80856001600160a01b03168486604051613c84919061563a565b5f6040518083038185875af1925050503d805f8114613cbe576040519150601f19603f3d011682016040523d82523d5f602084013e613cc3565b606091505b509150915061378d868383606082613ce357613cde82613d43565b610c2f565b8151158015613cfa57506001600160a01b0384163b155b15613d3c576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016137e1565b5080610c2f565b805115613d535780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8083601f840112613d95575f80fd5b5081356001600160401b03811115613dab575f80fd5b6020830191508360208260051b8501011115613dc5575f80fd5b9250929050565b5f8083601f840112613ddc575f80fd5b5081356001600160401b03811115613df2575f80fd5b60208301915083602060c083028501011115613dc5575f80fd5b6001600160401b03811681146139ca575f80fd5b8035613e2b81613e0c565b919050565b5f805f805f805f6080888a031215613e46575f80fd5b87356001600160401b0380821115613e5c575f80fd5b613e688b838c01613d85565b909950975060208a0135915080821115613e80575f80fd5b613e8c8b838c01613d85565b909750955060408a0135915080821115613ea4575f80fd5b50613eb18a828b01613dcc565b9094509250506060880135613ec581613e0c565b8091505092959891949750929550565b6001600160a01b03811681146139ca575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b0381118282101715613f1f57613f1f613ee9565b60405290565b604051608081016001600160401b0381118282101715613f1f57613f1f613ee9565b60405160e081016001600160401b0381118282101715613f1f57613f1f613ee9565b604051606081016001600160401b0381118282101715613f1f57613f1f613ee9565b604051601f8201601f191681016001600160401b0381118282101715613fb357613fb3613ee9565b604052919050565b5f6001600160401b03821115613fd357613fd3613ee9565b50601f01601f191660200190565b5f8060408385031215613ff2575f80fd5b8235613ffd81613ed5565b915060208301356001600160401b03811115614017575f80fd5b8301601f81018513614027575f80fd5b803561403a61403582613fbb565b613f8b565b81815286602083850101111561404e575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610c2f602083018461406d565b6001600160c01b03811681146139ca575f80fd5b5f602082840312156140d1575f80fd5b8135610c2f816140ad565b8060020b81146139ca575f80fd5b8035613e2b816140dc565b5f8060408385031215614106575f80fd5b8235614111816140ad565b91506020830135614121816140dc565b809150509250929050565b5f6020828403121561413c575f80fd5b5035919050565b5f60208284031215614153575f80fd5b8135610c2f816140dc565b5f8083601f84011261416e575f80fd5b5081356001600160401b03811115614184575f80fd5b60208301915083602060a083028501011115613dc5575f80fd5b5f805f805f805f805f805f60c08c8e0312156141b8575f80fd5b6001600160401b03808d3511156141cd575f80fd5b6141da8e8e358f01613d85565b909c509a5060208d01358110156141ef575f80fd5b6141ff8e60208f01358f01613d85565b909a50985060408d0135811015614214575f80fd5b6142248e60408f01358f01613d85565b909850965060608d0135811015614239575f80fd5b6142498e60608f01358f01613dcc565b909650945060808d013581101561425e575f80fd5b5061426f8d60808e01358e0161415e565b909350915061428060a08d01613e20565b90509295989b509295989b9093969950565b602080825282518282018190525f9190848201906040850190845b818110156142c9578351835292840192918401916001016142ad565b50909695505050505050565b5f805f805f805f6080888a0312156142eb575f80fd5b87356001600160401b0380821115614301575f80fd5b61430d8b838c01613d85565b909950975060208a0135915080821115614325575f80fd5b6143318b838c01613d85565b909750955060408a0135915080821115614349575f80fd5b50613eb18a828b0161415e565b5f805f60408486031215614368575f80fd5b83356001600160401b0381111561437d575f80fd5b61438986828701613d85565b909450925050602084013561439d81613e0c565b809150509250925092565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b5f8235609e198336030181126143e4575f80fd5b9190910192915050565b5f808335601e19843603018112614403575f80fd5b83016020810192503590506001600160401b03811115614421575f80fd5b803603821315613dc5575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8135614463816140ad565b6001600160c01b03811684525060208201356020840152604082013560408401526060820135606084015261449b60808301836143ee565b60a060808601526144b060a08601828461442f565b95945050505050565b602081525f610c2f6020830184614457565b5f600782106144e857634e487b7160e01b5f52602160045260245ffd5b50815260200190565b5f815180845260208085019450602084015f5b83811015614525576145178783516144cb565b965090820190600101614504565b509495945050505050565b5f8282518085526020808601955060208260051b840101602086015f5b8481101561457b57601f1986840301895261456983835161406d565b9884019892509083019060010161454d565b5090979650505050505050565b8183525f60208085019450825f5b858110156145255781356145a981613ed5565b6001600160a01b031687529582019590820190600101614596565b6001600160a01b0386168152608060208201525f6145e560808301876144f1565b82810360408401526145f78187614530565b9050828103606084015261373e818587614588565b6001600160a01b0383168152604060208201525f6136c2604083018461406d565b5f82601f83011261463c575f80fd5b815161464a61403582613fbb565b81815284602083860101111561465e575f80fd5b8160208501602083015e5f918101602001919091529392505050565b5f6020828403121561468a575f80fd5b81516001600160401b0381111561469f575f80fd5b6136c28482850161462d565b5f6001600160401b038211156146c3576146c3613ee9565b5060051b60200190565b600781106139ca575f80fd5b5f82601f8301126146e8575f80fd5b815160206146f8614035836146ab565b82815260059290921b84018101918181019086841115614716575f80fd5b8286015b848110156147535780516001600160401b03811115614737575f80fd5b6147458986838b010161462d565b84525091830191830161471a565b509695505050505050565b5f82601f83011261476d575f80fd5b8151602061477d614035836146ab565b8083825260208201915060208460051b87010193508684111561479e575f80fd5b602086015b848110156147535780516147b681613ed5565b83529183019183016147a3565b5f805f80608085870312156147d6575f80fd5b84516147e181613ed5565b809450506020808601516001600160401b03808211156147ff575f80fd5b818801915088601f830112614812575f80fd5b8151614820614035826146ab565b81815260059190911b8301840190848101908b83111561483e575f80fd5b938501935b82851015614865578451614856816146cd565b82529385019390850190614843565b60408b0151909850945050508083111561487d575f80fd5b61488989848a016146d9565b9450606088015192508083111561489e575f80fd5b50506148ac8782880161475e565b91505092959194509250565b62ffffff811681146139ca575f80fd5b5f60c082840312156148d8575f80fd5b60405160c081018181106001600160401b03821117156148fa576148fa613ee9565b8060405250809150825161490d81613ed5565b8152602083015161491d81613e0c565b6020820152604083015161493081613ed5565b60408201526060830151614943816148b8565b6060820152608083015161495681613ed5565b608082015260a0830151614969816148b8565b60a0919091015292915050565b5f60208284031215614986575f80fd5b81516001600160401b038082111561499c575f80fd5b9083019060e082860312156149af575f80fd5b6149b7613efd565b6149c186846148c8565b815260c0830151828111156149d4575f80fd5b6149e08782860161462d565b60208301525095945050505050565b8051613e2b816140ad565b8051613e2b816140dc565b5f60208284031215614a15575f80fd5b81516001600160401b0380821115614a2b575f80fd5b9083019060808286031215614a3e575f80fd5b614a46613f25565b8251614a51816140ad565b81526020830151614a61816140dc565b602082015260408381015190820152606083015182811115614a81575f80fd5b614a8d8782860161462d565b60608301525095945050505050565b634e487b7160e01b5f52601160045260245ffd5b5f60018201614ac157614ac1614a9c565b5060010190565b5f60208284031215614ad8575f80fd5b81516001600160401b0380821115614aee575f80fd5b9083019060e08286031215614b01575f80fd5b614b09613f47565b614b12836149ef565b8152614b20602084016149ef565b602082015260408301516040820152614b3b606084016149fa565b60608201526080830151608082015260a083015182811115614b5b575f80fd5b614b678782860161462d565b60a08301525060c083015182811115614b7e575f80fd5b614b8a8782860161462d565b60c08301525095945050505050565b5f60a08284031215614ba9575f80fd5b60405160a081016001600160401b038282108183111715614bcc57614bcc613ee9565b8160405282935084519150614be0826140ad565b8183526020850151602084015260408501516040840152606085015160608401526080850151915080821115614c14575f80fd5b50614c218582860161462d565b6080830152505092915050565b5f60208284031215614c3e575f80fd5b81516001600160401b03811115614c53575f80fd5b6136c284828501614b99565b5f60208284031215614c6f575f80fd5b81516001600160401b0380821115614c85575f80fd5b9083019060408286031215614c98575f80fd5b614ca0613efd565b825181526020830151828111156149d4575f80fd5b5f60208284031215614cc5575f80fd5b81516001600160401b0380821115614cdb575f80fd5b9083019060608286031215614cee575f80fd5b614cf6613f69565b8251815260208301516020820152604083015182811115614d15575f80fd5b614d218782860161462d565b60408301525095945050505050565b5f60208284031215614d40575f80fd5b8151610c2f816140dc565b5f60c08284031215614d5b575f80fd5b610c2f83836148c8565b5f60208284031215614d75575f80fd5b8151610c2f81613e0c565b8082028115828204841417610a2657610a26614a9c565b6001600160a01b0388168152608060208083018290529082018790525f90889060a08401835b8a811015614de9578335614dd0816146cd565b614dda83826144cb565b94840194925050600101614dbd565b5084810360408601528781528181019250600588901b81018201895f5b8a811015614e4057838303601f19018652614e21828d6143ee565b614e2c85828461442f565b978701979450505090840190600101614e06565b50508581036060870152614e5581888a614588565b9d9c50505050505050505050505050565b5f6020808385031215614e77575f80fd5b82516001600160401b03811115614e8c575f80fd5b8301601f81018513614e9c575f80fd5b8051614eaa614035826146ab565b81815260059190911b82018301908381019087831115614ec8575f80fd5b928401925b82841015614ee657835182529284019290840190614ecd565b979650505050505050565b5f8235607e198336030181126143e4575f80fd5b602081525f8235614f15816140ad565b6001600160c01b0381166020840152506020830135614f33816140dc565b8060020b60408401525060408301356060830152614f5460608401846143ee565b6080808501526144b060a08501828461442f565b5f8235603e198336030181126143e4575f80fd5b60208152813560208201525f614f9560208401846143ee565b6040808501526144b060608501828461442f565b5f8235605e198336030181126143e4575f80fd5b6020815281356020820152602082013560408201525f614fe060408401846143ee565b6060808501526144b060808501828461442f565b5f823560de198336030181126143e4575f80fd5b8035613e2b816148b8565b8035613e2b81613ed5565b602081525f823561502e81613ed5565b6001600160a01b0380821660208501526020850135915061504e82613e0c565b6001600160401b03821660408501526040850135915061506d82613ed5565b16606083810191909152830135615083816148b8565b62ffffff811660808401525061509b60808401615013565b6001600160a01b03811660a0840152506150b760a08401615008565b62ffffff811660c0840152506150d060c08401846143ee565b60e0808501526144b06101008501828461442f565b5f6001600160a01b03808716835260206080602085015261510960808501886144f1565b848103604086015261511b8188614530565b8581036060870152865180825260208089019350909101905f5b81811015615153578351861683529284019291840191600101615135565b50909a9950505050505050505050565b5f60608284031215615173575f80fd5b61517b613f69565b825161518681613ed5565b8152602083015161519681613e0c565b602082015260408301516151a981613e0c565b60408201529392505050565b5f7f800000000000000000000000000000000000000000000000000000000000000082036151e5576151e5614a9c565b505f0390565b80820180821115610a2657610a26614a9c565b81810381811115610a2657610a26614a9c565b602081525f8235615221816140ad565b6001600160c01b038116602084015250602083013561523f816140ad565b6001600160c01b03811660408401525060408301356060830152615265606084016140ea565b615274608084018260020b9052565b50608083013560a083015261528c60a08401846143ee565b60e060c08501526152a26101008501828461442f565b9150506152b260c08501856143ee565b848303601f190160e086015261378d83828461442f565b5f608082840312156152d9575f80fd5b6152e1613f25565b905081358152602082013560ff811681146152fa575f80fd5b80602083015250604082013560408201526060820135606082015292915050565b5f60c0828403121561532b575f80fd5b615333613f69565b823561533e81613ed5565b8152602083810135908201526151a984604085016152c9565b6153b981846001600160a01b038082511683526001600160401b036020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b60e060c08201525f6136c260e083018461406d565b634e487b7160e01b5f52601260045260245ffd5b5f826153fc57634e487b7160e01b5f52601260045260245ffd5b500490565b5f6101406154688386516001600160a01b038082511683526001600160401b036020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b602085015160020b60c08401526001600160401b0360408601511660e08401526001600160a01b03606086015116610100840152806101208401526144b08184018561406d565b5f80604083850312156154c0575f80fd5b505080516020909101519092909150565b5f602082840312156154e1575f80fd5b81518015158114610c2f575f80fd5b5f6101206155578386516001600160a01b038082511683526001600160401b036020830151166020840152806040830151166040840152606082015162ffffff80821660608601528260808501511660808601528060a08501511660a08601525050505050565b602085015160020b60c08401526001600160401b0360408601511660e0840152806101008401526144b08184018561406d565b5f6020828403121561559a575f80fd5b8151610c2f81613ed5565b828152604060208201525f6136c2604083018461406d565b5f602082840312156155cd575f80fd5b5051919050565b825181526001600160401b036020840151166020820152606060408201525f6136c2606083018461406d565b5f8160020b627fffff19810361561857615618614a9c565b5f0392915050565b5f60808284031215615630575f80fd5b610c2f83836152c9565b5f82518060208501845e5f92019182525091905056fea2646970667358221220813d6c16471676c72a924a49e4565436a793d186a3a4ad314c6f893e8ecbf0f864736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636
-----Decoded View---------------
Arg [0] : bookManager_ (address): 0xD4aD5Ed9E1436904624b6dB8B1BE31f36317C636
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d4ad5ed9e1436904624b6db8b1be31f36317c636
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.