Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 298 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 24163873 | 51 days ago | IN | 0 ETH | 0.00013849 | ||||
| Withdraw | 24097252 | 61 days ago | IN | 0 ETH | 0.00001251 | ||||
| Repay | 24091258 | 62 days ago | IN | 0 ETH | 0.00021809 | ||||
| Withdraw | 24067396 | 65 days ago | IN | 0 ETH | 0.00020081 | ||||
| Withdraw | 24020730 | 71 days ago | IN | 0 ETH | 0.00015257 | ||||
| Take Quote | 23939217 | 83 days ago | IN | 0 ETH | 0.00008632 | ||||
| Withdraw | 23939214 | 83 days ago | IN | 0 ETH | 0.0000879 | ||||
| Borrow | 23921067 | 85 days ago | IN | 0 ETH | 0.0003685 | ||||
| Withdraw | 23889765 | 90 days ago | IN | 0 ETH | 0.00014097 | ||||
| Take Quote | 23885781 | 90 days ago | IN | 0 ETH | 0.00077991 | ||||
| Take Swap Quote | 23885760 | 90 days ago | IN | 0 ETH | 0.00007559 | ||||
| Withdraw | 23885759 | 90 days ago | IN | 0 ETH | 0.00003794 | ||||
| Withdraw | 23885757 | 90 days ago | IN | 0 ETH | 0.00007191 | ||||
| Repay | 23867584 | 93 days ago | IN | 0 ETH | 0.00022372 | ||||
| Withdraw | 23845106 | 96 days ago | IN | 0 ETH | 0.00007508 | ||||
| Take Quote | 23841272 | 97 days ago | IN | 0 ETH | 0.00095078 | ||||
| Take Quote | 23834286 | 98 days ago | IN | 0 ETH | 0.00327986 | ||||
| Take Quote | 23834144 | 98 days ago | IN | 0 ETH | 0.00292395 | ||||
| Withdraw | 23833593 | 98 days ago | IN | 0 ETH | 0.000076 | ||||
| Withdraw | 23833592 | 98 days ago | IN | 0 ETH | 0.00007591 | ||||
| Withdraw | 23833586 | 98 days ago | IN | 0 ETH | 0.00005316 | ||||
| Take Quote | 23833581 | 98 days ago | IN | 0 ETH | 0.0005019 | ||||
| Withdraw | 23833578 | 98 days ago | IN | 0 ETH | 0.000053 | ||||
| Withdraw | 23783662 | 105 days ago | IN | 0 ETH | 0.00012756 | ||||
| Take Quote | 23783004 | 105 days ago | IN | 0 ETH | 0.00112049 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x3d602d80 | 24227022 | 43 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23991680 | 76 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23939217 | 83 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23891417 | 90 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23885781 | 90 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23841272 | 97 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23834286 | 98 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23834144 | 98 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23833581 | 98 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23783004 | 105 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23783002 | 105 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23769376 | 107 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23756348 | 109 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23739793 | 111 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23669272 | 121 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23633801 | 126 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23626112 | 127 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23626092 | 127 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23570199 | 135 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23568994 | 135 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23545870 | 138 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23545799 | 138 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23520838 | 142 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23512967 | 143 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 23512774 | 143 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Router
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {DataTypes} from "./DataTypes.sol";
import {Errors} from "./errors/Errors.sol";
import {IEscrow} from "./interfaces/IEscrow.sol";
import {IFeeHandler} from "./interfaces/IFeeHandler.sol";
import {IRouter} from "./interfaces/IRouter.sol";
contract Router is Ownable, IRouter {
using SafeERC20 for IERC20Metadata;
uint64 internal constant BASE = 1 ether;
uint96 internal constant MAX_MATCH_FEE = 0.2 ether;
uint96 internal constant MAX_EXERCISE_FEE = 0.005 ether;
// @dev: EIP-1271 with bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 internal constant EIP1271_SIG_AND_MAGIC_VALUE = 0x1626ba7e;
address public immutable escrowImpl;
address public feeHandler;
uint256 public numEscrows;
mapping(address => bool) public isEscrow;
mapping(bytes32 => bool) public isQuoteUsed;
mapping(bytes32 => bool) public isSwapQuoteUsed;
mapping(address => bool) public quotesPaused;
address[] internal _escrows;
constructor(address initOwner, address _escrowImpl) Ownable(initOwner) {
if (_escrowImpl == address(0)) {
revert Errors.InvalidAddress();
}
escrowImpl = _escrowImpl;
}
function createAuction(
address escrowOwner,
DataTypes.AuctionInitialization calldata auctionInitialization,
address distPartner
) external {
(address escrow, uint256 oTokenIndex) = _createEscrow();
uint96 exerciseFee = getExerciseFee();
IEscrow(escrow).initializeAuction(
address(this),
escrowOwner,
exerciseFee,
auctionInitialization,
oTokenIndex,
distPartner
);
IERC20Metadata(auctionInitialization.underlyingToken).safeTransferFrom(
msg.sender,
escrow,
auctionInitialization.notional
);
emit CreateAuction(
escrowOwner,
escrow,
auctionInitialization,
exerciseFee,
distPartner
);
}
function withdrawFromEscrowAndCreateAuction(
address oldEscrow,
address escrowOwner,
DataTypes.AuctionInitialization calldata auctionInitialization,
address distPartner
) external {
if (!isEscrow[oldEscrow]) {
revert Errors.NotAnEscrow();
}
if (msg.sender != IEscrow(oldEscrow).owner()) {
revert Errors.InvalidSender();
}
(address newEscrow, uint256 oTokenIndex) = _createEscrow();
IEscrow(newEscrow).initializeAuction(
address(this),
escrowOwner,
getExerciseFee(),
auctionInitialization,
oTokenIndex,
distPartner
);
uint256 oldEscrowBal = IERC20Metadata(
auctionInitialization.underlyingToken
).balanceOf(oldEscrow);
// @dev: if new notional gte old escrow balance
// then we can rollover funds
address withdrawTo = auctionInitialization.notional >= oldEscrowBal
? newEscrow
: msg.sender;
uint256 netTransferAmountNeeded = auctionInitialization.notional >=
oldEscrowBal
? auctionInitialization.notional - oldEscrowBal
: auctionInitialization.notional;
IEscrow(oldEscrow).handleWithdraw(
withdrawTo,
auctionInitialization.underlyingToken,
oldEscrowBal
);
// @dev: iff new notional equal old escrow balance
// then no transfer needed
if (netTransferAmountNeeded > 0) {
IERC20Metadata(auctionInitialization.underlyingToken)
.safeTransferFrom(
msg.sender,
newEscrow,
netTransferAmountNeeded
);
}
emit WithdrawFromEscrowAndCreateAuction(
escrowOwner,
oldEscrow,
newEscrow,
auctionInitialization
);
}
function withdraw(
address escrow,
address to,
address token,
uint256 amount
) external {
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
if (msg.sender != IEscrow(escrow).owner()) {
revert Errors.InvalidSender();
}
IEscrow(escrow).handleWithdraw(to, token, amount);
emit Withdraw(msg.sender, escrow, to, token, amount);
}
function bidOnAuction(
address escrow,
address optionReceiver,
uint256 relBid,
uint256 _refSpot,
bytes[] memory _oracleData
)
external
returns (DataTypes.BidPreview memory preview, address distPartner)
{
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
(preview, distPartner) = IEscrow(escrow).handleAuctionBid(
relBid,
optionReceiver,
_refSpot,
_oracleData
);
IERC20Metadata(preview.premiumToken).safeTransferFrom(
msg.sender,
IEscrow(escrow).owner(),
preview.premium -
preview.matchFeeDistPartner -
preview.matchFeeProtocol
);
if (preview.matchFeeDistPartner > 0) {
IERC20Metadata(preview.premiumToken).safeTransferFrom(
msg.sender,
distPartner,
preview.matchFeeDistPartner
);
}
if (preview.matchFeeProtocol > 0) {
address _feeHandler = feeHandler;
IERC20Metadata(preview.premiumToken).safeTransferFrom(
msg.sender,
_feeHandler,
preview.matchFeeProtocol
);
IFeeHandler(_feeHandler).provisionFees(
preview.premiumToken,
preview.matchFeeProtocol
);
}
emit BidOnAuction(
msg.sender,
escrow,
optionReceiver,
preview,
distPartner
);
}
function exercise(
address escrow,
address underlyingReceiver,
uint256 underlyingAmount,
bool payInSettlementToken,
bytes[] memory oracleData
) external {
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
(
address settlementToken,
uint256 settlementAmount,
uint256 exerciseFeeAmount
) = IEscrow(escrow).handleExercise(
msg.sender,
underlyingReceiver,
underlyingAmount,
payInSettlementToken,
oracleData
);
if (payInSettlementToken) {
IERC20Metadata(settlementToken).safeTransferFrom(
msg.sender,
IEscrow(escrow).owner(),
settlementAmount
);
}
address _feeHandler = feeHandler;
if (_feeHandler != address(0) && exerciseFeeAmount > 0) {
IERC20Metadata(settlementToken).safeTransferFrom(
msg.sender,
feeHandler,
exerciseFeeAmount
);
IFeeHandler(_feeHandler).provisionFees(
settlementToken,
exerciseFeeAmount
);
}
emit Exercise(
msg.sender,
escrow,
underlyingReceiver,
underlyingAmount,
exerciseFeeAmount
);
}
function borrow(
address escrow,
address underlyingReceiver,
uint128 borrowUnderlyingAmount
) external {
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
(
address settlementToken,
uint256 collateralAmount,
uint256 collateralFeeAmount
) = IEscrow(escrow).handleBorrow(
msg.sender,
underlyingReceiver,
borrowUnderlyingAmount
);
IERC20Metadata(settlementToken).safeTransferFrom(
msg.sender,
escrow,
collateralAmount
);
address _feeHandler = feeHandler;
if (_feeHandler != address(0) && collateralFeeAmount > 0) {
IERC20Metadata(settlementToken).safeTransferFrom(
msg.sender,
feeHandler,
collateralFeeAmount
);
IFeeHandler(_feeHandler).provisionFees(
settlementToken,
collateralFeeAmount
);
}
emit Borrow(
msg.sender,
escrow,
underlyingReceiver,
borrowUnderlyingAmount,
collateralAmount,
collateralFeeAmount
);
}
function repay(
address escrow,
address collateralReceiver,
uint128 repayUnderlyingAmount
) external {
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
(address underlyingToken, uint256 unlockedCollateralAmount) = IEscrow(
escrow
).handleRepay(msg.sender, collateralReceiver, repayUnderlyingAmount);
IERC20Metadata(underlyingToken).safeTransferFrom(
msg.sender,
escrow,
repayUnderlyingAmount
);
emit Repay(
escrow,
escrow,
collateralReceiver,
repayUnderlyingAmount,
unlockedCollateralAmount
);
}
function takeQuote(
address escrowOwner,
DataTypes.RFQInitialization calldata rfqInitialization,
address distPartner
) external {
DataTypes.TakeQuotePreview memory preview = previewTakeQuote(
rfqInitialization,
distPartner
);
if (preview.status != DataTypes.RFQStatus.Success) {
revert Errors.InvalidTakeQuote();
}
isQuoteUsed[preview.msgHash] = true;
(address escrow, uint256 oTokenIndex) = _createEscrow();
uint96 exerciseFee = getExerciseFee();
IEscrow(escrow).initializeRFQMatch(
address(this),
escrowOwner,
preview.quoter,
exerciseFee,
rfqInitialization,
oTokenIndex
);
IERC20Metadata(rfqInitialization.optionInfo.underlyingToken)
.safeTransferFrom(
msg.sender,
escrow,
rfqInitialization.optionInfo.notional
);
IERC20Metadata(preview.premiumToken).safeTransferFrom(
preview.quoter,
msg.sender,
rfqInitialization.rfqQuote.premium -
preview.matchFeeDistPartner -
preview.matchFeeProtocol
);
if (preview.matchFeeDistPartner > 0) {
IERC20Metadata(preview.premiumToken).safeTransferFrom(
preview.quoter,
distPartner,
preview.matchFeeDistPartner
);
}
if (preview.matchFeeProtocol > 0) {
address _feeHandler = feeHandler;
IERC20Metadata(preview.premiumToken).safeTransferFrom(
preview.quoter,
_feeHandler,
preview.matchFeeProtocol
);
IFeeHandler(_feeHandler).provisionFees(
preview.premiumToken,
preview.matchFeeProtocol
);
}
emit TakeQuote(
msg.sender,
escrowOwner,
escrow,
rfqInitialization,
preview,
exerciseFee,
distPartner
);
}
function takeSwapQuote(
address to,
DataTypes.SwapQuote calldata swapQuote
) external {
if (block.timestamp > swapQuote.validUntil) {
revert Errors.SwapQuoteExpired();
}
bytes32 msgHash = keccak256(
abi.encode(
block.chainid,
swapQuote.takerGiveToken,
swapQuote.takerGiveAmount,
swapQuote.makerGiveToken,
swapQuote.makerGiveAmount,
swapQuote.validUntil
)
);
address maker;
if (swapQuote.eip1271Maker == address(0)) {
maker = ECDSA.recover(
MessageHashUtils.toEthSignedMessageHash(msgHash),
swapQuote.signature
);
} else {
bool isValid = _checkEIP1271Signature(
swapQuote.eip1271Maker,
msgHash,
swapQuote.signature
);
if (!isValid) {
revert Errors.InvalidEIP1271Signature();
}
maker = swapQuote.eip1271Maker;
}
if (quotesPaused[maker]) {
revert Errors.SwapQuotePaused();
}
if (isSwapQuoteUsed[msgHash]) {
revert Errors.SwapQuoteAlreadyUsed();
}
isSwapQuoteUsed[msgHash] = true;
IERC20Metadata(swapQuote.takerGiveToken).safeTransferFrom(
msg.sender,
maker,
swapQuote.takerGiveAmount
);
IERC20Metadata(swapQuote.makerGiveToken).safeTransferFrom(
maker,
to,
swapQuote.makerGiveAmount
);
emit TakeSwapQuote(msg.sender, to, maker, swapQuote);
}
function togglePauseQuotes() external {
bool isPaused = quotesPaused[msg.sender];
quotesPaused[msg.sender] = !isPaused;
emit PauseQuotes(msg.sender, !isPaused);
}
function mintOption(
address optionReceiver,
address escrowOwner,
DataTypes.OptionInfo calldata optionInfo,
DataTypes.OptionNaming calldata optionNaming,
address distPartner
) external {
if (optionInfo.underlyingToken == optionInfo.settlementToken) {
revert Errors.InvalidTokenPair();
}
if (optionInfo.notional == 0) {
revert Errors.InvalidNotional();
}
if (block.timestamp > optionInfo.expiry) {
revert Errors.InvalidExpiry();
}
if (optionInfo.expiry < optionInfo.earliestExercise + 1 days) {
revert Errors.InvalidEarliestExercise();
}
if (optionInfo.advancedSettings.borrowCap > BASE) {
revert Errors.InvalidBorrowCap();
}
(address escrow, ) = _createEscrow();
(uint256 mintFeeProtocol, uint256 mintFeeDistPartner) = getMintFees(
distPartner,
optionInfo.notional
);
address mintOptionTokensTo = (mintFeeProtocol > 0 ||
mintFeeDistPartner > 0)
? address(this)
: optionReceiver;
IEscrow(escrow).initializeMintOption(
address(this),
escrowOwner,
mintOptionTokensTo,
getExerciseFee(),
optionInfo,
optionNaming
);
IERC20Metadata(optionInfo.underlyingToken).safeTransferFrom(
msg.sender,
escrow,
optionInfo.notional
);
if (mintOptionTokensTo == address(this)) {
IERC20Metadata(escrow).safeTransfer(
optionReceiver,
optionInfo.notional - mintFeeProtocol - mintFeeDistPartner
);
if (mintFeeDistPartner > 0) {
IERC20Metadata(escrow).safeTransfer(
distPartner,
mintFeeDistPartner
);
}
if (mintFeeProtocol > 0) {
IERC20Metadata(escrow).safeTransfer(
feeHandler,
mintFeeProtocol
);
IFeeHandler(feeHandler).provisionFees(escrow, mintFeeProtocol);
}
}
emit MintOption(
msg.sender,
optionReceiver,
escrowOwner,
optionInfo,
mintFeeProtocol,
mintFeeDistPartner,
distPartner
);
}
function setFeeHandler(address newFeeHandler) external onlyOwner {
address oldFeeHandler = feeHandler;
if (oldFeeHandler == newFeeHandler) {
revert Errors.FeeHandlerAlreadySet();
}
feeHandler = newFeeHandler;
emit NewFeeHandler(oldFeeHandler, newFeeHandler);
}
function emitTransferEvent(
address from,
address to,
uint256 value
) external {
address escrow = msg.sender;
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
emit Transfer(escrow, from, to, value);
}
function emitTransferOwnershipEvent(
address oldOwner,
address newOwner
) external {
address escrow = msg.sender;
if (!isEscrow[escrow]) {
revert Errors.NotAnEscrow();
}
emit TransferOwnership(escrow, oldOwner, newOwner);
}
function getExerciseFee() public view returns (uint96 exerciseFee) {
address _feeHandler = feeHandler;
if (_feeHandler == address(0)) {
return 0;
}
exerciseFee = IFeeHandler(_feeHandler).exerciseFee();
exerciseFee = exerciseFee > MAX_EXERCISE_FEE
? MAX_EXERCISE_FEE
: exerciseFee;
}
function getMatchFees(
address distPartner,
uint128 optionPremium,
DataTypes.OptionInfo calldata optionInfo
)
public
view
returns (uint128 matchFeeProtocol, uint128 matchFeeDistPartner)
{
address _feeHandler = feeHandler;
if (_feeHandler != address(0)) {
(uint256 matchFee, uint256 matchFeeDistPartnerShare) = IFeeHandler(
_feeHandler
).getMatchFeeInfo(distPartner, optionPremium, optionInfo);
uint256 cappedMatchFee = matchFee > MAX_MATCH_FEE
? MAX_MATCH_FEE
: matchFee;
uint256 cappedMatchFeeDistPartnerShare = matchFeeDistPartnerShare >
BASE
? BASE
: matchFeeDistPartnerShare;
uint256 totalMatchFee = (optionPremium * cappedMatchFee) / BASE;
matchFeeDistPartner = SafeCast.toUint128(
(totalMatchFee * cappedMatchFeeDistPartnerShare) / BASE
);
matchFeeProtocol = SafeCast.toUint128(
totalMatchFee - matchFeeDistPartner
);
}
}
function getMintFees(
address distPartner,
uint128 notional
)
public
view
returns (uint256 mintFeeProtocol, uint256 mintFeeDistPartner)
{
address _feeHandler = feeHandler;
if (_feeHandler != address(0)) {
(uint256 mintFee, uint256 mintFeeDistPartnerShare) = IFeeHandler(
_feeHandler
).getMintFeeInfo(distPartner);
// @dev: use same cap as for match fee
uint256 cappedMintFee = mintFee > MAX_MATCH_FEE
? MAX_MATCH_FEE
: mintFee;
uint256 cappedMintFeeDistPartnerShare = mintFeeDistPartnerShare >
BASE
? BASE
: mintFeeDistPartnerShare;
uint256 totalMintFee = (notional * cappedMintFee) / BASE;
mintFeeDistPartner =
(totalMintFee * cappedMintFeeDistPartnerShare) /
BASE;
mintFeeProtocol = totalMintFee - mintFeeDistPartner;
}
}
function previewTakeQuote(
DataTypes.RFQInitialization calldata rfqInitialization,
address distPartner
) public view returns (DataTypes.TakeQuotePreview memory) {
bytes32 msgHash = keccak256(
abi.encode(
block.chainid,
rfqInitialization.optionInfo,
rfqInitialization.rfqQuote.premium,
rfqInitialization.rfqQuote.validUntil
)
);
address quoter;
if (rfqInitialization.rfqQuote.eip1271Maker == address(0)) {
quoter = ECDSA.recover(
MessageHashUtils.toEthSignedMessageHash(msgHash),
rfqInitialization.rfqQuote.signature
);
} else {
bool isValid = _checkEIP1271Signature(
rfqInitialization.rfqQuote.eip1271Maker,
msgHash,
rfqInitialization.rfqQuote.signature
);
if (!isValid) {
return
_createTakeQuotePreview(
DataTypes.RFQStatus.InvalidEIP1271Signature,
msgHash,
quoter
);
}
quoter = rfqInitialization.rfqQuote.eip1271Maker;
}
if (
rfqInitialization.optionInfo.underlyingToken ==
rfqInitialization.optionInfo.settlementToken ||
rfqInitialization.optionInfo.notional == 0 ||
rfqInitialization.optionInfo.strike == 0 ||
rfqInitialization.optionInfo.expiry <
rfqInitialization.optionInfo.earliestExercise + 1 days ||
rfqInitialization.optionInfo.advancedSettings.borrowCap > BASE
) {
return
_createTakeQuotePreview(
DataTypes.RFQStatus.InvalidQuote,
msgHash,
quoter
);
}
if (
block.timestamp > rfqInitialization.rfqQuote.validUntil ||
block.timestamp > rfqInitialization.optionInfo.expiry
) {
return
_createTakeQuotePreview(
DataTypes.RFQStatus.Expired,
msgHash,
quoter
);
}
if (isQuoteUsed[msgHash]) {
return
_createTakeQuotePreview(
DataTypes.RFQStatus.AlreadyExecuted,
msgHash,
quoter
);
}
if (quotesPaused[quoter]) {
return
_createTakeQuotePreview(
DataTypes.RFQStatus.QuotesPaused,
msgHash,
quoter
);
}
(uint128 matchFeeProtocol, uint128 matchFeeDistPartner) = getMatchFees(
distPartner,
rfqInitialization.rfqQuote.premium,
rfqInitialization.optionInfo
);
return
DataTypes.TakeQuotePreview({
status: DataTypes.RFQStatus.Success,
msgHash: msgHash,
quoter: quoter,
premium: rfqInitialization.rfqQuote.premium,
premiumToken: rfqInitialization
.optionInfo
.advancedSettings
.premiumTokenIsUnderlying
? rfqInitialization.optionInfo.underlyingToken
: rfqInitialization.optionInfo.settlementToken,
matchFeeProtocol: matchFeeProtocol,
matchFeeDistPartner: matchFeeDistPartner
});
}
function getEscrows(
uint256 from,
uint256 numElements
) external view returns (address[] memory _escrowArray) {
uint256 length = _escrows.length;
if (numElements == 0 || from + numElements > length) {
revert Errors.InvalidGetEscrowsQuery();
}
_escrowArray = new address[](numElements);
for (uint256 i = 0; i < numElements; ++i) {
_escrowArray[i] = _escrows[from + i];
}
}
function _createEscrow()
internal
returns (address escrow, uint256 oTokenIndex)
{
oTokenIndex = numEscrows + 1;
escrow = Clones.cloneDeterministic(
escrowImpl,
keccak256(abi.encode(oTokenIndex))
);
numEscrows = oTokenIndex;
isEscrow[escrow] = true;
_escrows.push(escrow);
}
function _createTakeQuotePreview(
DataTypes.RFQStatus status,
bytes32 msgHash,
address quoter
) internal pure returns (DataTypes.TakeQuotePreview memory) {
return
DataTypes.TakeQuotePreview({
status: status,
msgHash: msgHash,
quoter: quoter,
premium: 0,
premiumToken: address(0),
matchFeeProtocol: 0,
matchFeeDistPartner: 0
});
}
function _checkEIP1271Signature(
address erc1271Wallet,
bytes32 msgHash,
bytes calldata signature
) internal view returns (bool isValid) {
// @dev: legacy EIP1271 wallets using bytes4(keccak256("isValidSignature(bytes,bytes)")
// are not supported
(bool success, bytes memory returnData) = erc1271Wallet.staticcall(
abi.encodeWithSelector(
EIP1271_SIG_AND_MAGIC_VALUE,
msgHash,
signature
)
);
if (success && returnData.length == 32) {
bytes4 result = abi.decode(returnData, (bytes4));
return result == EIP1271_SIG_AND_MAGIC_VALUE;
}
return false;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev A clone instance deployment failed.
*/
error ERC1167FailedCreateClone();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
library DataTypes {
struct OptionInfo {
address underlyingToken;
uint48 expiry;
address settlementToken;
uint48 earliestExercise;
uint128 notional;
uint128 strike;
AdvancedSettings advancedSettings;
}
struct AdvancedSettings {
uint64 borrowCap;
address oracle;
bool premiumTokenIsUnderlying;
bool votingDelegationAllowed;
address allowedDelegateRegistry;
}
struct AuctionInitialization {
address underlyingToken;
address settlementToken;
uint128 notional;
AuctionParams auctionParams;
AdvancedSettings advancedSettings;
}
struct AuctionParams {
uint128 relStrike;
uint48 tenor;
uint48 earliestExerciseTenor;
uint32 decayStartTime;
uint32 decayDuration;
uint64 relPremiumStart;
uint64 relPremiumFloor;
uint128 minSpot;
uint128 maxSpot;
}
struct RFQInitialization {
OptionInfo optionInfo;
RFQQuote rfqQuote;
}
struct RFQQuote {
uint128 premium;
uint256 validUntil;
bytes signature;
address eip1271Maker;
}
enum BidStatus {
Success,
SpotPriceTooLow,
OutOfRangeSpotPrice,
OptionAlreadyMinted,
PremiumTooLow,
AuctionCancelled
}
struct BidPreview {
BidStatus status;
address settlementToken;
address underlyingToken;
uint128 strike;
uint48 expiry;
uint48 earliestExercise;
uint128 premium;
address premiumToken;
uint256 oracleSpotPrice;
uint64 currAsk;
uint128 matchFeeProtocol;
uint128 matchFeeDistPartner;
}
enum RFQStatus {
Expired,
InvalidQuote,
AlreadyExecuted,
QuotesPaused,
Success,
InvalidEIP1271Signature
}
struct TakeQuotePreview {
RFQStatus status;
bytes32 msgHash;
address quoter;
uint128 premium;
address premiumToken;
uint128 matchFeeProtocol;
uint128 matchFeeDistPartner;
}
struct SwapQuote {
address takerGiveToken;
uint256 takerGiveAmount;
address makerGiveToken;
uint256 makerGiveAmount;
uint256 validUntil;
bytes signature;
address eip1271Maker;
}
struct OptionNaming {
string name;
string symbol;
}
struct MatchFeePerPair {
bool isSet;
uint96 matchFee;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
library Errors {
error AlreadyInitialized();
error DistPartnerFeeUnchanged();
error FeeHandlerAlreadySet();
error InvalidAddress();
error InvalidArrayLength();
error InvalidBid();
error InvalidBorrowAmount();
error InvalidBorrowCap();
error InvalidBorrowTime();
error InvalidDistPartnerFeeShare();
error InvalidEarliestExercise();
error InvalidEarliestExerciseTenor();
error InvalidEIP1271Signature();
error InvalidExpiry();
error InvalidExercise();
error InvalidExerciseAmount();
error InvalidExerciseFee();
error InvalidExerciseTime();
error InvalidGetEscrowsQuery();
error InvalidMatchFee();
error InvalidMaxTimeSinceLastUpdate();
error InvalidMintFee();
error InvalidMinMaxSpot();
error InvalidNotional();
error InvalidOracle();
error InvalidOracleAnswer();
error InvalidOracleDecimals();
error InvalidRelPremiums();
error InvalidRepayAmount();
error InvalidRepayTime();
error InvalidSender();
error InvalidStrike();
error InvalidTakeQuote();
error InvalidTenor();
error InvalidTokenPair();
error InvalidWithdraw();
error NoAllowedDelegateRegistry();
error NoOptionMinted();
error NoOracle();
error NotAnEscrow();
error NothingToRedeem();
error NothingToRepay();
error OnlyAvailableForAuctions();
error OracleAlreadySet(address oracleAddr);
error OwnerAlreadySet();
error SwapQuoteAlreadyUsed();
error SwapQuoteExpired();
error SwapQuotePaused();
error VotingDelegationNotAllowed();
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {DataTypes} from "../DataTypes.sol";
/**
* @title IEscrow
* @dev Interface for the Escrow contract.
* Provides functionality for initializing auctions, bids, options, and managing underlying tokens.
*/
interface IEscrow {
/// @notice Emitted when on-chain voting rights are delegated.
/// @param delegate The address delegated for on-chain voting.
event OnChainVotingDelegation(address delegate);
/// @notice Emitted when off-chain voting rights are delegated.
/// @param allowedDelegateRegistry Address of the allowed delegate registry.
/// @param spaceId ID of the delegation space (e.g., for Snapshot).
/// @param delegate The address delegated for off-chain voting.
event OffChainVotingDelegation(
address allowedDelegateRegistry,
bytes32 spaceId,
address delegate
);
/// @notice Emitted when tokens are withdrawn from the escrow.
/// @param sender The address initiating the withdrawal.
/// @param to The address receiving the withdrawn funds.
/// @param token The address of the token being withdrawn.
/// @param amount The amount of tokens withdrawn.
event Withdraw(
address indexed sender,
address indexed to,
address indexed token,
uint256 amount
);
/// @notice Emitted when escrow ownership is transferred to a new owner.
/// @param sender The address initiating the ownership transfer.
/// @param oldOwner The address of the previous owner.
/// @param newOwner The address of the new owner.
event TransferOwnership(
address indexed sender,
address oldOwner,
address newOwner
);
/// @notice Emitted when a redeem action is performed.
/// @param sender The address initiating the redemption.
/// @param to The address receiving the redeemed underlying tokens.
/// @param underlyingToken The address of the underlying token being redeemed.
/// @param amount The amount of underlying tokens redeemed.
event Redeem(
address indexed sender,
address to,
address underlyingToken,
uint256 amount
);
/// @notice Returns the premium paid for the option.
/// @return premiumPaid Amount of premium paid for the option.
function premiumPaid() external view returns (uint128);
/// @notice Returns the total amount borrowed in the underlying token.
/// @return totalBorrowed Total borrowed amount.
function totalBorrowed() external view returns (uint128);
/// @notice Returns the address of the router linked to this Escrow.
/// @return router The address of the router.
function router() external view returns (address);
/// @notice Returns the exercise fee set in the Escrow.
/// @return exerciseFee The exercise fee as a percentage.
function exerciseFee() external view returns (uint96);
/// @notice Returns the address of the owner of the Escrow.
/// @return owner The address of the current owner.
function owner() external view returns (address);
/// @notice Indicates if the escrow is set up for an auction.
/// @return isAuction Boolean indicating auction status.
function isAuction() external view returns (bool);
/// @notice Indicates if the option has been minted.
/// @return optionMinted Boolean indicating if the option is minted.
function optionMinted() external view returns (bool);
/// @notice Returns the distribution partner of an auction.
/// @return Returns the distribution partner of an auction.
function distPartner() external view returns (address);
/// @notice Initializes the Escrow contract for an auction.
/// @param _router The router address.
/// @param _owner The address of the auction owner.
/// @param _exerciseFee The exercise fee to be applied in case of exercise.
/// @param _auctionInitialization Struct containing auction parameters.
/// @param oTokenIndex Index for identifying the option token.
/// @param distPartner The distribution partner address.
function initializeAuction(
address _router,
address _owner,
uint96 _exerciseFee,
DataTypes.AuctionInitialization calldata _auctionInitialization,
uint256 oTokenIndex,
address distPartner
) external;
/// @notice Initializes the Escrow for a matched RFQ.
/// @param _router The router address.
/// @param _owner The address of the escrow owner.
/// @param optionReceiver Address receiving the option tokens.
/// @param _exerciseFee The exercise fee to be applied in case of exercise.
/// @param _rfqInitialization Struct containing RFQ parameters.
/// @param oTokenIndex Index for identifying the option token.
function initializeRFQMatch(
address _router,
address _owner,
address optionReceiver,
uint96 _exerciseFee,
DataTypes.RFQInitialization calldata _rfqInitialization,
uint256 oTokenIndex
) external;
/// @notice Initializes the Escrow when minting a standalone option.
/// @param _router The router address.
/// @param _owner The address of the option owner.
/// @param optionReceiver Address receiving the minted option tokens.
/// @param _exerciseFee The exercise fee to be applied in case of exercise.
/// @param _optionInfo Struct containing option information.
/// @param _optionNaming Struct containing the name and symbol of the option token.
function initializeMintOption(
address _router,
address _owner,
address optionReceiver,
uint96 _exerciseFee,
DataTypes.OptionInfo calldata _optionInfo,
DataTypes.OptionNaming calldata _optionNaming
) external;
/// @notice Handles bidding on an auction.
/// @param relBid Relative bid as percentage of notional.
/// @param optionReceiver Address receiving the option tokens.
/// @param _refSpot Reference spot price.
/// @param _oracleData Additional optional oracle data.
/// @return preview Returns a BidPreview struct with the bid's outcome.
/// @return distPartner Returns the address of the distribution partner.
function handleAuctionBid(
uint256 relBid,
address optionReceiver,
uint256 _refSpot,
bytes[] memory _oracleData
)
external
returns (DataTypes.BidPreview memory preview, address distPartner);
/// @notice Executes option exercise.
/// @param exerciser The address exercising the option.
/// @param underlyingReceiver Address receiving the underlying tokens.
/// @param underlyingExerciseAmount Amount of underlying tokens to exercise.
/// @param payInSettlementToken True if settlement is in the settlement token.
/// @param oracleData Additional optional oracle data.
/// @return settlementToken Address of the settlement token.
/// @return settlementAmount Amount of settlement tokens paid.
/// @return exerciseFeeAmount The fee applied for exercising.
function handleExercise(
address exerciser,
address underlyingReceiver,
uint256 underlyingExerciseAmount,
bool payInSettlementToken,
bytes[] memory oracleData
)
external
returns (
address settlementToken,
uint256 settlementAmount,
uint256 exerciseFeeAmount
);
/// @notice Handles borrowing of underlying tokens.
/// @param borrower The address borrowing the tokens.
/// @param underlyingReceiver Address receiving the borrowed tokens.
/// @param underlyingBorrowAmount Amount of underlying tokens to borrow.
/// @return settlementToken Address of the settlement token.
/// @return collateralAmount Amount of collateral required.
/// @return collateralFeeAmount The collateral fee applied for borrowing.
function handleBorrow(
address borrower,
address underlyingReceiver,
uint128 underlyingBorrowAmount
)
external
returns (
address settlementToken,
uint256 collateralAmount,
uint256 collateralFeeAmount
);
/// @notice Handles repayment of borrowed underlying tokens.
/// @param borrower The address repaying the loan.
/// @param collateralReceiver Address receiving the unlocked collateral.
/// @param underlyingRepayAmount Amount of underlying tokens to repay.
/// @return underlyingToken Address of the underlying token.
/// @return unlockedCollateralAmount Amount of collateral unlocked upon repayment.
function handleRepay(
address borrower,
address collateralReceiver,
uint128 underlyingRepayAmount
)
external
returns (address underlyingToken, uint256 unlockedCollateralAmount);
/// @notice Delegates voting rights on-chain to a specified delegate.
/// @param delegate The address to delegate voting rights to.
function handleOnChainVoting(address delegate) external;
/// @notice Delegates voting rights off-chain to a specified delegate.
/// @param spaceId ID of the delegation space (e.g., for Snapshot).
/// @param delegate The address to delegate voting rights to.
function handleOffChainVoting(bytes32 spaceId, address delegate) external;
/// @notice Withdraws a specified amount of tokens to a given address.
/// @param to Address receiving the withdrawn tokens.
/// @param token Address of the token to withdraw.
/// @param amount Amount of tokens to withdraw.
function handleWithdraw(address to, address token, uint256 amount) external;
/// @notice Allows the escrow owner to redeem option tokens for underlying.
/// @param to The address that will receive the underlying tokens upon redemption.
function redeem(address to) external;
/// @notice Transfers ownership of the Escrow to a new owner.
/// @param newOwner Address of the new owner.
function transferOwnership(address newOwner) external;
/// @notice Previews the result of a bid on the auction.
/// @param relBid Relative bid in percentage of notional.
/// @param _refSpot Reference spot price.
/// @param _oracleData Additional optional oracle data.
/// @return preview Returns a BidPreview struct with the bid's outcome.
/// @return __distPartner Returns the address of the distribution partner.
function previewBid(
uint256 relBid,
uint256 _refSpot,
bytes[] memory _oracleData
)
external
view
returns (DataTypes.BidPreview memory preview, address __distPartner);
/// @notice Returns the current ask of the auction in percentage of notional.
/// @return Current ask percentage.
function currAsk() external view returns (uint64);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {DataTypes} from "../DataTypes.sol";
/// @title IFeeHandler
/// @dev Interface for the FeeHandler contract.
/// Provides functionality for managing and distributing fees, and setting fee configurations.
interface IFeeHandler {
/// @notice Emitted when fees are provisioned.
/// @param token The address of the token in which fees are provisioned.
/// @param amount The amount of the token provisioned as fees.
event ProvisionFees(address indexed token, uint256 amount);
/// @notice Emitted when tokens are withdrawn from the FeeHandler.
/// @param to The address receiving the withdrawn tokens.
/// @param token The address of the token being withdrawn.
/// @param amount The amount of tokens withdrawn.
event Withdraw(address indexed to, address indexed token, uint256 amount);
/// @notice Emitted when match fee is set.
/// @param matchFee The match fee set as a percentage.
event SetMatchFee(uint256 matchFee);
/// @notice Emitted when token pair-specific match fees are set or removed.
/// @param underlyingTokens The underlying tokens per pair.
/// @param settlementTokens The settlement tokens per pair.
/// @param matchFeesPerPair The match fee structs per pair.
event SetMatchFeesPerPair(
address[] underlyingTokens,
address[] settlementTokens,
DataTypes.MatchFeePerPair[] matchFeesPerPair
);
/// @notice Emitted when mint fee is set.
/// @param mintFee The mint fee set as a percentage.
event SetMintFee(uint256 mintFee);
/// @notice Emitted when the exercise fee is set.
/// @param exerciseFee The exercise fee set as a percentage.
event SetExerciseFee(uint96 exerciseFee);
/// @notice Emitted when distribution partners are set.
/// @param accounts The addresses of the distribution partners.
/// @param feeShares The fee shares for given distribution partners.
event SetDistPartnerFeeShares(address[] accounts, uint256[] feeShares);
/// @notice Provisions fees in a specified token.
/// @param token The address of the token in which fees are provisioned.
/// @param amount The amount of the token provisioned as fees.
function provisionFees(address token, uint256 amount) external;
/// @notice Withdraws a specified amount of tokens to a given address.
/// @param to The address receiving the withdrawn tokens.
/// @param token The address of the token to withdraw.
/// @param amount The amount of tokens to withdraw.
function withdraw(address to, address token, uint256 amount) external;
/// @notice Returns the match fee and distribution partner fee share for a given option match.
/// @param distPartner The address of the distribution partner.
/// @param optionPremium The given option premium.
/// @param optionInfo The given option info.
/// @return _matchFee The applicable match fee for the given option.
/// @return _matchFeeDistPartnerShare The distribution partner's share of the match fee.
function getMatchFeeInfo(
address distPartner,
uint128 optionPremium,
DataTypes.OptionInfo calldata optionInfo
)
external
view
returns (uint256 _matchFee, uint256 _matchFeeDistPartnerShare);
/// @notice Returns the mint fee and fee share for given distribution partner.
/// @param distPartner The address of the distribution partner.
/// @return _mintFee The mint fee as a percentage.
/// @return _mintFeeDistPartnerShare The share of the mint fee for the distribution partner.
function getMintFeeInfo(
address distPartner
)
external
view
returns (uint256 _mintFee, uint256 _mintFeeDistPartnerShare);
/// @notice Sets distribution partners and their status.
/// @param accounts The addresses of the distribution partners.
/// @param feeShares The fee shares for given distribution partners.
function setDistPartnerFeeShares(
address[] calldata accounts,
uint256[] calldata feeShares
) external;
/// @notice Sets the match fee and distribution partner share.
/// @param _matchFee The match fee as a percentage.
function setMatchFee(uint96 _matchFee) external;
/// @notice Sets or removes a token pair-specific match fee.
/// @param underlyingTokens The underlying tokens per pair.
/// @param settlementTokens The settlement tokens per pair.
/// @param _matchFeePerPair The match fee structs per pair.
function setMatchFeesPerPair(
address[] calldata underlyingTokens,
address[] calldata settlementTokens,
DataTypes.MatchFeePerPair[] calldata _matchFeePerPair
) external;
/// @notice Sets the exercise fee.
/// @param _exerciseFee The exercise fee as a percentage.
function setExerciseFee(uint96 _exerciseFee) external;
/// @notice Returns the match fee set in the FeeHandler.
/// @return The match fee as a percentage.
function matchFee() external view returns (uint96);
/// @notice Returns the distribution fee share for a given account.
/// @param account The account to query the distribution fee share for.
/// @return The fee share for the given distribution partner.
function distPartnerFeeShare(
address account
) external view returns (uint256);
/// @notice Returns the exercise fee set in the FeeHandler.
/// @return The exercise fee as a percentage.
function exerciseFee() external view returns (uint96);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {DataTypes} from "../DataTypes.sol";
/// @title IRouter
/// @notice Interface for the Router contract handling auction creation, bidding, exercising, and other related functionalities
interface IRouter {
/// @notice Emitted when a new auction is created
/// @param escrowOwner The address of the escrow owner
/// @param escrow The address of the created escrow contract
/// @param auctionInitialization The initialization data for the auction
/// @param exerciseFee The applicable exercise fee
/// @param distPartner The distribution partner's address
event CreateAuction(
address indexed escrowOwner,
address indexed escrow,
DataTypes.AuctionInitialization auctionInitialization,
uint96 exerciseFee,
address distPartner
);
/// @notice Emitted when a withdrawal from escrow occurs and a new auction is created
/// @param escrowOwner The address of the escrow owner
/// @param oldEscrow The address of the old escrow
/// @param newEscrow The address of the new escrow
/// @param auctionInitialization The initialization data for the auction
event WithdrawFromEscrowAndCreateAuction(
address indexed escrowOwner,
address indexed oldEscrow,
address indexed newEscrow,
DataTypes.AuctionInitialization auctionInitialization
);
/// @notice Emitted when a withdrawal is made from an escrow
/// @param sender The address initiating the withdrawal
/// @param escrow The escrow address from which withdrawal occurs
/// @param to The address receiving the withdrawn tokens
/// @param token The token address being withdrawn
/// @param amount The amount of tokens withdrawn
event Withdraw(
address indexed sender,
address indexed escrow,
address to,
address indexed token,
uint256 amount
);
/// @notice Emitted when a bid is placed on an auction
/// @param sender The address initiating the bid
/// @param escrow The address of the escrow on which the bid is placed
/// @param optionReceiver The address receiving the option
/// @param bidPreview The bid preview
/// @param distPartner The distribution partner's address
event BidOnAuction(
address indexed sender,
address indexed escrow,
address optionReceiver,
DataTypes.BidPreview bidPreview,
address indexed distPartner
);
/// @notice Emitted when an exercise occurs on an option
/// @param sender The address initiating the exercise
/// @param escrow The address of the escrow smart contract = option token
/// @param underlyingReceiver The address receiving the underlying asset
/// @param underlyingAmount The amount of underlying tokens being exercised
/// @param exerciseFeeAmount The fee amount for exercising
event Exercise(
address indexed sender,
address indexed escrow,
address underlyingReceiver,
uint256 underlyingAmount,
uint256 exerciseFeeAmount
);
/// @notice Emitted when a loan is taken from an escrow
/// @param sender The address initiating the borrow
/// @param escrow The address of the escrow providing the loan
/// @param underlyingReceiver The address receiving the loaned underlying asset
/// @param underlyingAmount The amount of the loan
/// @param collateralAmount The amount of collateral provided
/// @param collateralFeeAmount The fee amount that is deducted from the collateral
event Borrow(
address indexed sender,
address indexed escrow,
address underlyingReceiver,
uint128 underlyingAmount,
uint256 collateralAmount,
uint256 collateralFeeAmount
);
/// @notice Emitted when a repayment is made to an escrow
/// @param sender The address initiating the repay
/// @param escrow The address of the escrow receiving the repayment
/// @param collateralReceiver The address receiving the collateral
/// @param repayUnderlyingAmount The amount of the underlying asset being repaid
/// @param unlockedCollateralAmount The amount of collateral being unlocked
event Repay(
address indexed sender,
address indexed escrow,
address collateralReceiver,
uint128 repayUnderlyingAmount,
uint256 unlockedCollateralAmount
);
/// @notice Emitted when a quote is taken
/// @param sender The address initiating the take quote
/// @param escrowOwner The owner of the escrow
/// @param escrow The escrow address
/// @param rfqInitialization The initialization data for the RFQ
/// @param takeQuotePreview The take quote preview
/// @param exerciseFee The applicable exercise fee
/// @param distPartner The distribution partner's address
event TakeQuote(
address indexed sender,
address escrowOwner,
address indexed escrow,
DataTypes.RFQInitialization rfqInitialization,
DataTypes.TakeQuotePreview takeQuotePreview,
uint96 exerciseFee,
address indexed distPartner
);
/// @notice Emitted when a swap quote is taken
/// @param sender The address initiating the take swap quote
/// @param to The address receiving the swapped tokens
/// @param maker The maker's address providing the swap
/// @param swapQuote The details of the swap quote
event TakeSwapQuote(
address indexed sender,
address indexed to,
address indexed maker,
DataTypes.SwapQuote swapQuote
);
/// @notice Emitted when an option is minted
/// @param sender The address initiating the mint option
/// @param optionReceiver The address receiving the minted option
/// @param escrowOwner The owner of the escrow minting the option
/// @param optionInfo The details of the option being minted
/// @param mintFeeProtocol The mint fee amount for the protocol
/// @param mintFeeDistPartner The mint fee amount for the distribution partner
/// @param distPartner The distribution partner
event MintOption(
address indexed sender,
address indexed optionReceiver,
address escrowOwner,
DataTypes.OptionInfo optionInfo,
uint256 mintFeeProtocol,
uint256 mintFeeDistPartner,
address indexed distPartner
);
/// @notice Emitted when a new fee handler is set
/// @param oldFeeHandler The previous fee handler address
/// @param newFeeHandler The new fee handler address
event NewFeeHandler(address oldFeeHandler, address newFeeHandler);
/// @notice Emitted when quote pause status changes
/// @param quoter The address whose pause status changed
/// @param isPaused The new pause status
event PauseQuotes(address indexed quoter, bool isPaused);
/// @notice Emitted when tokens are transferred between addresses.
/// @param token The address of the token contract.
/// @param from The address transferring the tokens.
/// @param to The address receiving the tokens.
/// @param value The amount of tokens transferred.
event Transfer(
address indexed token,
address indexed from,
address indexed to,
uint256 value
);
/// @notice Emitted when ownership of escrow is transferred
/// @param escrow The address of the escrow contract.
/// @param oldOwner The address of the old owner.
/// @param newOwner The address of the new owner.
event TransferOwnership(
address indexed escrow,
address indexed oldOwner,
address indexed newOwner
);
/// @notice Returns the address of the escrow implementation contract.
/// @return escrowImpl The address of the escrow implementation contract.
function escrowImpl() external view returns (address);
/// @notice Returns the address of the fee handler contract.
/// @return feeHandler The address of the fee handler.
function feeHandler() external view returns (address);
/// @notice Returns the total number of escrows created.
/// @return numEscrows The total number of escrows.
function numEscrows() external view returns (uint256);
/// @notice Checks if a specific address is registered as an escrow.
/// @param escrow The address to check.
/// @return True if the address is an escrow, false otherwise.
function isEscrow(address escrow) external view returns (bool);
/// @notice Checks if a specific quote has been used.
/// @param quoteHash The hash of the quote.
/// @return True if the quote has been used, false otherwise.
function isQuoteUsed(bytes32 quoteHash) external view returns (bool);
/// @notice Checks if a specific swap quote has been used.
/// @param swapQuoteHash The hash of the swap quote.
/// @return True if the swap quote has been used, false otherwise.
function isSwapQuoteUsed(
bytes32 swapQuoteHash
) external view returns (bool);
/// @notice Checks if quotes are paused for a specific address.
/// @param quoter The address to check.
/// @return True if quotes are paused for the address, false otherwise.
function quotesPaused(address quoter) external view returns (bool);
/// @notice Creates a new Dutch auction
/// @param escrowOwner The address of the escrow owner
/// @param auctionInitialization The initialization data for the auction
/// @param distPartner The address of the distribution partner
function createAuction(
address escrowOwner,
DataTypes.AuctionInitialization calldata auctionInitialization,
address distPartner
) external;
/// @notice Withdraws from an existing escrow and creates a new auction
/// @param oldEscrow The address of the old escrow
/// @param escrowOwner The address of the escrow owner
/// @param auctionInitialization The initialization data for the auction
/// @param distPartner The address of the distribution partner
function withdrawFromEscrowAndCreateAuction(
address oldEscrow,
address escrowOwner,
DataTypes.AuctionInitialization calldata auctionInitialization,
address distPartner
) external;
/// @notice Withdraws tokens from a specified escrow
/// @param escrow The escrow address from which to withdraw
/// @param to The address to receive the withdrawn tokens
/// @param token The token to be withdrawn
/// @param amount The amount of tokens to withdraw
function withdraw(
address escrow,
address to,
address token,
uint256 amount
) external;
/// @notice Places a bid on an auction
/// @param escrow The escrow address for the auction
/// @param optionReceiver The address to receive the option
/// @param relBid The relative bid in percentage of notional
/// @param refSpot The reference spot price
/// @param oracleData Additional optional oracle data for validation
/// @return preview The bid preview data
/// @return distPartner The distribution partner
function bidOnAuction(
address escrow,
address optionReceiver,
uint256 relBid,
uint256 refSpot,
bytes[] memory oracleData
)
external
returns (DataTypes.BidPreview memory preview, address distPartner);
/// @notice Exercises an option in an escrow
/// @param escrow The escrow address holding the option
/// @param underlyingReceiver The address receiving the underlying asset
/// @param underlyingAmount The amount of the underlying asset exercised
/// @param payInSettlementToken Whether payment is in the settlement token
/// @param oracleData Additional optional oracle data for validation
function exercise(
address escrow,
address underlyingReceiver,
uint256 underlyingAmount,
bool payInSettlementToken,
bytes[] memory oracleData
) external;
/// @notice Borrows underlying tokens from an escrow
/// @param escrow The escrow address providing the loan
/// @param underlyingReceiver The address to receive the loaned tokens
/// @param borrowUnderlyingAmount The amount of the loan
function borrow(
address escrow,
address underlyingReceiver,
uint128 borrowUnderlyingAmount
) external;
/// @notice Repays a loan to an escrow
/// @param escrow The escrow address receiving the repayment
/// @param collateralReceiver The address to receive collateral
/// @param repayUnderlyingAmount The amount of the underlying asset repaid
function repay(
address escrow,
address collateralReceiver,
uint128 repayUnderlyingAmount
) external;
/// @notice Takes an RFQ quote
/// @param escrowOwner The address of the escrow owner
/// @param rfqInitialization The initialization data for the RFQ
/// @param distPartner The distribution partner's address
function takeQuote(
address escrowOwner,
DataTypes.RFQInitialization calldata rfqInitialization,
address distPartner
) external;
/// @notice Takes a swap quote
/// @param to The address to receive the swapped tokens
/// @param swapQuote The swap quote details
function takeSwapQuote(
address to,
DataTypes.SwapQuote calldata swapQuote
) external;
/// @notice Toggles the pause status of quotes for the sender
function togglePauseQuotes() external;
/// @notice Mints a new option
/// @param optionReceiver The address to receive the minted option
/// @param escrowOwner The owner of the escrow minting the option
/// @param optionInfo The details of the option being minted
/// @param optionNaming The name and symbol of the option being minted
/// @param distPartner The distribution partner's address
function mintOption(
address optionReceiver,
address escrowOwner,
DataTypes.OptionInfo calldata optionInfo,
DataTypes.OptionNaming calldata optionNaming,
address distPartner
) external;
/// @notice Sets a new fee handler address
/// @param newFeeHandler The new fee handler address
function setFeeHandler(address newFeeHandler) external;
/// @notice Retrieves the current exercise fee
/// @return exerciseFee The current exercise fee as a `uint96`
function getExerciseFee() external view returns (uint96 exerciseFee);
/// @notice Returns the match fee and distribution partner fee share for a given option match.
/// @param distPartner The address of the distribution partner.
/// @param optionPremium The given option premium.
/// @param optionInfo The given option info.
/// @return matchFeeProtocol The protocol's match fee
/// @return matchFeeDistPartner The distribution partner's match fee
function getMatchFees(
address distPartner,
uint128 optionPremium,
DataTypes.OptionInfo calldata optionInfo
)
external
view
returns (uint128 matchFeeProtocol, uint128 matchFeeDistPartner);
/// @notice Calculates mint fees for a given distribution partner and notional
/// @param distPartner The distribution partner's address
/// @param notional The notional of the option in underlying token units
/// @return mintFeeProtocol The protocol's mint fee in option tokens
/// @return mintFeeDistPartner The distribution partner's mint fee in option tokens
function getMintFees(
address distPartner,
uint128 notional
)
external
view
returns (uint256 mintFeeProtocol, uint256 mintFeeDistPartner);
/// @notice Previews the result of taking a quote
/// @param rfqInitialization The initialization data for the RFQ
/// @param distPartner The distribution partner's address
/// @return A preview of the quote as a `TakeQuotePreview` struct
function previewTakeQuote(
DataTypes.RFQInitialization calldata rfqInitialization,
address distPartner
) external view returns (DataTypes.TakeQuotePreview memory);
/// @notice Retrieves a range of escrows
/// @param from The starting index of escrows to retrieve
/// @param numElements The number of escrows to retrieve
/// @return _escrows An array of escrow addresses
function getEscrows(
uint256 from,
uint256 numElements
) external view returns (address[] memory _escrows);
/// @notice Emits a `Transfer` event for a token.
/// @dev Callable only by registered escrows. Reverts if not an escrow.
/// @param from Address sending the tokens.
/// @param to Address receiving the tokens.
/// @param value Amount of tokens transferred.
function emitTransferEvent(
address from,
address to,
uint256 value
) external;
/// @notice Emits a `TransferOwnership` event for an escrow contract.
/// @dev Callable only by registered escrows. Reverts if not an escrow.
/// @param oldOwner Address of the old owner.
/// @param newOwner Address of the new owner.
function emitTransferOwnershipEvent(
address oldOwner,
address newOwner
) external;
}{
"optimizer": {
"enabled": true,
"runs": 1000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initOwner","type":"address"},{"internalType":"address","name":"_escrowImpl","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"ERC1167FailedCreateClone","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeHandlerAlreadySet","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidBorrowCap","type":"error"},{"inputs":[],"name":"InvalidEIP1271Signature","type":"error"},{"inputs":[],"name":"InvalidEarliestExercise","type":"error"},{"inputs":[],"name":"InvalidExpiry","type":"error"},{"inputs":[],"name":"InvalidGetEscrowsQuery","type":"error"},{"inputs":[],"name":"InvalidNotional","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidTakeQuote","type":"error"},{"inputs":[],"name":"InvalidTokenPair","type":"error"},{"inputs":[],"name":"NotAnEscrow","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"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":"SwapQuoteAlreadyUsed","type":"error"},{"inputs":[],"name":"SwapQuoteExpired","type":"error"},{"inputs":[],"name":"SwapQuotePaused","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"address","name":"optionReceiver","type":"address"},{"components":[{"internalType":"enum DataTypes.BidStatus","name":"status","type":"uint8"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint128","name":"strike","type":"uint128"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"address","name":"premiumToken","type":"address"},{"internalType":"uint256","name":"oracleSpotPrice","type":"uint256"},{"internalType":"uint64","name":"currAsk","type":"uint64"},{"internalType":"uint128","name":"matchFeeProtocol","type":"uint128"},{"internalType":"uint128","name":"matchFeeDistPartner","type":"uint128"}],"indexed":false,"internalType":"struct DataTypes.BidPreview","name":"bidPreview","type":"tuple"},{"indexed":true,"internalType":"address","name":"distPartner","type":"address"}],"name":"BidOnAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"address","name":"underlyingReceiver","type":"address"},{"indexed":false,"internalType":"uint128","name":"underlyingAmount","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralFeeAmount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"escrowOwner","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint128","name":"notional","type":"uint128"},{"components":[{"internalType":"uint128","name":"relStrike","type":"uint128"},{"internalType":"uint48","name":"tenor","type":"uint48"},{"internalType":"uint48","name":"earliestExerciseTenor","type":"uint48"},{"internalType":"uint32","name":"decayStartTime","type":"uint32"},{"internalType":"uint32","name":"decayDuration","type":"uint32"},{"internalType":"uint64","name":"relPremiumStart","type":"uint64"},{"internalType":"uint64","name":"relPremiumFloor","type":"uint64"},{"internalType":"uint128","name":"minSpot","type":"uint128"},{"internalType":"uint128","name":"maxSpot","type":"uint128"}],"internalType":"struct DataTypes.AuctionParams","name":"auctionParams","type":"tuple"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"indexed":false,"internalType":"struct DataTypes.AuctionInitialization","name":"auctionInitialization","type":"tuple"},{"indexed":false,"internalType":"uint96","name":"exerciseFee","type":"uint96"},{"indexed":false,"internalType":"address","name":"distPartner","type":"address"}],"name":"CreateAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"address","name":"underlyingReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exerciseFeeAmount","type":"uint256"}],"name":"Exercise","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"optionReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"escrowOwner","type":"address"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"notional","type":"uint128"},{"internalType":"uint128","name":"strike","type":"uint128"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"indexed":false,"internalType":"struct DataTypes.OptionInfo","name":"optionInfo","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"mintFeeProtocol","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintFeeDistPartner","type":"uint256"},{"indexed":true,"internalType":"address","name":"distPartner","type":"address"}],"name":"MintOption","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFeeHandler","type":"address"},{"indexed":false,"internalType":"address","name":"newFeeHandler","type":"address"}],"name":"NewFeeHandler","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"quoter","type":"address"},{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseQuotes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"address","name":"collateralReceiver","type":"address"},{"indexed":false,"internalType":"uint128","name":"repayUnderlyingAmount","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"unlockedCollateralAmount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"escrowOwner","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"components":[{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"notional","type":"uint128"},{"internalType":"uint128","name":"strike","type":"uint128"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.OptionInfo","name":"optionInfo","type":"tuple"},{"components":[{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"eip1271Maker","type":"address"}],"internalType":"struct DataTypes.RFQQuote","name":"rfqQuote","type":"tuple"}],"indexed":false,"internalType":"struct DataTypes.RFQInitialization","name":"rfqInitialization","type":"tuple"},{"components":[{"internalType":"enum DataTypes.RFQStatus","name":"status","type":"uint8"},{"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"internalType":"address","name":"quoter","type":"address"},{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"address","name":"premiumToken","type":"address"},{"internalType":"uint128","name":"matchFeeProtocol","type":"uint128"},{"internalType":"uint128","name":"matchFeeDistPartner","type":"uint128"}],"indexed":false,"internalType":"struct DataTypes.TakeQuotePreview","name":"takeQuotePreview","type":"tuple"},{"indexed":false,"internalType":"uint96","name":"exerciseFee","type":"uint96"},{"indexed":true,"internalType":"address","name":"distPartner","type":"address"}],"name":"TakeQuote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"components":[{"internalType":"address","name":"takerGiveToken","type":"address"},{"internalType":"uint256","name":"takerGiveAmount","type":"uint256"},{"internalType":"address","name":"makerGiveToken","type":"address"},{"internalType":"uint256","name":"makerGiveAmount","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"eip1271Maker","type":"address"}],"indexed":false,"internalType":"struct DataTypes.SwapQuote","name":"swapQuote","type":"tuple"}],"name":"TakeSwapQuote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"TransferOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"escrowOwner","type":"address"},{"indexed":true,"internalType":"address","name":"oldEscrow","type":"address"},{"indexed":true,"internalType":"address","name":"newEscrow","type":"address"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint128","name":"notional","type":"uint128"},{"components":[{"internalType":"uint128","name":"relStrike","type":"uint128"},{"internalType":"uint48","name":"tenor","type":"uint48"},{"internalType":"uint48","name":"earliestExerciseTenor","type":"uint48"},{"internalType":"uint32","name":"decayStartTime","type":"uint32"},{"internalType":"uint32","name":"decayDuration","type":"uint32"},{"internalType":"uint64","name":"relPremiumStart","type":"uint64"},{"internalType":"uint64","name":"relPremiumFloor","type":"uint64"},{"internalType":"uint128","name":"minSpot","type":"uint128"},{"internalType":"uint128","name":"maxSpot","type":"uint128"}],"internalType":"struct DataTypes.AuctionParams","name":"auctionParams","type":"tuple"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"indexed":false,"internalType":"struct DataTypes.AuctionInitialization","name":"auctionInitialization","type":"tuple"}],"name":"WithdrawFromEscrowAndCreateAuction","type":"event"},{"inputs":[{"internalType":"address","name":"escrow","type":"address"},{"internalType":"address","name":"optionReceiver","type":"address"},{"internalType":"uint256","name":"relBid","type":"uint256"},{"internalType":"uint256","name":"_refSpot","type":"uint256"},{"internalType":"bytes[]","name":"_oracleData","type":"bytes[]"}],"name":"bidOnAuction","outputs":[{"components":[{"internalType":"enum DataTypes.BidStatus","name":"status","type":"uint8"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint128","name":"strike","type":"uint128"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"address","name":"premiumToken","type":"address"},{"internalType":"uint256","name":"oracleSpotPrice","type":"uint256"},{"internalType":"uint64","name":"currAsk","type":"uint64"},{"internalType":"uint128","name":"matchFeeProtocol","type":"uint128"},{"internalType":"uint128","name":"matchFeeDistPartner","type":"uint128"}],"internalType":"struct DataTypes.BidPreview","name":"preview","type":"tuple"},{"internalType":"address","name":"distPartner","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"escrow","type":"address"},{"internalType":"address","name":"underlyingReceiver","type":"address"},{"internalType":"uint128","name":"borrowUnderlyingAmount","type":"uint128"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"escrowOwner","type":"address"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint128","name":"notional","type":"uint128"},{"components":[{"internalType":"uint128","name":"relStrike","type":"uint128"},{"internalType":"uint48","name":"tenor","type":"uint48"},{"internalType":"uint48","name":"earliestExerciseTenor","type":"uint48"},{"internalType":"uint32","name":"decayStartTime","type":"uint32"},{"internalType":"uint32","name":"decayDuration","type":"uint32"},{"internalType":"uint64","name":"relPremiumStart","type":"uint64"},{"internalType":"uint64","name":"relPremiumFloor","type":"uint64"},{"internalType":"uint128","name":"minSpot","type":"uint128"},{"internalType":"uint128","name":"maxSpot","type":"uint128"}],"internalType":"struct DataTypes.AuctionParams","name":"auctionParams","type":"tuple"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.AuctionInitialization","name":"auctionInitialization","type":"tuple"},{"internalType":"address","name":"distPartner","type":"address"}],"name":"createAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"emitTransferEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldOwner","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"emitTransferOwnershipEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"escrowImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"escrow","type":"address"},{"internalType":"address","name":"underlyingReceiver","type":"address"},{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"bool","name":"payInSettlementToken","type":"bool"},{"internalType":"bytes[]","name":"oracleData","type":"bytes[]"}],"name":"exercise","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeHandler","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"numElements","type":"uint256"}],"name":"getEscrows","outputs":[{"internalType":"address[]","name":"_escrowArray","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExerciseFee","outputs":[{"internalType":"uint96","name":"exerciseFee","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"distPartner","type":"address"},{"internalType":"uint128","name":"optionPremium","type":"uint128"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"notional","type":"uint128"},{"internalType":"uint128","name":"strike","type":"uint128"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.OptionInfo","name":"optionInfo","type":"tuple"}],"name":"getMatchFees","outputs":[{"internalType":"uint128","name":"matchFeeProtocol","type":"uint128"},{"internalType":"uint128","name":"matchFeeDistPartner","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"distPartner","type":"address"},{"internalType":"uint128","name":"notional","type":"uint128"}],"name":"getMintFees","outputs":[{"internalType":"uint256","name":"mintFeeProtocol","type":"uint256"},{"internalType":"uint256","name":"mintFeeDistPartner","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isEscrow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"isQuoteUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"isSwapQuoteUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"optionReceiver","type":"address"},{"internalType":"address","name":"escrowOwner","type":"address"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"notional","type":"uint128"},{"internalType":"uint128","name":"strike","type":"uint128"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.OptionInfo","name":"optionInfo","type":"tuple"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct DataTypes.OptionNaming","name":"optionNaming","type":"tuple"},{"internalType":"address","name":"distPartner","type":"address"}],"name":"mintOption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"numEscrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"notional","type":"uint128"},{"internalType":"uint128","name":"strike","type":"uint128"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.OptionInfo","name":"optionInfo","type":"tuple"},{"components":[{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"eip1271Maker","type":"address"}],"internalType":"struct DataTypes.RFQQuote","name":"rfqQuote","type":"tuple"}],"internalType":"struct DataTypes.RFQInitialization","name":"rfqInitialization","type":"tuple"},{"internalType":"address","name":"distPartner","type":"address"}],"name":"previewTakeQuote","outputs":[{"components":[{"internalType":"enum DataTypes.RFQStatus","name":"status","type":"uint8"},{"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"internalType":"address","name":"quoter","type":"address"},{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"address","name":"premiumToken","type":"address"},{"internalType":"uint128","name":"matchFeeProtocol","type":"uint128"},{"internalType":"uint128","name":"matchFeeDistPartner","type":"uint128"}],"internalType":"struct DataTypes.TakeQuotePreview","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"quotesPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"escrow","type":"address"},{"internalType":"address","name":"collateralReceiver","type":"address"},{"internalType":"uint128","name":"repayUnderlyingAmount","type":"uint128"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeHandler","type":"address"}],"name":"setFeeHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"escrowOwner","type":"address"},{"components":[{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint48","name":"expiry","type":"uint48"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint48","name":"earliestExercise","type":"uint48"},{"internalType":"uint128","name":"notional","type":"uint128"},{"internalType":"uint128","name":"strike","type":"uint128"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.OptionInfo","name":"optionInfo","type":"tuple"},{"components":[{"internalType":"uint128","name":"premium","type":"uint128"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"eip1271Maker","type":"address"}],"internalType":"struct DataTypes.RFQQuote","name":"rfqQuote","type":"tuple"}],"internalType":"struct DataTypes.RFQInitialization","name":"rfqInitialization","type":"tuple"},{"internalType":"address","name":"distPartner","type":"address"}],"name":"takeQuote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"address","name":"takerGiveToken","type":"address"},{"internalType":"uint256","name":"takerGiveAmount","type":"uint256"},{"internalType":"address","name":"makerGiveToken","type":"address"},{"internalType":"uint256","name":"makerGiveAmount","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"eip1271Maker","type":"address"}],"internalType":"struct DataTypes.SwapQuote","name":"swapQuote","type":"tuple"}],"name":"takeSwapQuote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"togglePauseQuotes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"escrow","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldEscrow","type":"address"},{"internalType":"address","name":"escrowOwner","type":"address"},{"components":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"uint128","name":"notional","type":"uint128"},{"components":[{"internalType":"uint128","name":"relStrike","type":"uint128"},{"internalType":"uint48","name":"tenor","type":"uint48"},{"internalType":"uint48","name":"earliestExerciseTenor","type":"uint48"},{"internalType":"uint32","name":"decayStartTime","type":"uint32"},{"internalType":"uint32","name":"decayDuration","type":"uint32"},{"internalType":"uint64","name":"relPremiumStart","type":"uint64"},{"internalType":"uint64","name":"relPremiumFloor","type":"uint64"},{"internalType":"uint128","name":"minSpot","type":"uint128"},{"internalType":"uint128","name":"maxSpot","type":"uint128"}],"internalType":"struct DataTypes.AuctionParams","name":"auctionParams","type":"tuple"},{"components":[{"internalType":"uint64","name":"borrowCap","type":"uint64"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"bool","name":"premiumTokenIsUnderlying","type":"bool"},{"internalType":"bool","name":"votingDelegationAllowed","type":"bool"},{"internalType":"address","name":"allowedDelegateRegistry","type":"address"}],"internalType":"struct DataTypes.AdvancedSettings","name":"advancedSettings","type":"tuple"}],"internalType":"struct DataTypes.AuctionInitialization","name":"auctionInitialization","type":"tuple"},{"internalType":"address","name":"distPartner","type":"address"}],"name":"withdrawFromEscrowAndCreateAuction","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b506040516200493c3803806200493c833981016040819052620000349162000118565b816001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f81620000ab565b506001600160a01b038116620000985760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03166080525062000150565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200011357600080fd5b919050565b600080604083850312156200012c57600080fd5b6200013783620000fb565b91506200014760208401620000fb565b90509250929050565b6080516147c962000173600039600081816104b70152612b6a01526147c96000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806377c05dec11610104578063b166a09f116100a2578063ca41363e11610071578063ca41363e14610479578063f2fde38b1461048c578063f9361aef1461049f578063fda25df4146104b257600080fd5b8063b166a09f146103fd578063b35c845e14610420578063b4df001e14610441578063c18abe0d1461046657600080fd5b80638da5cb5b116100de5780638da5cb5b146103a357806393594d7f146103b4578063a597ec1f146103d7578063a6d49dca146103ea57600080fd5b806377c05dec146103455780637d431c7c146103685780638c35dc4d1461037b57600080fd5b806347e5dc20116101715780635920d5771161014b5780635920d577146102f75780635a696cb81461030a578063715018a61461032a578063733140771461033257600080fd5b806347e5dc20146102915780634dcfbba4146102b15780635468fe95146102c457600080fd5b8063369bd2fe116101ad578063369bd2fe146102185780633849153b146102205780633c93adee146102535780633df8f62e1461027e57600080fd5b8063065d4a6d146101d45780630b620b81146101e957806318e2a560146101fc575b600080fd5b6101e76101e2366004613217565b6104d9565b005b6101e76101f736600461326e565b610805565b61020560025481565b6040519081526020015b60405180910390f35b6101e761099d565b61023361022e3660046132fd565b6109f8565b604080516001600160801b0393841681529290911660208301520161020f565b600154610266906001600160a01b031681565b6040516001600160a01b03909116815260200161020f565b6101e761028c366004613359565b610b45565b6102a461029f3660046133bd565b610e5b565b60405161020f91906133df565b6101e76102bf36600461343f565b610f71565b6102e76102d236600461349c565b60056020526000908152604090205460ff1681565b604051901515815260200161020f565b6101e76103053660046134b5565b6112e5565b61031d6103183660046134f6565b611407565b60405161020f91906135e1565b6101e7611826565b6101e76103403660046135ef565b61183a565b6102e76103533660046135ef565b60066020526000908152604090205460ff1681565b6101e761037636600461360c565b6118f7565b61038e61038936600461364c565b611af6565b6040805192835260208301919091520161020f565b6000546001600160a01b0316610266565b6102e76103c236600461349c565b60046020526000908152604090205460ff1681565b6101e76103e536600461360c565b611c42565b6101e76103f836600461367a565b611d9c565b6102e761040b3660046135ef565b60036020526000908152604090205460ff1681565b61043361042e366004613822565b611e1b565b60405161020f9291906139bf565b61044961215d565b6040516bffffffffffffffffffffffff909116815260200161020f565b6101e76104743660046139e5565b61220e565b6101e7610487366004613a21565b61228d565b6101e761049a3660046135ef565b6124c1565b6101e76104ad366004613a87565b61251d565b6102667f000000000000000000000000000000000000000000000000000000000000000081565b8060800135421115610517576040517f5c32099600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004661052760208401846135ef565b602084013561053c60608601604087016135ef565b6040805160208101959095526001600160a01b03938416908501526060808501929092529091166080808401919091529084013560a083015283013560c082015260e00160408051601f19818403018152919052805160209091012090506000806105ad60e0850160c086016135ef565b6001600160a01b03160361063c577f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c839052603c9020610635906105fb60a0860186613b18565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061292192505050565b90506106b1565b600061066461065160e0860160c087016135ef565b8461065f60a0880188613b18565b61294b565b90508061069d576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106ad60e0850160c086016135ef565b9150505b6001600160a01b03811660009081526006602052604090205460ff1615610704576040517f6cff8dd500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205460ff161561074d576040517f9b1475af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040909120805460ff191660011790556107919033908390860180359061078090886135ef565b6001600160a01b0316929190612a7e565b6107aa81856060860180359061078090604089016135ef565b806001600160a01b0316846001600160a01b0316336001600160a01b03167fc09ea7f7280174a395e9010b2e05ab1888cd36f5ad99b4429478af303ce78c3d866040516107f79190613bd5565b60405180910390a450505050565b6001600160a01b03841660009081526003602052604090205460ff1661083e576040516340d8c4db60e11b815260040160405180910390fd5b836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561087c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a09190613c7e565b6001600160a01b0316336001600160a01b0316146108d157604051636edaef2f60e11b815260040160405180910390fd5b6040517fd0e8dcff0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015283811660248301526044820183905285169063d0e8dcff90606401600060405180830381600087803b15801561093c57600080fd5b505af1158015610950573d6000803e3d6000fd5b5050604080516001600160a01b0387811682526020820186905280871694508816925033917fe826ecb5c03d4897f8ab426ee94064e06179dff39cd9fdd0776904cd935c95d891016107f7565b33600081815260066020908152604091829020805460ff8116801560ff199092168217909255925192835292917fdcbed411faf93d1cef89c9e1923cd8e047c29e2d465b976b24b0b22c054b340e910160405180910390a250565b60015460009081906001600160a01b03168015610b3c57600080826001600160a01b031663dd07ab1c8989896040518463ffffffff1660e01b8152600401610a4293929190613e04565b6040805180830381865afa158015610a5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a829190613e31565b909250905060006702c68af0bb1400008311610a9e5782610aa8565b6702c68af0bb1400005b90506000670de0b6b3a76400008311610ac15782610acb565b670de0b6b3a76400005b90506000670de0b6b3a7640000610aeb846001600160801b038d16613e6b565b610af59190613e82565b9050610b1c670de0b6b3a7640000610b0d8484613e6b565b610b179190613e82565b612b00565b9650610b34610b176001600160801b03891683613ea4565b975050505050505b50935093915050565b6000610b518383611407565b9050600481516005811115610b6857610b6861353d565b14610b9f576040517fe30578ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201516000908152600490915260408120805460ff1916600117905580610bc7612b51565b915091506000610bd561215d565b60408086015190517f537952080000000000000000000000000000000000000000000000000000000081529192506001600160a01b03851691635379520891610c2a9130918c9187908d908a90600401613f60565b600060405180830381600087803b158015610c4457600080fd5b505af1158015610c58573d6000803e3d6000fd5b50610c8a9250339150859050610c7460a08a0160808b01613fbb565b6001600160801b031661078060208b018b6135ef565b610cef8460400151338660a001518760c001518a806101600190610cae9190613fd8565b610cbc906020810190613fbb565b610cc69190613ff8565b610cd09190613ff8565b60808801516001600160a01b03169291906001600160801b0316612a7e565b60c08401516001600160801b031615610d3757610d378460400151868660c001516001600160801b031687608001516001600160a01b0316612a7e909392919063ffffffff16565b60a08401516001600160801b031615610df757600154604085015160a086015160808701516001600160a01b0393841693610d7f9391169184906001600160801b0316612a7e565b608085015160a08601516040516358c0528f60e01b81526001600160a01b0392831660048201526001600160801b039091166024820152908216906358c0528f90604401600060405180830381600087803b158015610ddd57600080fd5b505af1158015610df1573d6000803e3d6000fd5b50505050505b846001600160a01b0316836001600160a01b0316336001600160a01b03167f2603b553dc2ab4d1a644bb67a527695755c7c1adc290f4718813e649cc6c71888a8a8987604051610e4a949392919061401f565b60405180910390a450505050505050565b600754606090821580610e76575080610e748486614070565b115b15610ead576040517f6269996b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115610ec657610ec66136bb565b604051908082528060200260200182016040528015610eef578160200160208202803683370190505b50915060005b83811015610f69576007610f098287614070565b81548110610f1957610f19614083565b9060005260206000200160009054906101000a90046001600160a01b0316838281518110610f4957610f49614083565b6001600160a01b0390921660209283029190910190910152600101610ef5565b505092915050565b6001600160a01b03841660009081526003602052604090205460ff16610faa576040516340d8c4db60e11b815260040160405180910390fd5b836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fe8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c9190613c7e565b6001600160a01b0316336001600160a01b03161461103d57604051636edaef2f60e11b815260040160405180910390fd5b600080611048612b51565b91509150816001600160a01b03166323c8affa308761106561215d565b8886896040518763ffffffff1660e01b8152600401611089969594939291906141ec565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b50600092506110cc91505060208601866135ef565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b03898116600483015291909116906370a0823190602401602060405180830381865afa15801561112d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111519190614244565b90506000816111666060880160408901613fbb565b6001600160801b0316101561117b573361117d565b835b90506000826111926060890160408a01613fbb565b6001600160801b031610156111bf576111b16060880160408901613fbb565b6001600160801b03166111e3565b826111d06060890160408a01613fbb565b6001600160801b03166111e39190613ea4565b90506001600160a01b03891663d0e8dcff8361120260208b018b6135ef565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101869052606401600060405180830381600087803b15801561125157600080fd5b505af1158015611265573d6000803e3d6000fd5b5050505060008111156112855761128533868361078060208c018c6135ef565b846001600160a01b0316896001600160a01b0316896001600160a01b03167f957cced42c73d5e844e49787802497a4b4e27b8a7f239e76e7c35133f4a1ada08a6040516112d2919061425d565b60405180910390a4505050505050505050565b6000806112f0612b51565b9150915060006112fe61215d565b6040517f23c8affa0000000000000000000000000000000000000000000000000000000081529091506001600160a01b038416906323c8affa906113509030908a9086908b9089908c906004016141ec565b600060405180830381600087803b15801561136a57600080fd5b505af115801561137e573d6000803e3d6000fd5b505050506113b0338487604001602081019061139a9190613fbb565b6001600160801b031661078060208a018a6135ef565b826001600160a01b0316866001600160a01b03167f081c9ad95e93f5f9d217a45f3b87fd8f86ab622929ac7342f8eafacbd2c4ad3e8784886040516113f79392919061426c565b60405180910390a3505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101829052904684611450610160820182613fd8565b61145e906020810190613fbb565b61146c610160880188613fd8565b6020013560405160200161148394939291906142a8565b60408051601f19818403018152919052805160209091012090506000806114ae610160870187613fd8565b6114bf9060808101906060016135ef565b6001600160a01b031603611523577f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c839052603c902061151c9061150e610160880188613fd8565b6105fb906040810190613b18565b90506115a4565b6000611564611536610160880188613fd8565b6115479060808101906060016135ef565b846115566101608a018a613fd8565b61065f906040810190613b18565b9050806115815761157760058484612c34565b9350505050611820565b61158f610160870187613fd8565b6115a09060808101906060016135ef565b9150505b6115b460608601604087016135ef565b6001600160a01b03166115ca60208701876135ef565b6001600160a01b031614806115f557506115ea60a0860160808701613fbb565b6001600160801b0316155b80611616575061160b60c0860160a08701613fbb565b6001600160801b0316155b8061165b575061162c60808601606087016142da565b61163990620151806142f7565b65ffffffffffff1661165160408701602088016142da565b65ffffffffffff16105b806116865750670de0b6b3a764000061167a60e0870160c08801614316565b67ffffffffffffffff16115b156116a05761169760018383612c34565b92505050611820565b6116ae610160860186613fd8565b602001354211806116d557506116ca60408601602087016142da565b65ffffffffffff1642115b156116e65761169760008383612c34565b60008281526004602052604090205460ff16156117095761169760028383612c34565b6001600160a01b03811660009081526006602052604090205460ff16156117365761169760038383612c34565b60008061175f8661174b6101608a018a613fd8565b611759906020810190613fbb565b896109f8565b6040805160e0810190915291935091508060048152602081018690526001600160a01b038516604082015260600161179b6101608a018a613fd8565b6117a9906020810190613fbb565b6001600160801b031681526020016117c96101208a016101008b01614333565b6117e2576117dd60608a0160408b016135ef565b6117ef565b6117ef60208a018a6135ef565b6001600160a01b03168152602001836001600160801b03168152602001826001600160801b03168152509450505050505b92915050565b61182e612cc9565b6118386000612d0f565b565b611842612cc9565b6001546001600160a01b03908116908216810361188b576040517fc927103e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384811691821790925560408051928416835260208301919091527f9223780305f6b8602877f20db7cc3a6770c99586cb92db707a89375807e12337910160405180910390a15050565b6001600160a01b03831660009081526003602052604090205460ff16611930576040516340d8c4db60e11b815260040160405180910390fd5b6040517f67ff93a60000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0383811660248301526001600160801b038316604483015260009182918291908716906367ff93a6906064016060604051808303816000875af11580156119ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d29190614350565b919450925090506119ee6001600160a01b038416338885612a7e565b6001546001600160a01b03168015801590611a095750600082115b15611a8d57600154611a2a906001600160a01b038681169133911685612a7e565b6040516358c0528f60e01b81526001600160a01b038581166004830152602482018490528216906358c0528f90604401600060405180830381600087803b158015611a7457600080fd5b505af1158015611a88573d6000803e3d6000fd5b505050505b604080516001600160a01b0388811682526001600160801b0388166020830152918101859052606081018490529088169033907f0f6b57650350b4f610474b25b5969726ade85bd32d17cf9de29015bd617cc9fd9060800160405180910390a350505050505050565b60015460009081906001600160a01b03168015611c3a576040517f7eda99570000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526000918291841690637eda9957906024016040805180830381865afa158015611b70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b949190613e31565b909250905060006702c68af0bb1400008311611bb05782611bba565b6702c68af0bb1400005b90506000670de0b6b3a76400008311611bd35782611bdd565b670de0b6b3a76400005b90506000670de0b6b3a7640000611bfd846001600160801b038c16613e6b565b611c079190613e82565b9050670de0b6b3a7640000611c1c8383613e6b565b611c269190613e82565b9650611c328782613ea4565b975050505050505b509250929050565b6001600160a01b03831660009081526003602052604090205460ff16611c7b576040516340d8c4db60e11b815260040160405180910390fd5b6040517f9076e9040000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0383811660248301526001600160801b03831660448301526000918291861690639076e9049060640160408051808303816000875af1158015611cf5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d199190614387565b9092509050611d3c6001600160a01b03831633876001600160801b038716612a7e565b604080516001600160a01b0386811682526001600160801b03861660208301529181018390529086169081907ff6c7cbea93a9318a02e83b81b74aa67de77eaf4585af0f3118f30108f513849a9060600160405180910390a35050505050565b3360008181526003602052604090205460ff16611dcc576040516340d8c4db60e11b815260040160405180910390fd5b826001600160a01b0316846001600160a01b0316826001600160a01b03167fd1398bee19313d6bf672ccb116e51f4a1a947e91c757907f51fbb5b5e56c698f856040516107f791815260200190565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526001600160a01b03861660009081526003602052604081205460ff16611eb5576040516340d8c4db60e11b815260040160405180910390fd5b6040517fa3620ec40000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063a3620ec490611f009088908a9089908990600401614449565b6101a0604051808303816000875af1158015611f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4491906144a7565b8092508193505050611ff633886001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb29190613c7e565b8461014001518561016001518660c00151611fcd9190613ff8565b611fd79190613ff8565b60e08601516001600160a01b03169291906001600160801b0316612a7e565b6101608201516001600160801b03161561203c5761203c33828461016001516001600160801b03168560e001516001600160a01b0316612a7e909392919063ffffffff16565b6101408201516001600160801b0316156120fc5760015461014083015160e08401516001600160a01b039283169261208392911690339084906001600160801b0316612a7e565b60e08301516101408401516040516358c0528f60e01b81526001600160a01b0392831660048201526001600160801b039091166024820152908216906358c0528f90604401600060405180830381600087803b1580156120e257600080fd5b505af11580156120f6573d6000803e3d6000fd5b50505050505b806001600160a01b0316876001600160a01b0316336001600160a01b03167f7ebea06143b46f005fced4223cf841b88854a21cb67516c71838990a9f56f8e8898660405161214b9291906145b3565b60405180910390a49550959350505050565b6001546000906001600160a01b03168061217957600091505090565b806001600160a01b031663d1c699aa6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121db91906145d1565b91506611c37937e080006bffffffffffffffffffffffff8316116121ff5781612208565b6611c37937e080005b91505090565b3360008181526003602052604090205460ff1661223e576040516340d8c4db60e11b815260040160405180910390fd5b816001600160a01b0316836001600160a01b0316826001600160a01b03167f6954f1cdad46901994f29d9b1f78744c873c527bad04d294b4954cc8caf367da60405160405180910390a4505050565b6001600160a01b03851660009081526003602052604090205460ff166122c6576040516340d8c4db60e11b815260040160405180910390fd5b6000806000876001600160a01b03166331cd4e6233898989896040518663ffffffff1660e01b81526004016122ff9594939291906145ff565b6060604051808303816000875af115801561231e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123429190614350565b92509250925084156123c6576123c633896001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b49190613c7e565b6001600160a01b038616919085612a7e565b6001546001600160a01b031680158015906123e15750600082115b1561246557600154612402906001600160a01b038681169133911685612a7e565b6040516358c0528f60e01b81526001600160a01b038581166004830152602482018490528216906358c0528f90604401600060405180830381600087803b15801561244c57600080fd5b505af1158015612460573d6000803e3d6000fd5b505050505b604080516001600160a01b038a81168252602082018a9052918101849052908a169033907f5ee515779e0ca72dbfbc93b30480bbecf67910142933d89d3d89be8e28a9c8509060600160405180910390a3505050505050505050565b6124c9612cc9565b6001600160a01b038116612511576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b61251a81612d0f565b50565b61252d60608401604085016135ef565b6001600160a01b031661254360208501856135ef565b6001600160a01b031603612583576040517f8686656d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259360a0840160808501613fbb565b6001600160801b03166000036125d5576040517f950466ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125e560408401602085016142da565b65ffffffffffff16421115612626576040517fd36c850000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61263660808401606085016142da565b61264390620151806142f7565b65ffffffffffff1661265b60408501602086016142da565b65ffffffffffff16101561269b576040517f1e617b1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b670de0b6b3a76400006126b460e0850160c08601614316565b67ffffffffffffffff1611156126f6576040517fa7e9b5b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612700612b51565b50905060008061271a8461038960a0890160808a01613fbb565b9150915060008083118061272e5750600082115b612738578861273a565b305b9050836001600160a01b031663d951124d308a8461275661215d565b8c8c6040518763ffffffff1660e01b815260040161277996959493929190614644565b600060405180830381600087803b15801561279357600080fd5b505af11580156127a7573d6000803e3d6000fd5b505050506127d933858960800160208101906127c39190613fbb565b6001600160801b031661078060208c018c6135ef565b306001600160a01b038216036128ce5761282d8983856127ff60a08c0160808d01613fbb565b6001600160801b03166128129190613ea4565b61281c9190613ea4565b6001600160a01b0387169190612d6c565b8115612847576128476001600160a01b0385168684612d6c565b82156128ce57600154612867906001600160a01b03868116911685612d6c565b6001546040516358c0528f60e01b81526001600160a01b03868116600483015260248201869052909116906358c0528f90604401600060405180830381600087803b1580156128b557600080fd5b505af11580156128c9573d6000803e3d6000fd5b505050505b846001600160a01b0316896001600160a01b0316336001600160a01b03167f2e8d3d935843ef13282538bbbb45c3c49faa9797fe651d3fcb327f436a91116f8b8b88886040516112d294939291906146e5565b6000806000806129318686612da2565b9250925092506129418282612def565b5090949350505050565b6000806000866001600160a01b0316631626ba7e60e01b87878760405160240161297793929190614717565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516129ca919061473a565b600060405180830381855afa9150503d8060008114612a05576040519150601f19603f3d011682016040523d82523d6000602084013e612a0a565b606091505b5091509150818015612a1d575080516020145b15612a6f57600081806020019051810190612a38919061474c565b6001600160e01b0319167f1626ba7e00000000000000000000000000000000000000000000000000000000149350612a7692505050565b6000925050505b949350505050565b6040516001600160a01b038481166024830152838116604483015260648201839052612afa9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612ef7565b50505050565b60006001600160801b03821115612b4d576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526080600482015260248101839052604401612508565b5090565b6000806002546001612b639190614070565b9050612bb77f000000000000000000000000000000000000000000000000000000000000000082604051602001612b9c91815260200190565b60405160208183030381529060405280519060200120612f73565b60028290556001600160a01b0381166000818152600360205260408120805460ff191660019081179091556007805491820181559091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68801805473ffffffffffffffffffffffffffffffffffffffff1916909117905592909150565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e00160405280856005811115612c8a57612c8a61353d565b8152602081018590526001600160a01b03841660408201526000606082018190526080820181905260a0820181905260c09091015290505b9392505050565b6000546001600160a01b03163314611838576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401612508565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03838116602483015260448201839052612d9d91859182169063a9059cbb90606401612ab3565b505050565b60008060008351604103612ddc5760208401516040850151606086015160001a612dce88828585612ffa565b955095509550505050612de8565b50508151600091506002905b9250925092565b6000826003811115612e0357612e0361353d565b03612e0c575050565b6001826003811115612e2057612e2061353d565b03612e57576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002826003811115612e6b57612e6b61353d565b03612ea5576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401612508565b6003826003811115612eb957612eb961353d565b03612ef3576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401612508565b5050565b6000612f0c6001600160a01b038416836130c9565b90508051600014158015612f31575080806020019051810190612f2f9190614776565b155b15612d9d576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401612508565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611820576040517fc2f868f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561303557506000915060039050826130bf565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613089573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166130b5575060009250600191508290506130bf565b9250600091508190505b9450945094915050565b6060612cc28383600084600080856001600160a01b031684866040516130ef919061473a565b60006040518083038185875af1925050503d806000811461312c576040519150601f19603f3d011682016040523d82523d6000602084013e613131565b606091505b509150915061314186838361314b565b9695505050505050565b6060826131605761315b826131c0565b612cc2565b815115801561317757506001600160a01b0384163b155b156131b9576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401612508565b5080612cc2565b8051156131d05780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116811461251a57600080fd5b6000806040838503121561322a57600080fd5b823561323581613202565b9150602083013567ffffffffffffffff81111561325157600080fd5b830160e0818603121561326357600080fd5b809150509250929050565b6000806000806080858703121561328457600080fd5b843561328f81613202565b9350602085013561329f81613202565b925060408501356132af81613202565b9396929550929360600135925050565b6001600160801b038116811461251a57600080fd5b80356132df816132bf565b919050565b600061016082840312156132f757600080fd5b50919050565b60008060006101a0848603121561331357600080fd5b833561331e81613202565b9250602084013561332e816132bf565b915061333d85604086016132e4565b90509250925092565b600061018082840312156132f757600080fd5b60008060006060848603121561336e57600080fd5b833561337981613202565b9250602084013567ffffffffffffffff81111561339557600080fd5b6133a186828701613346565b92505060408401356133b281613202565b809150509250925092565b600080604083850312156133d057600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156134205783516001600160a01b0316835292840192918401916001016133fb565b50909695505050505050565b600061022082840312156132f757600080fd5b600080600080610280858703121561345657600080fd5b843561346181613202565b9350602085013561347181613202565b9250613480866040870161342c565b915061026085013561349181613202565b939692955090935050565b6000602082840312156134ae57600080fd5b5035919050565b600080600061026084860312156134cb57600080fd5b83356134d681613202565b92506134e5856020860161342c565b91506102408401356133b281613202565b6000806040838503121561350957600080fd5b823567ffffffffffffffff81111561352057600080fd5b61352c85828601613346565b925050602083013561326381613202565b634e487b7160e01b600052602160045260246000fd5b6006811061251a57634e487b7160e01b600052602160045260246000fd5b805161357c81613553565b808352506020810151602083015260408101516001600160a01b038082166040850152606083015191506001600160801b0380831660608601528160808501511660808601528060a08501511660a08601528060c08501511660c08601525050505050565b60e081016118208284613571565b60006020828403121561360157600080fd5b8135612cc281613202565b60008060006060848603121561362157600080fd5b833561362c81613202565b9250602084013561363c81613202565b915060408401356133b2816132bf565b6000806040838503121561365f57600080fd5b823561366a81613202565b91506020830135613263816132bf565b60008060006060848603121561368f57600080fd5b833561369a81613202565b925060208401356136aa81613202565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff811182821017156136f5576136f56136bb565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613724576137246136bb565b604052919050565b6000601f83601f84011261373f57600080fd5b8235602067ffffffffffffffff8083111561375c5761375c6136bb565b8260051b61376b8382016136fb565b938452868101830193838101908986111561378557600080fd5b84890192505b85831015613815578235848111156137a35760008081fd5b8901603f81018b136137b55760008081fd5b858101356040868211156137cb576137cb6136bb565b6137dc828b01601f191689016136fb565b8281528d828486010111156137f15760008081fd5b828285018a830137600092810189019290925250835250918401919084019061378b565b9998505050505050505050565b600080600080600060a0868803121561383a57600080fd5b853561384581613202565b9450602086013561385581613202565b93506040860135925060608601359150608086013567ffffffffffffffff81111561387f57600080fd5b61388b8882890161372c565b9150509295509295909350565b6138a181613553565b9052565b6138b0828251613898565b60208101516138ca60208401826001600160a01b03169052565b5060408101516138e560408401826001600160a01b03169052565b50606081015161390060608401826001600160801b03169052565b50608081015161391a608084018265ffffffffffff169052565b5060a081015161393460a084018265ffffffffffff169052565b5060c081015161394f60c08401826001600160801b03169052565b5060e081015161396a60e08401826001600160a01b03169052565b5061010081810151908301526101208082015167ffffffffffffffff8116828501525050610140818101516001600160801b038116848301525050610160818101516001600160801b03811684830152612afa565b6101a081016139ce82856138a5565b6001600160a01b0383166101808301529392505050565b600080604083850312156139f857600080fd5b8235613a0381613202565b9150602083013561326381613202565b801515811461251a57600080fd5b600080600080600060a08688031215613a3957600080fd5b8535613a4481613202565b94506020860135613a5481613202565b9350604086013592506060860135613a6b81613a13565b9150608086013567ffffffffffffffff81111561387f57600080fd5b60008060008060006101e08688031215613aa057600080fd5b8535613aab81613202565b94506020860135613abb81613202565b9350613aca87604088016132e4565b92506101a086013567ffffffffffffffff811115613ae757600080fd5b860160408189031215613af957600080fd5b91506101c0860135613b0a81613202565b809150509295509295909350565b6000808335601e19843603018112613b2f57600080fd5b83018035915067ffffffffffffffff821115613b4a57600080fd5b602001915036819003821315613b5f57600080fd5b9250929050565b6000808335601e19843603018112613b7d57600080fd5b830160208101925035905067ffffffffffffffff811115613b9d57600080fd5b803603821315613b5f57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260008235613be681613202565b6001600160a01b0380821660208501526020850135604085015260408501359150613c1082613202565b808216606085015260608501356080850152608085013560a0850152613c3960a0860186613b66565b925060e060c0860152613c5161010086018483613bac565b92505060c0850135613c6281613202565b1660e0939093019290925250919050565b80516132df81613202565b600060208284031215613c9057600080fd5b8151612cc281613202565b65ffffffffffff8116811461251a57600080fd5b80356132df81613c9b565b67ffffffffffffffff8116811461251a57600080fd5b80356132df81613cba565b8035613ce681613cba565b67ffffffffffffffff1682526020810135613d0081613202565b6001600160a01b039081166020840152604082013590613d1f82613a13565b9015156040840152606082013590613d3682613a13565b9015156060840152608082013590613d4d82613202565b808216608085015250505050565b8035613d6681613202565b6001600160a01b039081168352602082013590613d8282613c9b565b65ffffffffffff9182166020850152604083013591613da083613202565b9181166040850152606083013591613db783613c9b565b919091166060840152506080810135613dcf816132bf565b6001600160801b03908116608084015260a082013590613dee826132bf565b1660a0830152612ef360c0808401908301613cdb565b6001600160a01b03841681526001600160801b03831660208201526101a08101612a766040830184613d5b565b60008060408385031215613e4457600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761182057611820613e55565b600082613e9f57634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561182057611820613e55565b6000610180613ec68484613d5b565b61016080840135607e19853603018112613edf57600080fd5b9085018290528301803590613ef3826132bf565b6001600160801b0382168387015260208101356101a0870152613f196040820182613b66565b9350915060806101c0870152613f3461020087018484613bac565b9250606001359050613f4581613202565b6001600160a01b0381166101e0860152508091505092915050565b60006001600160a01b03808916835280881660208401528087166040840152506bffffffffffffffffffffffff8516606083015260c06080830152613fa860c0830185613eb7565b90508260a0830152979650505050505050565b600060208284031215613fcd57600080fd5b8135612cc2816132bf565b60008235607e19833603018112613fee57600080fd5b9190910192915050565b6001600160801b0382811682821603908082111561401857614018613e55565b5092915050565b60006101406001600160a01b038716835280602084015261404281840187613eb7565b9150506140526040830185613571565b6bffffffffffffffffffffffff831661012083015295945050505050565b8082018082111561182057611820613e55565b634e487b7160e01b600052603260045260246000fd5b803563ffffffff811681146132df57600080fd5b80356140b881613202565b6001600160a01b0390811683526020820135906140d482613202565b16602083015260408101356140e8816132bf565b6001600160801b039081166040840152606082013590614107826132bf565b16606083015261411960808201613caf565b65ffffffffffff16608083015261413260a08201613caf565b65ffffffffffff1660a083015261414b60c08201614099565b63ffffffff1660c083015261416260e08201614099565b63ffffffff1660e083015261010061417b828201613cd0565b67ffffffffffffffff1690830152610120614197828201613cd0565b67ffffffffffffffff16908301526101406141b38282016132d4565b6001600160801b0316908301526101606141ce8282016132d4565b6001600160801b031690830152610180612d9d818401838301613cdb565b6001600160a01b03878116825286811660208301526bffffffffffffffffffffffff861660408301526102c082019061422860608401876140ad565b846102808401528084166102a084015250979650505050505050565b60006020828403121561425657600080fd5b5051919050565b610220810161182082846140ad565b610260810161427b82866140ad565b6bffffffffffffffffffffffff84166102208301526001600160a01b038316610240830152949350505050565b8481526101c081016142bd6020830186613d5b565b6001600160801b03939093166101808201526101a0015292915050565b6000602082840312156142ec57600080fd5b8135612cc281613c9b565b65ffffffffffff81811683821601908082111561401857614018613e55565b60006020828403121561432857600080fd5b8135612cc281613cba565b60006020828403121561434557600080fd5b8135612cc281613a13565b60008060006060848603121561436557600080fd5b835161437081613202565b602085015160409095015190969495509392505050565b6000806040838503121561439a57600080fd5b82516143a581613202565b6020939093015192949293505050565b60005b838110156143d05781810151838201526020016143b8565b50506000910152565b600082825180855260208086019550808260051b84010181860160005b8481101561443c57601f1980878503018a528251805180865261441e818888018985016143b5565b9a86019a601f019091169390930184019250908301906001016143f6565b5090979650505050505050565b8481526001600160a01b038416602082015282604082015260806060820152600061314160808301846143d9565b8051600681106132df57600080fd5b80516132df816132bf565b80516132df81613c9b565b80516132df81613cba565b6000808284036101a08112156144bc57600080fd5b610180808212156144cc57600080fd5b6144d46136d1565b91506144df85614477565b82526144ed60208601613c73565b60208301526144fe60408601613c73565b604083015261450f60608601614486565b606083015261452060808601614491565b608083015261453160a08601614491565b60a083015261454260c08601614486565b60c083015261455360e08601613c73565b60e0830152610100858101519083015261012061457181870161449c565b90830152610140614583868201614486565b90830152610160614595868201614486565b81840152508193506145a8818601613c73565b925050509250929050565b6001600160a01b03831681526101a08101612cc260208301846138a5565b6000602082840312156145e357600080fd5b81516bffffffffffffffffffffffff81168114612cc257600080fd5b60006001600160a01b038088168352808716602084015250846040830152831515606083015260a0608083015261463960a08301846143d9565b979650505050505050565b6001600160a01b0387811682528681166020830152851660408201526bffffffffffffffffffffffff8416606082015260006102006146866080840186613d5b565b806101e08401526146978485613b66565b6040838601526146ac61024086018284613bac565b925050506146bd6020850185613b66565b8483036101ff19016102208601526146d6838284613bac565b9b9a5050505050505050505050565b6001600160a01b03851681526101c081016147036020830186613d5b565b6101808201939093526101a0015292915050565b838152604060208201526000614731604083018486613bac565b95945050505050565b60008251613fee8184602087016143b5565b60006020828403121561475e57600080fd5b81516001600160e01b031981168114612cc257600080fd5b60006020828403121561478857600080fd5b8151612cc281613a1356fea2646970667358221220f6e245ecce5ab5f48ad0f43e2292f95a39682fe0e92baa1ff4185ef2a7f1a9e664736f6c63430008180033000000000000000000000000c47e7bd855efaee7fb938ac593b9c74fd144728d0000000000000000000000008abf5358a88ca2586635d646aaaff172572fb0ed
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101cf5760003560e01c806377c05dec11610104578063b166a09f116100a2578063ca41363e11610071578063ca41363e14610479578063f2fde38b1461048c578063f9361aef1461049f578063fda25df4146104b257600080fd5b8063b166a09f146103fd578063b35c845e14610420578063b4df001e14610441578063c18abe0d1461046657600080fd5b80638da5cb5b116100de5780638da5cb5b146103a357806393594d7f146103b4578063a597ec1f146103d7578063a6d49dca146103ea57600080fd5b806377c05dec146103455780637d431c7c146103685780638c35dc4d1461037b57600080fd5b806347e5dc20116101715780635920d5771161014b5780635920d577146102f75780635a696cb81461030a578063715018a61461032a578063733140771461033257600080fd5b806347e5dc20146102915780634dcfbba4146102b15780635468fe95146102c457600080fd5b8063369bd2fe116101ad578063369bd2fe146102185780633849153b146102205780633c93adee146102535780633df8f62e1461027e57600080fd5b8063065d4a6d146101d45780630b620b81146101e957806318e2a560146101fc575b600080fd5b6101e76101e2366004613217565b6104d9565b005b6101e76101f736600461326e565b610805565b61020560025481565b6040519081526020015b60405180910390f35b6101e761099d565b61023361022e3660046132fd565b6109f8565b604080516001600160801b0393841681529290911660208301520161020f565b600154610266906001600160a01b031681565b6040516001600160a01b03909116815260200161020f565b6101e761028c366004613359565b610b45565b6102a461029f3660046133bd565b610e5b565b60405161020f91906133df565b6101e76102bf36600461343f565b610f71565b6102e76102d236600461349c565b60056020526000908152604090205460ff1681565b604051901515815260200161020f565b6101e76103053660046134b5565b6112e5565b61031d6103183660046134f6565b611407565b60405161020f91906135e1565b6101e7611826565b6101e76103403660046135ef565b61183a565b6102e76103533660046135ef565b60066020526000908152604090205460ff1681565b6101e761037636600461360c565b6118f7565b61038e61038936600461364c565b611af6565b6040805192835260208301919091520161020f565b6000546001600160a01b0316610266565b6102e76103c236600461349c565b60046020526000908152604090205460ff1681565b6101e76103e536600461360c565b611c42565b6101e76103f836600461367a565b611d9c565b6102e761040b3660046135ef565b60036020526000908152604090205460ff1681565b61043361042e366004613822565b611e1b565b60405161020f9291906139bf565b61044961215d565b6040516bffffffffffffffffffffffff909116815260200161020f565b6101e76104743660046139e5565b61220e565b6101e7610487366004613a21565b61228d565b6101e761049a3660046135ef565b6124c1565b6101e76104ad366004613a87565b61251d565b6102667f0000000000000000000000008abf5358a88ca2586635d646aaaff172572fb0ed81565b8060800135421115610517576040517f5c32099600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004661052760208401846135ef565b602084013561053c60608601604087016135ef565b6040805160208101959095526001600160a01b03938416908501526060808501929092529091166080808401919091529084013560a083015283013560c082015260e00160408051601f19818403018152919052805160209091012090506000806105ad60e0850160c086016135ef565b6001600160a01b03160361063c577f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c839052603c9020610635906105fb60a0860186613b18565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061292192505050565b90506106b1565b600061066461065160e0860160c087016135ef565b8461065f60a0880188613b18565b61294b565b90508061069d576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106ad60e0850160c086016135ef565b9150505b6001600160a01b03811660009081526006602052604090205460ff1615610704576040517f6cff8dd500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205460ff161561074d576040517f9b1475af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040909120805460ff191660011790556107919033908390860180359061078090886135ef565b6001600160a01b0316929190612a7e565b6107aa81856060860180359061078090604089016135ef565b806001600160a01b0316846001600160a01b0316336001600160a01b03167fc09ea7f7280174a395e9010b2e05ab1888cd36f5ad99b4429478af303ce78c3d866040516107f79190613bd5565b60405180910390a450505050565b6001600160a01b03841660009081526003602052604090205460ff1661083e576040516340d8c4db60e11b815260040160405180910390fd5b836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561087c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a09190613c7e565b6001600160a01b0316336001600160a01b0316146108d157604051636edaef2f60e11b815260040160405180910390fd5b6040517fd0e8dcff0000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015283811660248301526044820183905285169063d0e8dcff90606401600060405180830381600087803b15801561093c57600080fd5b505af1158015610950573d6000803e3d6000fd5b5050604080516001600160a01b0387811682526020820186905280871694508816925033917fe826ecb5c03d4897f8ab426ee94064e06179dff39cd9fdd0776904cd935c95d891016107f7565b33600081815260066020908152604091829020805460ff8116801560ff199092168217909255925192835292917fdcbed411faf93d1cef89c9e1923cd8e047c29e2d465b976b24b0b22c054b340e910160405180910390a250565b60015460009081906001600160a01b03168015610b3c57600080826001600160a01b031663dd07ab1c8989896040518463ffffffff1660e01b8152600401610a4293929190613e04565b6040805180830381865afa158015610a5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a829190613e31565b909250905060006702c68af0bb1400008311610a9e5782610aa8565b6702c68af0bb1400005b90506000670de0b6b3a76400008311610ac15782610acb565b670de0b6b3a76400005b90506000670de0b6b3a7640000610aeb846001600160801b038d16613e6b565b610af59190613e82565b9050610b1c670de0b6b3a7640000610b0d8484613e6b565b610b179190613e82565b612b00565b9650610b34610b176001600160801b03891683613ea4565b975050505050505b50935093915050565b6000610b518383611407565b9050600481516005811115610b6857610b6861353d565b14610b9f576040517fe30578ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201516000908152600490915260408120805460ff1916600117905580610bc7612b51565b915091506000610bd561215d565b60408086015190517f537952080000000000000000000000000000000000000000000000000000000081529192506001600160a01b03851691635379520891610c2a9130918c9187908d908a90600401613f60565b600060405180830381600087803b158015610c4457600080fd5b505af1158015610c58573d6000803e3d6000fd5b50610c8a9250339150859050610c7460a08a0160808b01613fbb565b6001600160801b031661078060208b018b6135ef565b610cef8460400151338660a001518760c001518a806101600190610cae9190613fd8565b610cbc906020810190613fbb565b610cc69190613ff8565b610cd09190613ff8565b60808801516001600160a01b03169291906001600160801b0316612a7e565b60c08401516001600160801b031615610d3757610d378460400151868660c001516001600160801b031687608001516001600160a01b0316612a7e909392919063ffffffff16565b60a08401516001600160801b031615610df757600154604085015160a086015160808701516001600160a01b0393841693610d7f9391169184906001600160801b0316612a7e565b608085015160a08601516040516358c0528f60e01b81526001600160a01b0392831660048201526001600160801b039091166024820152908216906358c0528f90604401600060405180830381600087803b158015610ddd57600080fd5b505af1158015610df1573d6000803e3d6000fd5b50505050505b846001600160a01b0316836001600160a01b0316336001600160a01b03167f2603b553dc2ab4d1a644bb67a527695755c7c1adc290f4718813e649cc6c71888a8a8987604051610e4a949392919061401f565b60405180910390a450505050505050565b600754606090821580610e76575080610e748486614070565b115b15610ead576040517f6269996b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8267ffffffffffffffff811115610ec657610ec66136bb565b604051908082528060200260200182016040528015610eef578160200160208202803683370190505b50915060005b83811015610f69576007610f098287614070565b81548110610f1957610f19614083565b9060005260206000200160009054906101000a90046001600160a01b0316838281518110610f4957610f49614083565b6001600160a01b0390921660209283029190910190910152600101610ef5565b505092915050565b6001600160a01b03841660009081526003602052604090205460ff16610faa576040516340d8c4db60e11b815260040160405180910390fd5b836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fe8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c9190613c7e565b6001600160a01b0316336001600160a01b03161461103d57604051636edaef2f60e11b815260040160405180910390fd5b600080611048612b51565b91509150816001600160a01b03166323c8affa308761106561215d565b8886896040518763ffffffff1660e01b8152600401611089969594939291906141ec565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b50600092506110cc91505060208601866135ef565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b03898116600483015291909116906370a0823190602401602060405180830381865afa15801561112d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111519190614244565b90506000816111666060880160408901613fbb565b6001600160801b0316101561117b573361117d565b835b90506000826111926060890160408a01613fbb565b6001600160801b031610156111bf576111b16060880160408901613fbb565b6001600160801b03166111e3565b826111d06060890160408a01613fbb565b6001600160801b03166111e39190613ea4565b90506001600160a01b03891663d0e8dcff8361120260208b018b6135ef565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101869052606401600060405180830381600087803b15801561125157600080fd5b505af1158015611265573d6000803e3d6000fd5b5050505060008111156112855761128533868361078060208c018c6135ef565b846001600160a01b0316896001600160a01b0316896001600160a01b03167f957cced42c73d5e844e49787802497a4b4e27b8a7f239e76e7c35133f4a1ada08a6040516112d2919061425d565b60405180910390a4505050505050505050565b6000806112f0612b51565b9150915060006112fe61215d565b6040517f23c8affa0000000000000000000000000000000000000000000000000000000081529091506001600160a01b038416906323c8affa906113509030908a9086908b9089908c906004016141ec565b600060405180830381600087803b15801561136a57600080fd5b505af115801561137e573d6000803e3d6000fd5b505050506113b0338487604001602081019061139a9190613fbb565b6001600160801b031661078060208a018a6135ef565b826001600160a01b0316866001600160a01b03167f081c9ad95e93f5f9d217a45f3b87fd8f86ab622929ac7342f8eafacbd2c4ad3e8784886040516113f79392919061426c565b60405180910390a3505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101829052904684611450610160820182613fd8565b61145e906020810190613fbb565b61146c610160880188613fd8565b6020013560405160200161148394939291906142a8565b60408051601f19818403018152919052805160209091012090506000806114ae610160870187613fd8565b6114bf9060808101906060016135ef565b6001600160a01b031603611523577f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c839052603c902061151c9061150e610160880188613fd8565b6105fb906040810190613b18565b90506115a4565b6000611564611536610160880188613fd8565b6115479060808101906060016135ef565b846115566101608a018a613fd8565b61065f906040810190613b18565b9050806115815761157760058484612c34565b9350505050611820565b61158f610160870187613fd8565b6115a09060808101906060016135ef565b9150505b6115b460608601604087016135ef565b6001600160a01b03166115ca60208701876135ef565b6001600160a01b031614806115f557506115ea60a0860160808701613fbb565b6001600160801b0316155b80611616575061160b60c0860160a08701613fbb565b6001600160801b0316155b8061165b575061162c60808601606087016142da565b61163990620151806142f7565b65ffffffffffff1661165160408701602088016142da565b65ffffffffffff16105b806116865750670de0b6b3a764000061167a60e0870160c08801614316565b67ffffffffffffffff16115b156116a05761169760018383612c34565b92505050611820565b6116ae610160860186613fd8565b602001354211806116d557506116ca60408601602087016142da565b65ffffffffffff1642115b156116e65761169760008383612c34565b60008281526004602052604090205460ff16156117095761169760028383612c34565b6001600160a01b03811660009081526006602052604090205460ff16156117365761169760038383612c34565b60008061175f8661174b6101608a018a613fd8565b611759906020810190613fbb565b896109f8565b6040805160e0810190915291935091508060048152602081018690526001600160a01b038516604082015260600161179b6101608a018a613fd8565b6117a9906020810190613fbb565b6001600160801b031681526020016117c96101208a016101008b01614333565b6117e2576117dd60608a0160408b016135ef565b6117ef565b6117ef60208a018a6135ef565b6001600160a01b03168152602001836001600160801b03168152602001826001600160801b03168152509450505050505b92915050565b61182e612cc9565b6118386000612d0f565b565b611842612cc9565b6001546001600160a01b03908116908216810361188b576040517fc927103e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384811691821790925560408051928416835260208301919091527f9223780305f6b8602877f20db7cc3a6770c99586cb92db707a89375807e12337910160405180910390a15050565b6001600160a01b03831660009081526003602052604090205460ff16611930576040516340d8c4db60e11b815260040160405180910390fd5b6040517f67ff93a60000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0383811660248301526001600160801b038316604483015260009182918291908716906367ff93a6906064016060604051808303816000875af11580156119ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d29190614350565b919450925090506119ee6001600160a01b038416338885612a7e565b6001546001600160a01b03168015801590611a095750600082115b15611a8d57600154611a2a906001600160a01b038681169133911685612a7e565b6040516358c0528f60e01b81526001600160a01b038581166004830152602482018490528216906358c0528f90604401600060405180830381600087803b158015611a7457600080fd5b505af1158015611a88573d6000803e3d6000fd5b505050505b604080516001600160a01b0388811682526001600160801b0388166020830152918101859052606081018490529088169033907f0f6b57650350b4f610474b25b5969726ade85bd32d17cf9de29015bd617cc9fd9060800160405180910390a350505050505050565b60015460009081906001600160a01b03168015611c3a576040517f7eda99570000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526000918291841690637eda9957906024016040805180830381865afa158015611b70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b949190613e31565b909250905060006702c68af0bb1400008311611bb05782611bba565b6702c68af0bb1400005b90506000670de0b6b3a76400008311611bd35782611bdd565b670de0b6b3a76400005b90506000670de0b6b3a7640000611bfd846001600160801b038c16613e6b565b611c079190613e82565b9050670de0b6b3a7640000611c1c8383613e6b565b611c269190613e82565b9650611c328782613ea4565b975050505050505b509250929050565b6001600160a01b03831660009081526003602052604090205460ff16611c7b576040516340d8c4db60e11b815260040160405180910390fd5b6040517f9076e9040000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0383811660248301526001600160801b03831660448301526000918291861690639076e9049060640160408051808303816000875af1158015611cf5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d199190614387565b9092509050611d3c6001600160a01b03831633876001600160801b038716612a7e565b604080516001600160a01b0386811682526001600160801b03861660208301529181018390529086169081907ff6c7cbea93a9318a02e83b81b74aa67de77eaf4585af0f3118f30108f513849a9060600160405180910390a35050505050565b3360008181526003602052604090205460ff16611dcc576040516340d8c4db60e11b815260040160405180910390fd5b826001600160a01b0316846001600160a01b0316826001600160a01b03167fd1398bee19313d6bf672ccb116e51f4a1a947e91c757907f51fbb5b5e56c698f856040516107f791815260200190565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526001600160a01b03861660009081526003602052604081205460ff16611eb5576040516340d8c4db60e11b815260040160405180910390fd5b6040517fa3620ec40000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063a3620ec490611f009088908a9089908990600401614449565b6101a0604051808303816000875af1158015611f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4491906144a7565b8092508193505050611ff633886001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb29190613c7e565b8461014001518561016001518660c00151611fcd9190613ff8565b611fd79190613ff8565b60e08601516001600160a01b03169291906001600160801b0316612a7e565b6101608201516001600160801b03161561203c5761203c33828461016001516001600160801b03168560e001516001600160a01b0316612a7e909392919063ffffffff16565b6101408201516001600160801b0316156120fc5760015461014083015160e08401516001600160a01b039283169261208392911690339084906001600160801b0316612a7e565b60e08301516101408401516040516358c0528f60e01b81526001600160a01b0392831660048201526001600160801b039091166024820152908216906358c0528f90604401600060405180830381600087803b1580156120e257600080fd5b505af11580156120f6573d6000803e3d6000fd5b50505050505b806001600160a01b0316876001600160a01b0316336001600160a01b03167f7ebea06143b46f005fced4223cf841b88854a21cb67516c71838990a9f56f8e8898660405161214b9291906145b3565b60405180910390a49550959350505050565b6001546000906001600160a01b03168061217957600091505090565b806001600160a01b031663d1c699aa6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121db91906145d1565b91506611c37937e080006bffffffffffffffffffffffff8316116121ff5781612208565b6611c37937e080005b91505090565b3360008181526003602052604090205460ff1661223e576040516340d8c4db60e11b815260040160405180910390fd5b816001600160a01b0316836001600160a01b0316826001600160a01b03167f6954f1cdad46901994f29d9b1f78744c873c527bad04d294b4954cc8caf367da60405160405180910390a4505050565b6001600160a01b03851660009081526003602052604090205460ff166122c6576040516340d8c4db60e11b815260040160405180910390fd5b6000806000876001600160a01b03166331cd4e6233898989896040518663ffffffff1660e01b81526004016122ff9594939291906145ff565b6060604051808303816000875af115801561231e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123429190614350565b92509250925084156123c6576123c633896001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b49190613c7e565b6001600160a01b038616919085612a7e565b6001546001600160a01b031680158015906123e15750600082115b1561246557600154612402906001600160a01b038681169133911685612a7e565b6040516358c0528f60e01b81526001600160a01b038581166004830152602482018490528216906358c0528f90604401600060405180830381600087803b15801561244c57600080fd5b505af1158015612460573d6000803e3d6000fd5b505050505b604080516001600160a01b038a81168252602082018a9052918101849052908a169033907f5ee515779e0ca72dbfbc93b30480bbecf67910142933d89d3d89be8e28a9c8509060600160405180910390a3505050505050505050565b6124c9612cc9565b6001600160a01b038116612511576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b61251a81612d0f565b50565b61252d60608401604085016135ef565b6001600160a01b031661254360208501856135ef565b6001600160a01b031603612583576040517f8686656d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259360a0840160808501613fbb565b6001600160801b03166000036125d5576040517f950466ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125e560408401602085016142da565b65ffffffffffff16421115612626576040517fd36c850000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61263660808401606085016142da565b61264390620151806142f7565b65ffffffffffff1661265b60408501602086016142da565b65ffffffffffff16101561269b576040517f1e617b1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b670de0b6b3a76400006126b460e0850160c08601614316565b67ffffffffffffffff1611156126f6576040517fa7e9b5b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612700612b51565b50905060008061271a8461038960a0890160808a01613fbb565b9150915060008083118061272e5750600082115b612738578861273a565b305b9050836001600160a01b031663d951124d308a8461275661215d565b8c8c6040518763ffffffff1660e01b815260040161277996959493929190614644565b600060405180830381600087803b15801561279357600080fd5b505af11580156127a7573d6000803e3d6000fd5b505050506127d933858960800160208101906127c39190613fbb565b6001600160801b031661078060208c018c6135ef565b306001600160a01b038216036128ce5761282d8983856127ff60a08c0160808d01613fbb565b6001600160801b03166128129190613ea4565b61281c9190613ea4565b6001600160a01b0387169190612d6c565b8115612847576128476001600160a01b0385168684612d6c565b82156128ce57600154612867906001600160a01b03868116911685612d6c565b6001546040516358c0528f60e01b81526001600160a01b03868116600483015260248201869052909116906358c0528f90604401600060405180830381600087803b1580156128b557600080fd5b505af11580156128c9573d6000803e3d6000fd5b505050505b846001600160a01b0316896001600160a01b0316336001600160a01b03167f2e8d3d935843ef13282538bbbb45c3c49faa9797fe651d3fcb327f436a91116f8b8b88886040516112d294939291906146e5565b6000806000806129318686612da2565b9250925092506129418282612def565b5090949350505050565b6000806000866001600160a01b0316631626ba7e60e01b87878760405160240161297793929190614717565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516129ca919061473a565b600060405180830381855afa9150503d8060008114612a05576040519150601f19603f3d011682016040523d82523d6000602084013e612a0a565b606091505b5091509150818015612a1d575080516020145b15612a6f57600081806020019051810190612a38919061474c565b6001600160e01b0319167f1626ba7e00000000000000000000000000000000000000000000000000000000149350612a7692505050565b6000925050505b949350505050565b6040516001600160a01b038481166024830152838116604483015260648201839052612afa9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612ef7565b50505050565b60006001600160801b03821115612b4d576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526080600482015260248101839052604401612508565b5090565b6000806002546001612b639190614070565b9050612bb77f0000000000000000000000008abf5358a88ca2586635d646aaaff172572fb0ed82604051602001612b9c91815260200190565b60405160208183030381529060405280519060200120612f73565b60028290556001600160a01b0381166000818152600360205260408120805460ff191660019081179091556007805491820181559091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68801805473ffffffffffffffffffffffffffffffffffffffff1916909117905592909150565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e00160405280856005811115612c8a57612c8a61353d565b8152602081018590526001600160a01b03841660408201526000606082018190526080820181905260a0820181905260c09091015290505b9392505050565b6000546001600160a01b03163314611838576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401612508565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03838116602483015260448201839052612d9d91859182169063a9059cbb90606401612ab3565b505050565b60008060008351604103612ddc5760208401516040850151606086015160001a612dce88828585612ffa565b955095509550505050612de8565b50508151600091506002905b9250925092565b6000826003811115612e0357612e0361353d565b03612e0c575050565b6001826003811115612e2057612e2061353d565b03612e57576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002826003811115612e6b57612e6b61353d565b03612ea5576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401612508565b6003826003811115612eb957612eb961353d565b03612ef3576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401612508565b5050565b6000612f0c6001600160a01b038416836130c9565b90508051600014158015612f31575080806020019051810190612f2f9190614776565b155b15612d9d576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401612508565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611820576040517fc2f868f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561303557506000915060039050826130bf565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613089573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166130b5575060009250600191508290506130bf565b9250600091508190505b9450945094915050565b6060612cc28383600084600080856001600160a01b031684866040516130ef919061473a565b60006040518083038185875af1925050503d806000811461312c576040519150601f19603f3d011682016040523d82523d6000602084013e613131565b606091505b509150915061314186838361314b565b9695505050505050565b6060826131605761315b826131c0565b612cc2565b815115801561317757506001600160a01b0384163b155b156131b9576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401612508565b5080612cc2565b8051156131d05780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116811461251a57600080fd5b6000806040838503121561322a57600080fd5b823561323581613202565b9150602083013567ffffffffffffffff81111561325157600080fd5b830160e0818603121561326357600080fd5b809150509250929050565b6000806000806080858703121561328457600080fd5b843561328f81613202565b9350602085013561329f81613202565b925060408501356132af81613202565b9396929550929360600135925050565b6001600160801b038116811461251a57600080fd5b80356132df816132bf565b919050565b600061016082840312156132f757600080fd5b50919050565b60008060006101a0848603121561331357600080fd5b833561331e81613202565b9250602084013561332e816132bf565b915061333d85604086016132e4565b90509250925092565b600061018082840312156132f757600080fd5b60008060006060848603121561336e57600080fd5b833561337981613202565b9250602084013567ffffffffffffffff81111561339557600080fd5b6133a186828701613346565b92505060408401356133b281613202565b809150509250925092565b600080604083850312156133d057600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156134205783516001600160a01b0316835292840192918401916001016133fb565b50909695505050505050565b600061022082840312156132f757600080fd5b600080600080610280858703121561345657600080fd5b843561346181613202565b9350602085013561347181613202565b9250613480866040870161342c565b915061026085013561349181613202565b939692955090935050565b6000602082840312156134ae57600080fd5b5035919050565b600080600061026084860312156134cb57600080fd5b83356134d681613202565b92506134e5856020860161342c565b91506102408401356133b281613202565b6000806040838503121561350957600080fd5b823567ffffffffffffffff81111561352057600080fd5b61352c85828601613346565b925050602083013561326381613202565b634e487b7160e01b600052602160045260246000fd5b6006811061251a57634e487b7160e01b600052602160045260246000fd5b805161357c81613553565b808352506020810151602083015260408101516001600160a01b038082166040850152606083015191506001600160801b0380831660608601528160808501511660808601528060a08501511660a08601528060c08501511660c08601525050505050565b60e081016118208284613571565b60006020828403121561360157600080fd5b8135612cc281613202565b60008060006060848603121561362157600080fd5b833561362c81613202565b9250602084013561363c81613202565b915060408401356133b2816132bf565b6000806040838503121561365f57600080fd5b823561366a81613202565b91506020830135613263816132bf565b60008060006060848603121561368f57600080fd5b833561369a81613202565b925060208401356136aa81613202565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff811182821017156136f5576136f56136bb565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613724576137246136bb565b604052919050565b6000601f83601f84011261373f57600080fd5b8235602067ffffffffffffffff8083111561375c5761375c6136bb565b8260051b61376b8382016136fb565b938452868101830193838101908986111561378557600080fd5b84890192505b85831015613815578235848111156137a35760008081fd5b8901603f81018b136137b55760008081fd5b858101356040868211156137cb576137cb6136bb565b6137dc828b01601f191689016136fb565b8281528d828486010111156137f15760008081fd5b828285018a830137600092810189019290925250835250918401919084019061378b565b9998505050505050505050565b600080600080600060a0868803121561383a57600080fd5b853561384581613202565b9450602086013561385581613202565b93506040860135925060608601359150608086013567ffffffffffffffff81111561387f57600080fd5b61388b8882890161372c565b9150509295509295909350565b6138a181613553565b9052565b6138b0828251613898565b60208101516138ca60208401826001600160a01b03169052565b5060408101516138e560408401826001600160a01b03169052565b50606081015161390060608401826001600160801b03169052565b50608081015161391a608084018265ffffffffffff169052565b5060a081015161393460a084018265ffffffffffff169052565b5060c081015161394f60c08401826001600160801b03169052565b5060e081015161396a60e08401826001600160a01b03169052565b5061010081810151908301526101208082015167ffffffffffffffff8116828501525050610140818101516001600160801b038116848301525050610160818101516001600160801b03811684830152612afa565b6101a081016139ce82856138a5565b6001600160a01b0383166101808301529392505050565b600080604083850312156139f857600080fd5b8235613a0381613202565b9150602083013561326381613202565b801515811461251a57600080fd5b600080600080600060a08688031215613a3957600080fd5b8535613a4481613202565b94506020860135613a5481613202565b9350604086013592506060860135613a6b81613a13565b9150608086013567ffffffffffffffff81111561387f57600080fd5b60008060008060006101e08688031215613aa057600080fd5b8535613aab81613202565b94506020860135613abb81613202565b9350613aca87604088016132e4565b92506101a086013567ffffffffffffffff811115613ae757600080fd5b860160408189031215613af957600080fd5b91506101c0860135613b0a81613202565b809150509295509295909350565b6000808335601e19843603018112613b2f57600080fd5b83018035915067ffffffffffffffff821115613b4a57600080fd5b602001915036819003821315613b5f57600080fd5b9250929050565b6000808335601e19843603018112613b7d57600080fd5b830160208101925035905067ffffffffffffffff811115613b9d57600080fd5b803603821315613b5f57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260008235613be681613202565b6001600160a01b0380821660208501526020850135604085015260408501359150613c1082613202565b808216606085015260608501356080850152608085013560a0850152613c3960a0860186613b66565b925060e060c0860152613c5161010086018483613bac565b92505060c0850135613c6281613202565b1660e0939093019290925250919050565b80516132df81613202565b600060208284031215613c9057600080fd5b8151612cc281613202565b65ffffffffffff8116811461251a57600080fd5b80356132df81613c9b565b67ffffffffffffffff8116811461251a57600080fd5b80356132df81613cba565b8035613ce681613cba565b67ffffffffffffffff1682526020810135613d0081613202565b6001600160a01b039081166020840152604082013590613d1f82613a13565b9015156040840152606082013590613d3682613a13565b9015156060840152608082013590613d4d82613202565b808216608085015250505050565b8035613d6681613202565b6001600160a01b039081168352602082013590613d8282613c9b565b65ffffffffffff9182166020850152604083013591613da083613202565b9181166040850152606083013591613db783613c9b565b919091166060840152506080810135613dcf816132bf565b6001600160801b03908116608084015260a082013590613dee826132bf565b1660a0830152612ef360c0808401908301613cdb565b6001600160a01b03841681526001600160801b03831660208201526101a08101612a766040830184613d5b565b60008060408385031215613e4457600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761182057611820613e55565b600082613e9f57634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561182057611820613e55565b6000610180613ec68484613d5b565b61016080840135607e19853603018112613edf57600080fd5b9085018290528301803590613ef3826132bf565b6001600160801b0382168387015260208101356101a0870152613f196040820182613b66565b9350915060806101c0870152613f3461020087018484613bac565b9250606001359050613f4581613202565b6001600160a01b0381166101e0860152508091505092915050565b60006001600160a01b03808916835280881660208401528087166040840152506bffffffffffffffffffffffff8516606083015260c06080830152613fa860c0830185613eb7565b90508260a0830152979650505050505050565b600060208284031215613fcd57600080fd5b8135612cc2816132bf565b60008235607e19833603018112613fee57600080fd5b9190910192915050565b6001600160801b0382811682821603908082111561401857614018613e55565b5092915050565b60006101406001600160a01b038716835280602084015261404281840187613eb7565b9150506140526040830185613571565b6bffffffffffffffffffffffff831661012083015295945050505050565b8082018082111561182057611820613e55565b634e487b7160e01b600052603260045260246000fd5b803563ffffffff811681146132df57600080fd5b80356140b881613202565b6001600160a01b0390811683526020820135906140d482613202565b16602083015260408101356140e8816132bf565b6001600160801b039081166040840152606082013590614107826132bf565b16606083015261411960808201613caf565b65ffffffffffff16608083015261413260a08201613caf565b65ffffffffffff1660a083015261414b60c08201614099565b63ffffffff1660c083015261416260e08201614099565b63ffffffff1660e083015261010061417b828201613cd0565b67ffffffffffffffff1690830152610120614197828201613cd0565b67ffffffffffffffff16908301526101406141b38282016132d4565b6001600160801b0316908301526101606141ce8282016132d4565b6001600160801b031690830152610180612d9d818401838301613cdb565b6001600160a01b03878116825286811660208301526bffffffffffffffffffffffff861660408301526102c082019061422860608401876140ad565b846102808401528084166102a084015250979650505050505050565b60006020828403121561425657600080fd5b5051919050565b610220810161182082846140ad565b610260810161427b82866140ad565b6bffffffffffffffffffffffff84166102208301526001600160a01b038316610240830152949350505050565b8481526101c081016142bd6020830186613d5b565b6001600160801b03939093166101808201526101a0015292915050565b6000602082840312156142ec57600080fd5b8135612cc281613c9b565b65ffffffffffff81811683821601908082111561401857614018613e55565b60006020828403121561432857600080fd5b8135612cc281613cba565b60006020828403121561434557600080fd5b8135612cc281613a13565b60008060006060848603121561436557600080fd5b835161437081613202565b602085015160409095015190969495509392505050565b6000806040838503121561439a57600080fd5b82516143a581613202565b6020939093015192949293505050565b60005b838110156143d05781810151838201526020016143b8565b50506000910152565b600082825180855260208086019550808260051b84010181860160005b8481101561443c57601f1980878503018a528251805180865261441e818888018985016143b5565b9a86019a601f019091169390930184019250908301906001016143f6565b5090979650505050505050565b8481526001600160a01b038416602082015282604082015260806060820152600061314160808301846143d9565b8051600681106132df57600080fd5b80516132df816132bf565b80516132df81613c9b565b80516132df81613cba565b6000808284036101a08112156144bc57600080fd5b610180808212156144cc57600080fd5b6144d46136d1565b91506144df85614477565b82526144ed60208601613c73565b60208301526144fe60408601613c73565b604083015261450f60608601614486565b606083015261452060808601614491565b608083015261453160a08601614491565b60a083015261454260c08601614486565b60c083015261455360e08601613c73565b60e0830152610100858101519083015261012061457181870161449c565b90830152610140614583868201614486565b90830152610160614595868201614486565b81840152508193506145a8818601613c73565b925050509250929050565b6001600160a01b03831681526101a08101612cc260208301846138a5565b6000602082840312156145e357600080fd5b81516bffffffffffffffffffffffff81168114612cc257600080fd5b60006001600160a01b038088168352808716602084015250846040830152831515606083015260a0608083015261463960a08301846143d9565b979650505050505050565b6001600160a01b0387811682528681166020830152851660408201526bffffffffffffffffffffffff8416606082015260006102006146866080840186613d5b565b806101e08401526146978485613b66565b6040838601526146ac61024086018284613bac565b925050506146bd6020850185613b66565b8483036101ff19016102208601526146d6838284613bac565b9b9a5050505050505050505050565b6001600160a01b03851681526101c081016147036020830186613d5b565b6101808201939093526101a0015292915050565b838152604060208201526000614731604083018486613bac565b95945050505050565b60008251613fee8184602087016143b5565b60006020828403121561475e57600080fd5b81516001600160e01b031981168114612cc257600080fd5b60006020828403121561478857600080fd5b8151612cc281613a1356fea2646970667358221220f6e245ecce5ab5f48ad0f43e2292f95a39682fe0e92baa1ff4185ef2a7f1a9e664736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c47e7bd855efaee7fb938ac593b9c74fd144728d0000000000000000000000008abf5358a88ca2586635d646aaaff172572fb0ed
-----Decoded View---------------
Arg [0] : initOwner (address): 0xc47e7bd855EfaeE7fb938AC593B9c74fd144728d
Arg [1] : _escrowImpl (address): 0x8AbF5358a88CA2586635d646aaaFF172572fB0eD
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c47e7bd855efaee7fb938ac593b9c74fd144728d
Arg [1] : 0000000000000000000000008abf5358a88ca2586635d646aaaff172572fb0ed
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 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.