Overview
ETH Balance
0.000005798415387207 ETH
ETH Value
$0.02 (@ $3,191.32/ETH)More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 71,156 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Settle Single An... | 747004 | 6 days ago | IN | 0 ETH | 0.00001822 | ||||
Settle Single An... | 746832 | 6 days ago | IN | 0 ETH | 0.00001618 | ||||
Settle Single | 746302 | 6 days ago | IN | 0 ETH | 0.00001318 | ||||
Settle Single | 746294 | 6 days ago | IN | 0 ETH | 0.00001311 | ||||
Settle Single | 746290 | 6 days ago | IN | 0 ETH | 0.0000131 | ||||
Settle Single | 746284 | 6 days ago | IN | 0 ETH | 0.00001311 | ||||
Settle Single | 746279 | 6 days ago | IN | 0 ETH | 0.00001489 | ||||
Settle Single | 746271 | 6 days ago | IN | 0 ETH | 0.00001317 | ||||
Settle Single | 746262 | 6 days ago | IN | 0 ETH | 0.00001311 | ||||
Settle Single | 746259 | 6 days ago | IN | 0 ETH | 0.00001484 | ||||
Settle Single An... | 746013 | 6 days ago | IN | 0 ETH | 0.00001428 | ||||
Settle Single An... | 745999 | 6 days ago | IN | 0 ETH | 0.00001726 | ||||
Settle Single | 743448 | 7 days ago | IN | 0 ETH | 0.00001361 | ||||
Settle Single | 743370 | 7 days ago | IN | 0 ETH | 0.00001317 | ||||
Settle Single | 743361 | 7 days ago | IN | 0 ETH | 0.00001386 | ||||
Settle Single An... | 743343 | 7 days ago | IN | 0 ETH | 0.00002069 | ||||
Settle Single An... | 743145 | 7 days ago | IN | 0 ETH | 0.00001562 | ||||
Settle Single An... | 742596 | 7 days ago | IN | 0 ETH | 0.00001692 | ||||
Settle Single | 742271 | 7 days ago | IN | 0 ETH | 0.00001319 | ||||
Settle Single | 741907 | 8 days ago | IN | 0 ETH | 0.00001393 | ||||
Settle Single | 741814 | 8 days ago | IN | 0 ETH | 0.00001484 | ||||
Settle Single An... | 741756 | 8 days ago | IN | 0 ETH | 0.00001544 | ||||
Settle Single An... | 741505 | 8 days ago | IN | 0 ETH | 0.00001817 | ||||
Settle Single | 741374 | 8 days ago | IN | 0 ETH | 0.00001483 | ||||
Settle Single An... | 741013 | 8 days ago | IN | 0 ETH | 0.00001677 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
764491 | 8 mins ago | 0.01162198 ETH | ||||
764491 | 8 mins ago | 0.01162198 ETH | ||||
764281 | 1 hr ago | 0.09889638 ETH | ||||
764281 | 1 hr ago | 0.09889638 ETH | ||||
763877 | 4 hrs ago | 0.06 ETH | ||||
763877 | 4 hrs ago | 0.06 ETH | ||||
762773 | 11 hrs ago | 0.00001 ETH | ||||
762773 | 11 hrs ago | 0.00001 ETH | ||||
762329 | 15 hrs ago | 0.00495727 ETH | ||||
762329 | 15 hrs ago | 0.00495727 ETH | ||||
762036 | 18 hrs ago | 0.0266 ETH | ||||
762036 | 18 hrs ago | 0.0266 ETH | ||||
762002 | 19 hrs ago | 0.00247046 ETH | ||||
762002 | 19 hrs ago | 0.00247046 ETH | ||||
761688 | 23 hrs ago | 0.00222753 ETH | ||||
761688 | 23 hrs ago | 0.00222753 ETH | ||||
761646 | 23 hrs ago | 0.13666312 ETH | ||||
761646 | 23 hrs ago | 0.13666312 ETH | ||||
761470 | 25 hrs ago | 0.00151347 ETH | ||||
761470 | 25 hrs ago | 0.00151347 ETH | ||||
761268 | 27 hrs ago | 0.00907826 ETH | ||||
761268 | 27 hrs ago | 0.00907826 ETH | ||||
761247 | 27 hrs ago | 0.00173046 ETH | ||||
761247 | 27 hrs ago | 0.00173046 ETH | ||||
760967 | 29 hrs ago | 0.00065591 ETH |
Loading...
Loading
Contract Name:
BebopSettlement
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 77 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interface/IBebopSettlement.sol"; import "./base/BebopSigning.sol"; import "./base/BebopTransfer.sol"; import "./libs/Order.sol"; import "./libs/Signature.sol"; import "./libs/Transfer.sol"; contract BebopSettlement is IBebopSettlement, BebopSigning, BebopTransfer { using SafeERC20 for IERC20; constructor(address _wrappedNativeToken, address _permit2, address _daiAddress) BebopTransfer(_wrappedNativeToken, _permit2, _daiAddress) { } receive() external payable {} //----------------------------------------- // // One-to-One trade with one maker // taker execution (RFQ-T) // // ----------------------------------------- /// @inheritdoc IBebopSettlement function swapSingle( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount ) external override payable { if (msg.sender != order.taker_address) revert InvalidSender(); _executeSingleOrder(order, makerSignature, filledTakerAmount, Commands.SIMPLE_TRANSFER, order.maker_amount); } /// @inheritdoc IBebopSettlement function swapSingleFromContract( Order.Single calldata order, Signature.MakerSignature calldata makerSignature ) external override payable { if (msg.sender != order.taker_address) revert InvalidSender(); _executeSingleOrder( order, makerSignature, IERC20(order.taker_token).balanceOf(address(this)), Commands.TRANSFER_FROM_CONTRACT, order.maker_amount ); } //----------------------------------------- // // One-to-One trade with one maker // maker execution (RFQ-M) // // ----------------------------------------- /// @inheritdoc IBebopSettlement function settleSingle( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external override payable { _validateTakerSignatureForSingleOrder(order, takerSignature, takerQuoteInfo); _executeSingleOrder( order, makerSignature, filledTakerAmount, Commands.SIMPLE_TRANSFER, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmount : order.maker_amount ); } /// @inheritdoc IBebopSettlement function settleSingleAndSignPermit( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.PermitSignature calldata takerPermitSignature ) external override payable { _validateTakerSignatureForSingleOrder(order, takerSignature, takerQuoteInfo); _tokenPermit(order.taker_address, order.taker_token, takerPermitSignature); _executeSingleOrder( order, makerSignature, filledTakerAmount, Commands.SIMPLE_TRANSFER, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmount : order.maker_amount ); } /// @inheritdoc IBebopSettlement function settleSingleAndSignPermit2( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.Permit2Signature calldata takerPermit2Signature ) external override payable { _validateTakerSignatureForSingleOrder(order, takerSignature, takerQuoteInfo); _tokenPermit2(order.taker_address, order.taker_token, takerPermit2Signature); _executeSingleOrder( order, makerSignature, filledTakerAmount, Commands.PERMIT2_TRANSFER, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmount : order.maker_amount ); } //------------------------------------------------------ // // Many-to-One or One-to-Many trade with one maker // taker execution (RFQ-T) // // ------------------------------------------------------ /// @inheritdoc IBebopSettlement function swapMulti( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount ) external override payable { if (msg.sender != order.taker_address) revert InvalidSender(); _executeMultiOrder(order, makerSignature, filledTakerAmount, order.maker_amounts); } //------------------------------------------------------ // // Many-to-One or One-to-Many trade with one maker // maker execution (RFQ-M) // // ------------------------------------------------------ /// @inheritdoc IBebopSettlement function settleMulti( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external override payable { _validateTakerSignatureForMultiOrder(order, takerSignature, takerQuoteInfo); _executeMultiOrder( order, makerSignature, filledTakerAmount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } /// @inheritdoc IBebopSettlement function settleMultiAndSignPermit( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.PermitSignature calldata takerPermitSignature ) external override payable { _validateTakerSignatureForMultiOrder(order, takerSignature, takerQuoteInfo); _tokenPermitForMultiOrder(order, takerPermitSignature); _executeMultiOrder( order, makerSignature, filledTakerAmount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } /// @inheritdoc IBebopSettlement function settleMultiAndSignPermit2( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.MultiTokensPermit2Signature calldata infoPermit2 ) external override payable { _validateTakerSignatureForMultiOrder(order, takerSignature, takerQuoteInfo); _tokensPermit2ForMultiOrder(order, infoPermit2); _executeMultiOrder( order, makerSignature, filledTakerAmount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } //----------------------------------------- // // Any trade with multiple makers // taker execution (RFQ-T) // // ---------------------------------------- /// @inheritdoc IBebopSettlement function swapAggregate( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount ) external override payable { if (msg.sender != order.taker_address) revert InvalidSender(); _executeAggregateOrder(order, makersSignatures, filledTakerAmount, order.maker_amounts); } //----------------------------------------- // // Any trade with multiple makers // maker execution (RFQ-M) // // ---------------------------------------- /// @inheritdoc IBebopSettlement function settleAggregate( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, Transfer.OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external override payable { _validateTakerSignatureForAggregateOrder(order, takerSignature, takerQuoteInfo); _executeAggregateOrder( order, makersSignatures, filledTakerAmount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } /// @inheritdoc IBebopSettlement function settleAggregateAndSignPermit( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, Transfer.OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.PermitSignature calldata takerPermitSignature ) external override payable { _validateTakerSignatureForAggregateOrder(order, takerSignature, takerQuoteInfo); _tokenPermitForAggregateOrder(order, takerPermitSignature); _executeAggregateOrder( order, makersSignatures, filledTakerAmount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } /// @inheritdoc IBebopSettlement function settleAggregateAndSignPermit2( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, Transfer.OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.MultiTokensPermit2Signature calldata infoPermit2 ) external override payable { _validateTakerSignatureForAggregateOrder(order, takerSignature, takerQuoteInfo); _tokensPermit2ForAggregateOrder(order, infoPermit2); _executeAggregateOrder( order, makersSignatures, filledTakerAmount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } /// @notice Execute One-to-One trade with one maker /// @param order All information about order /// @param makerSignature Maker signature for SingleOrder /// @param filledTakerAmount Token amount which taker wants to swap, should be less or equal to order.taker_amount /// if filledTakerAmount == 0 then order.taker_amount will be used /// @param takerTransferCommand Command to indicate how to transfer taker's token /// @param updatedMakerAmount for RFQ-M case maker amount can be improved function _executeSingleOrder( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, bytes1 takerTransferCommand, uint256 updatedMakerAmount ) internal { _validateSingleOrder(order, makerSignature); (uint128 eventId, uint64 partnerId) = Order.extractFlags(order.flags); (bool takerHasNative, bool makerHasNative, bool takerUsingPermit2) = Order.extractSingleOrderCommands(order.packed_commands); if (takerTransferCommand == Commands.TRANSFER_FROM_CONTRACT && takerHasNative){ filledTakerAmount = address(this).balance; } _transferToken( order.taker_address, order.maker_address, order.taker_token, filledTakerAmount == 0 || filledTakerAmount > order.taker_amount ? order.taker_amount : filledTakerAmount, takerHasNative ? Commands.NATIVE_TRANSFER : (takerUsingPermit2 ? Commands.PERMIT2_TRANSFER : takerTransferCommand), takerHasNative ? Transfer.Action.Wrap : Transfer.Action.None, 0 ); uint256 newMakerAmount = updatedMakerAmount; if (filledTakerAmount != 0 && filledTakerAmount < order.taker_amount){ newMakerAmount = (updatedMakerAmount * filledTakerAmount) / order.taker_amount; } (bool makerUsingPermit2, ) = Signature.extractMakerFlags(makerSignature.flags); _transferToken( order.maker_address, order.receiver, order.maker_token, newMakerAmount, makerUsingPermit2 ? Commands.PERMIT2_TRANSFER : Commands.SIMPLE_TRANSFER, makerHasNative ? Transfer.Action.Unwrap : Transfer.Action.None, partnerId ); emit BebopOrder(eventId); } /// @notice Execute Many-to-One or One-to-Many trade with one maker /// @param order All information about order /// @param makerSignature Maker signature for SingleOrder /// @param filledTakerAmount Token amount which taker wants to swap, should be less or equal to order.taker_amount /// if filledTakerAmount == 0 then order.taker_amounts will be used, Many-to-One trades don't support partial fill /// @param updatedMakerAmounts for RFQ-M case maker amounts can be improved function _executeMultiOrder( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, uint256[] calldata updatedMakerAmounts ) internal { _validateMultiOrder(order, makerSignature, filledTakerAmount); (uint128 eventId, uint64 partnerId) = Order.extractFlags(order.flags); (bool makerUsingPermit2, ) = Signature.extractMakerFlags(makerSignature.flags); if (order.taker_tokens.length > 1){ // Many-to-One // transfer taker's tokens _transferTakerTokens(order); // transfer maker's token _transferToken( order.maker_address, order.receiver, order.maker_tokens[0], updatedMakerAmounts[0], makerUsingPermit2 ? Commands.PERMIT2_TRANSFER : Commands.SIMPLE_TRANSFER, order.commands[0] == Commands.NATIVE_TRANSFER ? Transfer.Action.Unwrap : Transfer.Action.None, partnerId ); } else { // One-to-Many // transfer taker's token bytes1 takerCommand = order.commands[order.maker_tokens.length]; _transferToken( order.taker_address, order.maker_address, order.taker_tokens[0], filledTakerAmount == 0 || filledTakerAmount > order.taker_amounts[0] ? order.taker_amounts[0] : filledTakerAmount, takerCommand, takerCommand == Commands.NATIVE_TRANSFER ? Transfer.Action.Wrap : Transfer.Action.None, 0 ); // transfer maker's tokens uint[] memory makerAmounts = updatedMakerAmounts; if (filledTakerAmount > 0 && filledTakerAmount < order.taker_amounts[0]){ for (uint j; j < updatedMakerAmounts.length; ++j){ makerAmounts[j] = updatedMakerAmounts[j] * filledTakerAmount / order.taker_amounts[0]; } } uint nativeToTaker = _transferMakerTokens( order.maker_address, order.receiver, order.maker_tokens, makerAmounts, makerUsingPermit2, order.commands, partnerId ); if (nativeToTaker > 0){ IWETH(WRAPPED_NATIVE_TOKEN).withdraw(nativeToTaker); (bool sent,) = order.receiver.call{value: nativeToTaker}(""); if (!sent) revert FailedToSendNativeToken(); } } emit BebopOrder(eventId); } /// @notice Execute trade with multiple makers /// @param order All information about order /// @param makersSignatures Maker signatures for part of AggregateOrder(which is MultiOrder) /// @param filledTakerAmount Token amount which taker wants to swap, should be less or equal to order.taker_amount /// if filledTakerAmount == 0 then order.taker_amounts will be used, Many-to-One trades don't support partial fill /// @param updatedMakerAmounts for RFQ-M case maker amounts can be improved function _executeAggregateOrder( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, uint256[][] calldata updatedMakerAmounts ) internal { _validateAggregateOrder(order, makersSignatures); (uint quoteTakerAmount, Transfer.LengthsInfo memory lenInfo) = _getAggregateOrderInfo(order, filledTakerAmount); Transfer.IndicesInfo memory indices = Transfer.IndicesInfo(0, 0, 0); Transfer.NativeTokens memory nativeTokens = Transfer.NativeTokens(0, 0); Transfer.Pending[] memory pendingTransfers = new Transfer.Pending[](lenInfo.pendingTransfersLen); IPermit2.AllowanceTransferDetails[] memory batchTransferDetails = new IPermit2.AllowanceTransferDetails[](lenInfo.permit2Len); for (uint i; i < order.maker_tokens.length; ++i){ (bool makerUsingPermit2, ) = Signature.extractMakerFlags(makersSignatures[i].flags); uint[] memory makerAmounts = updatedMakerAmounts[i]; if (filledTakerAmount > 0 && filledTakerAmount < quoteTakerAmount){ // partial fill for (uint j; j < updatedMakerAmounts[i].length; ++j){ makerAmounts[j] = updatedMakerAmounts[i][j] * filledTakerAmount / quoteTakerAmount; } } nativeTokens.toTaker += _transferMakerTokens( order.maker_addresses[i], order.receiver, order.maker_tokens[i], makerAmounts, makerUsingPermit2, BytesLib.slice(order.commands, indices.commandsInd, order.maker_tokens[i].length), Order.extractPartnerId(order.flags) ); indices.commandsInd += order.maker_tokens[i].length; _transferTakerTokensForAggregateOrder( order, i, filledTakerAmount, quoteTakerAmount, indices, nativeTokens, pendingTransfers, batchTransferDetails ); indices.commandsInd += order.taker_tokens[i].length; } if (indices.pendingTransfersInd != lenInfo.pendingTransfersLen) revert InvalidPendingTransfersLength(); if (indices.permit2Ind != lenInfo.permit2Len) revert InvalidPermit2TransfersLength(); if (lenInfo.permit2Len > 0) { // Transfer taker's tokens with Permit2 batch PERMIT2.transferFrom(batchTransferDetails); } // Transfer tokens from contract to makers if (lenInfo.pendingTransfersLen > 0) { // Wrap taker's native token if (nativeTokens.toMakers > 0){ if (msg.value < nativeTokens.toMakers) revert NotEnoughNativeToken(); IWETH(WRAPPED_NATIVE_TOKEN).deposit{value: nativeTokens.toMakers}(); } for (uint i; i < pendingTransfers.length; ++i) { if (pendingTransfers[i].amount > 0) { IERC20(pendingTransfers[i].token).safeTransfer( pendingTransfers[i].to, pendingTransfers[i].amount ); } } } // Unwrap and transfer native token to receiver if (nativeTokens.toTaker > 0) { IWETH(WRAPPED_NATIVE_TOKEN).withdraw(nativeTokens.toTaker); (bool sent,) = order.receiver.call{value: nativeTokens.toTaker}(""); if (!sent) revert FailedToSendNativeToken(); } emit BebopOrder(Order.extractEventId(order.flags)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @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. */ 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]. */ 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 v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Errors.sol"; abstract contract BebopPartner { struct PartnerInfo { uint16 fee; address beneficiary; bool registered; } mapping(uint64 => PartnerInfo) public partners; uint16 internal constant HUNDRED_PERCENT = 10000; constructor(){ partners[0].registered = true; } /// @notice Register new partner /// @param partnerId the unique identifier for this partner /// @param fee the additional fee to add to each swap from this partner /// @param beneficiary the address to send the partner's share of fees to function registerPartner(uint64 partnerId, uint16 fee, address beneficiary) external { if(partners[partnerId].registered) revert PartnerAlreadyRegistered(); if(fee > HUNDRED_PERCENT) revert PartnerFeeTooHigh(); if (beneficiary == address(0)) revert NullBeneficiary(); partners[partnerId] = PartnerInfo(fee, beneficiary, true); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../libs/Order.sol"; import "../libs/Signature.sol"; import "../libs/common/BytesLib.sol"; import "./Errors.sol"; import "lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol"; import "../libs/Transfer.sol"; abstract contract BebopSigning { event OrderSignerRegistered(address maker, address signer, bool allowed); bytes32 private constant DOMAIN_NAME = keccak256("BebopSettlement"); bytes32 private constant DOMAIN_VERSION = keccak256("2"); // bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 private constant EIP1271_MAGICVALUE = 0x1626ba7e; uint256 private constant ETH_SIGN_HASH_PREFIX = 0x19457468657265756d205369676e6564204d6573736167653a0a333200000000; /// @dev This value is pre-computed from the following expression /// keccak256(abi.encodePacked( /// "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" /// )); bytes32 private constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev This value is pre-computed from the following expression /// keccak256(abi.encodePacked( /// "AggregateOrder(uint64 partner_id,uint256 expiry,address taker_address,address[] maker_addresses,uint256[] maker_nonces,address[][] taker_tokens,address[][] maker_tokens,uint256[][] taker_amounts,uint256[][] maker_amounts,address receiver,bytes commands)" /// )); bytes32 private constant AGGREGATED_ORDER_TYPE_HASH = 0xe850f4ac05cb765eff6f120037e6d3286f8f71aaedad7f9f242af69d53091265; /// @dev This value is pre-computed from the following expression /// keccak256(abi.encodePacked( /// "MultiOrder(uint64 partner_id,uint256 expiry,address taker_address,address maker_address,uint256 maker_nonce,address[] taker_tokens,address[] maker_tokens,uint256[] taker_amounts,uint256[] maker_amounts,address receiver,bytes commands)" /// )); bytes32 private constant MULTI_ORDER_TYPE_HASH = 0x34728ce057ec73e3b4f0871dced9cc875f5b1aece9fd07891e156fe852a858d9; /// @dev This value is pre-computed from the following expression /// keccak256(abi.encodePacked( /// "SingleOrder(uint64 partner_id,uint256 expiry,address taker_address,address maker_address,uint256 maker_nonce,address taker_token,address maker_token,uint256 taker_amount,uint256 maker_amount,address receiver,uint256 packed_commands)" /// )); bytes32 private constant SINGLE_ORDER_TYPE_HASH = 0xe34225bc7cd92038d42c258ee3ff66d30f9387dd932213ba32a52011df0603fc; bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; mapping(address => mapping(uint256 => uint256)) private makerNonceValidator; mapping(address => mapping(address => bool)) private orderSignerRegistry; constructor(){ _CACHED_CHAIN_ID = block.chainid; _CACHED_DOMAIN_SEPARATOR = keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, DOMAIN_NAME, DOMAIN_VERSION, block.chainid, address(this)) ); } /// @notice The domain separator used in the order validation signature /// @return The domain separator hash function DOMAIN_SEPARATOR() public view returns (bytes32) { return block.chainid == _CACHED_CHAIN_ID ? _CACHED_DOMAIN_SEPARATOR : keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, DOMAIN_NAME, DOMAIN_VERSION, block.chainid, address(this)) ); } /// @notice Register another order signer for a maker /// @param signer The address of the additional signer /// @param allowed Whether the signer is allowed to sign orders for the maker function registerAllowedOrderSigner(address signer, bool allowed) external { orderSignerRegistry[msg.sender][signer] = allowed; emit OrderSignerRegistered(msg.sender, signer, allowed); } /// @notice Hash partnerId + Order.Single struct without `flags` field /// @param order Order.Single struct /// @param partnerId Unique partner identifier, 0 for no partner /// @param updatedMakerAmount Updated maker amount, 0 for no update /// @param updatedMakerNonce Updated maker nonce, 0 for no update /// @return The hash of the order function hashSingleOrder( Order.Single calldata order, uint64 partnerId, uint256 updatedMakerAmount, uint256 updatedMakerNonce ) public view returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( SINGLE_ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address, order.maker_address, updatedMakerNonce != 0 ? updatedMakerNonce : order.maker_nonce, order.taker_token, order.maker_token, order.taker_amount, updatedMakerAmount != 0 ? updatedMakerAmount : order.maker_amount, order.receiver, order.packed_commands ) ))); } /// @notice Hash partnerId + Order.Multi struct without `flags` field /// @param order Order.Multi struct /// @param partnerId Unique partner identifier, 0 for no partner /// @param updatedMakerAmounts Updated maker amounts, it replaces order.maker_amounts /// @param updatedMakerNonce Updated maker nonce, it replaces order.maker_nonce /// @return The hash of the order function hashMultiOrder( Order.Multi memory order, uint64 partnerId, uint256[] calldata updatedMakerAmounts, uint256 updatedMakerNonce ) public view returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( MULTI_ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address, order.maker_address, updatedMakerNonce, keccak256(abi.encodePacked(order.taker_tokens)), keccak256(abi.encodePacked(order.maker_tokens)), keccak256(abi.encodePacked(order.taker_amounts)), keccak256(abi.encodePacked(updatedMakerAmounts)), order.receiver, keccak256(order.commands) ) ))); } /// @notice Hash partnerId + Order.Aggregate struct without `flags` field /// @param order Order.Aggregate struct /// @param partnerId Unique partner identifier, 0 for no partner /// @param updatedMakerAmounts Updated maker amounts, it replaces order.maker_amounts /// @param updatedMakerNonces Updated maker nonces, it replaces order.maker_nonces /// @return The hash of the order function hashAggregateOrder( Order.Aggregate calldata order, uint64 partnerId, uint256[][] calldata updatedMakerAmounts, uint256[] calldata updatedMakerNonces ) public view returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( AGGREGATED_ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address, keccak256(abi.encodePacked(order.maker_addresses)), keccak256(abi.encodePacked(updatedMakerNonces)), keccak256(_encodeTightlyPackedNested(order.taker_tokens)), keccak256(_encodeTightlyPackedNested(order.maker_tokens)), keccak256(_encodeTightlyPackedNestedInt(order.taker_amounts)), keccak256(_encodeTightlyPackedNestedInt(updatedMakerAmounts)), order.receiver, keccak256(order.commands) ) ))); } /// @notice Validate the order signature /// @param validationAddress The address to validate the signature against /// @param hash The hash of the order /// @param signature The signature to validate /// @param signatureType The type of the signature /// @param isMaker Whether external signer from orderSignerRegistry is allowed or not function _validateSignature( address validationAddress, bytes32 hash, bytes calldata signature, Signature.Type signatureType, bool isMaker ) internal view { if (signatureType == Signature.Type.EIP712) { (bytes32 r, bytes32 s, uint8 v) = Signature.getRsv(signature); address signer = ecrecover(hash, v, r, s); if (signer == address(0)) revert OrderInvalidSigner(); if (signer != validationAddress && (!isMaker || !orderSignerRegistry[validationAddress][signer])) { revert InvalidEIP721Signature(); } } else if (signatureType == Signature.Type.EIP1271) { if (IERC1271(validationAddress).isValidSignature(hash, signature) != EIP1271_MAGICVALUE){ revert InvalidEIP1271Signature(); } } else if (signatureType == Signature.Type.ETHSIGN) { bytes32 ethSignHash; assembly { mstore(0, ETH_SIGN_HASH_PREFIX) mstore(28, hash) ethSignHash := keccak256(0, 60) } (bytes32 r, bytes32 s, uint8 v) = Signature.getRsv(signature); address signer = ecrecover(ethSignHash, v, r, s); if (signer == address(0)) revert OrderInvalidSigner(); if (signer != validationAddress && (!isMaker || !orderSignerRegistry[validationAddress][signer])) { revert InvalidETHSIGNSignature(); } } else { revert InvalidSignatureType(); } } /// @notice Pack 2D array of integers into tightly packed bytes for hashing function _encodeTightlyPackedNestedInt(uint256[][] calldata _nested_array) private pure returns (bytes memory encoded) { uint nested_array_length = _nested_array.length; for (uint i; i < nested_array_length; ++i) { encoded = abi.encodePacked(encoded, keccak256(abi.encodePacked(_nested_array[i]))); } return encoded; } /// @notice Pack 2D array of addresses into tightly packed bytes for hashing function _encodeTightlyPackedNested(address[][] calldata _nested_array) private pure returns (bytes memory encoded) { uint nested_array_length = _nested_array.length; for (uint i; i < nested_array_length; ++i) { encoded = abi.encodePacked(encoded, keccak256(abi.encodePacked(_nested_array[i]))); } return encoded; } /// @notice Check maker nonce and invalidate it function _invalidateOrder(address maker, uint256 nonce) private { if (nonce == 0) revert ZeroNonce(); uint256 invalidatorSlot = nonce >> 8; uint256 invalidatorBit = 1 << (nonce & 0xff); mapping(uint256 => uint256) storage invalidatorStorage = makerNonceValidator[maker]; uint256 invalidator = invalidatorStorage[invalidatorSlot]; if (invalidator & invalidatorBit == invalidatorBit) revert InvalidNonce(); invalidatorStorage[invalidatorSlot] = invalidator | invalidatorBit; } /// @notice Validate maker signature and SingleOrder fields function _validateSingleOrder( Order.Single calldata order, Signature.MakerSignature calldata makerSignature ) internal { (, Signature.Type signatureType) = Signature.extractMakerFlags(makerSignature.flags); _validateSignature( order.maker_address, hashSingleOrder(order, Order.extractPartnerId(order.flags), 0, 0), makerSignature.signatureBytes, signatureType, true ); _invalidateOrder(order.maker_address, order.maker_nonce); if (order.expiry <= block.timestamp) revert OrderExpired(); } /// @notice Validate maker signature and MultiOrder fields function _validateMultiOrder( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount ) internal { (, Signature.Type signatureType) = Signature.extractMakerFlags(makerSignature.flags); _validateSignature( order.maker_address, hashMultiOrder(order, Order.extractPartnerId(order.flags), order.maker_amounts, order.maker_nonce), makerSignature.signatureBytes, signatureType, true ); _invalidateOrder(order.maker_address, order.maker_nonce); if ( order.taker_tokens.length != order.taker_amounts.length || order.maker_tokens.length != order.maker_amounts.length ) revert TokensLengthsMismatch(); if (order.commands.length != order.taker_tokens.length + order.maker_tokens.length) revert InvalidCommandsLength(); if (order.taker_tokens.length != 1 && order.maker_tokens.length != 1) revert ManyToManyNotSupported(); if (order.taker_tokens.length > 1 && filledTakerAmount != 0){ /// @dev Partial fill is not supported for many-to-one orders, so filledTakerAmount should be 0 revert PartialFillNotSupported(); } if (order.expiry <= block.timestamp) revert OrderExpired(); } /// @notice Validate makers signatures and AggregateOrder fields function _validateAggregateOrder( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures ) internal { uint makersNum = makersSignatures.length; if ( order.maker_addresses.length != makersNum || order.maker_nonces.length != makersNum || order.taker_tokens.length != makersNum || order.maker_tokens.length != makersNum || order.taker_amounts.length != makersNum || order.maker_amounts.length != makersNum ) revert OrdersLengthsMismatch(); uint tokenTransfers; for (uint i; i < makersNum; ++i) { if (order.maker_tokens[i].length != order.maker_amounts[i].length || order.taker_tokens[i].length != order.taker_amounts[i].length) revert TokensLengthsMismatch(); Order.Multi memory partialAggregateOrder = Order.Multi( order.expiry, order.taker_address, order.maker_addresses[i], order.maker_nonces[i], order.taker_tokens[i], order.maker_tokens[i], order.taker_amounts[i], order.maker_amounts[i], order.receiver, BytesLib.slice( order.commands, tokenTransfers, order.maker_tokens[i].length + order.taker_tokens[i].length ), 0 ); bytes32 multiOrderHash = hashMultiOrder( partialAggregateOrder, Order.extractPartnerId(order.flags), order.maker_amounts[i], order.maker_nonces[i] ); (, Signature.Type signatureType) = Signature.extractMakerFlags(makersSignatures[i].flags); _validateSignature( order.maker_addresses[i], multiOrderHash, makersSignatures[i].signatureBytes, signatureType, true ); _invalidateOrder(order.maker_addresses[i], order.maker_nonces[i]); tokenTransfers += order.maker_tokens[i].length + order.taker_tokens[i].length; } if (tokenTransfers != order.commands.length) revert CommandsLengthsMismatch(); if (order.expiry <= block.timestamp) revert OrderExpired(); } /// @notice Validate taker signature for SingleOrder function _validateTakerSignatureForSingleOrder( Order.Single calldata order, bytes calldata takerSignature, Transfer.OldSingleQuote calldata takerQuoteInfo ) internal { if (order.maker_amount < takerQuoteInfo.makerAmount) revert UpdatedMakerAmountsTooLow(); if (takerQuoteInfo.makerAmount == 0) revert ZeroMakerAmount(); if (takerQuoteInfo.makerNonce != order.maker_nonce){ _invalidateOrder(order.maker_address, takerQuoteInfo.makerNonce); } if (msg.sender != order.taker_address){ Signature.Type signatureType = Order.extractSignatureType(order.flags); _validateSignature( order.taker_address, hashSingleOrder(order, Order.extractPartnerId(order.flags), takerQuoteInfo.makerAmount, takerQuoteInfo.makerNonce), takerSignature, signatureType, false ); } } /// @notice Validate taker signature for MultiOrder function _validateTakerSignatureForMultiOrder( Order.Multi calldata order, bytes calldata takerSignature, Transfer.OldMultiQuote calldata takerQuoteInfo ) internal { if (takerQuoteInfo.makerAmounts.length != order.maker_amounts.length) revert MakerAmountsLengthsMismatch(); for (uint i; i < takerQuoteInfo.makerAmounts.length; ++i){ if (takerQuoteInfo.makerAmounts[i] == 0) revert ZeroMakerAmount(); if (order.maker_amounts[i] < takerQuoteInfo.makerAmounts[i]) revert UpdatedMakerAmountsTooLow(); } if (takerQuoteInfo.makerNonce != order.maker_nonce){ _invalidateOrder(order.maker_address, takerQuoteInfo.makerNonce); } if (msg.sender != order.taker_address){ Signature.Type signatureType = Order.extractSignatureType(order.flags); _validateSignature( order.taker_address, hashMultiOrder(order, Order.extractPartnerId(order.flags), takerQuoteInfo.makerAmounts, takerQuoteInfo.makerNonce), takerSignature, signatureType, false ); } } /// @notice Validate taker signature for AggregateOrder function _validateTakerSignatureForAggregateOrder( Order.Aggregate calldata order, bytes calldata takerSignature, Transfer.OldAggregateQuote calldata takerQuoteInfo ) internal { if (takerQuoteInfo.makerAmounts.length != order.maker_amounts.length) revert MakerAmountsLengthsMismatch(); for (uint i; i < order.maker_amounts.length; ++i){ if (takerQuoteInfo.makerAmounts[i].length != order.maker_amounts[i].length) revert MakerAmountsLengthsMismatch(); for (uint j; j < order.maker_amounts[i].length; ++j){ if (order.maker_amounts[i][j] < takerQuoteInfo.makerAmounts[i][j]) revert UpdatedMakerAmountsTooLow(); } if (takerQuoteInfo.makerNonces[i] != order.maker_nonces[i]){ _invalidateOrder(order.maker_addresses[i], takerQuoteInfo.makerNonces[i]); } } if (msg.sender != order.taker_address){ Signature.Type signatureType = Order.extractSignatureType(order.flags); _validateSignature( order.taker_address, hashAggregateOrder(order, Order.extractPartnerId(order.flags), takerQuoteInfo.makerAmounts, takerQuoteInfo.makerNonces), takerSignature, signatureType, false ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interface/IDaiLikePermit.sol"; import "../interface/IPermit2.sol"; import "../interface/IWETH.sol"; import "../libs/Order.sol"; import "../libs/Signature.sol"; import "../libs/Transfer.sol"; import "../libs/Commands.sol"; import "../libs/common/SafeCast160.sol"; import "./BebopSigning.sol"; import "./BebopPartner.sol"; import "./Errors.sol"; import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract BebopTransfer is BebopPartner { using SafeERC20 for IERC20; address internal immutable WRAPPED_NATIVE_TOKEN; address internal immutable DAI_TOKEN; IPermit2 internal immutable PERMIT2; uint private immutable _chainId; function _getChainId() private view returns (uint256 id) { assembly { id := chainid() } } constructor(address _wrappedNativeToken, address _permit2, address _daiAddress) { WRAPPED_NATIVE_TOKEN = _wrappedNativeToken; DAI_TOKEN = _daiAddress; PERMIT2 = IPermit2(_permit2); _chainId = _getChainId(); } /// @notice Validates that partial fill is allowed and extract necessary information from Aggregate order /// @return quoteTakerAmount - full taker_amount for One-to-One or One-to-Many trades, for Many-to-One orders it's 0 /// @return lenInfo - lengths of `pendingTransfers` and `batchTransferDetails` arrays function _getAggregateOrderInfo( Order.Aggregate calldata order, uint256 filledTakerAmount ) internal pure returns (uint quoteTakerAmount, Transfer.LengthsInfo memory lenInfo){ uint commandsInd; address tokenAddress = order.taker_tokens[0][0]; for (uint i; i < order.taker_tokens.length; ++i){ commandsInd += order.maker_tokens[i].length; for (uint j; j < order.taker_tokens[i].length; ++j) { bytes1 curCommand = order.commands[commandsInd + j]; if (curCommand != Commands.TRANSFER_FROM_CONTRACT){ if (filledTakerAmount > 0){ /// @dev partial fills works only for One-to-One or One-to-Many trades, /// filledTakerAmount is partially filled amount of taker's token, /// so filledTakerAmount should be 0 for Many-to-One orders and orders without partial fills quoteTakerAmount += order.taker_amounts[i][j]; if (tokenAddress != order.taker_tokens[i][j]){ revert PartialFillNotSupported(); } } if (curCommand == Commands.NATIVE_TRANSFER) { ++lenInfo.pendingTransfersLen; } else if (curCommand == Commands.PERMIT2_TRANSFER || curCommand == Commands.CALL_PERMIT2_THEN_TRANSFER) { ++lenInfo.permit2Len; } } else { ++lenInfo.pendingTransfersLen; } } commandsInd += order.taker_tokens[i].length; } } /// @notice Universal function for transferring tokens /// @param from address from which tokens will be transferred /// @param to address to which tokens will be transferred /// @param token address of token /// @param amount amount of token /// @param command Commands to indicate how to transfer token /// @param action Wrap or Unwrap native token /// @param partnerId identifier of partner to pay referral fee function _transferToken( address from, address to, address token, uint256 amount, bytes1 command, Transfer.Action action, uint64 partnerId ) internal { if (action == Transfer.Action.Wrap){ if (token != WRAPPED_NATIVE_TOKEN) revert WrongWrappedTokenAddress(); IWETH(WRAPPED_NATIVE_TOKEN).deposit{value: amount}(); } uint fee; PartnerInfo memory partnerInfo; if (partnerId != 0){ partnerInfo = partners[partnerId]; if (partnerInfo.registered && partnerInfo.fee > 0){ fee = amount * partnerInfo.fee / HUNDRED_PERCENT; } } address receiver = action == Transfer.Action.Unwrap ? address(this) : to; if (command == Commands.SIMPLE_TRANSFER || command == Commands.CALL_PERMIT_THEN_TRANSFER){ if (fee > 0){ IERC20(token).safeTransferFrom(from, partnerInfo.beneficiary, fee); amount -= fee; } IERC20(token).safeTransferFrom(from, receiver, amount); } else if (command == Commands.PERMIT2_TRANSFER || command == Commands.CALL_PERMIT2_THEN_TRANSFER){ if (fee > 0){ amount -= fee; IPermit2.AllowanceTransferDetails[] memory batchTransferDetails = new IPermit2.AllowanceTransferDetails[](2); batchTransferDetails[0] = IPermit2.AllowanceTransferDetails(from, partnerInfo.beneficiary, SafeCast160.toUint160(fee), token); batchTransferDetails[1] = IPermit2.AllowanceTransferDetails(from, receiver, SafeCast160.toUint160(amount), token); PERMIT2.transferFrom(batchTransferDetails); } else { PERMIT2.transferFrom(from, receiver, SafeCast160.toUint160(amount), token); } } else if (command == Commands.TRANSFER_FROM_CONTRACT || command == Commands.NATIVE_TRANSFER){ IERC20(token).safeTransfer(to, amount); } else { revert InvalidCommand(); } if (action == Transfer.Action.Unwrap){ if (token != WRAPPED_NATIVE_TOKEN) revert WrongWrappedTokenAddress(); IWETH(WRAPPED_NATIVE_TOKEN).withdraw(amount); (bool sent,) = to.call{value: amount}(""); if (!sent) revert FailedToSendNativeToken(); } } /// @notice For MultiOrder transfer taker's tokens to maker /// @param order MultiOrder function _transferTakerTokens(Order.Multi calldata order) internal { IPermit2.AllowanceTransferDetails[] memory batchTransferDetails; uint permit2Ind; for (uint i; i < order.taker_tokens.length; ++i) { bytes1 command = order.commands[i + order.maker_tokens.length]; if (command == Commands.SIMPLE_TRANSFER || command == Commands.CALL_PERMIT_THEN_TRANSFER){ IERC20(order.taker_tokens[i]).safeTransferFrom( order.taker_address, order.maker_address, order.taker_amounts[i] ); } else if (command == Commands.PERMIT2_TRANSFER || command == Commands.CALL_PERMIT2_THEN_TRANSFER){ if (batchTransferDetails.length == 0){ batchTransferDetails = new IPermit2.AllowanceTransferDetails[](order.taker_tokens.length - i); } batchTransferDetails[permit2Ind++] = IPermit2.AllowanceTransferDetails({ from: order.taker_address, to: order.maker_address, amount: SafeCast160.toUint160(order.taker_amounts[i]), token: order.taker_tokens[i] }); continue; } else if (command == Commands.NATIVE_TRANSFER) { if (order.taker_tokens[i] != WRAPPED_NATIVE_TOKEN) revert WrongWrappedTokenAddress(); IWETH(WRAPPED_NATIVE_TOKEN).deposit{value: order.taker_amounts[i]}(); IERC20(WRAPPED_NATIVE_TOKEN).safeTransfer(order.maker_address, order.taker_amounts[i]); } else { revert InvalidCommand(); } if (batchTransferDetails.length > 0){ assembly {mstore(batchTransferDetails, sub(mload(batchTransferDetails), 1))} } } if (batchTransferDetails.length > 0){ PERMIT2.transferFrom(batchTransferDetails); } } /// @notice Transfer tokens from maker to taker /// @param from maker_address from which tokens will be transferred /// @param to taker_address to which tokens will be transferred /// @param maker_tokens addresses of tokens /// @param maker_amounts amounts of tokens /// @param usingPermit2 indicates whether maker is Permit2 for transfers or not /// @param makerCommands commands to indicate how to transfer tokens /// @param partnerId identifier of partner to pay referral fee /// @return nativeToTaker amount of native token to transfer to taker function _transferMakerTokens( address from, address to, address[] calldata maker_tokens, uint256[] memory maker_amounts, bool usingPermit2, bytes memory makerCommands, uint64 partnerId ) internal returns (uint256) { uint256 nativeToTaker; IPermit2.AllowanceTransferDetails[] memory batchTransferDetails; uint batchInd; bool hasPartnerFee = partnerId != 0; PartnerInfo memory partnerInfo; if (hasPartnerFee){ partnerInfo = partners[partnerId]; hasPartnerFee = partnerInfo.registered && partnerInfo.fee > 0; } for (uint j; j < maker_tokens.length; ++j) { uint256 amount = maker_amounts[j]; address receiver = to; if (makerCommands[j] != Commands.SIMPLE_TRANSFER){ if (makerCommands[j] == Commands.TRANSFER_TO_CONTRACT) { receiver = address(this); } else if (makerCommands[j] == Commands.NATIVE_TRANSFER) { if (maker_tokens[j] != WRAPPED_NATIVE_TOKEN) revert WrongWrappedTokenAddress(); nativeToTaker += amount; receiver = address(this); } else { revert InvalidCommand(); } } if (usingPermit2) { if (batchTransferDetails.length == 0){ batchTransferDetails = new IPermit2.AllowanceTransferDetails[](hasPartnerFee ? 2 * maker_tokens.length : maker_tokens.length); } if (hasPartnerFee){ if (makerCommands[j] != Commands.TRANSFER_TO_CONTRACT){ uint256 fee = amount * partnerInfo.fee / HUNDRED_PERCENT; if (fee > 0){ batchTransferDetails[batchInd++] = IPermit2.AllowanceTransferDetails({ from: from, to: partnerInfo.beneficiary, amount: SafeCast160.toUint160(fee), token: maker_tokens[j] }); amount -= fee; if (makerCommands[j] == Commands.NATIVE_TRANSFER){ nativeToTaker -= fee; } } else { assembly {mstore(batchTransferDetails, sub(mload(batchTransferDetails), 1))} } } else { assembly {mstore(batchTransferDetails, sub(mload(batchTransferDetails), 1))} } } batchTransferDetails[batchInd++] = IPermit2.AllowanceTransferDetails({ from: from, to: receiver, amount: SafeCast160.toUint160(amount), token: maker_tokens[j] }); } else { if (hasPartnerFee && makerCommands[j] != Commands.TRANSFER_TO_CONTRACT){ uint256 fee = amount * partnerInfo.fee / HUNDRED_PERCENT; if (fee > 0){ IERC20(maker_tokens[j]).safeTransferFrom(from, partnerInfo.beneficiary, fee); amount -= fee; if (makerCommands[j] == Commands.NATIVE_TRANSFER){ nativeToTaker -= fee; } } } IERC20(maker_tokens[j]).safeTransferFrom(from, receiver, amount); } } if (usingPermit2){ if (batchInd != batchTransferDetails.length) revert InvalidPermit2Commands(); PERMIT2.transferFrom(batchTransferDetails); } return nativeToTaker; } /// @notice Transfer tokens from taker to maker with index=i in Aggregate order /// @param order AggregateOrder /// @param i index of current maker /// @param filledTakerAmount Token amount which taker wants to swap, should be less or equal to order.taker_amount /// if filledTakerAmount == 0 then order.taker_amounts will be used, Many-to-One trades don't support partial fill /// @param quoteTakerAmount - full taker_amount for One-to-One or One-to-Many trades, for Many-to-One orders it's 0 /// @param indices helper structure to track indices /// @param nativeTokens helper structure to track native token transfers /// @param pendingTransfers helper structure to track pending transfers /// @param batchTransferDetails helper structure to track permit2 transfer function _transferTakerTokensForAggregateOrder( Order.Aggregate calldata order, uint256 i, uint256 filledTakerAmount, uint256 quoteTakerAmount, Transfer.IndicesInfo memory indices, Transfer.NativeTokens memory nativeTokens, Transfer.Pending[] memory pendingTransfers, IPermit2.AllowanceTransferDetails[] memory batchTransferDetails ) internal { for (uint k; k < order.taker_tokens[i].length; ++k) { uint currentTakerAmount = filledTakerAmount > 0 && filledTakerAmount < quoteTakerAmount ? order.taker_amounts[i][k] * filledTakerAmount / quoteTakerAmount : order.taker_amounts[i][k]; bytes1 curCommand = order.commands[indices.commandsInd + k]; if (curCommand == Commands.SIMPLE_TRANSFER || curCommand == Commands.CALL_PERMIT_THEN_TRANSFER){ IERC20(order.taker_tokens[i][k]).safeTransferFrom( order.taker_address, order.maker_addresses[i], currentTakerAmount ); } else if (curCommand == Commands.PERMIT2_TRANSFER || curCommand == Commands.CALL_PERMIT2_THEN_TRANSFER){ batchTransferDetails[indices.permit2Ind++] = IPermit2.AllowanceTransferDetails({ from: order.taker_address, to: order.maker_addresses[i], amount: SafeCast160.toUint160(currentTakerAmount), token: order.taker_tokens[i][k] }); } else if (curCommand == Commands.NATIVE_TRANSFER) { if (order.taker_tokens[i][k] != WRAPPED_NATIVE_TOKEN) revert WrongWrappedTokenAddress(); nativeTokens.toMakers += currentTakerAmount; pendingTransfers[indices.pendingTransfersInd++] = Transfer.Pending( order.taker_tokens[i][k], order.maker_addresses[i], currentTakerAmount ); } else if (curCommand == Commands.TRANSFER_FROM_CONTRACT){ // If using contract as an intermediate recipient for tokens transferring pendingTransfers[indices.pendingTransfersInd++] = Transfer.Pending( order.taker_tokens[i][k], order.maker_addresses[i], currentTakerAmount ); } else { revert InvalidCommand(); } } } /// @notice Call 'permit' function for taker's token function _tokenPermit( address takerAddress, address tokenAddress, Signature.PermitSignature calldata takerPermitSignature ) internal { (bytes32 r, bytes32 s, uint8 v) = Signature.getRsv(takerPermitSignature.signatureBytes); if (tokenAddress == DAI_TOKEN){ if (_chainId == 137){ IDaiLikePermit(tokenAddress).permit( takerAddress, address(this), IDaiLikePermit(tokenAddress).getNonce(takerAddress), takerPermitSignature.deadline, true, v, r, s ); } else { IDaiLikePermit(tokenAddress).permit( takerAddress, address(this), IERC20Permit(tokenAddress).nonces(takerAddress), takerPermitSignature.deadline, true, v, r, s ); } } else { IERC20Permit(tokenAddress).permit(takerAddress, address(this), type(uint).max, takerPermitSignature.deadline, v, r, s); } } /// @notice On Permit2 contract call 'permit' function for taker's token function _tokenPermit2( address takerAddress, address tokenAddress, Signature.Permit2Signature calldata takerPermit2Signature ) internal { IPermit2.PermitDetails[] memory permitBatch = new IPermit2.PermitDetails[](1); permitBatch[0] = IPermit2.PermitDetails( tokenAddress, type(uint160).max, takerPermit2Signature.deadline, takerPermit2Signature.nonce ); PERMIT2.permit( takerAddress, IPermit2.PermitBatch(permitBatch, address(this), takerPermit2Signature.deadline), takerPermit2Signature.signatureBytes ); } /// @notice Call 'permit' function for one taker token that has command 'CALL_PERMIT_THEN_TRANSFER' function _tokenPermitForMultiOrder( Order.Multi calldata order, Signature.PermitSignature calldata takerPermitSignature ) internal { uint commandsInd = order.maker_tokens.length; for (uint i; i < order.taker_tokens.length; ++i){ if (order.commands[commandsInd++] == Commands.CALL_PERMIT_THEN_TRANSFER){ _tokenPermit(order.taker_address, order.taker_tokens[i], takerPermitSignature); return; } } } /// @notice On Permit2 contract call 'permit' for batch of tokens with transfer-command 'CALL_PERMIT2_THEN_TRANSFER' function _tokensPermit2ForMultiOrder( Order.Multi calldata order, Signature.MultiTokensPermit2Signature calldata infoPermit2 ) internal { uint commandsInd = order.maker_tokens.length; uint batchToApproveInd; IPermit2.PermitDetails[] memory batchToApprove = new IPermit2.PermitDetails[](infoPermit2.nonces.length); for (uint i; i < order.taker_tokens.length; ++i){ if (order.commands[commandsInd++] == Commands.CALL_PERMIT2_THEN_TRANSFER){ batchToApprove[batchToApproveInd] = IPermit2.PermitDetails( order.taker_tokens[i], type(uint160).max, infoPermit2.deadline, infoPermit2.nonces[batchToApproveInd] ); ++batchToApproveInd; } } if (batchToApproveInd != batchToApprove.length) revert InvalidPermit2Commands(); PERMIT2.permit( order.taker_address, IPermit2.PermitBatch(batchToApprove, address(this), infoPermit2.deadline), infoPermit2.signatureBytes ); } /// @notice Call 'permit' function for one taker token that has command 'CALL_PERMIT_THEN_TRANSFER' function _tokenPermitForAggregateOrder( Order.Aggregate calldata order, Signature.PermitSignature calldata takerPermitSignature ) internal { uint commandsInd; for (uint i; i < order.taker_tokens.length; ++i){ commandsInd += order.maker_tokens[i].length; for (uint j; j < order.taker_tokens[i].length; ++j) { if (order.commands[commandsInd++] == Commands.CALL_PERMIT_THEN_TRANSFER){ _tokenPermit(order.taker_address, order.taker_tokens[i][j], takerPermitSignature); return; } } } } /// @notice On Permit2 contract call 'permit' for batch of tokens with transfer-command 'CALL_PERMIT2_THEN_TRANSFER' function _tokensPermit2ForAggregateOrder( Order.Aggregate calldata order, Signature.MultiTokensPermit2Signature calldata infoPermit2 ) internal { uint commandsInd; uint batchToApproveInd; IPermit2.PermitDetails[] memory batchToApprove = new IPermit2.PermitDetails[](infoPermit2.nonces.length); for (uint i; i < order.taker_tokens.length; ++i){ commandsInd += order.maker_tokens[i].length; for (uint j; j < order.taker_tokens[i].length; ++j) { if (order.commands[commandsInd++] == Commands.CALL_PERMIT2_THEN_TRANSFER){ batchToApprove[batchToApproveInd] = IPermit2.PermitDetails( order.taker_tokens[i][j], type(uint160).max, infoPermit2.deadline, infoPermit2.nonces[batchToApproveInd] ); ++batchToApproveInd; } } } if (batchToApproveInd != batchToApprove.length) revert InvalidPermit2Commands(); PERMIT2.permit( order.taker_address, IPermit2.PermitBatch(batchToApprove, address(this), infoPermit2.deadline), infoPermit2.signatureBytes ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Signature Errors error OrderInvalidSigner(); error InvalidEIP721Signature(); error InvalidEIP1271Signature(); error InvalidETHSIGNSignature(); error InvalidSignatureType(); error InvalidSignatureLength(); error InvalidSignatureValueS(); error InvalidSignatureValueV(); // Validation Errors error ZeroNonce(); error InvalidNonce(); error OrderExpired(); error OrdersLengthsMismatch(); error TokensLengthsMismatch(); error CommandsLengthsMismatch(); error InvalidPermit2Commands(); error InvalidCommand(); error InvalidCommandsLength(); error InvalidFlags(); error PartialFillNotSupported(); error UpdatedMakerAmountsTooLow(); error ZeroMakerAmount(); error MakerAmountsLengthsMismatch(); error NotEnoughNativeToken(); error WrongWrappedTokenAddress(); error FailedToSendNativeToken(); error InvalidSender(); error ManyToManyNotSupported(); error InvalidPendingTransfersLength(); error InvalidPermit2TransfersLength(); // Partner Errors error PartnerAlreadyRegistered(); error PartnerFeeTooHigh(); error NullBeneficiary();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../libs/Order.sol"; import "../libs/Signature.sol"; import "../libs/Transfer.sol"; interface IBebopSettlement { event BebopOrder(uint128 indexed eventId); /// @notice Taker execution of one-to-one trade with one maker /// @param order Single order struct /// @param makerSignature Maker's signature for SingleOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill function swapSingle( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount ) external payable; /// @notice Taker execution of one-to-one trade with one maker. /// Using current contract's balance of taker_token as partial fill amount /// @param order Single order struct /// @param makerSignature Maker's signature for SingleOrder function swapSingleFromContract( Order.Single calldata order, Signature.MakerSignature calldata makerSignature ) external payable; /// @notice Maker execution of one-to-one trade with one maker /// @param order Single order struct /// @param makerSignature Maker's signature for SingleOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill /// @param takerQuoteInfo If maker_amount has improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' (recommended to use swapSingle for this case) function settleSingle( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external payable; /// @notice Maker execution of one-to-one trade with one maker. /// Sign permit for taker_token before execution of the order /// @param order Single order struct /// @param makerSignature Maker's signature for SingleOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill /// @param takerQuoteInfo If maker_amount has improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' /// @param takerPermitSignature Taker's signature to approve spending of taker_token by calling token.permit(..) function settleSingleAndSignPermit( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.PermitSignature calldata takerPermitSignature ) external payable; /// @notice Maker execution of one-to-one trade with one maker. /// Sign permit2 for taker_token before execution of the order /// @param order Single order struct /// @param makerSignature Maker's signature for SingleOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill /// @param takerQuoteInfo If maker_amount has improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' /// @param takerPermit2Signature Taker's signature to approve spending of taker_token by calling Permit2.permit(..) function settleSingleAndSignPermit2( Order.Single calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.Permit2Signature calldata takerPermit2Signature ) external payable; /// @notice Taker execution of one-to-many or many-to-one trade with one maker /// @param order Multi order struct /// @param makerSignature Maker's signature for MultiOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill function swapMulti( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount ) external payable; /// @notice Maker execution of one-to-many or many-to-one trade with one maker /// @param order Multi order struct /// @param makerSignature Maker's signature for MultiOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' (recommended to use swapMulti for this case) function settleMulti( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external payable; /// @notice Maker execution of one-to-many or many-to-one trade with one maker. /// Before execution of the order, signs permit for one of taker_tokens /// @param order Multi order struct /// @param makerSignature Maker's signature for MultiOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' /// @param takerPermitSignature Taker's signature to approve spending of taker_token by calling token.permit(..) function settleMultiAndSignPermit( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.PermitSignature calldata takerPermitSignature ) external payable; /// @notice Maker execution of one-to-many or many-to-one trade with one maker. /// Sign permit2 for taker_tokens before execution of the order /// @param order Multi order struct /// @param makerSignature Maker's signature for MultiOrder /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' /// @param infoPermit2 Taker's signature to approve spending of taker_tokens by calling Permit2.permit(..) function settleMultiAndSignPermit2( Order.Multi calldata order, Signature.MakerSignature calldata makerSignature, uint256 filledTakerAmount, Transfer.OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.MultiTokensPermit2Signature calldata infoPermit2 ) external payable; /// @notice Taker execution of any trade with multiple makers /// @param order Aggregate order struct /// @param makersSignatures Makers signatures for MultiOrder (can be contructed as part of current AggregateOrder) /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill function swapAggregate( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount ) external payable; /// @notice Maker execution of any trade with multiple makers /// @param order Aggregate order struct /// @param makersSignatures Makers signatures for MultiOrder (can be contructed as part of current AggregateOrder) /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' (recommended to use swapAggregate for this case) function settleAggregate( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, Transfer.OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external payable; /// @notice Maker execution of any trade with multiple makers. /// Before execution of the order, signs permit for one of taker_tokens /// @param order Aggregate order struct /// @param makersSignatures Makers signatures for MultiOrder (can be contructed as part of current AggregateOrder) /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' /// @param takerPermitSignature Taker's signature to approve spending of taker_token by calling token.permit(..) function settleAggregateAndSignPermit( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, Transfer.OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.PermitSignature calldata takerPermitSignature ) external payable; /// @notice Maker execution of any trade with multiple makers. /// Sign permit2 for taker_tokens before execution of the order /// @param order Aggregate order struct /// @param makersSignatures Makers signatures for MultiOrder (can be contructed as part of current AggregateOrder) /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed, /// otherwise it contains same values as in order /// @param takerSignature Taker's signature to approve executing order by maker, /// if taker executes order himself then signature can be '0x' /// @param infoPermit2 Taker's signature to approve spending of taker_tokens by calling Permit2.permit(..) function settleAggregateAndSignPermit2( Order.Aggregate calldata order, Signature.MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, Transfer.OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature, Signature.MultiTokensPermit2Signature calldata infoPermit2 ) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IDaiLikePermit { /// @param holder The address of the token owner. /// @param spender The address of the token spender. /// @param nonce The owner's nonce, increases at each call to permit. /// @param expiry The timestamp at which the permit is no longer valid. /// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0. /// @param v Must produce valid secp256k1 signature from the owner along with r and s. /// @param r Must produce valid secp256k1 signature from the owner along with v and s. /// @param s Must produce valid secp256k1 signature from the owner along with r and v. function permit( address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s ) external; // DAI's Polygon getNonce, instead of `nonces(address)` function function getNonce(address user) external view returns (uint256 nonce); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; // Part of IAllowanceTransfer(https://github.com/Uniswap/permit2/blob/main/src/interfaces/IAllowanceTransfer.sol) interface IPermit2 { // ------------------ // IAllowanceTransfer // ------------------ /// @notice Details for a token transfer. struct AllowanceTransferDetails { // the owner of the token address from; // the recipient of the token address to; // the amount of the token uint160 amount; // the token to be transferred address token; } /// @notice The permit data for a token struct PermitDetails { // ERC20 token address address token; // the maximum amount allowed to spend uint160 amount; // timestamp at which a spender's token allowances become invalid uint48 expiration; // an incrementing value indexed per owner,token,and spender for each signature uint48 nonce; } /// @notice The permit message signed for multiple token allowances struct PermitBatch { // the permit data for multiple token allowances PermitDetails[] details; // address permissioned on the allowed tokens address spender; // deadline on the permit signature uint256 sigDeadline; } /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval. /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress] /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals. function allowance(address user, address token, address spender) external view returns (uint160 amount, uint48 expiration, uint48 nonce); /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce /// @param owner The owner of the tokens being approved /// @param permitBatch Data signed over by the owner specifying the terms of approval /// @param signature The owner's signature over the permit data function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external; /// @notice Transfer approved tokens from one address to another /// @param from The address to transfer from /// @param to The address of the recipient /// @param amount The amount of the token to transfer /// @param token The token address to transfer /// @dev Requires the from address to have approved at least the desired amount /// of tokens to msg.sender. function transferFrom(address from, address to, uint160 amount, address token) external; /// @notice Transfer approved tokens in a batch /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers /// @dev Requires the from addresses to have approved at least the desired amount /// of tokens to msg.sender. function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IWETH { function deposit() external payable; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Commands /// @notice Commands are used to specify how tokens are transferred library Commands { bytes1 internal constant SIMPLE_TRANSFER = 0x00; // simple transfer with standard transferFrom bytes1 internal constant PERMIT2_TRANSFER = 0x01; // transfer using Permit2.transfer bytes1 internal constant CALL_PERMIT_THEN_TRANSFER = 0x02; // call permit then standard transferFrom bytes1 internal constant CALL_PERMIT2_THEN_TRANSFER = 0x03; // call Permit2.permit then Permit2.transfer bytes1 internal constant NATIVE_TRANSFER = 0x04; // wrap/unwrap native token and transfer bytes1 internal constant TRANSFER_TO_CONTRACT = 0x07; // transfer to bebop contract bytes1 internal constant TRANSFER_FROM_CONTRACT = 0x08; // transfer from bebop contract }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library BytesLib { function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; // Check length is 0. `iszero` return 1 for `true` and 0 for `false`. assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Calculate length mod 32 to handle slices that are not a multiple of 32 in size. let lengthmod := and(_length, 31) // tempBytes will have the following format in memory: <length><data> // When copying data we will offset the start forward to avoid allocating additional memory // Therefore part of the length area will be written, but this will be overwritten later anyways. // In case no offset is require, the start is set to the data region (0x20 from the tempBytes) // mc will be used to keep track where to copy the data to. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // Same logic as for mc is applied and additionally the start offset specified for the method is added let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { // increase `mc` and `cc` to read the next word from memory mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Copy the data from source (cc location) to the slice data (mc location) mstore(mc, mload(cc)) } // Store the length of the slice. This will overwrite any partial data that // was copied when having slices that are not a multiple of 32. mstore(tempBytes, _length) // update free-memory pointer // allocating the array padded to 32 bytes like the compiler does now // To set the used memory as a multiple of 32, add 31 to the actual memory usage (mc) // and remove the modulo 32 (the `and` with `not(31)`) mstore(0x40, and(add(mc, 31), not(31))) } // if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) // zero out the 32 bytes slice we are about to return // we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) // update free-memory pointer // tempBytes uses 32 bytes in memory (even when empty) for the length. mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library SafeCast160 { /// @notice Thrown when a valude greater than type(uint160).max is cast to uint160 error UnsafeCast(); /// @notice Safely casts uint256 to uint160 /// @param value The uint256 to be cast function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) revert UnsafeCast(); return uint160(value); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Signature.sol"; import "../base/Errors.sol"; library Order { /// @notice Struct for one-to-one trade with one maker struct Single { uint256 expiry; address taker_address; address maker_address; uint256 maker_nonce; address taker_token; address maker_token; uint256 taker_amount; uint256 maker_amount; address receiver; uint256 packed_commands; uint256 flags; // `hashSingleOrder` doesn't use this field for SingleOrder hash } /// @notice Struct for many-to-one or one-to-many trade with one maker /// Also this struct is used as maker order which is part of AggregateOrder struct Multi { uint256 expiry; address taker_address; address maker_address; uint256 maker_nonce; address[] taker_tokens; address[] maker_tokens; uint256[] taker_amounts; uint256[] maker_amounts; address receiver; bytes commands; uint256 flags; // `hashMultiOrder` doesn't use this field for MultiOrder hash } /// @notice Struct for any trade with multiple makers struct Aggregate { uint256 expiry; address taker_address; address[] maker_addresses; uint256[] maker_nonces; address[][] taker_tokens; address[][] maker_tokens; uint256[][] taker_amounts; uint256[][] maker_amounts; address receiver; bytes commands; uint256 flags; // `hashAggregateOrder` doesn't use this field for AggregateOrder hash } /// @dev Decode Single order packed_commands /// /// ... | 2 | 1 | 0 | /// -+------------+---+---+---+ /// | reserved | * | * | * | /// | | | /// | | +------- takerHasNative bit, 0 for erc20 token /// | | 1 for native token /// | +----------- makerHasNative bit, 0 for erc20 token /// | 1 for native token /// +-------------takerUsingPermit2 bit, 0 for standard transfer /// 1 for permit2 transfer function extractSingleOrderCommands( uint256 commands ) internal pure returns (bool takerHasNative, bool makerHasNative, bool takerUsingPermit2){ takerHasNative = (commands & 0x01) != 0; makerHasNative = (commands & 0x02) != 0; takerUsingPermit2 = (commands & 0x04) != 0; if (takerHasNative && takerUsingPermit2){ revert InvalidFlags(); } } /// @dev Order flags /// /// | 255..128 | 127..64 | ... | 1 | 0 | /// -+----------------+------------------+----------+---+---+ /// uint128 eventID | uint64 partnerId | reserved | * * | /// | | /// +---+----- signature type /// 00: EIP-712 /// 01: EIP-1271 /// 10: ETH_SIGN function extractSignatureType(uint256 flags) internal pure returns (Signature.Type signatureType){ signatureType = Signature.Type(flags & 0x03); } function extractFlags(uint256 flags) internal pure returns (uint128 eventId, uint64 partnerId){ eventId = uint128(flags >> 128); partnerId = uint64(flags >> 64); } function extractPartnerId(uint256 flags) internal pure returns (uint64 partnerId){ partnerId = uint64(flags >> 64); } function extractEventId(uint256 flags) internal pure returns (uint128 eventId){ eventId = uint128(flags >> 128); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../base/Errors.sol"; library Signature { enum Type { EIP712, //0 EIP1271, //1 ETHSIGN //2 } struct PermitSignature { bytes signatureBytes; uint256 deadline; } struct Permit2Signature { bytes signatureBytes; uint48 deadline; uint48 nonce; } struct MultiTokensPermit2Signature { bytes signatureBytes; uint48 deadline; uint48[] nonces; } struct MakerSignature { bytes signatureBytes; uint256 flags; } /// @dev Decode maker flags /// /// | ... | 2 | 1 | 0 | /// -+----------+---+-------+ /// | reserved | * | * * | /// | | | /// | +---+--- signature type bits /// | 00: EIP-712 /// | 01: EIP-1271 /// | 10: ETH_SIGN /// | /// +-------------makerUsingPermit2 bit, 0 for standard transfer /// 1 for permit2 transfer function extractMakerFlags(uint256 flags) internal pure returns (bool usingPermit2, Type signatureType){ signatureType = Type(flags & 0x03); usingPermit2 = (flags & 0x04) != 0; } /// @notice Split signature into `r`, `s`, `v` variables function getRsv(bytes calldata sig) internal pure returns (bytes32, bytes32, uint8){ if(sig.length != 65) revert InvalidSignatureLength(); bytes32 r; bytes32 s; uint8 v; assembly { r := calldataload(sig.offset) s := calldataload(add(sig.offset, 32)) v := calldataload(add(sig.offset, 33)) } if (v < 27) v += 27; if(uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidSignatureValueS(); if(v != 27 && v != 28) revert InvalidSignatureValueV(); return (r, s, v); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Transfer { struct OldSingleQuote { bool useOldAmount; uint256 makerAmount; uint256 makerNonce; } struct OldMultiQuote { bool useOldAmount; uint256[] makerAmounts; uint256 makerNonce; } struct OldAggregateQuote { bool useOldAmount; uint256[][] makerAmounts; uint256[] makerNonces; } //----------------------------------------- // Internal Helper Data Structures // ----------------------------------------- enum Action { None, Wrap, Unwrap } struct Pending { address token; address to; uint256 amount; } struct NativeTokens { uint256 toTaker; // accumulated amount of tokens that will be sent to the taker (receiver) uint256 toMakers; // accumulated amount of tokens that will be sent to the makers } struct LengthsInfo { uint48 pendingTransfersLen; // length of `pendingTransfers` array uint48 permit2Len; // length of `batchTransferDetails` array } struct IndicesInfo { uint48 pendingTransfersInd; uint48 permit2Ind; uint256 commandsInd; } }
{ "optimizer": { "enabled": true, "runs": 77 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_wrappedNativeToken","type":"address"},{"internalType":"address","name":"_permit2","type":"address"},{"internalType":"address","name":"_daiAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CommandsLengthsMismatch","type":"error"},{"inputs":[],"name":"FailedToSendNativeToken","type":"error"},{"inputs":[],"name":"InvalidCommand","type":"error"},{"inputs":[],"name":"InvalidCommandsLength","type":"error"},{"inputs":[],"name":"InvalidEIP1271Signature","type":"error"},{"inputs":[],"name":"InvalidEIP721Signature","type":"error"},{"inputs":[],"name":"InvalidETHSIGNSignature","type":"error"},{"inputs":[],"name":"InvalidFlags","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidPendingTransfersLength","type":"error"},{"inputs":[],"name":"InvalidPermit2Commands","type":"error"},{"inputs":[],"name":"InvalidPermit2TransfersLength","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"InvalidSignatureType","type":"error"},{"inputs":[],"name":"InvalidSignatureValueS","type":"error"},{"inputs":[],"name":"InvalidSignatureValueV","type":"error"},{"inputs":[],"name":"MakerAmountsLengthsMismatch","type":"error"},{"inputs":[],"name":"ManyToManyNotSupported","type":"error"},{"inputs":[],"name":"NotEnoughNativeToken","type":"error"},{"inputs":[],"name":"NullBeneficiary","type":"error"},{"inputs":[],"name":"OrderExpired","type":"error"},{"inputs":[],"name":"OrderInvalidSigner","type":"error"},{"inputs":[],"name":"OrdersLengthsMismatch","type":"error"},{"inputs":[],"name":"PartialFillNotSupported","type":"error"},{"inputs":[],"name":"PartnerAlreadyRegistered","type":"error"},{"inputs":[],"name":"PartnerFeeTooHigh","type":"error"},{"inputs":[],"name":"TokensLengthsMismatch","type":"error"},{"inputs":[],"name":"UnsafeCast","type":"error"},{"inputs":[],"name":"UpdatedMakerAmountsTooLow","type":"error"},{"inputs":[],"name":"WrongWrappedTokenAddress","type":"error"},{"inputs":[],"name":"ZeroMakerAmount","type":"error"},{"inputs":[],"name":"ZeroNonce","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"}],"name":"BebopOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"OrderSignerRegistered","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address[]","name":"maker_addresses","type":"address[]"},{"internalType":"uint256[]","name":"maker_nonces","type":"uint256[]"},{"internalType":"address[][]","name":"taker_tokens","type":"address[][]"},{"internalType":"address[][]","name":"maker_tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"taker_amounts","type":"uint256[][]"},{"internalType":"uint256[][]","name":"maker_amounts","type":"uint256[][]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Aggregate","name":"order","type":"tuple"},{"internalType":"uint64","name":"partnerId","type":"uint64"},{"internalType":"uint256[][]","name":"updatedMakerAmounts","type":"uint256[][]"},{"internalType":"uint256[]","name":"updatedMakerNonces","type":"uint256[]"}],"name":"hashAggregateOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address[]","name":"taker_tokens","type":"address[]"},{"internalType":"address[]","name":"maker_tokens","type":"address[]"},{"internalType":"uint256[]","name":"taker_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"maker_amounts","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Multi","name":"order","type":"tuple"},{"internalType":"uint64","name":"partnerId","type":"uint64"},{"internalType":"uint256[]","name":"updatedMakerAmounts","type":"uint256[]"},{"internalType":"uint256","name":"updatedMakerNonce","type":"uint256"}],"name":"hashMultiOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Single","name":"order","type":"tuple"},{"internalType":"uint64","name":"partnerId","type":"uint64"},{"internalType":"uint256","name":"updatedMakerAmount","type":"uint256"},{"internalType":"uint256","name":"updatedMakerNonce","type":"uint256"}],"name":"hashSingleOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"partners","outputs":[{"internalType":"uint16","name":"fee","type":"uint16"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"bool","name":"registered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"registerAllowedOrderSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"partnerId","type":"uint64"},{"internalType":"uint16","name":"fee","type":"uint16"},{"internalType":"address","name":"beneficiary","type":"address"}],"name":"registerPartner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address[]","name":"maker_addresses","type":"address[]"},{"internalType":"uint256[]","name":"maker_nonces","type":"uint256[]"},{"internalType":"address[][]","name":"taker_tokens","type":"address[][]"},{"internalType":"address[][]","name":"maker_tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"taker_amounts","type":"uint256[][]"},{"internalType":"uint256[][]","name":"maker_amounts","type":"uint256[][]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Aggregate","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature[]","name":"makersSignatures","type":"tuple[]"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[][]","name":"makerAmounts","type":"uint256[][]"},{"internalType":"uint256[]","name":"makerNonces","type":"uint256[]"}],"internalType":"struct Transfer.OldAggregateQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"}],"name":"settleAggregate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address[]","name":"maker_addresses","type":"address[]"},{"internalType":"uint256[]","name":"maker_nonces","type":"uint256[]"},{"internalType":"address[][]","name":"taker_tokens","type":"address[][]"},{"internalType":"address[][]","name":"maker_tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"taker_amounts","type":"uint256[][]"},{"internalType":"uint256[][]","name":"maker_amounts","type":"uint256[][]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Aggregate","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature[]","name":"makersSignatures","type":"tuple[]"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[][]","name":"makerAmounts","type":"uint256[][]"},{"internalType":"uint256[]","name":"makerNonces","type":"uint256[]"}],"internalType":"struct Transfer.OldAggregateQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct Signature.PermitSignature","name":"takerPermitSignature","type":"tuple"}],"name":"settleAggregateAndSignPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address[]","name":"maker_addresses","type":"address[]"},{"internalType":"uint256[]","name":"maker_nonces","type":"uint256[]"},{"internalType":"address[][]","name":"taker_tokens","type":"address[][]"},{"internalType":"address[][]","name":"maker_tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"taker_amounts","type":"uint256[][]"},{"internalType":"uint256[][]","name":"maker_amounts","type":"uint256[][]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Aggregate","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature[]","name":"makersSignatures","type":"tuple[]"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[][]","name":"makerAmounts","type":"uint256[][]"},{"internalType":"uint256[]","name":"makerNonces","type":"uint256[]"}],"internalType":"struct Transfer.OldAggregateQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint48","name":"deadline","type":"uint48"},{"internalType":"uint48[]","name":"nonces","type":"uint48[]"}],"internalType":"struct Signature.MultiTokensPermit2Signature","name":"infoPermit2","type":"tuple"}],"name":"settleAggregateAndSignPermit2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address[]","name":"taker_tokens","type":"address[]"},{"internalType":"address[]","name":"maker_tokens","type":"address[]"},{"internalType":"uint256[]","name":"taker_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"maker_amounts","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Multi","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[]","name":"makerAmounts","type":"uint256[]"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct Transfer.OldMultiQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"}],"name":"settleMulti","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address[]","name":"taker_tokens","type":"address[]"},{"internalType":"address[]","name":"maker_tokens","type":"address[]"},{"internalType":"uint256[]","name":"taker_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"maker_amounts","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Multi","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[]","name":"makerAmounts","type":"uint256[]"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct Transfer.OldMultiQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct Signature.PermitSignature","name":"takerPermitSignature","type":"tuple"}],"name":"settleMultiAndSignPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address[]","name":"taker_tokens","type":"address[]"},{"internalType":"address[]","name":"maker_tokens","type":"address[]"},{"internalType":"uint256[]","name":"taker_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"maker_amounts","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Multi","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[]","name":"makerAmounts","type":"uint256[]"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct Transfer.OldMultiQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint48","name":"deadline","type":"uint48"},{"internalType":"uint48[]","name":"nonces","type":"uint48[]"}],"internalType":"struct Signature.MultiTokensPermit2Signature","name":"infoPermit2","type":"tuple"}],"name":"settleMultiAndSignPermit2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Single","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256","name":"makerAmount","type":"uint256"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct Transfer.OldSingleQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"}],"name":"settleSingle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Single","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256","name":"makerAmount","type":"uint256"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct Transfer.OldSingleQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct Signature.PermitSignature","name":"takerPermitSignature","type":"tuple"}],"name":"settleSingleAndSignPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Single","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256","name":"makerAmount","type":"uint256"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct Transfer.OldSingleQuote","name":"takerQuoteInfo","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint48","name":"deadline","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct Signature.Permit2Signature","name":"takerPermit2Signature","type":"tuple"}],"name":"settleSingleAndSignPermit2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address[]","name":"maker_addresses","type":"address[]"},{"internalType":"uint256[]","name":"maker_nonces","type":"uint256[]"},{"internalType":"address[][]","name":"taker_tokens","type":"address[][]"},{"internalType":"address[][]","name":"maker_tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"taker_amounts","type":"uint256[][]"},{"internalType":"uint256[][]","name":"maker_amounts","type":"uint256[][]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Aggregate","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature[]","name":"makersSignatures","type":"tuple[]"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"}],"name":"swapAggregate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address[]","name":"taker_tokens","type":"address[]"},{"internalType":"address[]","name":"maker_tokens","type":"address[]"},{"internalType":"uint256[]","name":"taker_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"maker_amounts","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Multi","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"}],"name":"swapMulti","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Single","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"},{"internalType":"uint256","name":"filledTakerAmount","type":"uint256"}],"name":"swapSingle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Order.Single","name":"order","type":"tuple"},{"components":[{"internalType":"bytes","name":"signatureBytes","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct Signature.MakerSignature","name":"makerSignature","type":"tuple"}],"name":"swapSingleFromContract","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101403462000211576001600160401b03601f6200608f38819003918201601f19168401919083831185841017620001fb5781606092869260409586528339810103126200021157620000528362000216565b6200006d82620000656020870162000216565b950162000216565b914660a052805160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527fd6144400a4098bee31df789c6c534128424a333149eec40af03ae3b3223cd96f838201527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a560608201524660808201523060a082015260a0815260c081019581871090871117620001fb578583525190206080526000808052600260205220805460ff60b01b1916600160b01b17905560c05260e0526001600160a01b0390911661010090815246610120908152615e639291836200022c843960805183612ae1015260a05183612abb015260c051838181611fa30152818161264c01528181612799015281816144ed015281816146ca01528181614a4e01528181614d0f0152818161531a01526155a7015260e051836157ba0152518281816109540152818161150b0152818161181301528181612813015281816145a6015281816148e90152818161494401528181614de90152614ebc015251816157e20152f35b634e487b7160e01b600052604160045260246000fd5b600080fd5b51906001600160a01b0382168203620002115756fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806314e7a7ab1461015b5780631a499026146101565780631bceedd7146101515780633644e5151461014c578063384eada01461014757806338ec0211146101425780634dcebcba1461013d578063529c4a2f14610138578063602926bf1461013357806366a65e411461012e5780636d2a03d81461012957806372fc32e5146101245780638cce31401461011f5780639080ef021461011a5780639093bf7b14610115578063a2f7489314610110578063c38a44741461010b578063ea7faa6114610106578063ef7d27ad146101015763efe34fe60361000e57611209565b61115f565b6110bf565b610fdb565b610f5b565b610ebe565b610d9c565b610d21565b610c84565b610c27565b610b75565b610af5565b610aaf565b610a36565b61082d565b610794565b610779565b610703565b6102d9565b610204565b61016090600319011261017257600490565b600080fd5b90816101609103126101725790565b9181601f84011215610172578235916001600160401b038311610172576020808501948460051b01011161017257565b6060906101a3190112610172576101a490565b908160609103126101725790565b9181601f84011215610172578235916001600160401b038311610172576020838186019501011161017257565b60a0366003190112610172576001600160401b0360043581811161017257610230903690600401610177565b60243582811161017257610248903690600401610186565b9091606435848111610172576102629036906004016101c9565b60843594851161017257610288816102816100199736906004016101d7565b9085614047565b8035610293816110b5565b156102b4578060206102a69201906112fe565b929092935b604435926122e7565b506102c260e08201826112fe565b929092936102ab565b908160409103126101725790565b610220366003190112610172576102ef36610160565b6001600160401b039061016435828111610172576103119036906004016102cb565b9061031b366101b6565b61020435938411610172576103428161033b6100199636906004016101d7565b9085613e47565b803561034d816110b5565b156103625760200135915b610184359161193e565b5060e081013591610358565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161039757604052565b61036e565b606081019081106001600160401b0382111761039757604052565b608081019081106001600160401b0382111761039757604052565b604081019081106001600160401b0382111761039757604052565b90601f801991011681019081106001600160401b0382111761039757604052565b6040519061016082018281106001600160401b0382111761039757604052565b6040519061043b8261039c565b565b6040519061043b826103b7565b6040519061043b826103d2565b6001600160a01b0381160361017257565b359061043b82610457565b6001600160401b0381116103975760051b60200190565b929161049582610473565b916104a360405193846103ed565b829481845260208094019160051b810192831161017257905b8282106104c95750505050565b83809183356104d781610457565b8152019101906104bc565b9080601f83011215610172578160206104fd9335910161048a565b90565b929161050b82610473565b9161051960405193846103ed565b829481845260208094019160051b810192831161017257905b82821061053f5750505050565b81358152908301908301610532565b9080601f83011215610172578160206104fd93359101610500565b6001600160401b03811161039757601f01601f191660200190565b92919261059082610569565b9161059e60405193846103ed565b829481845281830111610172578281602093846000960137010152565b9080601f83011215610172578160206104fd93359101610584565b91909161016081840312610172576105ec61040e565b92813584526105fd60208301610468565b602085015261060e60408301610468565b60408501526060820135606085015260808201356001600160401b0390818111610172578261063e9185016104e2565b608086015260a0830135818111610172578261065b9185016104e2565b60a086015260c0830135818111610172578261067891850161054e565b60c086015260e0830135818111610172578261069591850161054e565b60e08601526101006106a8818501610468565b908601526101209182840135918211610172576106c69184016105bb565b908401526101408091013590830152565b602435906001600160401b038216820361017257565b600435906001600160401b038216820361017257565b34610172576080366003190112610172576001600160401b03600435818111610172576107349036906004016105d6565b9061073d6106d7565b916044359182116101725760209261075c610766933690600401610186565b9160643593612da4565b604051908152f35b600091031261017257565b34610172576000366003190112610172576020610766612ab8565b60c03660031901126101725760046001600160401b038135818111610172576107c09036908401610177565b602435828111610172576107d790369085016102cb565b91606435818111610172576107ef90369086016101c9565b6084358281116101725761080690369087016101d7565b93909260a4359081116101725761001996610823913691016102cb565b9460443591611333565b6102403660031901126101725761084336610160565b6001600160401b039061016435828111610172576108659036906004016102cb565b9061086f366101b6565b61020435848111610172576108889036906004016101d7565b909461022435908111610172576108af916108a8849236906004016101c9565b9685613e47565b60208201356108bd81610457565b6080830135946108cc86610457565b6109ab6108d761596a565b91602081019761093e6108e98a6159a6565b61092f6108f8604086016159a6565b9161091361090461043d565b6001600160a01b039096168652565b6001600160a01b03602086015265ffffffffffff166040850152565b65ffffffffffff166060830152565b61094784611d18565b5261095183611d18565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169765ffffffffffff9061098e906159a6565b61099661042e565b94855230602086015216604084015280611c97565b969091813b1561017257600080946109d96040519a8b9687958694632a2d80d160e01b8652600486016159b9565b03925af1938415610a315761001994610a18575b506109f7816112f4565b15610a0c5760200135915b6101843591611bc8565b5060e081013591610a02565b80610a25610a2b92610384565b8061076e565b386109ed565b6112e8565b6101a036600319011261017257610a4c36610160565b610164356001600160401b03811161017257610a6c9036906004016102cb565b6020820135610a7a81610457565b6001600160a01b03163303610a9d578160e061001993013591610184359161193e565b604051636edaef2f60e11b8152600490fd5b34610172576101c036600319011261017257610aca36610160565b61016435906001600160401b038216820361017257602091610766916101a435916101843591612c36565b6060366003190112610172576001600160401b0360043581811161017257610b21903690600401610177565b9060243590811161017257610b3a9036906004016102cb565b906020810135610b4981610457565b6001600160a01b03163303610a9d5761001991610b6960e08301836112fe565b92909160443591611d79565b60c03660031901126101725760046001600160401b03813581811161017257610ba19036908401610177565b60243582811161017257610bb890369085016102cb565b9160643581811161017257610bd090369086016101c9565b60843582811161017257610be790369087016101d7565b93909260a4359081116101725761001996610c04913691016101c9565b9460443591611386565b6001600160401b03166000526002602052604060002090565b34610172576020366003190112610172576001600160401b03610c486106ed565b166000526002602052606060406000205460ff6040519161ffff8116835260018060a01b038160101c16602084015260b01c1615156040820152f35b60c03660031901126101725760046001600160401b03813581811161017257610cb09036908401610177565b9060243581811161017257610cc89036908501610186565b91909260643582811161017257610ce290369087016101c9565b9060843583811161017257610cfa90369088016101d7565b94909360a4359081116101725761001997610d17913691016101c9565b9560443592611634565b34610172576080366003190112610172576001600160401b0360043581811161017257610d52903690600401610177565b90610d5b6106d7565b60443582811161017257610d73903690600401610186565b60649491943593841161017257602094610d94610766953690600401610186565b949093612fbc565b3461017257606036600319011261017257610db56106ed565b60243561ffff81168082036101725760443590610dd182610457565b610de7610ddd85610c0e565b5460b01c60ff1690565b610eac5761271010610e9b576001600160a01b03811615610e895761001992610e32610e3e92610e22610e1861042e565b61ffff9096168652565b6001600160a01b03166020850152565b60016040840152610c0e565b81518154602084015160409094015160ff60b01b90151560b01b1662010000600160b01b0360109590951b9490941661ffff9092166001600160b81b03199091161717919091179055565b604051636793040360e11b8152600490fd5b6040516214eb0160ea1b8152600490fd5b6040516335bf048b60e21b8152600490fd5b60c03660031901126101725760046001600160401b03813581811161017257610eea9036908401610177565b9060243581811161017257610f029036908501610186565b91909260643582811161017257610f1c90369087016101c9565b9060843583811161017257610f3490369088016101d7565b94909360a4359081116101725761001997610f51913691016102cb565b95604435926115e0565b6060366003190112610172576001600160401b0360043581811161017257610f87903690600401610177565b9060243590811161017257610fa0903690600401610186565b906020830135610faf81610457565b6001600160a01b03163303610a9d5782610fcf60e06100199501826112fe565b939092604435926122e7565b61018036600319011261017257610ff136610160565b610164356001600160401b038111610172576110119036906004016102cb565b9061102d611021602083016112cf565b6001600160a01b031690565b3303610a9d57611045611021611021608084016112cf565b6040516370a0823160e01b81523060048201529290602090849060249082905afa908115610a315761001993600092611085575b5060e083013592611ae8565b6110a791925060203d81116110ae575b61109f81836103ed565b8101906112d9565b9038611079565b503d611095565b8015150361017257565b34610172576040366003190112610172577f6ea9dbe8b2cc119348716a9220a0742ad62b7884ecb0ff4b32cd508121fd937960606004356110ff81610457565b60243561110b816110b5565b3360009081526001602090815260408083206001600160a01b03861684529091529020805460ff92151592831660ff1991909116179055604080513381526001600160a01b039093166020840152820152a1005b6102403660031901126101725761117536610160565b6001600160401b039061016435828111610172576111979036906004016102cb565b906111a1366101b6565b61020435848111610172576111ba9036906004016101d7565b949061022435918211610172576111e783610019976111e06103429536906004016102cb565b9387613e47565b60208401356111f581610457565b60808501359061120482610457565b615796565b60a0366003190112610172576001600160401b0360043581811161017257611235903690600401610177565b6024358281116101725761124d9036906004016102cb565b90606435838111610172576112669036906004016101c9565b6084359384116101725761128c816112856100199636906004016101d7565b9085613f10565b8035611297816110b5565b156112b8578060206112aa9201906112fe565b919091925b60443591611d79565b506112c660e08201826112fe565b919091926112af565b356104fd81610457565b90816020910312610172575190565b6040513d6000823e3d90fd5b356104fd816110b5565b903590601e198136030182121561017257018035906001600160401b03821161017257602001918160051b3603831361017257565b949561134b8461043b98611351949796959689613f10565b85615a75565b803561135c816110b5565b156113785780602061136f9201906112fe565b92909293611d79565b5061136f60e08401846112fe565b936113979197929695849186613f10565b6113a460a08401846112fe565b905091600096604092838701916113c56113be848a6112fe565b90506121c0565b958a905b60808901906113d8828b6112fe565b90508310156114f55761141594939291906114306114236113fd6101208e018e611c97565b98909361140981611d09565b99600360f81b95611ced565b356001600160f81b03191690565b6001600160f81b03191690565b14611448575b5061144090611d09565b9091926113c9565b819c8b6114d38861092f6114758f6114409861146a6114ee99611470936112fe565b90611cf9565b6112cf565b936114c561149c6114978861146a6020976114918988016159a6565b966112fe565b6159a6565b936114b76114a861043d565b6001600160a01b039098168852565b6001600160a01b0390870152565b65ffffffffffff16848e0152565b6114dd828c611d35565b526114e8818b611d35565b50611d09565b9b90611436565b505050959692939150979693968751036115d0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611572611542602089016112cf565b9365ffffffffffff611556602083016159a6565b61155e61042e565b9b8c523060208d015216848b015280611c97565b989092823b156101725760009461159f8692519b8c9687958694632a2d80d160e01b8652600486016159b9565b03925af1948515610a315761043b956115bd575b5061135c816112f4565b80610a256115ca92610384565b386115b3565b51637f7dfe8b60e11b8152600490fd5b95966115f98561043b996115ff9498979596978a614047565b86615b1a565b803561160a816110b5565b156116265780602061161d9201906112fe565b939093946122e7565b5061161d60e08501856112fe565b92949380979661164692999585614047565b600093846040918288019961165e6113be8c8b6112fe565b9483975b6080880194611671868a6112fe565b90508a10156117fb578b898f926116a59061169d8e61169760a0869b999a9b01866112fe565b90612246565b91905061226b565b6116b58d6116978b6000956112fe565b90508210156117e05790611415916116f06114236116d88f610120810190611c97565b9590936116e481611d09565b96600360f81b95611ced565b14611714575b906116b58d6116978b8f97969561170c90611d09565b9596976112fe565b9c90888d8f938d8f9796958e83918561172d888d6112fe565b6117379291612246565b6117419291611cf9565b61174a906112cf565b906020906117598a83016159a6565b90846117658d8d6112fe565b61176f9291611cf9565b611778906159a6565b9261178161043d565b6001600160a01b0390951685526001600160a01b039085015265ffffffffffff9091169083015265ffffffffffff1660608201526117bf8284611d35565b526117c991611d35565b506117d390611d09565b9f929394955050506116f6565b975050505091976117f390939193611d09565b979092611662565b509b509598939250969095509792978851036115d0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661187a61184a60208a016112cf565b9365ffffffffffff61185e602083016159a6565b61186661042e565b9c8d523060208e015216848c015280611c97565b999092823b15610172576000946118a78692519c8d9687958694632a2d80d160e01b8652600486016159b9565b03925af1958615610a315761043b966118c5575b5061160a816112f4565b80610a256118d292610384565b386118bb565b634e487b7160e01b600052601160045260246000fd5b600181901b91906001600160ff1b0381160361190657565b6118d8565b8181029291811591840414171561190657565b8115611928570490565b634e487b7160e01b600052601260045260246000fd5b611a43929361194d8383613284565b610140820135608081901c9060401c6001600160401b0316939095611976610120850135615be6565b93919290946119e161198a602089016112cf565b6040890195611998876112cf565b976119a560808c016112cf565b8615998a159a8b611adb575b15611ad45760c08d0135925b6000908515611abd5750600160fa1b9490505b60009015611ab75750600194614469565b809480611aaa575b611a7f575b5050611a006020611a07920135615c2c565b50916112cf565b93611a2160a0611a1a61010084016112cf565b92016112cf565b9160009015611a795750600160f81b935b60009015611a735750600294614739565b6001600160801b03167fadd7095becdaa725f0f33243630938c861b0bba83dfd217d4055701aa768ec2e600080a2565b94614739565b93611a32565b611a07929450611aa2611a97611a009360209361190b565b60c08901359061191e565b9492506119ee565b5060c087013582106119e9565b94614469565b15611acf5750600160f81b5b936119d0565b611ac9565b87926119bd565b5060c08d013588116119b1565b611a4392939193611af98583613284565b610140820135608081901c9060401c6001600160401b0316939095611b22610120850135615be6565b93829392959195611bc0575b6119e1611b3d602089016112cf565b6040890195611b4b876112cf565b97611b5860808c016112cf565b8615998a159a8b611bb3575b15611bac5760c08d0135925b60008515611b915750600160fa1b946000915015611ab75750600194614469565b5015611ba257600160f81b936119d0565b600160fb1b611ac9565b8792611b70565b5060c08d01358811611b64565b479150611b2e565b611a439293611bd78383613284565b610140820135608081901c9060401c6001600160401b0316939095611c00610120850135615be6565b93919290946119e1611c14602089016112cf565b6040890195611c22876112cf565b97611c2f60808c016112cf565b8615998a159a8b611c8a575b15611c835760c08d0135925b60008515611c685750600160fa1b946000915015611ab75750600194614469565b5015611c7957600160f81b936119d0565b600160f81b611ac9565b8792611c47565b5060c08d01358811611c3b565b903590601e198136030182121561017257018035906001600160401b0382116101725760200191813603831361017257565b634e487b7160e01b600052603260045260246000fd5b9015611ce85790565b611cc9565b90821015611ce8570190565b9190811015611ce85760051b0190565b60001981146119065760010190565b805115611ce85760200190565b805160011015611ce85760400190565b8051821015611ce85760209160051b010190565b3d15611d74573d90611d5a82610569565b91611d6860405193846103ed565b82523d6000602084013e565b606090565b60209295949193611d8b878684613811565b611db0610140830135608081901c9060401c6001600160401b03169590960135615c2c565b509060808301976001611dc38a866112fe565b905011600014611e795750611a4395969750611dde83614b15565b611dea604084016112cf565b93611e1b611dfb61010086016112cf565b91611e15611470611e0f60a08901896112fe565b90611cdf565b93611cdf565b359260009015611e6f5750600160f81b93611e3c905b610120810190611c97565b600160fa1b916001600160f81b031991611e5a916114159190611cdf565b1614600090600014611a735750600294614739565b611e3c9094611e31565b949390610120840190611e8c8286611c97565b60a087019891611e9c8a896112fe565b91611ea8939150611ced565b356001600160f81b03191693611ec0602088016112cf565b9b604088019c611ecf8e6112cf565b91611eda908a6112fe565b611ee391611cdf565b611eec906112cf565b96841592831598611f35948a6120c9575b156120c257611f12611e0f60c08e018e6112fe565b35915b60006001600160f81b03198516600160fa1b03611ab75750600194614469565b611f40368285610500565b94806120a9575b612051575b505050611f5e611f93969798996112cf565b93610100810197611f8d611f86611f7e611f778c6112cf565b93856112fe565b959094611c97565b3691610584565b95614e6d565b9081611fa1575b5050611a43565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b1561017257604051632e1a7d4d60e01b815260048101849052916000908390602490829084905af1918215610a31576000938493849384936120159261203e575b506112cf565b5af161201f611d49565b501561202c573880611f9a565b60405163d1a4579f60e01b8152600490fd5b80610a2561204b92610384565b3861200f565b60005b8181106120615750611f4c565b8061209461207d856120776120a495878a611cf9565b3561190b565b61208d611e0f60c08d018d6112fe565b359061191e565b61209e8289611d35565b52611d09565b612054565b506120ba611e0f60c08901896112fe565b358210611f47565b8691611f15565b506120da611e0f60c08e018e6112fe565b358711611efd565b604051906120ef8261039c565b60006040838281528260208201520152565b9061210b82610473565b61211860405191826103ed565b8281528092612129601f1991610473565b019060005b82811061213a57505050565b6020906121456120e2565b8282850101520161212e565b60405190608082018281106001600160401b038211176103975760405260006060838281528260208201528260408201520152565b6040908151916121958361039c565b600283528260005b8281106121a957505050565b6020906121b4612151565b8282850101520161219d565b906121ca82610473565b6121d760405191826103ed565b82815280926121e8601f1991610473565b019060005b8281106121f957505050565b602090612204612151565b828285010152016121ed565b9190811015611ce85760051b81013590603e1981360301821215610172570190565b9015611ce85780612242916112fe565b9091565b90821015611ce8576122429160051b8101906112fe565b90601f820180921161190657565b9190820180921161190657565b60208082019080835283518092528060408094019401926000905b8382106122a257505050505090565b845180516001600160a01b0390811688528185015181168886015281830151811688840152606091820151169087015260809095019493820193600190910190612293565b92949190916122f78284866139d2565b612301868561423c565b96909161230c61042e565b60008082526020820181905260408201529661232661044a565b6000808252602082015289519095906123469065ffffffffffff16612101565b9660208b015161235b9065ffffffffffff1690565b65ffffffffffff1661236c906121c0565b9b60005b61237d60a08c018c6112fe565b90508110156125655761239d6020612396838787612210565b0135615c2c565b506123b36123ac838989612246565b3691610500565b8815158061255c575b6124d0575b8f6124c38f928f958f8f978f8f96611697936124cb9b8a6124ae9460409b6124828a9f8b8f61247b926124b89f61245f6124068f948661146a611470928801886112fe565b948a6001600160401b0361014061246e60408961246961242961010083016112cf565b9661243b8961169760a08601866112fe565b9a909961169761244f610120870187611c97565b97909401519560a08101906112fe565b9490503691610584565b615d7b565b97013560401c1696614e6d565b855161226b565b84526124a36124988b61169760a08c018c6112fe565b90508e85015161226b565b8d840152898861538d565b60808101906112fe565b90508284015161226b565b910152611d09565b612370565b9c979a94919993909e95989b969d928e6124ee8c6000925b8d612246565b905081101561253b57908f949392918f8f8f928f928f8261252b612531956125266124ee998f8561146a8c6120779361209e9a612246565b61191e565b92611d35565b92939495966124e8565b50959e929d979c969b949a93999498939796939591949093919290916123c1565b508989106123bc565b509b96999550505050505094919294612584815165ffffffffffff1690565b906125a3612598855165ffffffffffff1690565b65ffffffffffff1690565b65ffffffffffff809316036128ad576020015165ffffffffffff16906125d5612598602086015165ffffffffffff1690565b91160361289b576125f2612598602084015165ffffffffffff1690565b612810575b505161260a9065ffffffffffff16612598565b6126ee575b508051908161264a575b5050610140013560801c7fadd7095becdaa725f0f33243630938c861b0bba83dfd217d4055701aa768ec2e600080a2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561017257604051632e1a7d4d60e01b815260048101939093526000908390602490829084905af1918215610a31576000928392839283926126db575b506126c161010087016112cf565b9051905af16126ce611d49565b501561202c573880612619565b80610a256126e892610384565b386126b3565b909160208301518061278c575b5060005b8251811015612782578060406127186127249386611d35565b51015161272957611d09565b6126ff565b61277d61274a61102161273c8488611d35565b51516001600160a01b031690565b61276860206127598589611d35565b5101516001600160a01b031690565b60406127748589611d35565b510151916128bf565b611d09565b509190503861260f565b34106127fe5760208301517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561017257600090600460405180948193630d0e30db60e41b83525af18015610a3157156126fb5780610a256127f892610384565b386126fb565b60405163f6ed5e0160e01b8152600490fd5b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561017257604051630d58b1db60e01b81529260009184918290849082906128689060048301612278565b03925af1908115610a315761260a9261259892612888575b5091506125f7565b80610a2561289592610384565b38612880565b604051631a44983960e31b8152600490fd5b60405163c37a566360e01b8152600490fd5b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815261043b916128f8826103b7565b604051612956916001600160a01b0316612911826103d2565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1612950611d49565b91612a24565b80518061296257505050565b8183918101031261017257810151612979816110b5565b156129815750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b156129df57565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b91929015612a445750815115612a38575090565b6104fd903b15156129d8565b825190915015612a575750805190602001fd5b6044604051809262461bcd60e51b825260206004830152612a878151809281602486015260208686019101612a95565b601f01601f19168101030190fd5b60005b838110612aa85750506000910152565b8181015183820152602001612a98565b467f000000000000000000000000000000000000000000000000000000000000000003612b03577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527fd6144400a4098bee31df789c6c534128424a333149eec40af03ae3b3223cd96f60408201527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a560608201524660808201523060a082015260a0815260c081018181106001600160401b038211176103975760405251902090565b979392909b9a9995610160999597926001600160401b036101808b019e7fe34225bc7cd92038d42c258ee3ff66d30f9387dd932213ba32a52011df0603fc8c521660208b015260408a015260018060a01b03978880958180951660608d01521660808b015260a08a01521660c08801521660e0860152610100850152610120840152166101408201520152565b91612cfc92612d089294612cbe612c4b612ab8565b96612c58602085016112cf565b93612c65604082016112cf565b938015612d1a57955b612c7a608083016112cf565b91612c8760a082016112cf565b918015612d0e57915b612c9d61010083016112cf565b93604051998a9860208a019a6101208601359860c08701359635908d612ba9565b0391612cd2601f19938481018352826103ed565b519020604051938491602083019687909160429261190160f01b8352600283015260228201520190565b039081018352826103ed565b51902090565b5060e081013591612c90565b50606081013595612c6e565b805160208092019160005b828110612d3f575050505090565b83516001600160a01b031685529381019392810192600101612d31565b805160208092019160005b828110612d75575050505090565b835185529381019392810192600101612d67565b91906001600160fb1b0381116101725760051b809282370190565b93929192612db0612ab8565b9385519160209384880151612dca9060018060a01b031690565b604089810151909991938a92916001600160a01b03169560808301519984519a8b8b81019182612df991612d26565b039b601f199c8d81018252612e0e90826103ed565b51902060a08501518b8d8851809281019384612e2991612d26565b039081018252612e3990826103ed565b519020918c8c60c0880151918951809281019384612e5691612d5c565b039081018252612e6690826103ed565b519020938d8d895192839182018095612e7e92612d89565b039081018252612e8e90826103ed565b5190206101008601519094906001600160a01b0316610120968701518051908e012097517f34728ce057ec73e3b4f0871dced9cc875f5b1aece9fd07891e156fe852a858d9818f019081526001600160401b03909a1660208b015260408a019c909c526001600160a01b03998a1660608a0152998916608089015260a088015260c087015260e0860152610100850152908301529190921661014083015261016082015290806101808301038481018252612f4990826103ed565b519020935161190160f01b9181019182526002820193909352602281019390935281604284015b039081018252612d0890826103ed565b9060005b818110612f915750505090565b9091926001908435612fa281610457565b828060a01b03168152602080910194019101919091612f84565b939492919091612fca612ab8565b946020968792838301612fdc906112cf565b94612fea60408501856112fe565b604099919951809a888201809361300092612f80565b0399601f199a8b8101825261301590826103ed565b519020936040518091888201809461302c92612d89565b038a8101825261303c90826103ed565b5190209161304d60808601866112fe565b61305691613238565b8051908701209161306a60a08701876112fe565b61307391613238565b8051908801209061308760c08801886112fe565b613090916131c3565b888151910120926130a0916131c3565b805190880120926130b461010088016112cf565b946130c3610120890189611c97565b36906130ce92610584565b898151910120966040519a8b9a8b019c8d9a359061316c9b97936101609995919c9b9a96929793976001600160401b036101808b019e7fe850f4ac05cb765eff6f120037e6d3286f8f71aaedad7f9f242af69d530912658c521660208b015260408a015260018060a01b0380981660608a0152608089015260a088015260c087015260e0860152610100850152610120840152166101408201520152565b03838101825261317c90826103ed565b51902060405161190160f01b948101948552600285019390935260228401528160428401612f70565b60209291906131bb849282815194859201612a95565b019081520190565b906060916000915b8083106131d85750505090565b9091926132319061322b6131ed868587612246565b90612cfc604080519384613208602095868301938491612d89565b039461321c601f19968781018352826103ed565b519020905195869384016131a5565b93611d09565b91906131cb565b906060916000915b80831061324d5750505090565b90919261327d9061322b613262868587612246565b90612cfc604080519384613208602095868301938491612f80565b9190613240565b9061335f906132966020820135615c2c565b91905061335160408501928335926132ad84610457565b61334a6132b8612ab8565b612cfc6133408a358b6132d76132d16020849f016112cf565b9b6112cf565b90612cbe60608201359c826132ef8f946080016112cf565b956132fc60a083016112cf565b9161330a61010082016112cf565b9260405198899760208901996101208501359760e0860135966001600160401b0361014060c089013598013560401c168d612ba9565b5190209180611c97565b91856133f2565b61335a81610457565b6137a2565b42101561336857565b6040516362b439dd60e11b8152600490fd5b6003111561338457565b634e487b7160e01b600052602160045260246000fd5b9081602091031261017257516001600160e01b0319811681036101725790565b908060209392818452848401376000828201840152601f01601f1916010190565b6040906104fd9492815281602082015201916133ba565b93929190926134008161337a565b806134e6575060209261341860009361343e93615c54565b6040805194855260ff909116602085015283019190915260608201529081906080820190565b838052039060015afa15610a31576000516001600160a01b038082169081156134d457831614159182613486575b505061347457565b60405163be109cb360e01b8152600490fd5b6001600160a01b031660009081526001602052604090206134cd92506134c9916134c2915b9060018060a01b0316600052602052604060002090565b5460ff1690565b1590565b388061346c565b604051637212c4e560e01b8152600490fd5b6134f3819593949561337a565b6001810361359057509160209161352293604051809581948293630b135d3f60e11b998a8552600485016133db565b03916001600160a01b03165afa908115610a3157600091613562575b506001600160e01b0319160361355057565b604051635d52cbe360e01b8152600490fd5b613583915060203d8111613589575b61357b81836103ed565b81019061339a565b3861353e565b503d613571565b806135a06002929693949661337a565b03613658576135e360209261341860009586947f19457468657265756d205369676e6564204d6573736167653a0a3332000000008652601c52603c852092615c54565b838052039060015afa15610a3157516001600160a01b038082169081156134d457831614159182613628575b50501561043b576040516311da12ed60e11b8152600490fd5b6001600160a01b0316600090815260016020526040902061365192506134c9916134c2916134ab565b388061360f565b6040516360cd402d60e01b8152600490fd5b93929190926136788161337a565b806136ca575060209261341860009361369093615c54565b838052039060015afa15610a31576000516001600160a01b039081169182156134d457161415806136c2575b61347457565b5060016136bc565b6136d7819593949561337a565b6001810361370657509160209161352293604051809581948293630b135d3f60e11b998a8552600485016133db565b806137166002929693949661337a565b036136585761375960209261341860009586947f19457468657265756d205369676e6564204d6573736167653a0a3332000000008652601c52603c852092615c54565b838052039060015afa15610a3157516001600160a01b039081169182156134d4571614158061379a575b1561043b576040516311da12ed60e11b8152600490fd5b506001613783565b9080156137ff57600160ff8260081c92161b60009260018060a01b0316835282602052604083208284528060205260408420549082808316146137ed57604093855260205217912055565b604051633ab3447f60e11b8152600490fd5b604051630a858a7760e11b8152600490fd5b90916138206020840135615c2c565b93905061388d6001600160401b0361335a60409661147088880191613844836112cf565b9660e08a019761388561387e8d8d61385c8d826112fe565b9161387960608201359d8e95610140840135901c169136906105d6565b612da4565b9280611c97565b9290916133f2565b608083019061389c82856112fe565b90506138ab60c08601866112fe565b91905014908115916139ac575b5061399b576138cb610120840184611c97565b90506138d782856112fe565b9190506138ec60a086019261169d84886112fe565b0361398b5760016138fd83866112fe565b905014159081613973575b5061395f57613919600191846112fe565b9050119081613955575b506139445742903511156139345750565b516362b439dd60e11b8152600490fd5b8151637d617bb360e01b8152600490fd5b9050151538613923565b835160016238137360e01b03198152600490fd5b6001915061398190856112fe565b9050141538613908565b845162e1bc0d60e21b8152600490fd5b8351631a26905d60e31b8152600490fd5b90506139c76139be60a08601866112fe565b929050856112fe565b9190501415386138b8565b9190816139e260408501856112fe565b905014801590613e2f575b8015613e17575b8015613dff575b8015613de7575b8015613dcf575b613dbd57906000916000915b808310613a5257505050613a2d610120830183611c97565b91905003613a4057429035111561336857565b60405163518b801560e01b8152600490fd5b909192613a668461169760a08801886112fe565b9050613a798561169760e08901896112fe565b91905014801590613d8e575b613d7c5784613a96602082016112cf565b8580613aa560408501856112fe565b613aaf9291611cf9565b613ab8906112cf565b81613ac660608601866112fe565b613ad09291611cf9565b3582613adf60808701876112fe565b613ae99291612246565b9084613af860a08901896112fe565b613b029291612246565b86613b1060c08b018b6112fe565b613b1a9291612246565b9390948860e08c01613b2c908d6112fe565b613b369291612246565b9790988d8d6101008101613b49906112cf565b9c613b58610120830183611c97565b92909180613b6960a08401846112fe565b613b739291612246565b92905060808101613b83916112fe565b613b8d9291612246565b9050613b989161226b565b913690613ba492610584565b91613bae92615d7b565b9b613bb761040e565b9d358e526001600160a01b031660208e01526001600160a01b031660408d015260608c01523690613be79261048a565b60808a01523690613bf79261048a565b60a08801523690613c0792610500565b60c08601523690613c1792610500565b60e08401526001600160a01b0316610100830152610120820152610140808201600090528560e08801613c4a90896112fe565b613c549291612246565b9087613c6360608b018b6112fe565b613c6d9291611cf9565b359289013560401c6001600160401b0316613c8794612da4565b613c92858486612210565b60200135613c9f90615c2c565b905085613caf60408901896112fe565b613cb99291611cf9565b613cc2906112cf565b91613cce878688612210565b80613cd891611c97565b91613ce2946133f2565b83613cf060408701876112fe565b613cfa9291611cf9565b613d03906112cf565b84613d1160608801886112fe565b613d1b9291611cf9565b35613d25916137a2565b83613d3360a08701876112fe565b613d3d9291612246565b905084613d4d60808801886112fe565b613d579291612246565b9050613d629161226b565b613d6b9161226b565b92613d7590611d09565b9190613a15565b604051631a26905d60e31b8152600490fd5b50613da08461169760808801886112fe565b9050613db38561169760c08901896112fe565b9190501415613a85565b6040516379b3909760e01b8152600490fd5b5081613dde60e08501856112fe565b90501415613a09565b5081613df660c08501856112fe565b90501415613a02565b5081613e0e60a08501856112fe565b905014156139fb565b5081613e2660808501856112fe565b905014156139f4565b5081613e3e60608501856112fe565b905014156139ed565b9291906020830135928360e086013510613efe578315613eec57604001359360608101358503613ed7575b6020810193613e83611021866112cf565b3303613e92575b505050505050565b613ecc95613ec691610140840135936001600160401b03613ebb613eb587615c20565b996112cf565b9560401c1690612c36565b9061366a565b388080808080613e8a565b613ee78561335a604084016112cf565b613e72565b604051630b2f300d60e41b8152600490fd5b60405163388edf2560e11b8152600490fd5b9093916020840192613f2284866112fe565b60e08501939150613f3384866112fe565b919050036140355760005b613f4886886112fe565b9050811015613f9657613f5f8161146a888a6112fe565b3515613eec57613f738161146a86886112fe565b35613f828261146a898b6112fe565b3511613efe57613f9190611d09565b613f3e565b5092949095915060408101359360608601358503614020575b6020860194613fc0611021876112cf565b3303613fd0575b50505050505050565b6001600160401b03613ec692886138796140056101406140149c013593613fff613ff986615c20565b9c6112cf565b986112fe565b94909360401c169136906105d6565b38808080808080613fc7565b6140308561335a604089016112cf565b613faf565b6040516348a1c34d60e11b8152600490fd5b93919091602084019161405a83866112fe565b60e0880193915061406b84896112fe565b919050036140355793600080955b614083858a6112fe565b905087101561418c5761409a87611697888b6112fe565b90506140aa88611697888d6112fe565b9190500361403557815b888a6140c48a6116978a846112fe565b9050831015614107578261146a8b6116978c6140ec8561146a8f61169787916140f39b6112fe565b35966112fe565b3511613efe5761410290611d09565b6140b4565b505050919561414d909391936040898b838383019361412a8261146a87876112fe565b3561413c8361146a60608701876112fe565b3503614157575b5050505050611d09565b9591929092614079565b614182946141756114708461146a8761146a9661417b9901906112fe565b946112fe565b35906137a2565b38898b8383614143565b9795505091509160208401936141a4611021866112cf565b33036141b257505050505050565b6001600160401b03816141ef613ecc98610140613ec6950135926141e26141db6132d186615c20565b97836112fe565b93909260408101906112fe565b95909460401c1690612fbc565b60405190604082018281106001600160401b038211176103975760405260006020838281520152565b65ffffffffffff8091169081146119065760010190565b909160009060009261424c6141fc565b928491608081019161426d611470611e0f61426786866112fe565b90612232565b9487945b61427b85856112fe565b9050861015614418576142999061169d8761169760a08801886112fe565b97805b6142aa8761169788886112fe565b90508110156143f1576142dd6114236114158c846142d76142cf6101208c018c611c97565b92909361226b565b91611ced565b600160fb1b81146143d6578b614374575b6143269190600160fa1b810361432b575061277d61431a6143158c5165ffffffffffff1690565b614225565b65ffffffffffff168b52565b61429c565b600160f81b8114908115614366575b501561277d5761277d60208b0161435a614315825165ffffffffffff1690565b65ffffffffffff169052565b600360f81b1490503861433a565b90936143969061438f8661146a8b61169760c08c018c6112fe565b359061226b565b936143af6110216114708361146a8c6116978d8d6112fe565b6001600160a01b038a16036143c457906142ee565b604051637d617bb360e01b8152600490fd5b506143269061277d61431a6143158c5165ffffffffffff1690565b509761440b6144119196929661169d8461169789896112fe565b91611d09565b9490614271565b50959650965050505050565b906040516144318161039c565b915461ffff81168352601081901c6001600160a01b0316602084015260b01c60ff1615156040830152565b9190820391821161190657565b9192949390936144788161337a565b600181146146c0575b6144896120e2565b506144938161337a565b856002821493846000146146b95730935b6001600160f81b031916801580156146ac575b1561458d57506144da936144d592916001600160a01b038816614abd565b61337a565b6144e357505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911681900361457b57803b1561017257604051632e1a7d4d60e01b815260048101849052906000908290602490829084905af18015610a3157600093849384938493614568575b505af1614560611d49565b501561202c57565b80610a2561457592610384565b38614555565b604051630f6f4f0d60e11b8152600490fd5b909150600160f81b8114801561469f575b1561464e57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166145d788615e07565b90803b1561017257604051631b63c28b60e11b81526001600160a01b0393841660048201529483166024860152908216604485015290851660648401526000908390818381608481015b03925af1918215610a31576144da9261463b575b5061337a565b80610a2561464892610384565b38614635565b91925050600160fb1b8114908115614691575b501561467f576144da906144d586866001600160a01b0387166128bf565b6040516312f269e560e01b8152600490fd5b600160fa1b14905038614661565b50600360f81b811461459e565b50600160f91b81146144b7565b86936144a4565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811690851681900361457b57803b156101725760008791600460405180948193630d0e30db60e41b83525af18015610a3157614726575b50614481565b80610a2561473392610384565b38614720565b959295949193909461474a8361337a565b60018314614a44575b600061475d6120e2565b946001600160401b0381166149c9575b506147778461337a565b600284149485156149c25730935b6001600160f81b031916801580156149b5575b156148055750816147c0575b506144da93926144d5928992506001600160a01b038816614abd565b816144da9594996147f56144d595946147e560206147fa96015160018060a01b031690565b866001600160a01b038d16614abd565b61445c565b9792938192506147a4565b919890949391600160f81b811480156149a8575b156149755750881561493e57906148806148b86148398b6148c49561445c565b809b61489061486361485d602061484e612186565b9c01516001600160a01b031690565b92615e07565b61488061486e61043d565b6001600160a01b038b16815293610e22565b6001600160a01b03166040830152565b6001600160a01b038b1660608201526148a889611d18565b526148b288611d18565b50615e07565b91610e2261090461043d565b6001600160a01b03851660608201526148dc83611d25565b526148e682611d25565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561017257604051630d58b1db60e01b81529260009184918290849082906146219060048301612278565b975092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166145d788615e07565b93945097505050600160fb1b811490811561469157501561467f576144da906144d586866001600160a01b0387166128bf565b50600360f81b8114614819565b50600160f91b8114614798565b8793614785565b6149dd9195506149d890610c0e565b614424565b936149eb6040860151151590565b80614a2c575b6149fc575b3861476d565b50614a27614a1f614a19614a12875161ffff1690565b61ffff1690565b8961190b565b612710900490565b6149f6565b5061ffff614a3c865161ffff1690565b1615156149f1565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811690861681900361457b57803b156101725760008891600460405180948193630d0e30db60e41b83525af18015610a3157614aaa575b50614753565b80610a25614ab792610384565b38614aa4565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a08101918183106001600160401b038411176103975761043b926040526128f8565b9060609081906000805b60808601614b2d81886112fe565b9050821015614dd757614b65611423611415614b4d6101208b018b611c97565b6142d7614b5d60a08e018e6112fe565b90508861226b565b80158015614dca575b15614bde575090614bc0614b8f6110216114708461146a614bcd978d6112fe565b614b9b60208a016112cf565b614ba760408b016112cf565b90614bb98561146a60c08e018e6112fe565b3592614abd565b845180614bd25750611d09565b614b1f565b600019018552386114e8565b909290600160f81b81148015614dbd575b15614ce75750845115614cb7575b906114e8614bcd92614c9c6020614c8d8b614c198382016112cf565b98614c7c604091614c506114708b61146a614c358789016112cf565b94613fff614c4a8461146a60c08d018d6112fe565b35615e07565b95614c6b614c5c61043d565b6001600160a01b03909e168e52565b6001600160a01b03909116908c0152565b6001600160a01b0390911690890152565b6001600160a01b0316868a0152565b614ca581611d09565b94614cb08289611d35565b5286611d35565b9350806114e8614cdd614cd8614bcd94614cd1878c6112fe565b905061445c565b6121c0565b9591925050614bfd565b909290600160fa1b0361467f576114708261146a614d05938a6112fe565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692911682900361457b5760c08701614d4c8261146a838b6112fe565b3592803b15610172576004916000604095865194858092630d0e30db60e41b8252865af1928315610a31578461146a614d97614bcd988e614d9e95614da599614daa575b50016112cf565b938d6112fe565b35916128bf565b614bc0565b80610a25614db792610384565b38614d90565b50600360f81b8114614bef565b50600160f91b8114614b6e565b505050925090508051614de75750565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561017257604051630d58b1db60e01b8152916000918391829084908290614e3e9060048301612278565b03925af18015610a3157614e4f5750565b80610a2561043b92610384565b908151811015611ce8570160200190565b90969493919260009760609789976001600160401b03811615158091614e916120e2565b92615353575b508b5b858110614f4257505050505050505050614eb357505090565b815103614f30577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561017257604051630d58b1db60e01b8152916000918391829084908290614f119060048301612278565b03925af18015610a3157614f23575090565b80610a256104fd92610384565b604051637f7dfe8b60e11b8152600490fd5b614f5081899e9d9c9e611d35565b519c85614f71611423614f638589614e5c565b516001600160f81b03191690565b6152bc575b8b156151be578c5115615197575b8361501c575b878d9e9f84614f998e92615e07565b92614fa392611cf9565b614fac906112cf565b90614fb561043d565b6001600160a01b038c168152926001600160a01b031660208401526001600160a01b031660408301526001600160a01b03166060820152819c614ff88e93611d09565b9d61500291611d35565b5261500d908d611d35565b5061501790611d09565b614e9a565b9060ff60f81b9e8f600760f81b90615037614f63878b614e5c565b161461517a57615058614a1f615052614a12895161ffff1690565b8361190b565b91821561515d5790828f8c9594938f8d602091828d015161507e9060018060a01b031690565b908b61508988615e07565b9361509392611cf9565b61509c906112cf565b926150a561043d565b6001600160a01b03909b168b526001600160a01b03909116908a01526001600160a01b031660408901526001600160a01b031660608801526150e681611d09565b966150f18284611d35565b526150fb91611d35565b506151059161445c565b9f600160fa1b90615116868a614e5c565b516001600160f81b0319161614615142575b50878d9e9f84614f998e925b9e5050509b9f9e5050614f8a565b8b8e9f6151518b93879261445c565b9f5050509d9c9d615128565b9291508d9e9f508b848f8b93614f99916000198151019052615134565b8d9e9f508b848f8b93614f99916000979697198151019052615134565b839c50836000146151b5576151ae614cd8896118ee565b9c50614f84565b6151ae886121c0565b889d9e919c9d888c8680615298575b6151f2575b916151ed6110216114708861277d97956150179a9997611cf9565b614abd565b61520d614a1f615207614a128b5161ffff1690565b8761190b565b80615219575b506151d2565b94908561524d946152356110216114708b85986147f597611cf9565b60208c01519091906001600160a01b03165b91614abd565b91600160fa1b6001600160f81b0319615269614f63878b614e5c565b1614615279575b888c8b92615213565b918b9f918a61528a86958c9561445c565b9d50509150919e9a9e615270565b50600760f81b6001600160f81b03196152b4614f63898d614e5c565b1614156151cd565b506001600160f81b0319600760f81b816152d9614f63868a614e5c565b16036152e6575030614f76565b909c90600160fa1b906152fc614f638589614e5c565b160361467f5761531061147083898d611cf9565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691160361457b578d61534c9161226b565b9b30614f76565b61536292506149d89150610c0e565b6040810151151580615375575b38614e97565b5061ffff615385825161ffff1690565b16151561536f565b94959792969197939093600097885b60808801906153af88611697848c6112fe565b9050811015615744578885898e868f821515908161573a575b501561571c576125266153ea926120778861146a8761169760c08c018c6112fe565b945b615412611423611415615403610120880188611c97565b6142d78a6040809a015161226b565b8015801561570f575b156154685750916152476114708361146a61544d6110216114708b61146a8c9a6154639f9c6116979061277d9f6112fe565b9561545a602082016112cf565b958101906112fe565b61539c565b9185969394959192600160f81b81148015615702575b1561557157505050602092858c858701615497906112cf565b96816154a5858301836112fe565b6154af9291611cf9565b6154b8906112cf565b956154c290615e07565b946154cc916112fe565b6154d69291612246565b6154e09291611cf9565b6154e9906112cf565b926154f261043d565b6001600160a01b0390961686526001600160a01b0316858501526001600160a01b03909116908401526001600160a01b031660608301528501805165ffffffffffff169061553f82614225565b65ffffffffffff16905265ffffffffffff169061555c8288611d35565b526155679086611d35565b5061546390611d09565b95839496600160fa959394951b811460001461569d57506114709261169761559d959361146a936112fe565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691160361568c57826114e8926156478e61561b8f958f61146a6156116114708d61146a6154639f9e611697611470988f899361560a60209e8f0191825161226b565b90526112fe565b98878101906112fe565b9061563661562761042e565b6001600160a01b039097168752565b6001600160a01b0390911690850152565b82015265ffffffffffff615661885165ffffffffffff1690565b61567961566d82614225565b65ffffffffffff168a52565b16906156858288611d35565b5285611d35565b8151630f6f4f0d60e11b8152600490fd5b600160fb1b141593506156f1925050505783926114e8926156476156e66114708f958f906156dc6114706154639c61146a8561169761146a968e6112fe565b97868101906112fe565b610e2261090461042e565b81516312f269e560e01b8152600490fd5b50600360f81b811461547e565b50600160f91b811461541b565b50506157338461146a8361169760c08801886112fe565b35946153ec565b82841091506153c8565b505050505050945050505050565b9360ff929897969360e0969261010087019a60018060a01b03809216885216602087015260408601526060850152600160808501521660a083015260c08201520152565b916157aa6157a48280611c97565b90615c54565b936001600160a01b0390811692907f00000000000000000000000000000000000000000000000000000000000000001683036158fc577f000000000000000000000000000000000000000000000000000000000000000060890361589357604051632d0335ab60e01b81526001600160a01b038716600482015293602085602481875afa948515610a3157600095615873575b50833b1561017257614e3e6020936000979388946040519a8b998a9889976323f2ebc360e21b8952013591309060048901615752565b61588c91955060203d81116110ae5761109f81836103ed565b933861583d565b604051623f675f60e91b81526001600160a01b038716600482015293602085602481875afa948515610a31576000956158735750833b1561017257614e3e6020936000979388946040519a8b998a9889976323f2ebc360e21b8952013591309060048901615752565b9082959394953b156101725760405163d505accf60e01b81526001600160a01b0390941660048501523060248501526000196044850152602090940135606484015260ff909416608483015260a482019390935260c481019190915290600090829081838160e48101614e3e565b60405190615977826103d2565b600182528160005b602090818110156159a157602091615995612151565b9082850101520161597f565b505050565b3565ffffffffffff811681036101725790565b9493919492909260018060a01b0380941681526060602090808284015260c08301885196828086015287518092528360e086019801926000915b838310615a2e5750505050908701516001600160a01b031660808301525093946104fd94906040015160a082015260408185039101526133ba565b8451805182168b52808701518216878c015260408082015165ffffffffffff908116918d019190915290830151168a830152608090990198938501936001909201916159f3565b90615a8360a08301836112fe565b90509160005b60808201615a9781846112fe565b9050821015615b1357615aae610120840184611c97565b90615ad1615abb88611d09565b97600160f91b936001600160f81b031993611ced565b351614615ae75750615ae290611d09565b615a89565b61043b94509061146a615b0892602085013594615b0386610457565b6112fe565b359061120482610457565b5050505050565b90600091825b6080820193615b2f85846112fe565b9050821015615b1357615b4d9061169d8361169760a08701876112fe565b9360005b615b5f8361169784876112fe565b9050811015615bd65761141595615b98611423615b80610120880188611c97565b999093615b8c81611d09565b9a600160f91b95611ced565b14615bab57615ba690611d09565b615b51565b61043b955061146a615bd09361169761147094615bca602089016112cf565b976112fe565b90615796565b5050615be190611d09565b615b20565b60018116151591600460028316151592161515908380615c19575b615c0757565b6040516389702c9b60e01b8152600490fd5b5081615c01565b6003166104fd8161337a565b600460038216615c3b8161337a565b9116151591565b60ff601b9116019060ff821161190657565b90604103615cec57602081013591602182013591601b60ff841610615cdc575b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411615cca5760ff8316601b8114159081615cbe575b50615cac5735929190565b60405163f5d7a23b60e01b8152600490fd5b601c9150141538615ca1565b604051630696fe3b60e21b8152600490fd5b91615ce690615c42565b91615c74565b604051634be6321b60e01b8152600490fd5b15615d0557565b60405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606490fd5b15615d4257565b60405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606490fd5b91615d9081615d898161225d565b1015615cfe565b615da68351615d9f838561226b565b1115615d3b565b80615dbf57505050604051600081526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b808410615df45750508252601f01601f191660405290565b9092835181526020809101930190615ddc565b6001600160a01b0390818111615e1b571690565b60405163c4bd89a960e01b8152600490fdfea26469706673582212206d1f42fe032bb9158201fcf8f408851331d3fdb2799a6eeb085c91f81889dcf764736f6c63430008130033000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806314e7a7ab1461015b5780631a499026146101565780631bceedd7146101515780633644e5151461014c578063384eada01461014757806338ec0211146101425780634dcebcba1461013d578063529c4a2f14610138578063602926bf1461013357806366a65e411461012e5780636d2a03d81461012957806372fc32e5146101245780638cce31401461011f5780639080ef021461011a5780639093bf7b14610115578063a2f7489314610110578063c38a44741461010b578063ea7faa6114610106578063ef7d27ad146101015763efe34fe60361000e57611209565b61115f565b6110bf565b610fdb565b610f5b565b610ebe565b610d9c565b610d21565b610c84565b610c27565b610b75565b610af5565b610aaf565b610a36565b61082d565b610794565b610779565b610703565b6102d9565b610204565b61016090600319011261017257600490565b600080fd5b90816101609103126101725790565b9181601f84011215610172578235916001600160401b038311610172576020808501948460051b01011161017257565b6060906101a3190112610172576101a490565b908160609103126101725790565b9181601f84011215610172578235916001600160401b038311610172576020838186019501011161017257565b60a0366003190112610172576001600160401b0360043581811161017257610230903690600401610177565b60243582811161017257610248903690600401610186565b9091606435848111610172576102629036906004016101c9565b60843594851161017257610288816102816100199736906004016101d7565b9085614047565b8035610293816110b5565b156102b4578060206102a69201906112fe565b929092935b604435926122e7565b506102c260e08201826112fe565b929092936102ab565b908160409103126101725790565b610220366003190112610172576102ef36610160565b6001600160401b039061016435828111610172576103119036906004016102cb565b9061031b366101b6565b61020435938411610172576103428161033b6100199636906004016101d7565b9085613e47565b803561034d816110b5565b156103625760200135915b610184359161193e565b5060e081013591610358565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161039757604052565b61036e565b606081019081106001600160401b0382111761039757604052565b608081019081106001600160401b0382111761039757604052565b604081019081106001600160401b0382111761039757604052565b90601f801991011681019081106001600160401b0382111761039757604052565b6040519061016082018281106001600160401b0382111761039757604052565b6040519061043b8261039c565b565b6040519061043b826103b7565b6040519061043b826103d2565b6001600160a01b0381160361017257565b359061043b82610457565b6001600160401b0381116103975760051b60200190565b929161049582610473565b916104a360405193846103ed565b829481845260208094019160051b810192831161017257905b8282106104c95750505050565b83809183356104d781610457565b8152019101906104bc565b9080601f83011215610172578160206104fd9335910161048a565b90565b929161050b82610473565b9161051960405193846103ed565b829481845260208094019160051b810192831161017257905b82821061053f5750505050565b81358152908301908301610532565b9080601f83011215610172578160206104fd93359101610500565b6001600160401b03811161039757601f01601f191660200190565b92919261059082610569565b9161059e60405193846103ed565b829481845281830111610172578281602093846000960137010152565b9080601f83011215610172578160206104fd93359101610584565b91909161016081840312610172576105ec61040e565b92813584526105fd60208301610468565b602085015261060e60408301610468565b60408501526060820135606085015260808201356001600160401b0390818111610172578261063e9185016104e2565b608086015260a0830135818111610172578261065b9185016104e2565b60a086015260c0830135818111610172578261067891850161054e565b60c086015260e0830135818111610172578261069591850161054e565b60e08601526101006106a8818501610468565b908601526101209182840135918211610172576106c69184016105bb565b908401526101408091013590830152565b602435906001600160401b038216820361017257565b600435906001600160401b038216820361017257565b34610172576080366003190112610172576001600160401b03600435818111610172576107349036906004016105d6565b9061073d6106d7565b916044359182116101725760209261075c610766933690600401610186565b9160643593612da4565b604051908152f35b600091031261017257565b34610172576000366003190112610172576020610766612ab8565b60c03660031901126101725760046001600160401b038135818111610172576107c09036908401610177565b602435828111610172576107d790369085016102cb565b91606435818111610172576107ef90369086016101c9565b6084358281116101725761080690369087016101d7565b93909260a4359081116101725761001996610823913691016102cb565b9460443591611333565b6102403660031901126101725761084336610160565b6001600160401b039061016435828111610172576108659036906004016102cb565b9061086f366101b6565b61020435848111610172576108889036906004016101d7565b909461022435908111610172576108af916108a8849236906004016101c9565b9685613e47565b60208201356108bd81610457565b6080830135946108cc86610457565b6109ab6108d761596a565b91602081019761093e6108e98a6159a6565b61092f6108f8604086016159a6565b9161091361090461043d565b6001600160a01b039096168652565b6001600160a01b03602086015265ffffffffffff166040850152565b65ffffffffffff166060830152565b61094784611d18565b5261095183611d18565b507f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b03169765ffffffffffff9061098e906159a6565b61099661042e565b94855230602086015216604084015280611c97565b969091813b1561017257600080946109d96040519a8b9687958694632a2d80d160e01b8652600486016159b9565b03925af1938415610a315761001994610a18575b506109f7816112f4565b15610a0c5760200135915b6101843591611bc8565b5060e081013591610a02565b80610a25610a2b92610384565b8061076e565b386109ed565b6112e8565b6101a036600319011261017257610a4c36610160565b610164356001600160401b03811161017257610a6c9036906004016102cb565b6020820135610a7a81610457565b6001600160a01b03163303610a9d578160e061001993013591610184359161193e565b604051636edaef2f60e11b8152600490fd5b34610172576101c036600319011261017257610aca36610160565b61016435906001600160401b038216820361017257602091610766916101a435916101843591612c36565b6060366003190112610172576001600160401b0360043581811161017257610b21903690600401610177565b9060243590811161017257610b3a9036906004016102cb565b906020810135610b4981610457565b6001600160a01b03163303610a9d5761001991610b6960e08301836112fe565b92909160443591611d79565b60c03660031901126101725760046001600160401b03813581811161017257610ba19036908401610177565b60243582811161017257610bb890369085016102cb565b9160643581811161017257610bd090369086016101c9565b60843582811161017257610be790369087016101d7565b93909260a4359081116101725761001996610c04913691016101c9565b9460443591611386565b6001600160401b03166000526002602052604060002090565b34610172576020366003190112610172576001600160401b03610c486106ed565b166000526002602052606060406000205460ff6040519161ffff8116835260018060a01b038160101c16602084015260b01c1615156040820152f35b60c03660031901126101725760046001600160401b03813581811161017257610cb09036908401610177565b9060243581811161017257610cc89036908501610186565b91909260643582811161017257610ce290369087016101c9565b9060843583811161017257610cfa90369088016101d7565b94909360a4359081116101725761001997610d17913691016101c9565b9560443592611634565b34610172576080366003190112610172576001600160401b0360043581811161017257610d52903690600401610177565b90610d5b6106d7565b60443582811161017257610d73903690600401610186565b60649491943593841161017257602094610d94610766953690600401610186565b949093612fbc565b3461017257606036600319011261017257610db56106ed565b60243561ffff81168082036101725760443590610dd182610457565b610de7610ddd85610c0e565b5460b01c60ff1690565b610eac5761271010610e9b576001600160a01b03811615610e895761001992610e32610e3e92610e22610e1861042e565b61ffff9096168652565b6001600160a01b03166020850152565b60016040840152610c0e565b81518154602084015160409094015160ff60b01b90151560b01b1662010000600160b01b0360109590951b9490941661ffff9092166001600160b81b03199091161717919091179055565b604051636793040360e11b8152600490fd5b6040516214eb0160ea1b8152600490fd5b6040516335bf048b60e21b8152600490fd5b60c03660031901126101725760046001600160401b03813581811161017257610eea9036908401610177565b9060243581811161017257610f029036908501610186565b91909260643582811161017257610f1c90369087016101c9565b9060843583811161017257610f3490369088016101d7565b94909360a4359081116101725761001997610f51913691016102cb565b95604435926115e0565b6060366003190112610172576001600160401b0360043581811161017257610f87903690600401610177565b9060243590811161017257610fa0903690600401610186565b906020830135610faf81610457565b6001600160a01b03163303610a9d5782610fcf60e06100199501826112fe565b939092604435926122e7565b61018036600319011261017257610ff136610160565b610164356001600160401b038111610172576110119036906004016102cb565b9061102d611021602083016112cf565b6001600160a01b031690565b3303610a9d57611045611021611021608084016112cf565b6040516370a0823160e01b81523060048201529290602090849060249082905afa908115610a315761001993600092611085575b5060e083013592611ae8565b6110a791925060203d81116110ae575b61109f81836103ed565b8101906112d9565b9038611079565b503d611095565b8015150361017257565b34610172576040366003190112610172577f6ea9dbe8b2cc119348716a9220a0742ad62b7884ecb0ff4b32cd508121fd937960606004356110ff81610457565b60243561110b816110b5565b3360009081526001602090815260408083206001600160a01b03861684529091529020805460ff92151592831660ff1991909116179055604080513381526001600160a01b039093166020840152820152a1005b6102403660031901126101725761117536610160565b6001600160401b039061016435828111610172576111979036906004016102cb565b906111a1366101b6565b61020435848111610172576111ba9036906004016101d7565b949061022435918211610172576111e783610019976111e06103429536906004016102cb565b9387613e47565b60208401356111f581610457565b60808501359061120482610457565b615796565b60a0366003190112610172576001600160401b0360043581811161017257611235903690600401610177565b6024358281116101725761124d9036906004016102cb565b90606435838111610172576112669036906004016101c9565b6084359384116101725761128c816112856100199636906004016101d7565b9085613f10565b8035611297816110b5565b156112b8578060206112aa9201906112fe565b919091925b60443591611d79565b506112c660e08201826112fe565b919091926112af565b356104fd81610457565b90816020910312610172575190565b6040513d6000823e3d90fd5b356104fd816110b5565b903590601e198136030182121561017257018035906001600160401b03821161017257602001918160051b3603831361017257565b949561134b8461043b98611351949796959689613f10565b85615a75565b803561135c816110b5565b156113785780602061136f9201906112fe565b92909293611d79565b5061136f60e08401846112fe565b936113979197929695849186613f10565b6113a460a08401846112fe565b905091600096604092838701916113c56113be848a6112fe565b90506121c0565b958a905b60808901906113d8828b6112fe565b90508310156114f55761141594939291906114306114236113fd6101208e018e611c97565b98909361140981611d09565b99600360f81b95611ced565b356001600160f81b03191690565b6001600160f81b03191690565b14611448575b5061144090611d09565b9091926113c9565b819c8b6114d38861092f6114758f6114409861146a6114ee99611470936112fe565b90611cf9565b6112cf565b936114c561149c6114978861146a6020976114918988016159a6565b966112fe565b6159a6565b936114b76114a861043d565b6001600160a01b039098168852565b6001600160a01b0390870152565b65ffffffffffff16848e0152565b6114dd828c611d35565b526114e8818b611d35565b50611d09565b9b90611436565b505050959692939150979693968751036115d0577f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316611572611542602089016112cf565b9365ffffffffffff611556602083016159a6565b61155e61042e565b9b8c523060208d015216848b015280611c97565b989092823b156101725760009461159f8692519b8c9687958694632a2d80d160e01b8652600486016159b9565b03925af1948515610a315761043b956115bd575b5061135c816112f4565b80610a256115ca92610384565b386115b3565b51637f7dfe8b60e11b8152600490fd5b95966115f98561043b996115ff9498979596978a614047565b86615b1a565b803561160a816110b5565b156116265780602061161d9201906112fe565b939093946122e7565b5061161d60e08501856112fe565b92949380979661164692999585614047565b600093846040918288019961165e6113be8c8b6112fe565b9483975b6080880194611671868a6112fe565b90508a10156117fb578b898f926116a59061169d8e61169760a0869b999a9b01866112fe565b90612246565b91905061226b565b6116b58d6116978b6000956112fe565b90508210156117e05790611415916116f06114236116d88f610120810190611c97565b9590936116e481611d09565b96600360f81b95611ced565b14611714575b906116b58d6116978b8f97969561170c90611d09565b9596976112fe565b9c90888d8f938d8f9796958e83918561172d888d6112fe565b6117379291612246565b6117419291611cf9565b61174a906112cf565b906020906117598a83016159a6565b90846117658d8d6112fe565b61176f9291611cf9565b611778906159a6565b9261178161043d565b6001600160a01b0390951685526001600160a01b039085015265ffffffffffff9091169083015265ffffffffffff1660608201526117bf8284611d35565b526117c991611d35565b506117d390611d09565b9f929394955050506116f6565b975050505091976117f390939193611d09565b979092611662565b509b509598939250969095509792978851036115d0577f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b031661187a61184a60208a016112cf565b9365ffffffffffff61185e602083016159a6565b61186661042e565b9c8d523060208e015216848c015280611c97565b999092823b15610172576000946118a78692519c8d9687958694632a2d80d160e01b8652600486016159b9565b03925af1958615610a315761043b966118c5575b5061160a816112f4565b80610a256118d292610384565b386118bb565b634e487b7160e01b600052601160045260246000fd5b600181901b91906001600160ff1b0381160361190657565b6118d8565b8181029291811591840414171561190657565b8115611928570490565b634e487b7160e01b600052601260045260246000fd5b611a43929361194d8383613284565b610140820135608081901c9060401c6001600160401b0316939095611976610120850135615be6565b93919290946119e161198a602089016112cf565b6040890195611998876112cf565b976119a560808c016112cf565b8615998a159a8b611adb575b15611ad45760c08d0135925b6000908515611abd5750600160fa1b9490505b60009015611ab75750600194614469565b809480611aaa575b611a7f575b5050611a006020611a07920135615c2c565b50916112cf565b93611a2160a0611a1a61010084016112cf565b92016112cf565b9160009015611a795750600160f81b935b60009015611a735750600294614739565b6001600160801b03167fadd7095becdaa725f0f33243630938c861b0bba83dfd217d4055701aa768ec2e600080a2565b94614739565b93611a32565b611a07929450611aa2611a97611a009360209361190b565b60c08901359061191e565b9492506119ee565b5060c087013582106119e9565b94614469565b15611acf5750600160f81b5b936119d0565b611ac9565b87926119bd565b5060c08d013588116119b1565b611a4392939193611af98583613284565b610140820135608081901c9060401c6001600160401b0316939095611b22610120850135615be6565b93829392959195611bc0575b6119e1611b3d602089016112cf565b6040890195611b4b876112cf565b97611b5860808c016112cf565b8615998a159a8b611bb3575b15611bac5760c08d0135925b60008515611b915750600160fa1b946000915015611ab75750600194614469565b5015611ba257600160f81b936119d0565b600160fb1b611ac9565b8792611b70565b5060c08d01358811611b64565b479150611b2e565b611a439293611bd78383613284565b610140820135608081901c9060401c6001600160401b0316939095611c00610120850135615be6565b93919290946119e1611c14602089016112cf565b6040890195611c22876112cf565b97611c2f60808c016112cf565b8615998a159a8b611c8a575b15611c835760c08d0135925b60008515611c685750600160fa1b946000915015611ab75750600194614469565b5015611c7957600160f81b936119d0565b600160f81b611ac9565b8792611c47565b5060c08d01358811611c3b565b903590601e198136030182121561017257018035906001600160401b0382116101725760200191813603831361017257565b634e487b7160e01b600052603260045260246000fd5b9015611ce85790565b611cc9565b90821015611ce8570190565b9190811015611ce85760051b0190565b60001981146119065760010190565b805115611ce85760200190565b805160011015611ce85760400190565b8051821015611ce85760209160051b010190565b3d15611d74573d90611d5a82610569565b91611d6860405193846103ed565b82523d6000602084013e565b606090565b60209295949193611d8b878684613811565b611db0610140830135608081901c9060401c6001600160401b03169590960135615c2c565b509060808301976001611dc38a866112fe565b905011600014611e795750611a4395969750611dde83614b15565b611dea604084016112cf565b93611e1b611dfb61010086016112cf565b91611e15611470611e0f60a08901896112fe565b90611cdf565b93611cdf565b359260009015611e6f5750600160f81b93611e3c905b610120810190611c97565b600160fa1b916001600160f81b031991611e5a916114159190611cdf565b1614600090600014611a735750600294614739565b611e3c9094611e31565b949390610120840190611e8c8286611c97565b60a087019891611e9c8a896112fe565b91611ea8939150611ced565b356001600160f81b03191693611ec0602088016112cf565b9b604088019c611ecf8e6112cf565b91611eda908a6112fe565b611ee391611cdf565b611eec906112cf565b96841592831598611f35948a6120c9575b156120c257611f12611e0f60c08e018e6112fe565b35915b60006001600160f81b03198516600160fa1b03611ab75750600194614469565b611f40368285610500565b94806120a9575b612051575b505050611f5e611f93969798996112cf565b93610100810197611f8d611f86611f7e611f778c6112cf565b93856112fe565b959094611c97565b3691610584565b95614e6d565b9081611fa1575b5050611a43565b7f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b66001600160a01b031690813b1561017257604051632e1a7d4d60e01b815260048101849052916000908390602490829084905af1918215610a31576000938493849384936120159261203e575b506112cf565b5af161201f611d49565b501561202c573880611f9a565b60405163d1a4579f60e01b8152600490fd5b80610a2561204b92610384565b3861200f565b60005b8181106120615750611f4c565b8061209461207d856120776120a495878a611cf9565b3561190b565b61208d611e0f60c08d018d6112fe565b359061191e565b61209e8289611d35565b52611d09565b612054565b506120ba611e0f60c08901896112fe565b358210611f47565b8691611f15565b506120da611e0f60c08e018e6112fe565b358711611efd565b604051906120ef8261039c565b60006040838281528260208201520152565b9061210b82610473565b61211860405191826103ed565b8281528092612129601f1991610473565b019060005b82811061213a57505050565b6020906121456120e2565b8282850101520161212e565b60405190608082018281106001600160401b038211176103975760405260006060838281528260208201528260408201520152565b6040908151916121958361039c565b600283528260005b8281106121a957505050565b6020906121b4612151565b8282850101520161219d565b906121ca82610473565b6121d760405191826103ed565b82815280926121e8601f1991610473565b019060005b8281106121f957505050565b602090612204612151565b828285010152016121ed565b9190811015611ce85760051b81013590603e1981360301821215610172570190565b9015611ce85780612242916112fe565b9091565b90821015611ce8576122429160051b8101906112fe565b90601f820180921161190657565b9190820180921161190657565b60208082019080835283518092528060408094019401926000905b8382106122a257505050505090565b845180516001600160a01b0390811688528185015181168886015281830151811688840152606091820151169087015260809095019493820193600190910190612293565b92949190916122f78284866139d2565b612301868561423c565b96909161230c61042e565b60008082526020820181905260408201529661232661044a565b6000808252602082015289519095906123469065ffffffffffff16612101565b9660208b015161235b9065ffffffffffff1690565b65ffffffffffff1661236c906121c0565b9b60005b61237d60a08c018c6112fe565b90508110156125655761239d6020612396838787612210565b0135615c2c565b506123b36123ac838989612246565b3691610500565b8815158061255c575b6124d0575b8f6124c38f928f958f8f978f8f96611697936124cb9b8a6124ae9460409b6124828a9f8b8f61247b926124b89f61245f6124068f948661146a611470928801886112fe565b948a6001600160401b0361014061246e60408961246961242961010083016112cf565b9661243b8961169760a08601866112fe565b9a909961169761244f610120870187611c97565b97909401519560a08101906112fe565b9490503691610584565b615d7b565b97013560401c1696614e6d565b855161226b565b84526124a36124988b61169760a08c018c6112fe565b90508e85015161226b565b8d840152898861538d565b60808101906112fe565b90508284015161226b565b910152611d09565b612370565b9c979a94919993909e95989b969d928e6124ee8c6000925b8d612246565b905081101561253b57908f949392918f8f8f928f928f8261252b612531956125266124ee998f8561146a8c6120779361209e9a612246565b61191e565b92611d35565b92939495966124e8565b50959e929d979c969b949a93999498939796939591949093919290916123c1565b508989106123bc565b509b96999550505050505094919294612584815165ffffffffffff1690565b906125a3612598855165ffffffffffff1690565b65ffffffffffff1690565b65ffffffffffff809316036128ad576020015165ffffffffffff16906125d5612598602086015165ffffffffffff1690565b91160361289b576125f2612598602084015165ffffffffffff1690565b612810575b505161260a9065ffffffffffff16612598565b6126ee575b508051908161264a575b5050610140013560801c7fadd7095becdaa725f0f33243630938c861b0bba83dfd217d4055701aa768ec2e600080a2565b7f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b66001600160a01b0316803b1561017257604051632e1a7d4d60e01b815260048101939093526000908390602490829084905af1918215610a31576000928392839283926126db575b506126c161010087016112cf565b9051905af16126ce611d49565b501561202c573880612619565b80610a256126e892610384565b386126b3565b909160208301518061278c575b5060005b8251811015612782578060406127186127249386611d35565b51015161272957611d09565b6126ff565b61277d61274a61102161273c8488611d35565b51516001600160a01b031690565b61276860206127598589611d35565b5101516001600160a01b031690565b60406127748589611d35565b510151916128bf565b611d09565b509190503861260f565b34106127fe5760208301517f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b66001600160a01b0316803b1561017257600090600460405180948193630d0e30db60e41b83525af18015610a3157156126fb5780610a256127f892610384565b386126fb565b60405163f6ed5e0160e01b8152600490fd5b907f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316803b1561017257604051630d58b1db60e01b81529260009184918290849082906128689060048301612278565b03925af1908115610a315761260a9261259892612888575b5091506125f7565b80610a2561289592610384565b38612880565b604051631a44983960e31b8152600490fd5b60405163c37a566360e01b8152600490fd5b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815261043b916128f8826103b7565b604051612956916001600160a01b0316612911826103d2565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1612950611d49565b91612a24565b80518061296257505050565b8183918101031261017257810151612979816110b5565b156129815750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b156129df57565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b91929015612a445750815115612a38575090565b6104fd903b15156129d8565b825190915015612a575750805190602001fd5b6044604051809262461bcd60e51b825260206004830152612a878151809281602486015260208686019101612a95565b601f01601f19168101030190fd5b60005b838110612aa85750506000910152565b8181015183820152602001612a98565b467f0000000000000000000000000000000000000000000000000000000000028c5803612b03577fc1d55d2819112d8e804b83e0f098f87cbe24401fb170c80ac82f8aeaed3f7d5890565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527fd6144400a4098bee31df789c6c534128424a333149eec40af03ae3b3223cd96f60408201527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a560608201524660808201523060a082015260a0815260c081018181106001600160401b038211176103975760405251902090565b979392909b9a9995610160999597926001600160401b036101808b019e7fe34225bc7cd92038d42c258ee3ff66d30f9387dd932213ba32a52011df0603fc8c521660208b015260408a015260018060a01b03978880958180951660608d01521660808b015260a08a01521660c08801521660e0860152610100850152610120840152166101408201520152565b91612cfc92612d089294612cbe612c4b612ab8565b96612c58602085016112cf565b93612c65604082016112cf565b938015612d1a57955b612c7a608083016112cf565b91612c8760a082016112cf565b918015612d0e57915b612c9d61010083016112cf565b93604051998a9860208a019a6101208601359860c08701359635908d612ba9565b0391612cd2601f19938481018352826103ed565b519020604051938491602083019687909160429261190160f01b8352600283015260228201520190565b039081018352826103ed565b51902090565b5060e081013591612c90565b50606081013595612c6e565b805160208092019160005b828110612d3f575050505090565b83516001600160a01b031685529381019392810192600101612d31565b805160208092019160005b828110612d75575050505090565b835185529381019392810192600101612d67565b91906001600160fb1b0381116101725760051b809282370190565b93929192612db0612ab8565b9385519160209384880151612dca9060018060a01b031690565b604089810151909991938a92916001600160a01b03169560808301519984519a8b8b81019182612df991612d26565b039b601f199c8d81018252612e0e90826103ed565b51902060a08501518b8d8851809281019384612e2991612d26565b039081018252612e3990826103ed565b519020918c8c60c0880151918951809281019384612e5691612d5c565b039081018252612e6690826103ed565b519020938d8d895192839182018095612e7e92612d89565b039081018252612e8e90826103ed565b5190206101008601519094906001600160a01b0316610120968701518051908e012097517f34728ce057ec73e3b4f0871dced9cc875f5b1aece9fd07891e156fe852a858d9818f019081526001600160401b03909a1660208b015260408a019c909c526001600160a01b03998a1660608a0152998916608089015260a088015260c087015260e0860152610100850152908301529190921661014083015261016082015290806101808301038481018252612f4990826103ed565b519020935161190160f01b9181019182526002820193909352602281019390935281604284015b039081018252612d0890826103ed565b9060005b818110612f915750505090565b9091926001908435612fa281610457565b828060a01b03168152602080910194019101919091612f84565b939492919091612fca612ab8565b946020968792838301612fdc906112cf565b94612fea60408501856112fe565b604099919951809a888201809361300092612f80565b0399601f199a8b8101825261301590826103ed565b519020936040518091888201809461302c92612d89565b038a8101825261303c90826103ed565b5190209161304d60808601866112fe565b61305691613238565b8051908701209161306a60a08701876112fe565b61307391613238565b8051908801209061308760c08801886112fe565b613090916131c3565b888151910120926130a0916131c3565b805190880120926130b461010088016112cf565b946130c3610120890189611c97565b36906130ce92610584565b898151910120966040519a8b9a8b019c8d9a359061316c9b97936101609995919c9b9a96929793976001600160401b036101808b019e7fe850f4ac05cb765eff6f120037e6d3286f8f71aaedad7f9f242af69d530912658c521660208b015260408a015260018060a01b0380981660608a0152608089015260a088015260c087015260e0860152610100850152610120840152166101408201520152565b03838101825261317c90826103ed565b51902060405161190160f01b948101948552600285019390935260228401528160428401612f70565b60209291906131bb849282815194859201612a95565b019081520190565b906060916000915b8083106131d85750505090565b9091926132319061322b6131ed868587612246565b90612cfc604080519384613208602095868301938491612d89565b039461321c601f19968781018352826103ed565b519020905195869384016131a5565b93611d09565b91906131cb565b906060916000915b80831061324d5750505090565b90919261327d9061322b613262868587612246565b90612cfc604080519384613208602095868301938491612f80565b9190613240565b9061335f906132966020820135615c2c565b91905061335160408501928335926132ad84610457565b61334a6132b8612ab8565b612cfc6133408a358b6132d76132d16020849f016112cf565b9b6112cf565b90612cbe60608201359c826132ef8f946080016112cf565b956132fc60a083016112cf565b9161330a61010082016112cf565b9260405198899760208901996101208501359760e0860135966001600160401b0361014060c089013598013560401c168d612ba9565b5190209180611c97565b91856133f2565b61335a81610457565b6137a2565b42101561336857565b6040516362b439dd60e11b8152600490fd5b6003111561338457565b634e487b7160e01b600052602160045260246000fd5b9081602091031261017257516001600160e01b0319811681036101725790565b908060209392818452848401376000828201840152601f01601f1916010190565b6040906104fd9492815281602082015201916133ba565b93929190926134008161337a565b806134e6575060209261341860009361343e93615c54565b6040805194855260ff909116602085015283019190915260608201529081906080820190565b838052039060015afa15610a31576000516001600160a01b038082169081156134d457831614159182613486575b505061347457565b60405163be109cb360e01b8152600490fd5b6001600160a01b031660009081526001602052604090206134cd92506134c9916134c2915b9060018060a01b0316600052602052604060002090565b5460ff1690565b1590565b388061346c565b604051637212c4e560e01b8152600490fd5b6134f3819593949561337a565b6001810361359057509160209161352293604051809581948293630b135d3f60e11b998a8552600485016133db565b03916001600160a01b03165afa908115610a3157600091613562575b506001600160e01b0319160361355057565b604051635d52cbe360e01b8152600490fd5b613583915060203d8111613589575b61357b81836103ed565b81019061339a565b3861353e565b503d613571565b806135a06002929693949661337a565b03613658576135e360209261341860009586947f19457468657265756d205369676e6564204d6573736167653a0a3332000000008652601c52603c852092615c54565b838052039060015afa15610a3157516001600160a01b038082169081156134d457831614159182613628575b50501561043b576040516311da12ed60e11b8152600490fd5b6001600160a01b0316600090815260016020526040902061365192506134c9916134c2916134ab565b388061360f565b6040516360cd402d60e01b8152600490fd5b93929190926136788161337a565b806136ca575060209261341860009361369093615c54565b838052039060015afa15610a31576000516001600160a01b039081169182156134d457161415806136c2575b61347457565b5060016136bc565b6136d7819593949561337a565b6001810361370657509160209161352293604051809581948293630b135d3f60e11b998a8552600485016133db565b806137166002929693949661337a565b036136585761375960209261341860009586947f19457468657265756d205369676e6564204d6573736167653a0a3332000000008652601c52603c852092615c54565b838052039060015afa15610a3157516001600160a01b039081169182156134d4571614158061379a575b1561043b576040516311da12ed60e11b8152600490fd5b506001613783565b9080156137ff57600160ff8260081c92161b60009260018060a01b0316835282602052604083208284528060205260408420549082808316146137ed57604093855260205217912055565b604051633ab3447f60e11b8152600490fd5b604051630a858a7760e11b8152600490fd5b90916138206020840135615c2c565b93905061388d6001600160401b0361335a60409661147088880191613844836112cf565b9660e08a019761388561387e8d8d61385c8d826112fe565b9161387960608201359d8e95610140840135901c169136906105d6565b612da4565b9280611c97565b9290916133f2565b608083019061389c82856112fe565b90506138ab60c08601866112fe565b91905014908115916139ac575b5061399b576138cb610120840184611c97565b90506138d782856112fe565b9190506138ec60a086019261169d84886112fe565b0361398b5760016138fd83866112fe565b905014159081613973575b5061395f57613919600191846112fe565b9050119081613955575b506139445742903511156139345750565b516362b439dd60e11b8152600490fd5b8151637d617bb360e01b8152600490fd5b9050151538613923565b835160016238137360e01b03198152600490fd5b6001915061398190856112fe565b9050141538613908565b845162e1bc0d60e21b8152600490fd5b8351631a26905d60e31b8152600490fd5b90506139c76139be60a08601866112fe565b929050856112fe565b9190501415386138b8565b9190816139e260408501856112fe565b905014801590613e2f575b8015613e17575b8015613dff575b8015613de7575b8015613dcf575b613dbd57906000916000915b808310613a5257505050613a2d610120830183611c97565b91905003613a4057429035111561336857565b60405163518b801560e01b8152600490fd5b909192613a668461169760a08801886112fe565b9050613a798561169760e08901896112fe565b91905014801590613d8e575b613d7c5784613a96602082016112cf565b8580613aa560408501856112fe565b613aaf9291611cf9565b613ab8906112cf565b81613ac660608601866112fe565b613ad09291611cf9565b3582613adf60808701876112fe565b613ae99291612246565b9084613af860a08901896112fe565b613b029291612246565b86613b1060c08b018b6112fe565b613b1a9291612246565b9390948860e08c01613b2c908d6112fe565b613b369291612246565b9790988d8d6101008101613b49906112cf565b9c613b58610120830183611c97565b92909180613b6960a08401846112fe565b613b739291612246565b92905060808101613b83916112fe565b613b8d9291612246565b9050613b989161226b565b913690613ba492610584565b91613bae92615d7b565b9b613bb761040e565b9d358e526001600160a01b031660208e01526001600160a01b031660408d015260608c01523690613be79261048a565b60808a01523690613bf79261048a565b60a08801523690613c0792610500565b60c08601523690613c1792610500565b60e08401526001600160a01b0316610100830152610120820152610140808201600090528560e08801613c4a90896112fe565b613c549291612246565b9087613c6360608b018b6112fe565b613c6d9291611cf9565b359289013560401c6001600160401b0316613c8794612da4565b613c92858486612210565b60200135613c9f90615c2c565b905085613caf60408901896112fe565b613cb99291611cf9565b613cc2906112cf565b91613cce878688612210565b80613cd891611c97565b91613ce2946133f2565b83613cf060408701876112fe565b613cfa9291611cf9565b613d03906112cf565b84613d1160608801886112fe565b613d1b9291611cf9565b35613d25916137a2565b83613d3360a08701876112fe565b613d3d9291612246565b905084613d4d60808801886112fe565b613d579291612246565b9050613d629161226b565b613d6b9161226b565b92613d7590611d09565b9190613a15565b604051631a26905d60e31b8152600490fd5b50613da08461169760808801886112fe565b9050613db38561169760c08901896112fe565b9190501415613a85565b6040516379b3909760e01b8152600490fd5b5081613dde60e08501856112fe565b90501415613a09565b5081613df660c08501856112fe565b90501415613a02565b5081613e0e60a08501856112fe565b905014156139fb565b5081613e2660808501856112fe565b905014156139f4565b5081613e3e60608501856112fe565b905014156139ed565b9291906020830135928360e086013510613efe578315613eec57604001359360608101358503613ed7575b6020810193613e83611021866112cf565b3303613e92575b505050505050565b613ecc95613ec691610140840135936001600160401b03613ebb613eb587615c20565b996112cf565b9560401c1690612c36565b9061366a565b388080808080613e8a565b613ee78561335a604084016112cf565b613e72565b604051630b2f300d60e41b8152600490fd5b60405163388edf2560e11b8152600490fd5b9093916020840192613f2284866112fe565b60e08501939150613f3384866112fe565b919050036140355760005b613f4886886112fe565b9050811015613f9657613f5f8161146a888a6112fe565b3515613eec57613f738161146a86886112fe565b35613f828261146a898b6112fe565b3511613efe57613f9190611d09565b613f3e565b5092949095915060408101359360608601358503614020575b6020860194613fc0611021876112cf565b3303613fd0575b50505050505050565b6001600160401b03613ec692886138796140056101406140149c013593613fff613ff986615c20565b9c6112cf565b986112fe565b94909360401c169136906105d6565b38808080808080613fc7565b6140308561335a604089016112cf565b613faf565b6040516348a1c34d60e11b8152600490fd5b93919091602084019161405a83866112fe565b60e0880193915061406b84896112fe565b919050036140355793600080955b614083858a6112fe565b905087101561418c5761409a87611697888b6112fe565b90506140aa88611697888d6112fe565b9190500361403557815b888a6140c48a6116978a846112fe565b9050831015614107578261146a8b6116978c6140ec8561146a8f61169787916140f39b6112fe565b35966112fe565b3511613efe5761410290611d09565b6140b4565b505050919561414d909391936040898b838383019361412a8261146a87876112fe565b3561413c8361146a60608701876112fe565b3503614157575b5050505050611d09565b9591929092614079565b614182946141756114708461146a8761146a9661417b9901906112fe565b946112fe565b35906137a2565b38898b8383614143565b9795505091509160208401936141a4611021866112cf565b33036141b257505050505050565b6001600160401b03816141ef613ecc98610140613ec6950135926141e26141db6132d186615c20565b97836112fe565b93909260408101906112fe565b95909460401c1690612fbc565b60405190604082018281106001600160401b038211176103975760405260006020838281520152565b65ffffffffffff8091169081146119065760010190565b909160009060009261424c6141fc565b928491608081019161426d611470611e0f61426786866112fe565b90612232565b9487945b61427b85856112fe565b9050861015614418576142999061169d8761169760a08801886112fe565b97805b6142aa8761169788886112fe565b90508110156143f1576142dd6114236114158c846142d76142cf6101208c018c611c97565b92909361226b565b91611ced565b600160fb1b81146143d6578b614374575b6143269190600160fa1b810361432b575061277d61431a6143158c5165ffffffffffff1690565b614225565b65ffffffffffff168b52565b61429c565b600160f81b8114908115614366575b501561277d5761277d60208b0161435a614315825165ffffffffffff1690565b65ffffffffffff169052565b600360f81b1490503861433a565b90936143969061438f8661146a8b61169760c08c018c6112fe565b359061226b565b936143af6110216114708361146a8c6116978d8d6112fe565b6001600160a01b038a16036143c457906142ee565b604051637d617bb360e01b8152600490fd5b506143269061277d61431a6143158c5165ffffffffffff1690565b509761440b6144119196929661169d8461169789896112fe565b91611d09565b9490614271565b50959650965050505050565b906040516144318161039c565b915461ffff81168352601081901c6001600160a01b0316602084015260b01c60ff1615156040830152565b9190820391821161190657565b9192949390936144788161337a565b600181146146c0575b6144896120e2565b506144938161337a565b856002821493846000146146b95730935b6001600160f81b031916801580156146ac575b1561458d57506144da936144d592916001600160a01b038816614abd565b61337a565b6144e357505050565b6001600160a01b037f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b68116911681900361457b57803b1561017257604051632e1a7d4d60e01b815260048101849052906000908290602490829084905af18015610a3157600093849384938493614568575b505af1614560611d49565b501561202c57565b80610a2561457592610384565b38614555565b604051630f6f4f0d60e11b8152600490fd5b909150600160f81b8114801561469f575b1561464e57507f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b03166145d788615e07565b90803b1561017257604051631b63c28b60e11b81526001600160a01b0393841660048201529483166024860152908216604485015290851660648401526000908390818381608481015b03925af1918215610a31576144da9261463b575b5061337a565b80610a2561464892610384565b38614635565b91925050600160fb1b8114908115614691575b501561467f576144da906144d586866001600160a01b0387166128bf565b6040516312f269e560e01b8152600490fd5b600160fa1b14905038614661565b50600360f81b811461459e565b50600160f91b81146144b7565b86936144a4565b6001600160a01b037f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6811690851681900361457b57803b156101725760008791600460405180948193630d0e30db60e41b83525af18015610a3157614726575b50614481565b80610a2561473392610384565b38614720565b959295949193909461474a8361337a565b60018314614a44575b600061475d6120e2565b946001600160401b0381166149c9575b506147778461337a565b600284149485156149c25730935b6001600160f81b031916801580156149b5575b156148055750816147c0575b506144da93926144d5928992506001600160a01b038816614abd565b816144da9594996147f56144d595946147e560206147fa96015160018060a01b031690565b866001600160a01b038d16614abd565b61445c565b9792938192506147a4565b919890949391600160f81b811480156149a8575b156149755750881561493e57906148806148b86148398b6148c49561445c565b809b61489061486361485d602061484e612186565b9c01516001600160a01b031690565b92615e07565b61488061486e61043d565b6001600160a01b038b16815293610e22565b6001600160a01b03166040830152565b6001600160a01b038b1660608201526148a889611d18565b526148b288611d18565b50615e07565b91610e2261090461043d565b6001600160a01b03851660608201526148dc83611d25565b526148e682611d25565b507f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316803b1561017257604051630d58b1db60e01b81529260009184918290849082906146219060048301612278565b975092507f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b03166145d788615e07565b93945097505050600160fb1b811490811561469157501561467f576144da906144d586866001600160a01b0387166128bf565b50600360f81b8114614819565b50600160f91b8114614798565b8793614785565b6149dd9195506149d890610c0e565b614424565b936149eb6040860151151590565b80614a2c575b6149fc575b3861476d565b50614a27614a1f614a19614a12875161ffff1690565b61ffff1690565b8961190b565b612710900490565b6149f6565b5061ffff614a3c865161ffff1690565b1615156149f1565b6001600160a01b037f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6811690861681900361457b57803b156101725760008891600460405180948193630d0e30db60e41b83525af18015610a3157614aaa575b50614753565b80610a25614ab792610384565b38614aa4565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a08101918183106001600160401b038411176103975761043b926040526128f8565b9060609081906000805b60808601614b2d81886112fe565b9050821015614dd757614b65611423611415614b4d6101208b018b611c97565b6142d7614b5d60a08e018e6112fe565b90508861226b565b80158015614dca575b15614bde575090614bc0614b8f6110216114708461146a614bcd978d6112fe565b614b9b60208a016112cf565b614ba760408b016112cf565b90614bb98561146a60c08e018e6112fe565b3592614abd565b845180614bd25750611d09565b614b1f565b600019018552386114e8565b909290600160f81b81148015614dbd575b15614ce75750845115614cb7575b906114e8614bcd92614c9c6020614c8d8b614c198382016112cf565b98614c7c604091614c506114708b61146a614c358789016112cf565b94613fff614c4a8461146a60c08d018d6112fe565b35615e07565b95614c6b614c5c61043d565b6001600160a01b03909e168e52565b6001600160a01b03909116908c0152565b6001600160a01b0390911690890152565b6001600160a01b0316868a0152565b614ca581611d09565b94614cb08289611d35565b5286611d35565b9350806114e8614cdd614cd8614bcd94614cd1878c6112fe565b905061445c565b6121c0565b9591925050614bfd565b909290600160fa1b0361467f576114708261146a614d05938a6112fe565b6001600160a01b037f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6811692911682900361457b5760c08701614d4c8261146a838b6112fe565b3592803b15610172576004916000604095865194858092630d0e30db60e41b8252865af1928315610a31578461146a614d97614bcd988e614d9e95614da599614daa575b50016112cf565b938d6112fe565b35916128bf565b614bc0565b80610a25614db792610384565b38614d90565b50600360f81b8114614bef565b50600160f91b8114614b6e565b505050925090508051614de75750565b7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316803b1561017257604051630d58b1db60e01b8152916000918391829084908290614e3e9060048301612278565b03925af18015610a3157614e4f5750565b80610a2561043b92610384565b908151811015611ce8570160200190565b90969493919260009760609789976001600160401b03811615158091614e916120e2565b92615353575b508b5b858110614f4257505050505050505050614eb357505090565b815103614f30577f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316803b1561017257604051630d58b1db60e01b8152916000918391829084908290614f119060048301612278565b03925af18015610a3157614f23575090565b80610a256104fd92610384565b604051637f7dfe8b60e11b8152600490fd5b614f5081899e9d9c9e611d35565b519c85614f71611423614f638589614e5c565b516001600160f81b03191690565b6152bc575b8b156151be578c5115615197575b8361501c575b878d9e9f84614f998e92615e07565b92614fa392611cf9565b614fac906112cf565b90614fb561043d565b6001600160a01b038c168152926001600160a01b031660208401526001600160a01b031660408301526001600160a01b03166060820152819c614ff88e93611d09565b9d61500291611d35565b5261500d908d611d35565b5061501790611d09565b614e9a565b9060ff60f81b9e8f600760f81b90615037614f63878b614e5c565b161461517a57615058614a1f615052614a12895161ffff1690565b8361190b565b91821561515d5790828f8c9594938f8d602091828d015161507e9060018060a01b031690565b908b61508988615e07565b9361509392611cf9565b61509c906112cf565b926150a561043d565b6001600160a01b03909b168b526001600160a01b03909116908a01526001600160a01b031660408901526001600160a01b031660608801526150e681611d09565b966150f18284611d35565b526150fb91611d35565b506151059161445c565b9f600160fa1b90615116868a614e5c565b516001600160f81b0319161614615142575b50878d9e9f84614f998e925b9e5050509b9f9e5050614f8a565b8b8e9f6151518b93879261445c565b9f5050509d9c9d615128565b9291508d9e9f508b848f8b93614f99916000198151019052615134565b8d9e9f508b848f8b93614f99916000979697198151019052615134565b839c50836000146151b5576151ae614cd8896118ee565b9c50614f84565b6151ae886121c0565b889d9e919c9d888c8680615298575b6151f2575b916151ed6110216114708861277d97956150179a9997611cf9565b614abd565b61520d614a1f615207614a128b5161ffff1690565b8761190b565b80615219575b506151d2565b94908561524d946152356110216114708b85986147f597611cf9565b60208c01519091906001600160a01b03165b91614abd565b91600160fa1b6001600160f81b0319615269614f63878b614e5c565b1614615279575b888c8b92615213565b918b9f918a61528a86958c9561445c565b9d50509150919e9a9e615270565b50600760f81b6001600160f81b03196152b4614f63898d614e5c565b1614156151cd565b506001600160f81b0319600760f81b816152d9614f63868a614e5c565b16036152e6575030614f76565b909c90600160fa1b906152fc614f638589614e5c565b160361467f5761531061147083898d611cf9565b6001600160a01b037f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6811691160361457b578d61534c9161226b565b9b30614f76565b61536292506149d89150610c0e565b6040810151151580615375575b38614e97565b5061ffff615385825161ffff1690565b16151561536f565b94959792969197939093600097885b60808801906153af88611697848c6112fe565b9050811015615744578885898e868f821515908161573a575b501561571c576125266153ea926120778861146a8761169760c08c018c6112fe565b945b615412611423611415615403610120880188611c97565b6142d78a6040809a015161226b565b8015801561570f575b156154685750916152476114708361146a61544d6110216114708b61146a8c9a6154639f9c6116979061277d9f6112fe565b9561545a602082016112cf565b958101906112fe565b61539c565b9185969394959192600160f81b81148015615702575b1561557157505050602092858c858701615497906112cf565b96816154a5858301836112fe565b6154af9291611cf9565b6154b8906112cf565b956154c290615e07565b946154cc916112fe565b6154d69291612246565b6154e09291611cf9565b6154e9906112cf565b926154f261043d565b6001600160a01b0390961686526001600160a01b0316858501526001600160a01b03909116908401526001600160a01b031660608301528501805165ffffffffffff169061553f82614225565b65ffffffffffff16905265ffffffffffff169061555c8288611d35565b526155679086611d35565b5061546390611d09565b95839496600160fa959394951b811460001461569d57506114709261169761559d959361146a936112fe565b6001600160a01b037f000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6811691160361568c57826114e8926156478e61561b8f958f61146a6156116114708d61146a6154639f9e611697611470988f899361560a60209e8f0191825161226b565b90526112fe565b98878101906112fe565b9061563661562761042e565b6001600160a01b039097168752565b6001600160a01b0390911690850152565b82015265ffffffffffff615661885165ffffffffffff1690565b61567961566d82614225565b65ffffffffffff168a52565b16906156858288611d35565b5285611d35565b8151630f6f4f0d60e11b8152600490fd5b600160fb1b141593506156f1925050505783926114e8926156476156e66114708f958f906156dc6114706154639c61146a8561169761146a968e6112fe565b97868101906112fe565b610e2261090461042e565b81516312f269e560e01b8152600490fd5b50600360f81b811461547e565b50600160f91b811461541b565b50506157338461146a8361169760c08801886112fe565b35946153ec565b82841091506153c8565b505050505050945050505050565b9360ff929897969360e0969261010087019a60018060a01b03809216885216602087015260408601526060850152600160808501521660a083015260c08201520152565b916157aa6157a48280611c97565b90615c54565b936001600160a01b0390811692907f00000000000000000000000000000000000000000000000000000000000000001683036158fc577f0000000000000000000000000000000000000000000000000000000000028c5860890361589357604051632d0335ab60e01b81526001600160a01b038716600482015293602085602481875afa948515610a3157600095615873575b50833b1561017257614e3e6020936000979388946040519a8b998a9889976323f2ebc360e21b8952013591309060048901615752565b61588c91955060203d81116110ae5761109f81836103ed565b933861583d565b604051623f675f60e91b81526001600160a01b038716600482015293602085602481875afa948515610a31576000956158735750833b1561017257614e3e6020936000979388946040519a8b998a9889976323f2ebc360e21b8952013591309060048901615752565b9082959394953b156101725760405163d505accf60e01b81526001600160a01b0390941660048501523060248501526000196044850152602090940135606484015260ff909416608483015260a482019390935260c481019190915290600090829081838160e48101614e3e565b60405190615977826103d2565b600182528160005b602090818110156159a157602091615995612151565b9082850101520161597f565b505050565b3565ffffffffffff811681036101725790565b9493919492909260018060a01b0380941681526060602090808284015260c08301885196828086015287518092528360e086019801926000915b838310615a2e5750505050908701516001600160a01b031660808301525093946104fd94906040015160a082015260408185039101526133ba565b8451805182168b52808701518216878c015260408082015165ffffffffffff908116918d019190915290830151168a830152608090990198938501936001909201916159f3565b90615a8360a08301836112fe565b90509160005b60808201615a9781846112fe565b9050821015615b1357615aae610120840184611c97565b90615ad1615abb88611d09565b97600160f91b936001600160f81b031993611ced565b351614615ae75750615ae290611d09565b615a89565b61043b94509061146a615b0892602085013594615b0386610457565b6112fe565b359061120482610457565b5050505050565b90600091825b6080820193615b2f85846112fe565b9050821015615b1357615b4d9061169d8361169760a08701876112fe565b9360005b615b5f8361169784876112fe565b9050811015615bd65761141595615b98611423615b80610120880188611c97565b999093615b8c81611d09565b9a600160f91b95611ced565b14615bab57615ba690611d09565b615b51565b61043b955061146a615bd09361169761147094615bca602089016112cf565b976112fe565b90615796565b5050615be190611d09565b615b20565b60018116151591600460028316151592161515908380615c19575b615c0757565b6040516389702c9b60e01b8152600490fd5b5081615c01565b6003166104fd8161337a565b600460038216615c3b8161337a565b9116151591565b60ff601b9116019060ff821161190657565b90604103615cec57602081013591602182013591601b60ff841610615cdc575b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411615cca5760ff8316601b8114159081615cbe575b50615cac5735929190565b60405163f5d7a23b60e01b8152600490fd5b601c9150141538615ca1565b604051630696fe3b60e21b8152600490fd5b91615ce690615c42565b91615c74565b604051634be6321b60e01b8152600490fd5b15615d0557565b60405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606490fd5b15615d4257565b60405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606490fd5b91615d9081615d898161225d565b1015615cfe565b615da68351615d9f838561226b565b1115615d3b565b80615dbf57505050604051600081526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b808410615df45750508252601f01601f191660405290565b9092835181526020809101930190615ddc565b6001600160a01b0390818111615e1b571690565b60405163c4bd89a960e01b8152600490fdfea26469706673582212206d1f42fe032bb9158201fcf8f408851331d3fdb2799a6eeb085c91f81889dcf764736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _wrappedNativeToken (address): 0xA51894664A773981C6C112C43ce576f315d5b1B6
Arg [1] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [2] : _daiAddress (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000a51894664a773981c6c112c43ce576f315d5b1b6
Arg [1] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
[ 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.