Overview
ETH Balance
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,319 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Settle | 999439 | 6 hrs ago | IN | 0 ETH | 0.00000459 | ||||
Settle | 999401 | 6 hrs ago | IN | 0.00003 ETH | 0.00002249 | ||||
Settle | 999380 | 6 hrs ago | IN | 0.0000199 ETH | 0.00000236 | ||||
Settle | 998882 | 12 hrs ago | IN | 0.005 ETH | 0.00002415 | ||||
Settle Bebop Ble... | 998362 | 17 hrs ago | IN | 0 ETH | 0.00001782 | ||||
Settle Bebop Ble... | 998356 | 17 hrs ago | IN | 0 ETH | 0.00001608 | ||||
Settle Bebop Ble... | 998354 | 17 hrs ago | IN | 0 ETH | 0.00001857 | ||||
Settle Bebop Ble... | 998347 | 17 hrs ago | IN | 0 ETH | 0.00001618 | ||||
Settle Bebop Ble... | 998341 | 17 hrs ago | IN | 0 ETH | 0.00001791 | ||||
Settle Bebop Ble... | 998337 | 17 hrs ago | IN | 0 ETH | 0.00001608 | ||||
Settle | 998321 | 18 hrs ago | IN | 0 ETH | 0.0000032 | ||||
Settle Bebop Ble... | 998321 | 18 hrs ago | IN | 0 ETH | 0.00001955 | ||||
Settle | 998296 | 18 hrs ago | IN | 0.00020993 ETH | 0.00000247 | ||||
Settle | 998069 | 20 hrs ago | IN | 0.0001 ETH | 0.00002143 | ||||
Settle | 998061 | 20 hrs ago | IN | 0.000183 ETH | 0.00002448 | ||||
Settle Bebop Ble... | 998036 | 20 hrs ago | IN | 0 ETH | 0.0000193 | ||||
Settle | 998030 | 20 hrs ago | IN | 0.0104 ETH | 0.00002341 | ||||
Settle Bebop Ble... | 997259 | 29 hrs ago | IN | 0 ETH | 0.00002896 | ||||
Settle | 997161 | 30 hrs ago | IN | 0 ETH | 0.00000734 | ||||
Settle Bebop Ble... | 997050 | 31 hrs ago | IN | 0 ETH | 0.0000192 | ||||
Settle | 997047 | 31 hrs ago | IN | 0 ETH | 0.00000432 | ||||
Settle | 996530 | 37 hrs ago | IN | 0 ETH | 0.00000417 | ||||
Settle Bebop Ble... | 996516 | 37 hrs ago | IN | 0 ETH | 0.00002896 | ||||
Settle | 996440 | 38 hrs ago | IN | 0 ETH | 0.00001074 | ||||
Settle Bebop Ble... | 996140 | 41 hrs ago | IN | 0 ETH | 0.00001771 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
999401 | 6 hrs ago | 0.00003 ETH | ||||
999380 | 6 hrs ago | 0.0000199 ETH | ||||
998882 | 12 hrs ago | 0.005 ETH | ||||
998321 | 18 hrs ago | 0.0002056 ETH | ||||
998321 | 18 hrs ago | 0.0002056 ETH | ||||
998296 | 18 hrs ago | 0.00020993 ETH | ||||
998069 | 20 hrs ago | 0.0001 ETH | ||||
998061 | 20 hrs ago | 0.000183 ETH | ||||
998030 | 20 hrs ago | 0.0104 ETH | ||||
996530 | 37 hrs ago | 0.00638212 ETH | ||||
996530 | 37 hrs ago | 0.00638212 ETH | ||||
996440 | 38 hrs ago | 0.00065868 ETH | ||||
996440 | 38 hrs ago | 0.00065868 ETH | ||||
996236 | 40 hrs ago | 0.01182988 ETH | ||||
996236 | 40 hrs ago | 0.01182988 ETH | ||||
994849 | 2 days ago | 0.0446689 ETH | ||||
994849 | 2 days ago | 0.0446689 ETH | ||||
994702 | 2 days ago | 0.03175385 ETH | ||||
994702 | 2 days ago | 0.03175385 ETH | ||||
994648 | 2 days ago | 0.002 ETH | ||||
994648 | 2 days ago | 0.002 ETH | ||||
994568 | 2 days ago | 0.00487817 ETH | ||||
994568 | 2 days ago | 0.00487817 ETH | ||||
994242 | 2 days ago | 0.00032288 ETH | ||||
994242 | 2 days ago | 0.00032288 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
JamSettlement
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 1239 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "./base/JamValidation.sol"; import "./base/JamTransfer.sol"; import "./interfaces/IJamSettlement.sol"; import "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol"; /// @title JamSettlement /// @notice The settlement contract executes the full lifecycle of a trade on chain. /// Solvers figure out what "interactions" to pass to this contract such that the user order is fulfilled. /// The contract ensures that only the user agreed price can be executed and otherwise will fail to execute. /// As long as the trade is fulfilled, the solver is allowed to keep any potential excess. contract JamSettlement is IJamSettlement, ReentrancyGuard, JamValidation, JamTransfer { address public immutable bebopBlend; using BlendAggregateOrderLib for BlendAggregateOrder; using BlendMultiOrderLib for BlendMultiOrder; constructor(address _permit2, address _bebopBlend, address _treasuryAddress) JamPartner(_treasuryAddress) JamValidation(_permit2) { bebopBlend = _bebopBlend; } receive() external payable {} /// @inheritdoc IJamSettlement function settle( JamOrder calldata order, bytes calldata signature, JamInteraction.Data[] calldata interactions, bytes memory hooksData, address balanceRecipient ) external payable nonReentrant { JamHooks.Def memory hooks = hooksData.length != 0 ? abi.decode(hooksData, (JamHooks.Def)) : JamHooks.Def(new JamInteraction.Data[](0), new JamInteraction.Data[](0)); bytes32 hooksHash = hooksData.length != 0 ? JamHooks.hash(hooks) : JamHooks.EMPTY_HOOKS_HASH; validateOrder(order, signature, hooksHash); if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){ require(JamInteraction.runInteractionsM(hooks.beforeSettle, balanceManager), BeforeSettleHooksFailed()); } if (order.usingPermit2) { balanceManager.transferTokensWithPermit2(order, signature, hooksHash, balanceRecipient); } else { balanceManager.transferTokens(order.sellTokens, order.sellAmounts, order.taker, balanceRecipient); } require(JamInteraction.runInteractions(interactions, balanceManager), InteractionsFailed()); uint256[] memory buyAmounts = order.buyAmounts; transferTokensFromContract(order.buyTokens, order.buyAmounts, buyAmounts, order.receiver, order.partnerInfo, false); if (order.receiver == address(this)){ require(!hasDuplicates(order.buyTokens), DuplicateTokens()); } emit BebopJamOrderFilled( order.nonce, order.taker, order.sellTokens, order.buyTokens, order.sellAmounts, buyAmounts ); if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){ require(JamInteraction.runInteractionsM(hooks.afterSettle, balanceManager), AfterSettleHooksFailed()); } } /// @inheritdoc IJamSettlement function settleInternal( JamOrder calldata order, bytes calldata signature, uint256[] calldata filledAmounts, bytes memory hooksData ) external payable nonReentrant { JamHooks.Def memory hooks = hooksData.length != 0 ? abi.decode(hooksData, (JamHooks.Def)) : JamHooks.Def(new JamInteraction.Data[](0),new JamInteraction.Data[](0)); bytes32 hooksHash = hooksData.length != 0 ? JamHooks.hash(hooks) : JamHooks.EMPTY_HOOKS_HASH; validateOrder(order, signature, hooksHash); if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){ require(JamInteraction.runInteractionsM(hooks.beforeSettle, balanceManager), BeforeSettleHooksFailed()); } if (order.usingPermit2) { balanceManager.transferTokensWithPermit2(order, signature, hooksHash, msg.sender); } else { balanceManager.transferTokens(order.sellTokens, order.sellAmounts, order.taker, msg.sender); } if (order.partnerInfo == 0){ uint256[] calldata buyAmounts = validateFilledAmounts(filledAmounts, order.buyAmounts); balanceManager.transferTokens(order.buyTokens, buyAmounts, msg.sender, order.receiver); emit BebopJamOrderFilled(order.nonce, order.taker, order.sellTokens, order.buyTokens, order.sellAmounts, buyAmounts); } else { ( uint256[] memory buyAmounts, uint256[] memory protocolFees, uint256[] memory partnerFees, address partner ) = getUpdatedAmountsAndFees(filledAmounts, order.buyAmounts, order.partnerInfo); balanceManager.transferTokens(order.buyTokens, buyAmounts, msg.sender, order.receiver); if (protocolFees.length != 0){ balanceManager.transferTokens(order.buyTokens, protocolFees, msg.sender, protocolFeeAddress); } if (partnerFees.length != 0){ balanceManager.transferTokens(order.buyTokens, partnerFees, msg.sender, partner); } emit BebopJamOrderFilled(order.nonce, order.taker, order.sellTokens, order.buyTokens, order.sellAmounts, buyAmounts); } if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){ require(JamInteraction.runInteractionsM(hooks.afterSettle, balanceManager), AfterSettleHooksFailed()); } } /// @inheritdoc IJamSettlement function settleBatch( JamOrder[] calldata orders, bytes[] calldata signatures, JamInteraction.Data[] calldata interactions, JamHooks.Def[] calldata hooks, address balanceRecipient ) external payable nonReentrant { validateBatchOrders(orders, hooks, signatures); bool executeHooks = hooks.length != 0; for (uint i; i < orders.length; ++i) { if (executeHooks){ require(JamInteraction.runInteractions(hooks[i].beforeSettle, balanceManager), BeforeSettleHooksFailed()); } if (orders[i].usingPermit2) { balanceManager.transferTokensWithPermit2( orders[i], signatures[i], executeHooks ? JamHooks.hash(hooks[i]) : JamHooks.EMPTY_HOOKS_HASH, balanceRecipient ); } else { balanceManager.transferTokens(orders[i].sellTokens, orders[i].sellAmounts, orders[i].taker, balanceRecipient); } } require(JamInteraction.runInteractions(interactions, balanceManager), InteractionsFailed()); for (uint i; i < orders.length; ++i) { uint256[] memory buyAmounts = calculateNewAmounts(i, orders); transferTokensFromContract( orders[i].buyTokens, orders[i].buyAmounts, buyAmounts, orders[i].receiver, orders[i].partnerInfo, true ); emit BebopJamOrderFilled( orders[i].nonce, orders[i].taker, orders[i].sellTokens, orders[i].buyTokens, orders[i].sellAmounts, buyAmounts ); if (executeHooks){ require(JamInteraction.runInteractions(hooks[i].afterSettle, balanceManager), AfterSettleHooksFailed()); } } } /// @inheritdoc IJamSettlement function settleBebopBlend( address takerAddress, IBebopBlend.BlendOrderType orderType, bytes memory data, bytes memory hooksData ) external payable nonReentrant { JamHooks.Def memory hooks = hooksData.length != 0 ? abi.decode(hooksData, (JamHooks.Def)) : JamHooks.Def(new JamInteraction.Data[](0),new JamInteraction.Data[](0)); bytes32 hooksHash = hooksData.length != 0 ? JamHooks.hash(hooks) : JamHooks.EMPTY_HOOKS_HASH; if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){ require(JamInteraction.runInteractionsM(hooks.beforeSettle, balanceManager), BeforeSettleHooksFailed()); } if (orderType == IBebopBlend.BlendOrderType.Single){ ( BlendSingleOrder memory order, IBebopBlend.MakerSignature memory makerSignature, IBebopBlend.OldSingleQuote memory takerQuoteInfo, address makerAddress, uint256 newFlags, bytes memory takerSignature ) = abi.decode(data, (BlendSingleOrder, IBebopBlend.MakerSignature, IBebopBlend.OldSingleQuote, address, uint256, bytes)); balanceManager.transferTokenForBlendSingleOrder(order, takerQuoteInfo, takerSignature, takerAddress, hooksHash); order.maker_address = makerAddress; if (newFlags != 0){ require(uint64(order.flags >> 64) == uint64(newFlags >> 64), InvalidBlendPartnerId()); order.flags = newFlags; } approveToken(IERC20(order.taker_token), order.taker_amount, bebopBlend); IBebopBlend(bebopBlend).settleSingle(order, makerSignature, 0, takerQuoteInfo, "0x"); emit BebopBlendSingleOrderFilled( uint128(order.flags >> 128), order.receiver, order.taker_token, (order.packed_commands & 0x02) != 0 ? JamOrderLib.NATIVE_TOKEN : order.maker_token, order.taker_amount, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmount : order.maker_amount ); } else if (orderType == IBebopBlend.BlendOrderType.Multi){ ( BlendMultiOrder memory order, IBebopBlend.MakerSignature memory makerSignature, IBebopBlend.OldMultiQuote memory takerQuoteInfo, address makerAddress, uint256 newFlags, bytes memory takerSignature ) = abi.decode(data, (BlendMultiOrder, IBebopBlend.MakerSignature, IBebopBlend.OldMultiQuote, address, uint256, bytes)); balanceManager.transferTokensForMultiBebopOrder(order, takerQuoteInfo, takerSignature, takerAddress, hooksHash); order.maker_address = makerAddress; if (newFlags != 0){ require(uint64(order.flags >> 64) == uint64(newFlags >> 64), InvalidBlendPartnerId()); order.flags = newFlags; } for (uint i; i < order.taker_tokens.length; ++i) { approveToken(IERC20(order.taker_tokens[i]), order.taker_amounts[i], bebopBlend); } IBebopBlend(bebopBlend).settleMulti(order, makerSignature, 0, takerQuoteInfo, "0x"); emit BebopBlendMultiOrderFilled( uint128(order.flags >> 128), order.receiver, order.taker_tokens, order.getMakerTokens(), order.taker_amounts, takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts ); } else if (orderType == IBebopBlend.BlendOrderType.Aggregate){ ( BlendAggregateOrder memory order, IBebopBlend.MakerSignature[] memory makerSignatures, IBebopBlend.OldAggregateQuote memory takerQuoteInfo, uint256 newFlags, bytes memory takerSignature ) = abi.decode(data, (BlendAggregateOrder, IBebopBlend.MakerSignature[], IBebopBlend.OldAggregateQuote, uint256, bytes)); balanceManager.transferTokensForAggregateBebopOrder(order, takerQuoteInfo, takerSignature, takerAddress, hooksHash); if (newFlags != 0){ require(uint64(order.flags >> 64) == uint64(newFlags >> 64), InvalidBlendPartnerId()); order.flags = newFlags; } (address[] memory tokens, uint256[] memory amounts) = order.unpackTokensAndAmounts(true, takerQuoteInfo); for (uint i; i < tokens.length; ++i) { approveToken(IERC20(tokens[i]), amounts[i], bebopBlend); } IBebopBlend(bebopBlend).settleAggregate(order, makerSignatures, 0, takerQuoteInfo, "0x"); (address[] memory buyTokens, uint256[] memory buyAmounts) = order.unpackTokensAndAmounts(false, takerQuoteInfo); emit BebopBlendAggregateOrderFilled( uint128(order.flags >> 128), order.receiver, tokens, buyTokens, amounts, buyAmounts ); } else { revert InvalidBlendOrderType(); } if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){ require(JamInteraction.runInteractionsM(hooks.afterSettle, balanceManager), AfterSettleHooksFailed()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ 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 (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; /// @notice Thrown when solver sends less than expected to settlement contract error InvalidOutputBalance(address token, uint256 expected, uint256 actual); /// @notice Thrown when sending ETH via call fails error FailedToSendEth(); /// @notice Thrown when the passed in signature is not a valid length error InvalidSignatureLength(); /// @notice Thrown when the recovered signer is equal to the zero address error InvalidSignature(); /// @notice Thrown when the recovered signer does not equal the claimedSigner error InvalidSigner(); /// @notice Thrown when the recovered contract signature is incorrect error InvalidContractSignature(); /// @notice Thrown when msg.sender is not allowed to call a function error InvalidExecutor(); /// @notice Thrown when length of sell tokens and sell amounts are not equal error SellTokensInvalidLength(); /// @notice Thrown when length of buy tokens and buy amounts are not equal error BuyTokensInvalidLength(); /// @notice Thrown when order is expired error OrderExpired(); /// @notice Thrown when nonce is already invalidated error InvalidNonce(); /// @notice Thrown when nonce is zero error ZeroNonce(); /// @notice Thrown when length of filled amounts is not equal to tokens length error InvalidFilledAmountsLength(); /// @notice Thrown when filled amounts is less than previous amount error InvalidFilledAmounts(uint256 expected, uint256 actual); /// @notice Thrown when length of signatures array is not equal to batch length error InvalidBatchSignaturesLength(); /// @notice Thrown when length of hooks array is not equal to batch length error InvalidBatchHooksLength(); /// @notice Thrown when one of the orders in batch has settlement contract as receiver error InvalidReceiverInBatch(); /// @notice Thrown when different fees are passed in batch error DifferentFeesInBatch(); /// @notice Thrown when invalid partner address is passed error InvalidPartnerAddress(); /// @notice Thrown when caller is not settlement contract error InvalidCaller(); /// @notice Thrown when interactions failed error InteractionsFailed(); /// @notice Thrown when beforeSettle hooks failed error BeforeSettleHooksFailed(); /// @notice Thrown when beforeSettle hooks failed error AfterSettleHooksFailed(); /// @notice Thrown for unknown blend order type error InvalidBlendOrderType(); /// @notice Thrown when invalid fee percentage is passed error InvalidFeePercentage(); /// @notice Thrown when interactions contain call to balance manager error CallToBalanceManagerNotAllowed(); /// @notice Thrown when there are duplicate buy tokens in the order error DuplicateTokens(); /// @notice Thrown when new partner-id is different from the current one error InvalidBlendPartnerId();
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../base/Errors.sol"; import "../libraries/JamOrder.sol"; import "../external-libs/SafeTransferLib.sol"; /// @title JamPartner abstract contract JamPartner { uint16 internal constant HUNDRED_PERCENT = 10000; // 100% in bps address internal immutable protocolFeeAddress; event NativeTransfer(address indexed receiver, uint256 amount); using SafeTransferLib for IERC20; constructor(address _protocolFeeAddress){ protocolFeeAddress = _protocolFeeAddress; } /// @notice Distribute fees to the partner and protocol, fees are optional /// @param partnerInfo The partner info, packed with the partner address, partner fee and protocol fee /// @param token The token to distribute fees in /// @param amount Token amount in order to distribute fees from /// @return totalFeesSent The total amount of tokens sent as fees function distributeFees(uint256 partnerInfo, address token, uint256 amount) internal returns (uint256 totalFeesSent){ (address partnerAddress, uint16 partnerFee, uint16 protocolFee) = unpackPartnerInfo(partnerInfo); if (partnerFee > 0) { totalFeesSent += sendPartnerFee(token, amount, partnerFee, partnerAddress); } if (protocolFee > 0) { totalFeesSent += sendPartnerFee(token, amount, protocolFee, protocolFeeAddress); } return totalFeesSent; } /// @notice Unpack the partner info /// @param partnerInfo Packed info: [ .... | address | uint16 | uint16 ] function unpackPartnerInfo(uint256 partnerInfo) private pure returns (address, uint16, uint16) { uint16 protocolFeeBps = uint16(partnerInfo & 0xFFFF); uint16 partnerFeeBps = uint16((partnerInfo >> 16) & 0xFFFF); address partnerAddress = address(uint160(partnerInfo >> 32)); require(partnerFeeBps + protocolFeeBps < HUNDRED_PERCENT, InvalidFeePercentage()); require(partnerFeeBps > 0 || (partnerFeeBps == 0 && partnerAddress == address(0)), InvalidPartnerAddress()); return (partnerAddress, partnerFeeBps, protocolFeeBps); } /// @notice Send the partner fee /// @param token The token to send /// @param amount The amount to send /// @param fee The fee percentage /// @param receiver The receiver of the fee /// @return feeAmount The amount of fee sent function sendPartnerFee(address token, uint256 amount, uint16 fee, address receiver) private returns (uint256){ uint256 feeAmount = amount * fee / HUNDRED_PERCENT; if (token == JamOrderLib.NATIVE_TOKEN) { (bool sent, ) = payable(receiver).call{value: feeAmount}(""); require(sent, FailedToSendEth()); emit NativeTransfer(receiver, feeAmount); } else { IERC20(token).safeTransfer(receiver, feeAmount); } return feeAmount; } /// @notice Get total fees in bps /// @param partnerInfo The partner info /// @return totalFeesBps The total fees in bps function getTotalFeesBps(uint256 partnerInfo) internal pure returns (uint16){ uint16 protocolFeeBps = uint16(partnerInfo & 0xFFFF); uint16 partnerFeeBps = uint16((partnerInfo >> 16) & 0xFFFF); return protocolFeeBps + partnerFeeBps; } /// @notice Get arrays with fees amounts for each token /// @param amounts The amounts to calculate fees for /// @param minAmounts Minimum amounts that user signed for /// @param partnerInfo The partner info /// @return newAmounts The new amounts after fees /// @return protocolFees The protocol fees, if empty then no protocol fees /// @return partnerFees The partner fees, if empty then no partner fees /// @return partnerAddress The partner address, or zero address if no partner fees function getUpdatedAmountsAndFees( uint256[] calldata amounts, uint256[] calldata minAmounts, uint256 partnerInfo ) internal pure returns (uint256[] memory newAmounts, uint256[] memory protocolFees, uint256[] memory partnerFees, address) { (address partnerAddress, uint16 partnerFee, uint16 protocolFee) = unpackPartnerInfo(partnerInfo); uint tokensLength = amounts.length; require(minAmounts.length == tokensLength, InvalidFilledAmountsLength()); newAmounts = new uint256[](tokensLength); if (protocolFee > 0) { protocolFees = new uint256[](tokensLength); for (uint256 i; i < tokensLength; ++i) { protocolFees[i] = amounts[i] * protocolFee / HUNDRED_PERCENT; newAmounts[i] = amounts[i] - protocolFees[i]; } } if (partnerFee > 0) { partnerFees = new uint256[](tokensLength); for (uint256 i; i < tokensLength; ++i) { partnerFees[i] = amounts[i] * partnerFee / HUNDRED_PERCENT; newAmounts[i] = newAmounts[i] == 0 ? amounts[i] - partnerFees[i] : newAmounts[i] - partnerFees[i]; } } for (uint256 i; i < tokensLength; ++i) { require(newAmounts[i] >= minAmounts[i], InvalidFilledAmounts(minAmounts[i], newAmounts[i])); } return (newAmounts, protocolFees, partnerFees, partnerAddress); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "./JamPartner.sol"; /// @title JamTransfer /// @notice Functions for transferring tokens from SettlementContract abstract contract JamTransfer is JamPartner { using SafeTransferLib for IERC20; /// @dev Check if token is approved for spender, max approve if not /// max approval is fine for settlement contract, because we use BalanceManager for users approvals /// @param token token's address /// @param amount transfer amount /// @param spender spender's address, in our case it will BebopBlend contract function approveToken(IERC20 token, uint256 amount, address spender) internal { uint256 allowance = token.allowance(address(this), spender); if (allowance < amount) { token.safeApproveWithRetry(spender, type(uint256).max); } } /// @dev After solver settlement, transfer tokens from this contract to receiver /// @param tokens tokens' addresses /// @param minAmounts minimum amounts from order /// @param amounts tokens' filled amounts /// @param receiver address /// @param transferExactAmounts if true, transfer exact amounts, otherwise transfer full tokens balance function transferTokensFromContract( address[] calldata tokens, uint256[] calldata minAmounts, uint256[] memory amounts, address receiver, uint256 partnerInfo, bool transferExactAmounts ) internal { for (uint i; i < tokens.length; ++i) { if (!transferExactAmounts) { amounts[i] = tokens[i] == JamOrderLib.NATIVE_TOKEN ? address(this).balance : IERC20(tokens[i]).balanceOf(address(this)); } if (partnerInfo != 0){ amounts[i] -= distributeFees(partnerInfo, tokens[i], amounts[i]); } require(amounts[i] >= minAmounts[i], InvalidOutputBalance(tokens[i], minAmounts[i], amounts[i])); if (tokens[i] == JamOrderLib.NATIVE_TOKEN) { (bool sent, ) = payable(receiver).call{value: amounts[i]}(""); require(sent, FailedToSendEth()); emit NativeTransfer(receiver, amounts[i]); } else { IERC20(tokens[i]).safeTransfer(receiver, amounts[i]); } } } /// @dev Transfer native tokens to receiver from this contract /// @param receiver address /// @param amount amount of native tokens function transferNativeFromContract(address receiver, uint256 amount) public { (bool sent, ) = payable(receiver).call{value: amount}(""); require(sent, FailedToSendEth()); } /// @dev Calculate new amounts of tokens if solver transferred excess to contract during settleBatch /// @param curInd index of current order /// @param orders array of orders /// @return array of new amounts function calculateNewAmounts(uint256 curInd, JamOrder[] calldata orders) internal view returns (uint256[] memory) { JamOrder calldata curOrder = orders[curInd]; uint256[] memory newAmounts = new uint256[](curOrder.buyTokens.length); for (uint i; i < curOrder.buyTokens.length; ++i) { uint256 fullAmount; for (uint j = curInd; j < orders.length; ++j) { for (uint k; k < orders[j].buyTokens.length; ++k) { if (orders[j].buyTokens[k] == curOrder.buyTokens[i]) { fullAmount += orders[j].buyAmounts[k]; require( getTotalFeesBps(curOrder.partnerInfo) == getTotalFeesBps(orders[j].partnerInfo), DifferentFeesInBatch() ); } } } uint256 tokenBalance = curOrder.buyTokens[i] == JamOrderLib.NATIVE_TOKEN ? address(this).balance : IERC20(curOrder.buyTokens[i]).balanceOf(address(this)); // if at least two takers buy same token, we need to divide the whole tokenBalance among them. // for edge case with newAmounts[i] overflow, solver shouldn't submit txs in a batch newAmounts[i] = tokenBalance * curOrder.buyAmounts[i] / fullAmount; if (newAmounts[i] < curOrder.buyAmounts[i]) { newAmounts[i] = curOrder.buyAmounts[i]; } } return newAmounts; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../base/Errors.sol"; import "../libraries/JamOrder.sol"; import "../libraries/JamHooks.sol"; import "../JamBalanceManager.sol"; import "lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol"; import "lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol"; /// @title JamValidation /// @notice Functions which handles the signing and validation of Jam orders abstract contract JamValidation is IERC5267 { mapping(address => mapping(uint256 => uint256)) private standardNonces; mapping(address => mapping(uint256 => uint256)) private limitOrdersNonces; uint256 private constant INF_EXPIRY = 9999999999; // expiry for limit orders string public constant DOMAIN_NAME = "JamSettlement"; string public constant DOMAIN_VERSION = "2"; bytes32 private constant UPPER_BIT_MASK = (0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); bytes4 private constant EIP1271_MAGICVALUE = bytes4(keccak256("isValidSignature(bytes32,bytes)")); bytes32 public constant EIP712_DOMAIN_TYPEHASH = keccak256(abi.encodePacked( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" )); IJamBalanceManager public immutable balanceManager; IPermit2 private immutable PERMIT2; bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; using JamOrderLib for JamOrder; constructor(address _permit2){ balanceManager = new JamBalanceManager(address(this), _permit2); _CACHED_CHAIN_ID = block.chainid; _CACHED_DOMAIN_SEPARATOR = keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(DOMAIN_NAME)), keccak256(bytes(DOMAIN_VERSION)), block.chainid, address(this)) ); PERMIT2 = IPermit2(_permit2); } /// @notice The domain separator used in the order validation signature /// @return The domain separator used in encoding of order signature function DOMAIN_SEPARATOR() public view returns (bytes32) { return block.chainid == _CACHED_CHAIN_ID ? _CACHED_DOMAIN_SEPARATOR : keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(DOMAIN_NAME)), keccak256(bytes(DOMAIN_VERSION)), block.chainid, address(this)) ); } /// @notice ERC5267 implementation for requesting the EIP712 domain values function eip712Domain() public view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ){ return (hex"0f", DOMAIN_NAME, DOMAIN_VERSION, block.chainid, address(this), bytes32(0), new uint256[](0)); } /// @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 function validateSignature(address validationAddress, bytes32 hash, bytes calldata signature) public view { bytes32 r; bytes32 s; uint8 v; if (validationAddress.code.length == 0) { if (signature.length == 65) { (r, s) = abi.decode(signature, (bytes32, bytes32)); v = uint8(signature[64]); } else if (signature.length == 64) { // EIP-2098 bytes32 vs; (r, vs) = abi.decode(signature, (bytes32, bytes32)); s = vs & UPPER_BIT_MASK; v = uint8(uint256(vs >> 255)) + 27; } else { revert InvalidSignatureLength(); } address signer = ecrecover(hash, v, r, s); if (signer == address(0)) revert InvalidSignature(); if (signer != validationAddress) revert InvalidSigner(); } else { bytes4 magicValue = IERC1271(validationAddress).isValidSignature(hash, signature); if (magicValue != EIP1271_MAGICVALUE) revert InvalidContractSignature(); } } /// @notice Hash hooks and return the hash /// @param hooks The hooks to hash function hashHooks(JamHooks.Def calldata hooks) external pure returns (bytes32) { return JamHooks.hash(hooks); } /// @notice Hash Jam order and return the hash /// @param order The order to hash /// @param hooksHash The hash of the hooks to include in the order hash, 0x000..00 if no hooks function hashJamOrder(JamOrder calldata order, bytes32 hooksHash) external view returns (bytes32) { if (order.usingPermit2){ return keccak256(abi.encodePacked( "\x19\x01", PERMIT2.DOMAIN_SEPARATOR(), order.permit2OrderHash(hooksHash, address(balanceManager)) )); } else { return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), order.hash(hooksHash))); } } /// @notice Cancel limit order by invalidating nonce for the sender address /// @param nonce The nonce to invalidate function cancelLimitOrder(uint256 nonce) external { invalidateOrderNonce(msg.sender, nonce, true); } /// @notice Check if taker's limit order nonce is valid /// @param taker address /// @param nonce to check /// @return True if nonce is valid function isLimitOrderNonceValid(address taker, uint256 nonce) external view returns (bool) { uint256 invalidatorSlot = nonce >> 8; uint256 invalidatorBit = 1 << (nonce & 0xff); return (limitOrdersNonces[taker][invalidatorSlot] & invalidatorBit) == 0; } /// @notice Validate order data and in case of standard approvals validate the signature /// @param order The order to validate /// @param signature The signature to validate /// @param hooksHash The hash of the hooks to include in the order hash function validateOrder(JamOrder calldata order, bytes calldata signature, bytes32 hooksHash) internal { // Allow settle from user without sig; For permit2 case, we already validated witness during the transfer if (order.taker != msg.sender && !order.usingPermit2) { bytes32 orderHash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), order.hash(hooksHash))); validateSignature(order.taker, orderHash, signature); } if (!order.usingPermit2 || order.expiry == INF_EXPIRY){ invalidateOrderNonce(order.taker, order.nonce, order.expiry == INF_EXPIRY); } require( order.executor == msg.sender || order.executor == address(0) || block.timestamp > order.exclusivityDeadline, InvalidExecutor() ); require(order.buyTokens.length == order.buyAmounts.length, BuyTokensInvalidLength()); require(order.sellTokens.length == order.sellAmounts.length, SellTokensInvalidLength()); require(block.timestamp < order.expiry, OrderExpired()); } /// @notice Check if nonce is valid and invalidate it /// @param taker address /// @param nonce The nonce to invalidate /// @param isLimitOrder True if it is a limit order function invalidateOrderNonce(address taker, uint256 nonce, bool isLimitOrder) private { require(nonce != 0, ZeroNonce()); uint256 invalidatorSlot = nonce >> 8; uint256 invalidatorBit = 1 << (nonce & 0xff); mapping(uint256 => uint256) storage invalidNonces = isLimitOrder ? limitOrdersNonces[taker] : standardNonces[taker]; uint256 invalidator = invalidNonces[invalidatorSlot]; require(invalidator & invalidatorBit != invalidatorBit, InvalidNonce()); invalidNonces[invalidatorSlot] = invalidator | invalidatorBit; } /// @notice validate if filled amounts are more than initial amounts that user signed /// @param filledAmounts The increased amounts to validate (if empty, return initial amounts) /// @param initialAmounts The initial amounts to validate against /// @return The filled amounts if exist, otherwise the initial amounts function validateFilledAmounts( uint256[] calldata filledAmounts, uint256[] calldata initialAmounts ) internal pure returns (uint256[] calldata){ if (filledAmounts.length == 0) { return initialAmounts; } require(filledAmounts.length == initialAmounts.length, InvalidFilledAmountsLength()); for (uint256 i; i < filledAmounts.length; ++i) { require(filledAmounts[i] >= initialAmounts[i], InvalidFilledAmounts(initialAmounts[i], filledAmounts[i])); } return filledAmounts; } /// @notice Validate batch data and all orders in a batch /// @param orders The orders to validate /// @param hooks The array of hooks corresponding to each order, or empty array if no hooks /// @param signatures The signatures corresponding to each order function validateBatchOrders( JamOrder[] calldata orders, JamHooks.Def[] calldata hooks, bytes[] calldata signatures ) internal { bool noHooks = hooks.length == 0; require(orders.length == signatures.length, InvalidBatchSignaturesLength()); require(orders.length == hooks.length || noHooks, InvalidBatchHooksLength()); for (uint i; i < orders.length; ++i) { require(orders[i].receiver != address(this), InvalidReceiverInBatch()); validateOrder(orders[i], signatures[i], noHooks ? JamHooks.EMPTY_HOOKS_HASH : JamHooks.hash(hooks[i])); } } /// @notice Check if there are any duplicates in the array of tokens /// @param tokens The array of tokens to validate /// @return True if there are duplicates function hasDuplicates(address[] calldata tokens) internal pure returns (bool) { for (uint i; i < tokens.length - 1; ++i) { for (uint j = i + 1; j < tokens.length; ++j) { if (tokens[i] == tokens[j]) { return true; } } } return false; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../interfaces/IPermit2.sol"; // from PermitHash.sol in Permit2 // https://github.com/Uniswap/permit2/blob/main/src/libraries/PermitHash.sol library PermitHash { bytes32 private constant _TOKEN_PERMISSIONS_TYPEHASH = keccak256("TokenPermissions(address token,uint256 amount)"); string private constant _PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB = "PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,"; function hashWithWitness( IPermit2.PermitBatchTransferFrom memory permit, bytes32 witness, string memory witnessTypeString, address spender ) internal pure returns (bytes32) { bytes32 typeHash = keccak256(abi.encodePacked(_PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB, witnessTypeString)); uint256 numPermitted = permit.permitted.length; bytes32[] memory tokenPermissionHashes = new bytes32[](numPermitted); for (uint256 i = 0; i < numPermitted; ++i) { tokenPermissionHashes[i] = _hashTokenPermissions(permit.permitted[i]); } return keccak256( abi.encode( typeHash, keccak256(abi.encodePacked(tokenPermissionHashes)), spender, permit.nonce, permit.deadline, witness ) ); } function _hashTokenPermissions(IPermit2.TokenPermissions memory permitted) private pure returns (bytes32){ return keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permitted)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; /// @notice Safe ERC20 transfer library that gracefully handles missing return values. /// From: Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// https://github.com/Vectorized/solady/blob/main/src/utils/SafeTransferLib.sol library SafeTransferLib { /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( IERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(IERC20 token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../libraries/BlendSingleOrder.sol"; import "../libraries/BlendMultiOrder.sol"; import "../libraries/BlendAggregateOrder.sol"; /// @title IBebopBlend is interface for interacting with BebopBlend contract, which aggregates PMM liquidity. /// Swaps through that contract have zero slippage. /// Deployed on 0xbbbbbBB520d69a9775E85b458C58c648259FAD5F interface IBebopBlend { enum BlendOrderType { Single, // 0 Multi, // 1 Aggregate // 2 } struct OldSingleQuote { bool useOldAmount; uint256 makerAmount; uint256 makerNonce; } struct OldMultiQuote { bool useOldAmount; uint256[] makerAmounts; uint256 makerNonce; } struct OldAggregateQuote { bool useOldAmount; uint256[][] makerAmounts; uint256[] makerNonces; } struct MakerSignature { bytes signatureBytes; uint256 flags; } /// @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( BlendSingleOrder calldata order, MakerSignature calldata makerSignature, uint256 filledTakerAmount, OldSingleQuote calldata takerQuoteInfo, bytes calldata takerSignature ) 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( BlendMultiOrder calldata order, MakerSignature calldata makerSignature, uint256 filledTakerAmount, OldMultiQuote calldata takerQuoteInfo, bytes calldata takerSignature ) 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( BlendAggregateOrder calldata order, MakerSignature[] calldata makersSignatures, uint256 filledTakerAmount, OldAggregateQuote calldata takerQuoteInfo, bytes calldata takerSignature ) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../libraries/JamOrder.sol"; import "../libraries/BlendSingleOrder.sol"; import "../libraries/BlendMultiOrder.sol"; import "../libraries/BlendAggregateOrder.sol"; import "./IBebopBlend.sol"; /// @title IJamBalanceManager /// @notice User approvals are made here. This handles the complexity of multiple allowance types. interface IJamBalanceManager { /// @dev Transfer user's tokens to receiver address for JamOrder /// @param order user signed order /// @param signature permit2 signature with order as witness /// @param hooksHash hash of hooks data /// @param receiver address to receive tokens, it can be operator address or solver address function transferTokensWithPermit2( JamOrder calldata order, bytes calldata signature, bytes32 hooksHash, address receiver ) external; /// @dev Transfer tokens to receiver address /// this function can be used not only for user's tokens, but also for maker's tokens in settleInternal /// @param tokens list of tokens to transfer /// @param amounts list of amounts to transfer /// @param sender address to transfer tokens from /// @param receiver address to transfer tokens to function transferTokens( address[] calldata tokens, uint256[] calldata amounts, address sender, address receiver ) external; /// @dev Transfer user's tokens to operator address for BlendSingleOrder /// @param order user signed order /// @param oldSingleQuote in case of amounts improvement, old quote is used to get old amounts signed by user /// @param takerSignature permit2 signature with order as witness /// @param takerAddress user address /// @param hooksHash hash of hooks data function transferTokenForBlendSingleOrder( BlendSingleOrder memory order, IBebopBlend.OldSingleQuote memory oldSingleQuote, bytes memory takerSignature, address takerAddress, bytes32 hooksHash ) external; /// @dev Transfer user's tokens to operator address for BlendMultiOrder /// @param order user signed order /// @param oldMultiQuote in case of amounts improvement, old quote is used to get old amounts signed by user /// @param takerSignature permit2 signature with order as witness /// @param takerAddress user address /// @param hooksHash hash of hooks data function transferTokensForMultiBebopOrder( BlendMultiOrder memory order, IBebopBlend.OldMultiQuote memory oldMultiQuote, bytes memory takerSignature, address takerAddress, bytes32 hooksHash ) external; /// @dev Transfer user's tokens to operator address for BlendAggregateOrder /// @param order user signed order /// @param oldAggregateQuote in case of amounts improvement, old quote is used to get old amounts signed by user /// @param takerSignature permit2 signature with order as witness /// @param takerAddress user address /// @param hooksHash hash of hooks data function transferTokensForAggregateBebopOrder( BlendAggregateOrder memory order, IBebopBlend.OldAggregateQuote memory oldAggregateQuote, bytes memory takerSignature, address takerAddress, bytes32 hooksHash ) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../libraries/JamInteraction.sol"; import "../libraries/JamOrder.sol"; import "../libraries/JamHooks.sol"; interface IJamSettlement { /// @dev Event emitted when a settlement of JamOrder is executed successfully event BebopJamOrderFilled( uint256 indexed nonce, address indexed user, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts ); /// @dev Event with same eventId as will be emitted by the BebopBlend contract for SingleOrder using Order.extractEventId() event BebopBlendSingleOrderFilled( uint128 indexed eventId, address indexed receiver, address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount ); /// @dev Event with same eventId as will be emitted by the BebopBlend contract for MultiOrder using Order.extractEventId() event BebopBlendMultiOrderFilled( uint128 indexed eventId, address indexed receiver, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts ); /// @dev Event with same eventId as will be emitted by the BebopBlend contract for AggregateOrder using Order.extractEventId() event BebopBlendAggregateOrderFilled( uint128 indexed eventId, address indexed receiver, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts ); /// @dev Settle a jam order. /// Pulls sell tokens into the contract and ensures that after running interactions receiver has the minimum of buy /// @param order user signed order /// @param signature user signature /// @param interactions list of interactions to settle the order /// @param hooksData encoded hooks for pre and post interactions, empty if no hooks /// @param balanceRecipient solver specifies this address to receive the initial tokens from user function settle( JamOrder calldata order, bytes calldata signature, JamInteraction.Data[] calldata interactions, bytes memory hooksData, address balanceRecipient ) external payable; /// @dev Settle a jam order without interactions, just using balance of executor /// @param order user signed order /// @param signature user signature /// @param filledAmounts amounts that maker is transferring to taker /// @param hooksData encoded hooks for pre and post interactions, empty if no hooks function settleInternal( JamOrder calldata order, bytes calldata signature, uint256[] calldata filledAmounts, bytes memory hooksData ) external payable; /// @dev Settle a batch of orders. /// Pulls sell tokens into the contract and ensures that after running interactions receivers have the minimum of buy /// @param orders takers signed orders /// @param signatures takers signatures /// @param interactions list of interactions to settle the order /// @param hooks pre and post takers interactions, if empty then no interactions are run /// @param balanceRecipient solver specifies this address to receive the initial tokens from users function settleBatch( JamOrder[] calldata orders, bytes[] calldata signatures, JamInteraction.Data[] calldata interactions, JamHooks.Def[] calldata hooks, address balanceRecipient ) external payable; /// @dev Execute order on BebopBlend contract /// Using this contract as entry point for executing BebopBlend orders /// @param takerAddress address of the user /// @param orderType type of the order, Single, Multi or Aggregate /// @param data encoded order data, order has same structure as in BebopBlend contract /// @param hooksData encoded hooks for pre and post interactions, empty if no hooks function settleBebopBlend( address takerAddress, IBebopBlend.BlendOrderType orderType, bytes memory data, bytes memory hooksData ) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; // Part of ISignatureTransfer(https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol) interface IPermit2 { /// @notice The token and amount details for a transfer signed in the permit transfer signature struct TokenPermissions { // ERC20 token address address token; // the maximum amount that can be spent uint256 amount; } /// @notice The signed permit message for a single token transfer struct PermitTransferFrom { TokenPermissions permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice Used to reconstruct the signed permit message for multiple token transfers /// @dev Do not need to pass in spender address as it is required that it is msg.sender /// @dev Note that a user still signs over a spender address struct PermitBatchTransferFrom { // the tokens and corresponding amounts permitted for a transfer TokenPermissions[] permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice Specifies the recipient address and amount for batched transfers. /// @dev Recipients and amounts correspond to the index of the signed token permissions array. /// @dev Reverts if the requested amount is greater than the permitted signed amount. struct SignatureTransferDetails { // recipient address address to; // spender requested amount uint256 requestedAmount; } /// @notice Transfers a token using a signed permit message /// @notice Includes extra data provided by the caller to verify signature over /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; /// @notice Transfers multiple tokens using a signed permit message /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @notice Includes extra data provided by the caller to verify signature over /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails Specifies the recipient and requested amount for the token transfer /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitBatchTransferFrom memory permit, SignatureTransferDetails[] calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "./base/JamTransfer.sol"; import "./interfaces/IJamBalanceManager.sol"; import "./interfaces/IPermit2.sol"; /// @title JamBalanceManager /// @notice The reason a balance manager exists is to prevent interaction to the settlement contract draining user funds /// By having another contract that allowances are made to, we can enforce that it is only used to draw in user balances to settlement and not sent out contract JamBalanceManager is IJamBalanceManager { using SafeTransferLib for IERC20; using JamOrderLib for JamOrder; using BlendSingleOrderLib for BlendSingleOrder; using BlendMultiOrderLib for BlendMultiOrder; using BlendAggregateOrderLib for BlendAggregateOrder; address private immutable operator; IPermit2 private immutable PERMIT2; constructor(address _operator, address _permit2) { // Operator can be defined at creation time with `msg.sender` // Pass in the settlement - and that can be the only caller. operator = _operator; PERMIT2 = IPermit2(_permit2); } modifier onlyOperator(address account) { require(account == operator, InvalidCaller()); _; } /// @inheritdoc IJamBalanceManager function transferTokensWithPermit2( JamOrder calldata order, bytes calldata signature, bytes32 hooksHash, address receiver ) onlyOperator(msg.sender) external { PERMIT2.permitWitnessTransferFrom( order.toBatchPermit2(), order.toSignatureTransferDetails(receiver), order.taker, order.hash(hooksHash), JamOrderLib.PERMIT2_ORDER_TYPE, signature ); } /// @inheritdoc IJamBalanceManager function transferTokens( address[] calldata tokens, uint256[] calldata amounts, address sender, address receiver ) onlyOperator(msg.sender) external { for (uint i; i < tokens.length; ++i){ if (tokens[i] != JamOrderLib.NATIVE_TOKEN){ IERC20(tokens[i]).safeTransferFrom(sender, receiver, amounts[i]); } else if (receiver != operator){ JamTransfer(operator).transferNativeFromContract(receiver, amounts[i]); } } } /// @inheritdoc IJamBalanceManager function transferTokenForBlendSingleOrder( BlendSingleOrder memory order, IBebopBlend.OldSingleQuote memory oldSingleQuote, bytes memory takerSignature, address takerAddress, bytes32 hooksHash ) onlyOperator(msg.sender) external { PERMIT2.permitWitnessTransferFrom( IPermit2.PermitTransferFrom( IPermit2.TokenPermissions(order.taker_token, order.taker_amount), order.flags >> 128, order.expiry ), IPermit2.SignatureTransferDetails(operator, order.taker_amount), takerAddress, order.hash(oldSingleQuote.makerAmount, oldSingleQuote.makerNonce, hooksHash), BlendSingleOrderLib.PERMIT2_ORDER_TYPE, takerSignature ); } /// @inheritdoc IJamBalanceManager function transferTokensForMultiBebopOrder( BlendMultiOrder memory order, IBebopBlend.OldMultiQuote memory oldMultiQuote, bytes memory takerSignature, address takerAddress, bytes32 hooksHash ) onlyOperator(msg.sender) external { PERMIT2.permitWitnessTransferFrom( order.toBatchPermit2(), order.toSignatureTransferDetails(operator), takerAddress, order.hash(oldMultiQuote.makerAmounts, oldMultiQuote.makerNonce, hooksHash), BlendMultiOrderLib.PERMIT2_ORDER_TYPE, takerSignature ); } /// @inheritdoc IJamBalanceManager function transferTokensForAggregateBebopOrder( BlendAggregateOrder memory order, IBebopBlend.OldAggregateQuote memory oldAggregateQuote, bytes memory takerSignature, address takerAddress, bytes32 hooksHash ) onlyOperator(msg.sender) external { (address[] memory tokens, uint256[] memory amounts) = order.unpackTokensAndAmounts(true, oldAggregateQuote); PERMIT2.permitWitnessTransferFrom( order.toBatchPermit2(tokens, amounts), BlendAggregateOrderLib.toSignatureTransferDetails(amounts, operator), takerAddress, order.hash(oldAggregateQuote.makerAmounts, oldAggregateQuote.makerNonces, hooksHash), BlendAggregateOrderLib.PERMIT2_ORDER_TYPE, takerSignature ); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../interfaces/IPermit2.sol"; import "../interfaces/IBebopBlend.sol"; /// @notice Struct for any trade with multiple makers struct BlendAggregateOrder { 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; } library BlendAggregateOrderLib { bytes internal constant ORDER_TYPE = 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 hooksHash)" ); bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE); string internal constant PERMIT2_ORDER_TYPE = string( abi.encodePacked("AggregateOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)") ); address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @notice hash the given order using same schema as in BebopBlend contract /// @param order the order to hash /// @param updatedMakerAmounts amounts that taker signed /// @param updatedMakerNonces nonce that taker signed /// @return the eip-712 order hash function hash( BlendAggregateOrder memory order, uint256[][] memory updatedMakerAmounts, uint256[] memory updatedMakerNonces, bytes32 hooksHash ) internal pure returns (bytes32) { uint64 partnerId = uint64(order.flags >> 64); return keccak256( abi.encode( 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), hooksHash ) ); } function toBatchPermit2( BlendAggregateOrder memory order, address[] memory tokens, uint256[] memory amounts ) internal pure returns (IPermit2.PermitBatchTransferFrom memory) { IPermit2.TokenPermissions[] memory permitted = new IPermit2.TokenPermissions[](tokens.length); for (uint i; i < tokens.length; ++i) { permitted[i] = IPermit2.TokenPermissions(tokens[i], amounts[i]); } return IPermit2.PermitBatchTransferFrom(permitted, order.flags >> 128, order.expiry); } function toSignatureTransferDetails( uint256[] memory amounts, address receiver ) internal pure returns (IPermit2.SignatureTransferDetails[] memory) { IPermit2.SignatureTransferDetails[] memory details = new IPermit2.SignatureTransferDetails[](amounts.length); for (uint i; i < amounts.length; ++i) { details[i] = IPermit2.SignatureTransferDetails(receiver, amounts[i]); } return details; } /// @notice Unpack 2d arrays of tokens and amounts into 1d array without duplicates /// @param order the order to unpack /// @param unpackTakerAmounts if true, unpack taker amounts, otherwise unpack maker amounts function unpackTokensAndAmounts( BlendAggregateOrder memory order, bool unpackTakerAmounts, IBebopBlend.OldAggregateQuote memory oldAggregateQuote ) internal pure returns (address[] memory tokens, uint256[] memory amounts){ uint maxLen; for (uint i; i < order.maker_addresses.length; ++i) { maxLen += unpackTakerAmounts ? order.taker_tokens[i].length : order.maker_tokens[i].length; } tokens = new address[](maxLen); amounts = new uint256[](maxLen); uint uniqueTokensCnt; uint commandsInd; for (uint256 i; i < order.maker_addresses.length; ++i) { if (unpackTakerAmounts) { commandsInd += order.maker_tokens[i].length; } uint curTokensLen = unpackTakerAmounts ? order.taker_tokens[i].length : order.maker_tokens[i].length; for (uint256 j; j < curTokensLen; ++j) { /// @dev AggregateOrder contains multiple maker orders, 'commands' field indicates how to transfer tokens /// All commands packed into one variable with bytes type, for each token - command is 1 byte: /// '0x[maker1-order_maker-token1][maker1-order_taker-token1][maker2-order_maker-token1][maker2-order_taker-token1]...' /// ignoring TRANSFER_FROM_CONTRACT and TRANSFER_TO_CONTRACT commands, since they are transfers between makers if ( (unpackTakerAmounts && order.commands[commandsInd + j] != 0x08) || // Commands.TRANSFER_FROM_CONTRACT=0x08 (!unpackTakerAmounts && order.commands[commandsInd + j] != 0x07) //Commands.TRANSFER_TO_CONTRACT=0x07 ) { bool isNew = true; address token = unpackTakerAmounts ? order.taker_tokens[i][j] : order.maker_tokens[i][j]; if (order.commands[commandsInd + j] == 0x04) { // Commands.NATIVE_TRANSFER=0x04 token = NATIVE_TOKEN; } uint256 amount = unpackTakerAmounts ? order.taker_amounts[i][j] : ( oldAggregateQuote.useOldAmount ? oldAggregateQuote.makerAmounts[i][j] : order.maker_amounts[i][j] ); for (uint256 k; k < uniqueTokensCnt; ++k) { if (tokens[k] == token) { amounts[k] += amount; isNew = false; break; } } if (isNew) { tokens[uniqueTokensCnt] = token; amounts[uniqueTokensCnt++] = amount; } } } if (unpackTakerAmounts) { commandsInd += order.taker_tokens[i].length; } else { commandsInd += order.maker_tokens[i].length + order.taker_tokens[i].length; } } assembly { mstore(tokens, uniqueTokensCnt) mstore(amounts, uniqueTokensCnt) } } /// @notice Pack 2D array of integers into tightly packed bytes for hashing function _encodeTightlyPackedNestedInt(uint256[][] memory nestedArray) private pure returns (bytes memory encoded) { uint nestedArrayLen = nestedArray.length; for (uint i; i < nestedArrayLen; ++i) { encoded = abi.encodePacked(encoded, keccak256(abi.encodePacked(nestedArray[i]))); } return encoded; } /// @notice Pack 2D array of addresses into tightly packed bytes for hashing function _encodeTightlyPackedNested(address[][] memory nestedArray) private pure returns (bytes memory encoded) { uint nestedArrayLen = nestedArray.length; for (uint i; i < nestedArrayLen; ++i) { encoded = abi.encodePacked(encoded, keccak256(abi.encodePacked(nestedArray[i]))); } return encoded; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../interfaces/IPermit2.sol"; /// @notice Struct for many-to-one or one-to-many trade with one maker struct BlendMultiOrder { 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; } library BlendMultiOrderLib { bytes internal constant ORDER_TYPE = 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 hooksHash)" ); bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE); string internal constant PERMIT2_ORDER_TYPE = string( abi.encodePacked("MultiOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)") ); address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @notice hash the given order using same schema as in BebopBlend contract /// @param order the order to hash /// @param updatedMakerAmounts amounts that taker signed /// @param updatedMakerNonce nonce that taker signed /// @return the eip-712 order hash function hash( BlendMultiOrder memory order, uint256[] memory updatedMakerAmounts, uint256 updatedMakerNonce, bytes32 hooksHash ) internal pure returns (bytes32) { uint64 partnerId = uint64(order.flags >> 64); return keccak256( abi.encode( 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), hooksHash ) ); } function toBatchPermit2(BlendMultiOrder memory order) internal pure returns (IPermit2.PermitBatchTransferFrom memory) { IPermit2.TokenPermissions[] memory permitted = new IPermit2.TokenPermissions[](order.taker_tokens.length); for (uint i; i < order.taker_tokens.length; ++i) { permitted[i] = IPermit2.TokenPermissions(order.taker_tokens[i], order.taker_amounts[i]); } return IPermit2.PermitBatchTransferFrom(permitted, order.flags >> 128, order.expiry); } function toSignatureTransferDetails( BlendMultiOrder memory order, address receiver ) internal pure returns (IPermit2.SignatureTransferDetails[] memory) { IPermit2.SignatureTransferDetails[] memory details = new IPermit2.SignatureTransferDetails[](order.taker_tokens.length); for (uint i; i < order.taker_tokens.length; ++i) { details[i] = IPermit2.SignatureTransferDetails(receiver, order.taker_amounts[i]); } return details; } /// @notice Get maker tokens from the order /// replace all tokens with command=0x04(Commands.NATIVE_TRANSFER) with native token address function getMakerTokens(BlendMultiOrder memory order) internal pure returns (address[] memory makerTokens) { makerTokens = new address[](order.maker_tokens.length); for (uint i; i < order.maker_tokens.length; ++i) { makerTokens[i] = order.commands[i] == 0x04 ? NATIVE_TOKEN : order.maker_tokens[i]; } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../interfaces/IPermit2.sol"; /// @notice BebopBlend struct for one-to-one trade with one maker struct BlendSingleOrder { 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; } library BlendSingleOrderLib { bytes internal constant ORDER_TYPE = 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 hooksHash)" ); bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE); string internal constant PERMIT2_ORDER_TYPE = string( abi.encodePacked("SingleOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)") ); /// @notice hash the given order using same schema as in BebopBlend contract /// @param order the order to hash /// @param updatedMakerAmount amount that taker signed /// @param updatedMakerNonce nonce that taker signed /// @return the eip-712 order hash function hash( BlendSingleOrder memory order, uint256 updatedMakerAmount, uint256 updatedMakerNonce, bytes32 hooksHash ) internal pure returns (bytes32) { uint64 partnerId = uint64(order.flags >> 64); return keccak256( abi.encode( ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address, order.maker_address, updatedMakerNonce, order.taker_token, order.maker_token, order.taker_amount, updatedMakerAmount, order.receiver, order.packed_commands, hooksHash ) ); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../libraries/JamInteraction.sol"; /// @title JamHooks /// @notice JamHooks is a library for managing pre and post interactions library JamHooks { bytes32 internal constant EMPTY_HOOKS_HASH = bytes32(0); /// @dev Data structure for pre and post interactions struct Def { JamInteraction.Data[] beforeSettle; JamInteraction.Data[] afterSettle; } function hash(Def memory hooks) internal pure returns (bytes32) { if (hooks.afterSettle.length == 0 && hooks.beforeSettle.length == 0){ return EMPTY_HOOKS_HASH; } return keccak256(abi.encode(hooks)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../interfaces/IJamBalanceManager.sol"; import "../base/Errors.sol"; library JamInteraction { /// @dev Data representing an interaction on the chain struct Data { bool result; // If the interaction is required to succeed address to; uint256 value; bytes data; } function runInteractions(Data[] calldata interactions, IJamBalanceManager balanceManager) internal returns (bool) { for (uint i; i < interactions.length; ++i) { Data calldata interaction = interactions[i]; require(interaction.to != address(balanceManager), CallToBalanceManagerNotAllowed()); (bool execResult,) = payable(interaction.to).call{ value: interaction.value }(interaction.data); if (!execResult && interaction.result) return false; } return true; } function runInteractionsM(Data[] memory interactions, IJamBalanceManager balanceManager) internal returns (bool) { for (uint i; i < interactions.length; ++i) { Data memory interaction = interactions[i]; require(interaction.to != address(balanceManager), CallToBalanceManagerNotAllowed()); (bool execResult,) = payable(interaction.to).call{ value: interaction.value }(interaction.data); if (!execResult && interaction.result) return false; } return true; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.27; import "../interfaces/IPermit2.sol"; import "./JamHooks.sol"; import "../external-libs/PermitHash.sol"; /// @dev Data representing a Jam Order. struct JamOrder { address taker; address receiver; uint256 expiry; uint256 exclusivityDeadline; // if block.timestamp > exclusivityDeadline, then order can be executed by any executor uint256 nonce; address executor; // only msg.sender=executor is allowed to execute (if executor=address(0), then order can be executed by anyone) uint256 partnerInfo; // partnerInfo is a packed struct of [partnerAddress,partnerFee,protocolFee] address[] sellTokens; address[] buyTokens; uint256[] sellAmounts; uint256[] buyAmounts; bool usingPermit2; // this field is excluded from ORDER_TYPE, so taker doesnt need to sign it } /// @title JamOrderLib library JamOrderLib { address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; bytes internal constant ORDER_TYPE = abi.encodePacked( "JamOrder(address taker,address receiver,uint256 expiry,uint256 exclusivityDeadline,uint256 nonce,address executor,uint256 partnerInfo,address[] sellTokens,address[] buyTokens,uint256[] sellAmounts,uint256[] buyAmounts,bytes32 hooksHash)" ); bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE); string internal constant PERMIT2_ORDER_TYPE = string( abi.encodePacked("JamOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)") ); /// @notice hash the given order /// @param order the order to hash /// @return the eip-712 order hash function hash(JamOrder calldata order, bytes32 hooksHash) internal pure returns (bytes32) { return keccak256( abi.encode( ORDER_TYPE_HASH, order.taker, order.receiver, order.expiry, order.exclusivityDeadline, order.nonce, order.executor, order.partnerInfo, keccak256(abi.encodePacked(order.sellTokens)), keccak256(abi.encodePacked(order.buyTokens)), keccak256(abi.encodePacked(order.sellAmounts)), keccak256(abi.encodePacked(order.buyAmounts)), hooksHash ) ); } function toBatchPermit2(JamOrder calldata order) internal pure returns (IPermit2.PermitBatchTransferFrom memory) { IPermit2.TokenPermissions[] memory permitted = new IPermit2.TokenPermissions[](order.sellTokens.length); for (uint i; i < order.sellTokens.length; ++i) { permitted[i] = IPermit2.TokenPermissions(order.sellTokens[i], order.sellAmounts[i]); } return IPermit2.PermitBatchTransferFrom(permitted, order.nonce, order.expiry); } function toSignatureTransferDetails( JamOrder calldata order, address receiver ) internal pure returns (IPermit2.SignatureTransferDetails[] memory details) { details = new IPermit2.SignatureTransferDetails[](order.sellTokens.length); for (uint i; i < order.sellTokens.length; ++i) { details[i] = IPermit2.SignatureTransferDetails(receiver, order.sellAmounts[i]); } } function permit2OrderHash(JamOrder calldata order, bytes32 hooksHash, address spender) internal pure returns (bytes32) { return PermitHash.hashWithWitness(toBatchPermit2(order), hash(order, hooksHash), PERMIT2_ORDER_TYPE, spender); } }
{ "optimizer": { "enabled": true, "runs": 1239 }, "viaIR": true, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_permit2","type":"address"},{"internalType":"address","name":"_bebopBlend","type":"address"},{"internalType":"address","name":"_treasuryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AfterSettleHooksFailed","type":"error"},{"inputs":[],"name":"BeforeSettleHooksFailed","type":"error"},{"inputs":[],"name":"BuyTokensInvalidLength","type":"error"},{"inputs":[],"name":"CallToBalanceManagerNotAllowed","type":"error"},{"inputs":[],"name":"DifferentFeesInBatch","type":"error"},{"inputs":[],"name":"DuplicateTokens","type":"error"},{"inputs":[],"name":"FailedToSendEth","type":"error"},{"inputs":[],"name":"InteractionsFailed","type":"error"},{"inputs":[],"name":"InvalidBatchHooksLength","type":"error"},{"inputs":[],"name":"InvalidBatchSignaturesLength","type":"error"},{"inputs":[],"name":"InvalidBlendOrderType","type":"error"},{"inputs":[],"name":"InvalidBlendPartnerId","type":"error"},{"inputs":[],"name":"InvalidContractSignature","type":"error"},{"inputs":[],"name":"InvalidExecutor","type":"error"},{"inputs":[],"name":"InvalidFeePercentage","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InvalidFilledAmounts","type":"error"},{"inputs":[],"name":"InvalidFilledAmountsLength","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InvalidOutputBalance","type":"error"},{"inputs":[],"name":"InvalidPartnerAddress","type":"error"},{"inputs":[],"name":"InvalidReceiverInBatch","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"OrderExpired","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SellTokensInvalidLength","type":"error"},{"inputs":[],"name":"ZeroNonce","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address[]","name":"sellTokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"buyTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"}],"name":"BebopBlendAggregateOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address[]","name":"sellTokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"buyTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"}],"name":"BebopBlendMultiOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"sellToken","type":"address"},{"indexed":false,"internalType":"address","name":"buyToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"sellAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"buyAmount","type":"uint256"}],"name":"BebopBlendSingleOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address[]","name":"sellTokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"buyTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"}],"name":"BebopJamOrderFilled","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NativeTransfer","type":"event"},{"inputs":[],"name":"DOMAIN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceManager","outputs":[{"internalType":"contract IJamBalanceManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bebopBlend","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"cancelLimitOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"beforeSettle","type":"tuple[]"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"afterSettle","type":"tuple[]"}],"internalType":"struct JamHooks.Def","name":"hooks","type":"tuple"}],"name":"hashHooks","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder","name":"order","type":"tuple"},{"internalType":"bytes32","name":"hooksHash","type":"bytes32"}],"name":"hashJamOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"isLimitOrderNonceValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"interactions","type":"tuple[]"},{"internalType":"bytes","name":"hooksData","type":"bytes"},{"internalType":"address","name":"balanceRecipient","type":"address"}],"name":"settle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder[]","name":"orders","type":"tuple[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"interactions","type":"tuple[]"},{"components":[{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"beforeSettle","type":"tuple[]"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"afterSettle","type":"tuple[]"}],"internalType":"struct JamHooks.Def[]","name":"hooks","type":"tuple[]"},{"internalType":"address","name":"balanceRecipient","type":"address"}],"name":"settleBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"enum IBebopBlend.BlendOrderType","name":"orderType","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"hooksData","type":"bytes"}],"name":"settleBebopBlend","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"filledAmounts","type":"uint256[]"},{"internalType":"bytes","name":"hooksData","type":"bytes"}],"name":"settleInternal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferNativeFromContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validationAddress","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"validateSignature","outputs":[],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
61014080604052346102e557606081618d6b803803809161002082856102ea565b8339810103126102e5576100338161030d565b61004b60406100446020850161030d565b930161030d565b60016000556040519091612ad88083019291906001600160401b038411838510176102cf57604091839161629383393085526001600160a01b031660208501819052930301906000f080156102c35760018060a01b03166080524660e05260405160208101907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672082527f76657273696f6e2c75696e7432353620636861696e49642c6164647265737320604082015271766572696679696e67436f6e74726163742960701b6060820152605281526101246072826102ea565b5190206040516101356040826102ea565b600d81526c12985b54d95d1d1b195b595b9d609a1b602090910152604080517f05fca2bf864448463a9141ae37fa0b2158f24d3135772bc23bc081c1765a8c2c9161018090826102ea565b600181526020810190601960f91b82525190206040519160208301938452604083015260608201524660808201523060a082015260a081526101c360c0826102ea565b51902060c05260a0526101005261012052604051615f71908161032282396080518181816103d7015281816104d70152818161074c0152818161085601528181610b0401528181610d4f0152818161142d0152818161149601528181611615015281816116ca015281816130f90152818161318801528181613294015281816132fc01528181613515015281816135c0015281816136d7015281816138860152818161395501528181613a1b0152613cc3015260a05181613c7c015260c05181611db7015260e05181611d9101526101005181818161348d0152615a400152610120518181816105ae015281816108f601528181610b9601526111c30152f35b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176102cf57604052565b51906001600160a01b03821682036102e55756fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80632143d82c1461012b5780633644e51514610126578063416e6d5e146101215780634a0d98781461011c578063796f077b146101175780637c317e0f146101125780637eea39f21461010d57806384b0196e14610108578063971604c614610103578063a03f5274146100fe578063a5cdc8fc146100f9578063acb8cc49146100f4578063b06b61db146100ef578063b57f9fed146100ea578063c7977be7146100e5578063f0a5f8f2146100e05763f80b26e30361000e57611375565b611336565b61131b565b6111e7565b6111a3565b611187565b6110ba565b611020565b610fd4565b610f38565b610ea3565b610e61565b610e2d565b6103fb565b6103b7565b610394565b6102e3565b908161018091031261013f5790565b600080fd5b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020838186019501011161013f57565b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020808501948460051b01011161013f57565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff8211176101d557604052565b6101a3565b6040810190811067ffffffffffffffff8211176101d557604052565b6060810190811067ffffffffffffffff8211176101d557604052565b90601f8019910116810190811067ffffffffffffffff8211176101d557604052565b60405190610243604083610212565b565b6040519061024361016083610212565b60405190610243606083610212565b67ffffffffffffffff81116101d557601f01601f191660200190565b81601f8201121561013f5780359061029782610264565b926102a56040519485610212565b8284526020838301011161013f57816000926020809301838601378301015290565b6001600160a01b0381160361013f57565b3590610243826102c7565b60a036600319011261013f5760043567ffffffffffffffff811161013f5761030f903690600401610130565b60243567ffffffffffffffff811161013f5761032f903690600401610144565b919060443567ffffffffffffffff811161013f57610351903690600401610172565b906064359467ffffffffffffffff861161013f57610376610019963690600401610280565b9360843595610384876102c7565b6113be565b600091031261013f57565b3461013f57600036600319011261013f5760206103af611d8e565b604051908152f35b3461013f57600036600319011261013f5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261013f57600435610413816102c7565b602435600381101561013f5760443567ffffffffffffffff811161013f5761043f903690600401610280565b9160643567ffffffffffffffff811161013f57610460903690600401610280565b92610469613d76565b835115610d845761048360208551860101602086016118da565b935b5160009015610d7e575061049884613e3a565b905b8115159384610d45575b6104ad81611e2f565b8061081c5750806020806104c693518301019101612a48565b6001600160a01b03979396919495977f000000000000000000000000000000000000000000000000000000000000000016803b1561013f578760008a61053d8296604051998a97889687957f57c3af1e00000000000000000000000000000000000000000000000000000000875260048701612c0c565b03925af19081156107b75761056c926001600160a01b0392610807575b50166001600160a01b03166040860152565b806107bc575b50608083019061059861058c83516001600160a01b031690565b6001600160a01b031690565b916001600160a01b0360c08601936105d58551917f0000000000000000000000000000000000000000000000000000000000000000928391614be3565b16803b1561013f578460009161061c94836040518097819582947f1a4990260000000000000000000000000000000000000000000000000000000084528d60048501612c6f565b03925af180156107b7577fca180a308256a6e9607c256dd145d700f18b1ee21e9bfa2919258b31a211bb8a936001600160a01b039361072c9261079c575b5061068261066d61014089015160801c90565b6fffffffffffffffffffffffffffffffff1690565b966106a961069b6101008301516001600160a01b031690565b94516001600160a01b031690565b610120820151909790600216156107885773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee925b51916106dd8251151590565b1561077c575060200151915b6fffffffffffffffffffffffffffffffff6040519687961699169785909493926001600160a01b0360609381608085019816845216602083015260408201520152565b0390a35b61073f575b6100196001600055565b61077160206107769201517f00000000000000000000000000000000000000000000000000000000000000009061412f565b611d5d565b38610735565b60e091500151916106e9565b60a08201516001600160a01b0316926106d1565b806107ab60006107b193610212565b80610389565b3861065a565b611a91565b61014084016108006107df6107d2835160401c90565b67ffffffffffffffff1690565b67ffffffffffffffff6107f86107d26107d28760401c90565b911614612568565b5238610572565b806107ab600061081693610212565b3861055a565b61082881949394611e2f565b60018103610acb57508060208061084493518301019101612840565b6001600160a01b0399959693979194997f000000000000000000000000000000000000000000000000000000000000000016803b1561013f57886000896108bc8296604051998a97889687957ffbfa3c5b00000000000000000000000000000000000000000000000000000000875260048701612995565b03925af19081156107b7576108eb926001600160a01b0392610ab6575b50166001600160a01b03166040850152565b80610a99575b5091927f0000000000000000000000000000000000000000000000000000000000000000929060005b6080840151805182101561096757906109618661094c61058c61093f856001976125af565b516001600160a01b031690565b61095a8460c08a01516125af565b5190614be3565b0161091a565b505093926001600160a01b039095919516803b1561013f57836000916109be93836040518096819582947fefe34fe60000000000000000000000000000000000000000000000000000000084528a600485016129cc565b03925af180156107b757610a84575b507fa3f15217206817f5e14f76307e5f65cfdc211516553c6638ef4fc79c4d6a0f0a6001600160a01b03610a0961066d61014085015160801c90565b93610a70610a226101008601516001600160a01b031690565b91608086015195610a3281614cff565b9160c082015191610a438251151590565b15610a78575060200151915b6fffffffffffffffffffffffffffffffff604051968796169916978561268b565b0390a3610730565b60e09150015191610a4f565b806107ab6000610a9393610212565b386109cd565b6101408301610aaf6107df6107d2835160401c90565b52386108f1565b806107ab6000610ac593610212565b386108d9565b80610ada600292979697611e2f565b03610d1b5780602080610af29351830101910161214b565b6001600160a01b0397949592969193977f000000000000000000000000000000000000000000000000000000000000000016803b1561013f5787600088610b6a8296604051988997889687957f77c19c1f00000000000000000000000000000000000000000000000000000000875260048701612518565b03925af180156107b757610d06575b5080610ce9575b50610b8e8383959495614721565b9590926000947f0000000000000000000000000000000000000000000000000000000000000000955b8551811015610be85780610be2888b61095a84610bdc61058c61093f6001998f6125af565b926125af565b01610bb7565b50929690946001600160a01b039096929616803b1561013f5782600091610c4095836040518098819582947f14e7a7ab0000000000000000000000000000000000000000000000000000000084528d600485016125df565b03925af19283156107b757610c896001600160a01b0393610a70927f85272ea7cbfb5ccba50d6cfaad14ff2ea471614d48c96ed5ecef53f11e56657996610cd4575b5087614977565b9092610cb2610100610ca361066d6101408c015160801c90565b9901516001600160a01b031690565b936fffffffffffffffffffffffffffffffff604051968796169916978561268b565b806107ab6000610ce393610212565b38610c82565b6101408301610cff6107df6107d2835160401c90565b5238610b80565b806107ab6000610d1593610212565b38610b79565b7f7082a8de0000000000000000000000000000000000000000000000000000000060005260046000fd5b610d79610d7487517f00000000000000000000000000000000000000000000000000000000000000009061412f565b611953565b6104a4565b9061049a565b610d8c611737565b610d94611737565b610d9c610234565b918252602082015293610485565b60405190610db9604083610212565b600d82527f4a616d536574746c656d656e74000000000000000000000000000000000000006020830152565b60005b838110610df85750506000910152565b8181015183820152602001610de8565b90602091610e2181518092818552858086019101610de5565b601f01601f1916010190565b3461013f57600036600319011261013f57610e5d610e49610daa565b604051918291602083526020830190610e08565b0390f35b3461013f57604036600319011261013f576100196000808080600435610e86816102c7565b6001600160a01b0360243591165af1610e9d612ce3565b50612d13565b3461013f57604036600319011261013f57600160ff600435610ec4816102c7565b6001600160a01b036024359116600052600260205260406000208160081c600052602052161b604060002054161560405180916020820190151582520390f35b906020808351928381520192019060005b818110610f225750505090565b8251845260209384019390920191600101610f15565b3461013f57600036600319011261013f57610fa5610f54610daa565b610e5d610f5f61114c565b610fb3610f6a612d44565b916040519586957f0f00000000000000000000000000000000000000000000000000000000000000875260e0602088015260e0870190610e08565b908582036040870152610e08565b90466060850152306080850152600060a085015283820360c0850152610f04565b3461013f57606036600319011261013f57600435610ff1816102c7565b6024356044359167ffffffffffffffff831161013f57611018610019933690600401610144565b929091612e33565b608036600319011261013f5760043567ffffffffffffffff811161013f5761104c903690600401610130565b60243567ffffffffffffffff811161013f5761106c903690600401610144565b60449291923567ffffffffffffffff811161013f5761108f903690600401610172565b916064359467ffffffffffffffff861161013f576110b4610019963690600401610280565b94613089565b3461013f57602036600319011261013f5760043580156111225761111f600160ff8360081c93161b91336000526002602052604060002092816000528360205260406000205461110e828083161415615051565b179290600052602052604060002090565b55005b7f150b14ee0000000000000000000000000000000000000000000000000000000060005260046000fd5b6040519061115b604083610212565b600182527f32000000000000000000000000000000000000000000000000000000000000006020830152565b3461013f57600036600319011261013f57610e5d610e4961114c565b3461013f57600036600319011261013f5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60a036600319011261013f5760043567ffffffffffffffff811161013f57611213903690600401610172565b9060243567ffffffffffffffff811161013f57611234903690600401610172565b9260443567ffffffffffffffff811161013f57611255903690600401610172565b906064359567ffffffffffffffff871161013f5761127a610019973690600401610172565b9590946084359761128a896102c7565b613697565b60405160208101907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672082527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060408201527f766572696679696e67436f6e7472616374290000000000000000000000000000606082015260528152611315607282610212565b51902090565b3461013f57600036600319011261013f5760206103af61128f565b3461013f57604036600319011261013f5760043567ffffffffffffffff811161013f576103af61136c6020923690600401610130565b60243590613c33565b3461013f57602036600319011261013f5760043567ffffffffffffffff811161013f576040600319823603011261013f576103af6113b96020923690600401613bbd565b613e3a565b9290959193956113cc613d76565b8551156116f9576113e660208751880101602088016118da565b955b51600090156116f457506113fb86613e3a565b61140781878488613f5e565b80151595866116c0575b61141e6101608701611984565b15611608576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690813b1561013f576000809461147a604051988996879586946332910d0160e11b86528d60048701611afe565b03925af19081156107b7576114c2926114bd926115f3575b505b7f00000000000000000000000000000000000000000000000000000000000000009687916141fd565b611c63565b6101408101907f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b036115056114fe858561198e565b3691611c94565b92611549846115446101008401976115296115208a8761198e565b9190928761198e565b602088019591611538876119c4565b9360c08a013595614310565b6119c4565b821630146115cc575b6115a0608082013594611564836119c4565b9261158161158f61157860e084018461198e565b92909a8461198e565b91909361012081019061198e565b939092604051988998169b88611d11565b0390a36115b4575b50506102436001600055565b6115c591602061077192015161412f565b38806115a8565b6115ee6115e96115e56115df888561198e565b90614683565b1590565b611ce0565b611552565b806107ab600061160293610212565b38611492565b5050506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661164260e085018561198e565b93909161165361012087018761198e565b95909261165f886119c4565b94833b1561013f5761168d6000969287936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19081156107b7576114c2926114bd926116ab575b50611494565b806107ab60006116ba93610212565b386116a5565b6116ef610d7489517f00000000000000000000000000000000000000000000000000000000000000009061412f565b611411565b6113fb565b611701611737565b611709611737565b611711610234565b9182526020820152956113e8565b67ffffffffffffffff81116101d55760051b60200190565b60405190611746602083610212565b6000825281601f19611758600061171f565b019060005b82811061176957505050565b602090604051611778816101b9565b60008152600083820152600060408201526060808201528282850101520161175d565b8015150361013f57565b5190610243826102c7565b81601f8201121561013f5780516117c681610264565b926117d46040519485610212565b8184526020828401011161013f576117f29160208085019101610de5565b90565b9080601f8301121561013f5781519161180d8361171f565b9261181b6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b83831061184757505050505090565b825167ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190611876826101b9565b60208301516118848161179b565b82526040830151611894816102c7565b60208301526060830151604083015260808301519167ffffffffffffffff831161013f576118ca886020809695819601016117b0565b6060820152815201920191611838565b60208183031261013f5780519067ffffffffffffffff821161013f570160408183031261013f576040519161190e836101da565b815167ffffffffffffffff811161013f578161192b9184016117f5565b8352602082015167ffffffffffffffff811161013f5761194b92016117f5565b602082015290565b1561195a57565b7f08f0f0fa0000000000000000000000000000000000000000000000000000000060005260046000fd5b356117f28161179b565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f57602001918160051b3603831361013f57565b356117f2816102c7565b9160209082815201919060005b8181106119e85750505090565b9091926020806001926001600160a01b038735611a04816102c7565b1681520194019291016119db565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161013f5760209260051b809284830137010190565b949695916001600160a01b0393606095611a768694611a849460808b5260808b01916119ce565b9188830360208a0152611a12565b9616604085015216910152565b6040513d6000823e3d90fd5b9035601e198236030181121561013f57016020813591019167ffffffffffffffff821161013f578160051b3603831361013f57565b35906102438261179b565b908060209392818452848401376000828201840152601f01601f1916010190565b90611c4e906102439597969460609460808552611b2e60808601611b21856102d8565b6001600160a01b03169052565b611b4d611b3d602085016102d8565b6001600160a01b031660a0870152565b604083013560c08601528583013560e08601526080830135610100860152611b8b611b7a60a085016102d8565b6001600160a01b0316610120870152565b60c0830135610140860152611c41611c37610160611c30611c0f611bee611bcd8b610200611bbc60e08d018d611a9d565b9190926101808982015201916119ce565b611bdb6101008b018b611a9d565b8d8303607f19016101808f0152906119ce565b611bfc6101208a018a611a9d565b8c8303607f19016101a08e015290611a12565b611c1d610140890189611a9d565b8b8303607f19016101c08d015290611a12565b9501611ad2565b15156101e0870152565b8483036020860152611add565b95604082015201906001600160a01b03169052565b15611c6a57565b7fff774c530000000000000000000000000000000000000000000000000000000060005260046000fd5b929190611ca08161171f565b93611cae6040519586610212565b602085838152019160051b810192831161013f57905b828210611cd057505050565b8135815260209182019101611cc4565b15611ce757565b7f7a745d4b0000000000000000000000000000000000000000000000000000000060005260046000fd5b959192611d4f94611d33611d41936117f29a989660808b5260808b01916119ce565b9188830360208a01526119ce565b918583036040870152611a12565b916060818403910152610f04565b15611d6457565b7fe70c1fc90000000000000000000000000000000000000000000000000000000060005260046000fd5b467f000000000000000000000000000000000000000000000000000000000000000003611dd9577f000000000000000000000000000000000000000000000000000000000000000090565b611de161128f565b611de9610daa565b60208151910120611df861114c565b602081519101206040519160208301938452604083015260608201524660808201523060a082015260a0815261131560c082610212565b60031115611e3957565b634e487b7160e01b600052602160045260246000fd5b9080601f8301121561013f578151611e668161171f565b92611e746040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611e9c5750505090565b602080918351611eab816102c7565b815201910190611e8f565b9080601f8301121561013f578151611ecd8161171f565b92611edb6040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611f035750505090565b8151815260209182019101611ef6565b9080601f8301121561013f578151611f2a8161171f565b92611f386040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611f6457505050505090565b815167ffffffffffffffff811161013f57602091611f8787848094880101611e4f565b815201910190611f55565b9080601f8301121561013f578151611fa98161171f565b92611fb76040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611fe357505050505090565b815167ffffffffffffffff811161013f5760209161200687848094880101611eb6565b815201910190611fd4565b91909160408184031261013f576040519061202b826101da565b819381519167ffffffffffffffff831161013f5761204f60209392849383016117b0565b84520151910152565b9080601f8301121561013f57815161206f8161171f565b9261207d6040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b8382106120a957505050505090565b815167ffffffffffffffff811161013f576020916120cc87848094880101612011565b81520191019061209a565b919060608382031261013f57604051906120f0826101f6565b819380516120fd8161179b565b8352602081015167ffffffffffffffff811161013f578261211f918301611f92565b602084015260408101519167ffffffffffffffff831161013f576040926121469201611eb6565b910152565b91909160a08184031261013f57805167ffffffffffffffff811161013f5781016101608185031261013f5761217e610245565b908051825261218f602082016117a5565b6020830152604081015167ffffffffffffffff811161013f57856121b4918301611e4f565b6040830152606081015167ffffffffffffffff811161013f57856121d9918301611eb6565b6060830152608081015167ffffffffffffffff811161013f57856121fe918301611f13565b608083015260a081015167ffffffffffffffff811161013f5785612223918301611f13565b60a083015260c081015167ffffffffffffffff811161013f5785612248918301611f92565b60c083015260e081015167ffffffffffffffff811161013f578561226d918301611f92565b60e083015261227f61010082016117a5565b6101008301526101208101519067ffffffffffffffff821161013f576122aa866101409383016117b0565b610120840152015161014082015292602082015167ffffffffffffffff811161013f57816122d9918401612058565b92604083015167ffffffffffffffff811161013f57826122fa9185016120d7565b92606081015192608082015167ffffffffffffffff811161013f576117f292016117b0565b906020808351928381520192019060005b81811061233d5750505090565b82516001600160a01b0316845260209384019390920191600101612330565b9080602083519182815201916020808360051b8301019401926000915b83831061238857505050505090565b90919293946020806123a6600193601f19868203018752895161231f565b97019301930191939290612379565b9080602083519182815201916020808360051b8301019401926000915b8383106123e157505050505090565b90919293946020806123ff600193601f198682030187528951610f04565b970193019301919392906123d2565b805182526020808201516001600160a01b03169083015290610140806124d96124b161249f61248d61247b61246961245760408b015161016060408c01526101608b019061231f565b60608b01518a820360608c0152610f04565b60808a015189820360808b015261235c565b60a089015188820360a08a015261235c565b60c088015187820360c08901526123b5565b60e087015186820360e08801526123b5565b610100868101516001600160a01b031690860152610120860151858203610120870152610e08565b93015191015290565b6117f291815115158152604061250760208401516060602085015260608401906123b5565b920151906040818403910152610f04565b9160809361254f61255d926125416001600160a01b03959a99989a60a0885260a088019061240e565b9086820360208801526124e2565b908482036040860152610e08565b951660608201520152565b1561256f57565b7fe823bd5a0000000000000000000000000000000000000000000000000000000060005260046000fd5b634e487b7160e01b600052603260045260246000fd5b80518210156125c35760209160051b010190565b612599565b906020806124d98451604085526040850190610e08565b92906125f39060a0855260a085019061240e565b8381036020850152825180825260208201916020808360051b8301019501926000915b83831061265e575050505050829161263f91600060406117f296015283820360608501526124e2565b9060808183039101526040906002815261060f60f31b60208201520190565b909192939560208061267c600193601f198682030187528a516125c8565b98019301930191939290612616565b926126b76117f295936126a9611d4f9460808852608088019061231f565b90868203602088015261231f565b908482036040860152610f04565b91906101608382031261013f576126da610245565b92805184526126eb602082016117a5565b60208501526126fc604082016117a5565b604085015260608101516060850152608081015167ffffffffffffffff811161013f578261272b918301611e4f565b608085015260a081015167ffffffffffffffff811161013f5782612750918301611e4f565b60a085015260c081015167ffffffffffffffff811161013f5782612775918301611eb6565b60c085015260e081015167ffffffffffffffff811161013f578261279a918301611eb6565b60e08501526127ac61010082016117a5565b61010085015261012081015167ffffffffffffffff811161013f57610140926127d69183016117b0565b6101208501520151610140830152565b91909160608184031261013f5760405190612800826101f6565b8193815161280d8161179b565b835260208201519167ffffffffffffffff831161013f576128346040939284938301611eb6565b60208501520151910152565b9160c08383031261013f57825167ffffffffffffffff811161013f57826128689185016126c5565b92602081015167ffffffffffffffff811161013f5783612889918301612011565b92604082015167ffffffffffffffff811161013f57816128aa9184016127e6565b926128b7606084016117a5565b9260808101519260a082015167ffffffffffffffff811161013f576117f292016117b0565b805182526020808201516001600160a01b031690830152906040828101516001600160a01b03169082015260608201516060820152610140806124d96124b161296061294e61293c608089015161016060808a015261016089019061231f565b60a089015188820360a08a015261231f565b60c088015187820360c0890152610f04565b60e087015186820360e0880152610f04565b908151151581526040806124d96020850151606060208601526060850190610f04565b9160809361254f61255d926129be6001600160a01b03959a99989a60a0885260a08801906128dc565b908682036020880152612972565b91926129f86117f2946129ea61263f9460a0875260a08701906128dc565b9085820360208701526125c8565b90600060408501528382036060850152612972565b919082606091031261013f57604051612a25816101f6565b60408082948051612a358161179b565b8452602081015160208501520151910152565b91828203610240811261013f576101601361013f57612a65610245565b83518152612a75602085016117a5565b6020820152612a86604085016117a5565b604082015260608401516060820152612aa1608085016117a5565b6080820152612ab260a085016117a5565b60a082015260c084015160c082015260e084015160e0820152612ad861010085016117a5565b6101008201526101208401516101208201526101408401516101408201529261016081015167ffffffffffffffff811161013f5783612b18918301612011565b92612b27816101808401612a0d565b92612b356101e084016117a5565b926102008101519261022082015167ffffffffffffffff811161013f576117f292016117b0565b610140809180518452612b7f602082015160208601906001600160a01b03169052565b6040818101516001600160a01b03169085015260608101516060850152612bb6608082015160808601906001600160a01b03169052565b60a0818101516001600160a01b03169085015260c081015160c085015260e081015160e0850152612bf96101008201516101008601906001600160a01b03169052565b6101208101516101208501520151910152565b9161020093612c4f612c6392612c2e866001600160a01b03969b9a999b612b5c565b805115156101608701526020810151610180870152604001516101a0860152565b6102206101c0850152610220840190610e08565b95166101e08201520152565b90612c996117f29493612c8584612cc494612b5c565b6102206101608501526102208401906125c8565b6000610180840152835115156101a084015260208401516101c08401526040909301516101e0830152565b6102008183039101526040906002815261060f60f31b60208201520190565b3d15612d0e573d90612cf482610264565b91612d026040519384610212565b82523d6000602084013e565b606090565b15612d1a57565b7ffe8a94f40000000000000000000000000000000000000000000000000000000060005260046000fd5b60405190612d53602083610212565b6000808352366020840137565b90612d6a8261171f565b612d776040519182610212565b8281528092612d88601f199161171f565b0190602036910137565b9081602091031261013f57517fffffffff000000000000000000000000000000000000000000000000000000008116810361013f5790565b6040906117f2949281528160208201520191611add565b919082604091031261013f576020823592013590565b634e487b7160e01b600052601160045260246000fd5b60ff601b9116019060ff8211612e1f57565b612df7565b90604010156125c35760400190565b929091906000843b612fbd5760418203612f30575090602092612eab83612e83612e7d612e6f612e67600098880188612de1565b949097612e24565b356001600160f81b03191690565b60f81c90565b935b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156107b7576001600160a01b0360005116908115612f06576001600160a01b031603612edc57565b7f815e1d640000000000000000000000000000000000000000000000000000000060005260046000fd5b7f8baa579f0000000000000000000000000000000000000000000000000000000060005260046000fd5b60408203612f955750602092612f4e83612eab936000950190612de1565b929092612f8f612f8a612f847f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c90565b60ff1690565b612e0d565b93612e85565b807f4be6321b0000000000000000000000000000000000000000000000000000000060049252fd5b936020926001600160a01b03612fea9560405196879586948593630b135d3f60e11b855260048501612dca565b0392165afa9081156107b757630b135d3f60e11b917fffffffff0000000000000000000000000000000000000000000000000000000091849161305a575b5016036130325750565b807fb0669cbc0000000000000000000000000000000000000000000000000000000060049252fd5b61307c915060203d602011613082575b6130748183610212565b810190612d92565b38613028565b503d61306a565b9291939093613096613d76565b8551156135f0576130b060208751880101602088016118da565b955b51600090156135ea57506130c586613e3a565b945b6130d386838388613f5e565b85151595866135b6575b6130ea6101608701611984565b15613508576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b1561013f57869360008094613148604051978896879586946332910d0160e11b8652339360048701611afe565b03925af180156107b7576134f3575b505b60c0830135806132d4575061317e9161317661014085018561198e565b929091614fde565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166101008401936131b8858261198e565b90926131c6602084016119c4565b90803b1561013f5786600080946131f78995604051998a9788968795635abff4df60e01b8752339360048801611a4f565b03925af180156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd936001600160a01b0393613273926132bf575b50608083013595613245846119c4565b9361158161326261325960e084018461198e565b92909b8461198e565b939092604051998a99169c8961364b565b0390a35b613287575b506102436001600055565b61077160206132b99201517f00000000000000000000000000000000000000000000000000000000000000009061412f565b3861327c565b806107ab60006132ce93610212565b38613235565b906132ef926132e761014086018661198e565b929091614e3d565b9193906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169061010083019561332d878561198e565b613339602087016119c4565b853b1561013f576000916133658a926040519586948594635abff4df60e01b8652339260048701613616565b038183885af180156107b7576134de575b508051613460575b5080516133ce575b50507f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd91506001600160a01b03906133c6608082013594611564836119c4565b0390a3613277565b6133d8868461198e565b929091813b1561013f576000809461340860405198899687958694635abff4df60e01b8652339260048701613616565b03925af19081156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd926001600160a01b039261344b575b819250613386565b806107ab600061345a93610212565b38613443565b61346a878561198e565b9190843b1561013f576000916134b86040519485938493635abff4df60e01b85527f000000000000000000000000000000000000000000000000000000000000000092339260048701613616565b038183875af180156107b7571561337e57806107ab60006134d893610212565b3861337e565b806107ab60006134ed93610212565b38613376565b806107ab600061350293610212565b38613157565b5050506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661354260e085018561198e565b909161355261012087018761198e565b919061355d886119c4565b94823b1561013f5760009461358c869260405198899788968795635abff4df60e01b8752339460048801611a4f565b03925af180156107b7576135a1575b50613159565b806107ab60006135b093610212565b3861359b565b6135e5610d7489517f00000000000000000000000000000000000000000000000000000000000000009061412f565b6130dd565b946130c7565b6135f8611737565b613600611737565b613608610234565b9182526020820152956130b2565b93959490611a8460609461363d6001600160a01b039593869460808a5260808a01916119ce565b908782036020890152610f04565b9694926136899461366d61367b936117f29b999560808c5260808c01916119ce565b9189830360208b01526119ce565b918683036040880152611a12565b926060818503910152611a12565b92979097969495969391936136aa613d76565b6136b88186888b8d89615157565b851515948860005b878c8210613855575050505050506114bd6136fe917f00000000000000000000000000000000000000000000000000000000000000009687916141fd565b60005b86811061371957505050505050506102436001600055565b808388613729818660019661525d565b61378f818761374761373c888784613a67565b61010081019061198e565b6137636137588a8986979597613a67565b61014081019061198e565b9160c06137878c8b613781602061377b84848d613a67565b016119c4565b98613a67565b013595614532565b7f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b0360806137c587868b613a67565b01359261381d6137d961154489888d613a67565b918a6137f36137e98b8a84613a67565b60e081019061198e565b909861158f6138128d61380a61373c828689613a67565b949096613a67565b61012081019061198e565b0390a361382b575b01613701565b6138506107718761384a613840858a8d613a45565b602081019061198e565b906141fd565b613825565b6139ff575b8b61387261016061386c84848c613a67565b01611984565b1561394957896138ad836001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016938b613a67565b91836138ba818989613abd565b9390968d60009060001461393f57506138df926113b9926138da92613a45565b613c19565b945b813b1561013f576000809461390d8b604051998a97889687956332910d0160e11b875260048701611afe565b03925af19182156107b75760019261392a575b505b0189906136c0565b806107ab600061393993610212565b38613920565b92505050946138e1565b91506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016876139846137e9848684613a67565b6139a46115448661399c613812828b899a989a613a67565b999096613a67565b823b1561013f576000946139d18b87936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19182156107b7576001926139ea575b50613922565b806107ab60006139f993610212565b386139e4565b613a40610d74613a19613a13848d87613a45565b8061198e565b7f0000000000000000000000000000000000000000000000000000000000000000916141fd565b61385a565b91908110156125c35760051b81013590603e198136030182121561013f570190565b91908110156125c35760051b8101359061017e198136030182121561013f570190565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f5760200191813603831361013f57565b908210156125c357613ad49160051b810190613a8a565b9091565b9080601f8301121561013f57813591613af08361171f565b92613afe6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b838310613b2a57505050505090565b823567ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190613b59826101b9565b6020830135613b678161179b565b82526040830135613b77816102c7565b60208301526060830135604083015260808301359167ffffffffffffffff831161013f57613bad88602080969581960101610280565b6060820152815201920191613b1b565b919060408382031261013f5760405190613bd6826101da565b8193803567ffffffffffffffff811161013f5782613bf5918301613ad8565b835260208101359167ffffffffffffffff831161013f576020926121469201613ad8565b6117f2903690613bbd565b9081602091031261013f575190565b613c406101608201611984565b15613d5d57604051917f3644e5150000000000000000000000000000000000000000000000000000000083526020836004816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9283156107b757600093613d1e575b50613ce9613d1092611315926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161592f565b604051928391602083019586909160429261190160f01b8352600283015260228201520190565b03601f198101835282610212565b611315919350613d1092613d4c613ce99260203d602011613d56575b613d448183610212565b810190613c24565b9492509250613cad565b503d613d3a565b90611315613ce9613d1092613d70611d8e565b946156b3565b600260005414613d87576002600055565b7f3ee5aeb50000000000000000000000000000000000000000000000000000000060005260046000fd5b9080602083519182815201916020808360051b8301019401926000915b838310613ddd57505050505090565b9091929394602080613e2b600193601f19868203018752608060608b518051151584526001600160a01b03868201511686850152604081015160408501520151918160608201520190610e08565b97019301930191939290613dce565b602081018051511580613e90575b613e8957611315613d1091604051928391613e76602084019660208852516040808601526080850190613db1565b9051838203603f19016060850152613db1565b5050600090565b5081515115613e48565b15613ea157565b7f710c94970000000000000000000000000000000000000000000000000000000060005260046000fd5b15613ed257565b7f83dfb46e0000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f0357565b7fec7706630000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f3457565b7fc56873ba0000000000000000000000000000000000000000000000000000000060005260046000fd5b909260409261024394613f70846119c4565b6001600160a01b0316331415806140e8575b61408d575b505050613f9a6115e56101608301611984565b801561407c575b614055575b60a0810133613fb761058c836119c4565b1490811561403a575b50801561402d575b613fd190613e9a565b613ffb613fe261010083018361198e565b9050613ff261014084018461198e565b91905014613ecb565b61402461400b60e083018361198e565b905061401b61012084018461198e565b91905014613efc565b01354210613f2d565b5060608101354211613fc8565b6001600160a01b03915061404d906119c4565b161538613fc0565b614077614061826119c4565b60808301356402540be3ff858501351491615082565b613fa6565b506402540be3ff8282013514613fa1565b6140e092613d106140cf6140a96140a2611d8e565b93886156b3565b8851928391602083019586909160429261190160f01b8352600283015260228201520190565b5190206140db856119c4565b612e33565b388080613f87565b506140f96115e56101608601611984565b613f82565b1561410557565b7f9eb00a7e0000000000000000000000000000000000000000000000000000000060005260046000fd5b9060005b82518110156141c55761414681846125af565b5160008061417f61058c61058c6020860161093f61416b82516001600160a01b031690565b6001600160a01b03808c16911614156140fe565b604084015190606085015191602083519301915af161419c612ce3565b501590816141ba575b506141b257600101614133565b505050600090565b5115159050386141a5565b505050600190565b91908110156125c35760051b81013590607e198136030182121561013f570190565b908092918237016000815290565b91909160005b8381106142135750505050600190565b61421e8185846141cd565b60008061424e61058c61058c6020860161154461423a826119c4565b6001600160a01b03808d16911614156140fe565b60408401356142606060860186613a8a565b9190614271604051809481936141ef565b03925af161427d612ce3565b5015908161429c575b5061429357600101614203565b50505050600090565b6142a69150611984565b38614286565b91908110156125c35760051b0190565b91908203918211612e1f57565b156142d357505050565b6001600160a01b03907f875c683c000000000000000000000000000000000000000000000000000000006000521660045260245260445260646000fd5b909194929460005b838110614329575050505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61434f61058c6115448488886142ac565b60009291036144ca5760019150475b61436882896125af565b5288614484575b6143b761437c82896125af565b51614388838b876142ac565b35614397611544858a8a6142ac565b6143a2858d896142ac565b35916143ae868d6125af565b519310156142c9565b86818773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6143e061058c611544858c8c6142ac565b03614456576000808061440161440d956001600160a01b03839616976125af565b51865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061444c61443b848b6125af565b516040519081529081906020820190565b0390a25b01614318565b5061447f915061058c61154461446d9289896142ac565b87614478848b6125af565b5191615a8b565b614450565b6144ba6144aa6144986115448489896142ac565b6144a2848b6125af565b51908c615a0f565b6144b4838a6125af565b516142bc565b6144c482896125af565b5261436f565b6144de61058c61058c6115448489896142ac565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b75760019391614514575b5061435e565b61452c915060203d8111613d5657613d448183610212565b3861450e565b91909294939460005b84811061454c575050505050505050565b6001908861463e575b614595614562828a6125af565b518961456f8487896142ac565b3561457e611544868c8c6142ac565b906143ae8661458e818b8d6142ac565b35946125af565b87818873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6145be61058c611544858d8d6142ac565b0361461757600080806144016145df956001600160a01b03839616976125af565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061460d61443b848c6125af565b0390a25b0161453b565b50614639915061058c61154461462e928a8a6142ac565b88614478848c6125af565b614611565b61466661465c614652611544848a8a6142ac565b6144a2848c6125af565b6144b4838b6125af565b614670828a6125af565b52614555565b91908201809211612e1f57565b9060005b6000198201828111612e1f578110156141b25760018101808211612e1f575b8281106146b65750600101614687565b6146c382848694966142ac565b356146cd816102c7565b6001600160a01b036146e661058c6115448588886142ac565b9116146146f8576001019290926146a6565b50505050600190565b9081518110156125c3570160200190565b6000198114612e1f5760010190565b6000929150825b604082015151841015614759576147516001916147498660808601516125af565b515190614676565b930192614728565b92509061476e61476884612d60565b93612d60565b60009384805b60408601515187101561496b57614793906147498860a08901516125af565b6147a18760808801516125af565b515160005b8181106147cb5750506147c36001916147498960808a01516125af565b960195614774565b7f08000000000000000000000000000000000000000000000000000000000000006001600160f81b031961481f6148116101208c015161480b8689614676565b90614701565b516001600160f81b03191690565b1614158015614963575b614836575b6001016147a6565b8761485461093f8361484e8d608060019601516125af565b516125af565b8a838b600160fa1b6001600160f81b031961487c6148118b61480b8761012088015192614676565b1614614947575b6148949260c061484e9201516125af565b519160005b8781106148ed575b509060019392916148b6575b5050905061482e565b6148d2906148c4888a6125af565b906001600160a01b03169052565b6148e56148de87614712565b96896125af565b5238806148ad565b896148fb61093f838c6125af565b6001600160a01b038086169116146149165750600101614899565b849392506149346001969561492e8461493b946125af565b51614676565b918b6125af565b526000909192936148a1565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614883565b506000614829565b50808252825293509150565b600092835b6040830151518510156149a55761499d6001916147498760a08701516125af565b94019361497c565b935090916149bb6149b585612d60565b94612d60565b6000916001918391829190825b604089015151871015614bd4576149e38760a08b01516125af565b5151855b818110614a26575050614a1e600191614a188b6147498b6080614a0e8260a08601516125af565b51519301516125af565b90614676565b9601956149c8565b868b89614b89575b50614a3c575b6001016149e7565b60018b8a83614a5661093f8261484e8560a08801516125af565b92600160fa1b6001600160f81b0319614a7c6148118b61480b8761012088015192614676565b1614614b6d575b885115614b4f575061484e614a9c9260208a01516125af565b519088908f9493945b8b5b838110614aed575b50600195614ac3575b505050509050614a34565b614ad0926148c4916125af565b614ae3614adc89614712565b98886125af565b523887818f614ab8565b9193949592908a614b0161093f85846125af565b6001600160a01b03808816911614614b2557505050600101918f8a92959493614aa7565b8391929450614b408761492e60019a999896614b47946125af565b918c6125af565b528b95614aaf565b614b609260e061484e9201516125af565b519088908f949394614aa5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614a83565b7f07000000000000000000000000000000000000000000000000000000000000009150614bcb6148116101206001600160f81b031993015161480b8689614676565b1614158b614a2e565b50509550925050508084528252565b91906040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03831660248201526020816044816001600160a01b0388165afa9081156107b757600091614ce0575b5010614c4b575050565b6014526000196034526f095ea7b3000000000000000000000000600052602060006044601082855af13d15600160005114171615614c8c575b506000603452565b60006044601082602094816034526f095ea7b300000000000000000000000082528138858583855af15081196034525af13d15600160005114171615614cd25738614c84565b633e3f8f736000526004601cfd5b614cf9915060203d602011613d5657613d448183610212565b38614c41565b9060a08201614d0f815151612d60565b9060005b815151811015614d9a5780600160fa1b6001600160f81b0319614d3d6001946101208a0151614701565b511614600090600014614d7d575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03614d7383876125af565b9116905201614d13565b6001600160a01b0390614d918386516125af565b90505116614d61565b50509150565b15614da757565b7f692f31020000000000000000000000000000000000000000000000000000000060005260046000fd5b81810292918115918404141715612e1f57565b8115614dee570490565b634e487b7160e01b600052601260045260246000fd5b15614e0d575050565b7f871cbeab0000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b92949190606095614e4e8796615b5b565b94919690614e5d858514614da0565b61ffff614e6986612d60565b961680614f7f575b5061ffff1680614ed5575b505060005b838110614e92575050505093929190565b80614ecf614ea2600193886125af565b51614eae8387876142ac565b35614eba8488886142ac565b3590614ec6858b6125af565b51921015614e04565b01614e81565b909750614ee184612d60565b9760005b858110614ef25750614e7c565b80614f15614f0d85614f076001958b886142ac565b35614dd1565b612710900490565b614f1f828d6125af565b52614f2a81896125af565b51614f6157614f508b614f4983614f42818c896142ac565b35926125af565b51906142bc565b614f5a828a6125af565b5201614ee5565b614f7a8b614f4983614f73818d6125af565b51926125af565b614f50565b9950614f8a85612d60565b9960005b8b87808310614f9f57505050614e71565b90614fb983610bdc614f0d87614f0784600199988d6142ac565b52614fcd8d614f4983614f42818d8b6142ac565b614fd7828b6125af565b5201614f8e565b91909392841561504957614ff3818614614da0565b60005b858110615004575050509190565b8061504361501560019389886142ac565b356150218386886142ac565b3561502d8487896142ac565b359061503a858c8b6142ac565b35921015614e04565b01614ff6565b935090509190565b1561505857565b7f756688fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b908015611122576150d891600160ff8360081c93161b936000906000146150db57506001600160a01b031660005260026020526040600020925b816000528360205260406000205461110e828083161415615051565b55565b6001600160a01b03604092168152600160205220926150bc565b156150fc57565b7fa18792da0000000000000000000000000000000000000000000000000000000060005260046000fd5b1561512d57565b7fb82564ab0000000000000000000000000000000000000000000000000000000060005260046000fd5b939295948615918181036152025787811480156151fb575b615178906150f5565b60005b81811061518d57505050505050509050565b6001906151ae306151a761058c602061377b86898f613a67565b1415615126565b6151de6151bc82858b613a67565b828c6151c982898d613abd565b9290918b8b156151e457505050600092613f5e565b0161517b565b6151f5926113b9926138da92613a45565b92613f5e565b508261516f565b7f6e3779d80000000000000000000000000000000000000000000000000000000060005260046000fd5b1561523357565b7fadfbc6fc0000000000000000000000000000000000000000000000000000000060005260046000fd5b929161526a848284613a67565b93610100850161528461527d828861198e565b9050612d60565b9361014087019360005b615298848a61198e565b90508110156154e357600090855b8381106153f5575089878973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6152e061058c611544876152da8d8961198e565b906142ac565b14886000916000146153635750506152da8261533086809461532060019a61531b8a615314866152da6153379d479461198e565b3590614dd1565b614de4565b61532a83836125af565b526125af565b519461198e565b3511615344575b0161528e565b615352816152da898d61198e565b3561535d828a6125af565b5261533e565b61537f935061058c9250856152da6115449261058c949761198e565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b7576152da8a6153308f958e61532060019a61531b8a6153148d6152da8a6153379e839e849b916153d7575b509461198e565b6153ef915060203d8111613d5657613d448183610212565b386153d0565b95909860009a989294979a9593955b61541261373c89898c613a67565b90508110156154cd57896001600160a01b0361545161058c6115448f6152da8f8f8f8a8f9361373c61544b94611544946152da93613a67565b9761198e565b911614615461575b600101615404565b948561546e89898c613a67565b610140810161547c9161198e565b61548692916142ac565b3561549091614676565b9461549e60c08b0135615c0e565b6154a989898c613a67565b60c001356154b690615c0e565b61ffff166154c89161ffff161461522c565b615459565b509890956001909a979492989a959395016152a6565b509496505050505050565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec81526117f261010c82610212565b61563a6154ee565b6020815191012090565b9060005b8181106156555750505090565b9091926020806001926001600160a01b038735615671816102c7565b168152019401929101615648565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811161013f5760051b809282370190565b6156bb615632565b916156c5826119c4565b926156d2602084016119c4565b91604084013593606081013590608081013560a082016156f1906119c4565b60c083013561570360e085018561198e565b90604051809160208201809461571892615644565b03601f198101825261572a9082610212565b5190209161573c61010086018661198e565b90604051809160208201809461575192615644565b03601f19810182526157639082610212565b5190209361577561012087018761198e565b90604051809160208201809461578a9261567f565b03601f198101825261579c9082610212565b5190209561014081016157ae9161198e565b9060405180916020820180946157c39261567f565b03601f19810182526157d59082610212565b519020966040519b8c9b60208d019e8f9c61585d9d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b03601f19810182526113159082610212565b9061588260209282815194859201610de5565b0190565b61588e6154ee565b6117f2602e603160405180947f4a616d4f72646572207769746e6573732900000000000000000000000000000060208301526158d38151809260208686019101610de5565b81017f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75838201527f696e7432353620616d6f756e742900000000000000000000000000000000000060518201520301600e810184520182610212565b9091615939615c22565b5060e0820161595261594b828561198e565b9050615c42565b9461012084019260005b615966848761198e565b90508110156159cd57806159836115446001936152da888b61198e565b615991826152da898b61198e565b356159ac61599d610234565b6001600160a01b039093168352565b60208201526159bb828b6125af565b526159c6818a6125af565b500161595c565b50936117f29591969350615a01925060808101356040820135906159ef610255565b958652602086015260408501526156b3565b615a09615886565b91615d7b565b9190615a1c600093615b5b565b919061ffff8116615a76575b505061ffff8116615a3a575b50505090565b615a65927f000000000000000000000000000000000000000000000000000000000000000092615e57565b8101809111612e1f57388080615a34565b615a839295508484615e57565b923880615a28565b600091826044926020956001600160a01b03604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d1160016000511416171615615ae757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b9061ffff8091169116019061ffff8211612e1f57565b9061ffff8216906001600160a01b0361ffff8460101c169360201c1661271061ffff615b878587615b45565b161015615be457831580801591615bce575b5015615ba457929190565b7fb7273bd50000000000000000000000000000000000000000000000000000000060005260046000fd5b905080615bdc575b38615b99565b508015615bd6565b7f721dbfea0000000000000000000000000000000000000000000000000000000060005260046000fd5b6117f29061ffff808260101c169116615b45565b60405190615c2f826101f6565b6000604083606081528260208201520152565b90615c4c8261171f565b615c596040519182610212565b8281528092615c6a601f199161171f565b019060005b828110615c7b57505050565b602090604051615c8a816101da565b6000815260008382015282828501015201615c6f565b60405190615caf60a083610212565b606b82527f3620646561646c696e652c0000000000000000000000000000000000000000006080837f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208201527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c6164647260408201527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608201520152565b805160209091019060005b818110615d655750505090565b8251845260209384019390920191600101615d58565b909291613d10615da7615d8c615ca0565b92604051928391615da160208401809761586f565b9061586f565b51902092815151615db781612d60565b9060005b818110615e2f5750506113159291613d1091604051615de281613d10602082018095615d4d565b51902092604060208201519101519060405196879560208701998a926001600160a01b039060a095929897969360c086019986526020860152166040840152606083015260808201520152565b80615e46615e4060019388516125af565b51615ee9565b615e5082866125af565b5201615dbb565b90615e736127109161ffff6001600160a01b0396951690614dd1565b049283911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103615edf5750506001600160a01b0316615eb2600080808086865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b66206020604051848152a290565b916117f292615a8b565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a184526001600160a01b038151166040840152015160608201526060815261131560808261021256fea2646970667358221220da6c85282a2cc6cde7c75dcde65f8361cd5c7c90ecba328016a401e28804a3c364736f6c634300081b003360c0346100bd57601f612ad838819003918201601f19168301916001600160401b038311848410176100c25780849260409485528339810103126100bd57610052602061004b836100d8565b92016100d8565b6080919091526001600160a01b031660a0526040516129eb90816100ed82396080518181816103b001528181610c140152818161109a015281816114e80152818161184a0152611ad7015260a051818181610c52015281816110cb015281816118200152611b150152f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036100bd5756fe6080604052600436101561001257600080fd5b60003560e01c806357c3af1e146100675780635abff4df1461006257806365221a021461005d57806377c19c1f146100585763fbfa3c5b1461005357600080fd5b610a27565b6107e5565b61050c565b610337565b34610141573660031901610220811261014157610160136101415761008a6101bb565b60043581526100976101fc565b60208201526100a4610209565b604082015260643560608201526100b9610216565b60808201526100c6610223565b60a082015260c43560c082015260e43560e08201526100e3610230565b610100820152610124356101208201526101443561014082015261010636610271565b906101c4359167ffffffffffffffff83116101415761012c61013f9336906004016102af565b61013461023e565b916102043593610c0b565b005b600080fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761017857604052565b610146565b6040810190811067ffffffffffffffff82111761017857604052565b90601f8019910116810190811067ffffffffffffffff82111761017857604052565b604051906101cb61016083610199565b565b604051906101cb604083610199565b604051906101cb606083610199565b6001600160a01b0381160361014157565b602435906101cb826101eb565b604435906101cb826101eb565b608435906101cb826101eb565b60a435906101cb826101eb565b61010435906101cb826101eb565b6101e435906101cb826101eb565b606435906101cb826101eb565b35906101cb826101eb565b3590811515820361014157565b606090610163190112610141576040519061028b8261015c565b8161016435801515810361014157815261018435602082015260406101a435910152565b81601f820112156101415780359067ffffffffffffffff821161017857604051926102e4601f8401601f191660200185610199565b8284526020838301011161014157816000926020809301838601378301015290565b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b346101415760803660031901126101415760043567ffffffffffffffff811161014157610368903690600401610306565b9060243567ffffffffffffffff811161014157610389903690600401610306565b60449391933590610399826101eb565b606435926103a6846101eb565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016946103dc863314610bda565b60005b8281106103e857005b87868686868673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6104256104196104148a868661106b565b611080565b6001600160a01b031690565b1461045c578661045695936104496104196104148460019c9b999761044f9761106b565b9561106b565b3592611f0a565b016103df565b505050508891506001600160a01b03160361047a575b600190610456565b61048581858a61106b565b3590873b15610141576040517f7c317e0f0000000000000000000000000000000000000000000000000000000081526001600160a01b03881660048201526024810192909252600082604481838c5af1918215610507576001926104ec575b509050610472565b806104fb600061050193610199565b80610f88565b386104e4565b611049565b346101415760803660031901126101415760043567ffffffffffffffff81116101415761018060031982360301126101415760243567ffffffffffffffff811161014157366023820112156101415780600401359167ffffffffffffffff83116101415736602484840101116101415761013f9260443591602461058e61024c565b94019060040161108a565b67ffffffffffffffff81116101785760051b60200190565b9080601f830112156101415781356105c881610599565b926105d66040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106105fe5750505090565b60208091833561060d816101eb565b8152019101906105f1565b9080601f8301121561014157813561062f81610599565b9261063d6040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106106655750505090565b8135815260209182019101610658565b9080601f8301121561014157813561068c81610599565b9261069a6040519485610199565b81845260208085019260051b820101918383116101415760208201905b8382106106c657505050505090565b813567ffffffffffffffff8111610141576020916106e9878480948801016105b1565b8152019101906106b7565b9080601f8301121561014157813561070b81610599565b926107196040519485610199565b81845260208085019260051b820101918383116101415760208201905b83821061074557505050505090565b813567ffffffffffffffff81116101415760209161076887848094880101610618565b815201910190610736565b9190606083820312610141576040519061078c8261015c565b819361079781610264565b8352602081013567ffffffffffffffff811161014157826107b99183016106f4565b602084015260408101359167ffffffffffffffff8311610141576040926107e09201610618565b910152565b346101415760a03660031901126101415760043567ffffffffffffffff81116101415761016060031982360301126101415761081f6101bb565b908060040135825261083360248201610259565b6020830152604481013567ffffffffffffffff81116101415761085c90600436918401016105b1565b6040830152606481013567ffffffffffffffff8111610141576108859060043691840101610618565b6060830152608481013567ffffffffffffffff8111610141576108ae9060043691840101610675565b608083015260a481013567ffffffffffffffff8111610141576108d79060043691840101610675565b60a083015260c481013567ffffffffffffffff81116101415761090090600436918401016106f4565b60c083015260e481013567ffffffffffffffff81116101415761092990600436918401016106f4565b60e083015261093b6101048201610259565b6101008301526101248101359067ffffffffffffffff82116101415761096a61014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610998903690600401610773565b906044359167ffffffffffffffff8311610141576109bd61013f9336906004016102af565b6109c561024c565b91608435936114d9565b91909160608184031261014157604051906109e98261015c565b81936109f482610264565b835260208201359167ffffffffffffffff831161014157610a1b6040939284938301610618565b60208501520135910152565b346101415760a03660031901126101415760043567ffffffffffffffff811161014157610160600319823603011261014157610a616101bb565b9080600401358252610a7560248201610259565b6020830152610a8660448201610259565b604083015260648101356060830152608481013567ffffffffffffffff811161014157610ab990600436918401016105b1565b608083015260a481013567ffffffffffffffff811161014157610ae290600436918401016105b1565b60a083015260c481013567ffffffffffffffff811161014157610b0b9060043691840101610618565b60c083015260e481013567ffffffffffffffff811161014157610b349060043691840101610618565b60e0830152610b466101048201610259565b6101008301526101248101359067ffffffffffffffff821161014157610b7561014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610ba39036906004016109cf565b906044359167ffffffffffffffff831161014157610bc861013f9336906004016102af565b610bd061024c565b9160843593611ad0565b15610be157565b7f48f5c3ed0000000000000000000000000000000000000000000000000000000060005260046000fd5b90929193610cfe7f000000000000000000000000000000000000000000000000000000000000000091610c486001600160a01b0384163314610bda565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693610c8760808201516001600160a01b031690565b9660c082018051610ca8610c996101cd565b6001600160a01b03909b168b52565b60208a015261014083015160801c835190610cc16101dc565b9a8b5260208b015260408a015251610ce9610cda6101cd565b6001600160a01b039097168752565b60208601526040602082015191015191611e40565b94610d07610ed8565b94833b1561014157610d4e600096928793604051998a98899788967f137c29fe00000000000000000000000000000000000000000000000000000000885260048801610fb8565b03925af1801561050757610d5f5750565b806104fb60006101cb93610199565b6040517f53696e676c654f726465722875696e74363420706172746e65725f69642c756960208201527f6e74323536206578706972792c616464726573732074616b65725f616464726560408201527f73732c61646472657373206d616b65725f616464726573732c75696e7432353660608201527f206d616b65725f6e6f6e63652c616464726573732074616b65725f746f6b656e60808201527f2c61646472657373206d616b65725f746f6b656e2c75696e743235362074616b60a08201527f65725f616d6f756e742c75696e74323536206d616b65725f616d6f756e742c6160c08201527f6464726573732072656365697665722c75696e74323536207061636b65645f6360e08201527f6f6d6d616e64732c6279746573333220686f6f6b73486173682900000000000061010082015260fa8152610eb261011a82610199565b90565b60005b838110610ec85750506000910152565b8181015183820152602001610eb8565b6034610eb2610ee5610d6e565b610f7a6040519384927f53696e676c654f72646572207769746e657373290000000000000000000000006020850152610f278151809260208588019101610eb5565b830101602e907f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7581527f696e7432353620616d6f756e742900000000000000000000000000000000000060208201520190565b03601f198101835282610199565b600091031261014157565b90602091610fac81518092818552858086019101610eb5565b601f01601f1916010190565b949161103a9361101b6001600160a01b03926040610eb29a9895610ff08b8251602080916001600160a01b0381511684520151910152565b6020818101518c84015291015160608b015281516001600160a01b031660808b0152015160a0890152565b1660c086015260e0850152610140610100850152610140840190610f93565b91610120818403910152610f93565b6040513d6000823e3d90fd5b634e487b7160e01b600052603260045260246000fd5b919081101561107b5760051b0190565b611055565b35610eb2816101eb565b9190946110c16001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314610bda565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916110f4611fcc565b5060e084019261110e6111078587611fec565b9050612022565b956000986101208701995b6111238789611fec565b905081101561119257808b6111568261114961114f6104146001978f8f61114991611fec565b9061106b565b938d611fec565b356111716111626101cd565b6001600160a01b039093168352565b6020820152611180828c612080565b5261118b818b612080565b5001611119565b509296976111c9919499506111d992955060808701356040880135906111b66101dc565b9a8b5260208b015260408a015286612094565b926111d386611080565b95612191565b956111e2611353565b843b15610141576000968793610d4e926040519a8b998a98899763fe8ec1a760e01b895260048901611464565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec8152610eb261010c82610199565b6031610eb261136061120f565b610f7a6040519384927f4a616d4f72646572207769746e657373290000000000000000000000000000006020850152610f278151809260208588019101610eb5565b90606081019180519260608352835180915260206080840194019060005b8181106113e0575050506040816020829301516020850152015191015290565b90919460206040826114086001948a51602080916001600160a01b0381511684520151910152565b0196019291016113c0565b906020808351928381520192019060005b8181106114315750505090565b90919260206040826114596001948851602080916001600160a01b0381511684520151910152565b019401929101611424565b959290948795946001600160a01b0361149c6114b59561148f60209c9960c08d5260c08d01906113a2565b908b82038d8d0152611413565b9316604089015260608801528682036080880152610f93565b9360a0818603910152818452848401376000828201840152601f01601f1916010190565b949361150f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314610bda565b600092839484955b604089015151871015611548576115406001916115388960808d0151612080565b515190612351565b960195611517565b93979691945091945061156361155d84612363565b93612363565b936000926000986000995b60408a0151518b10156117fc5761158d906115388c60a08d0151612080565b8a8a61159d826080830151612080565b515160005b8181106115c7575050916115386115bf9260806001950151612080565b9a019961156e565b917f080000000000000000000000000000000000000000000000000000000000000091935061164f6116296101207fff000000000000000000000000000000000000000000000000000000000000009301516116238689612351565b90612395565b517fff000000000000000000000000000000000000000000000000000000000000001690565b16141580156117f4575b61166a575b6001018c918c916115a2565b8c8c6001918361169861168b82611685856080880151612080565b51612080565b516001600160a01b031690565b917f04000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006116f26116298b611623876101208b015192612351565b16146117d8575b6117148f94968f928f959497989060c0611685920151612080565b51936000905b84821061176f575b5050600195611737575b50505050905061165e565b6117529261174491612080565b906001600160a01b03169052565b61176561175e8b6123a6565b9a8d612080565b523889818c61172c565b9092949596939161168b8461178392612080565b6001600160a01b038087169116146117a7575050600101918c8c929594938f61171a565b9092506117cd826117c7876117c160019a99989686612080565b51612351565b92612080565b528c6000958f611722565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92506116f9565b506000611659565b5093611880939950979095969197808652875261186f611847886001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001697846123b5565b977f000000000000000000000000000000000000000000000000000000000000000090612455565b936040602082015191015191612528565b94611889611a23565b94833b1561014157610d4e600096928793604051998a988997889663fe8ec1a760e01b885260048801611a72565b6040517f4167677265676174654f726465722875696e74363420706172746e65725f696460208201527f2c75696e74323536206578706972792c616464726573732074616b65725f616460408201527f64726573732c616464726573735b5d206d616b65725f6164647265737365732c60608201527f75696e743235365b5d206d616b65725f6e6f6e6365732c616464726573735b5d60808201527f5b5d2074616b65725f746f6b656e732c616464726573735b5d5b5d206d616b6560a08201527f725f746f6b656e732c75696e743235365b5d5b5d2074616b65725f616d6f756e60c08201527f74732c75696e743235365b5d5b5d206d616b65725f616d6f756e74732c61646460e08201527f726573732072656365697665722c627974657320636f6d6d616e64732c6279746101008201527f6573333220686f6f6b734861736829000000000000000000000000000000000061012082015261010f8152610eb261012f82610199565b6037610eb2611a306118b7565b610f7a6040519384927f4167677265676174654f72646572207769746e657373290000000000000000006020850152610f278151809260208588019101610eb5565b9490936001600160a01b03611aa9611ac29594611a9b610eb29a9860c08b5260c08b01906113a2565b9089820360208b0152611413565b9316604087015260608601528482036080860152610f93565b9160a0818403910152610f93565b94909392917f000000000000000000000000000000000000000000000000000000000000000092611b0b6001600160a01b0385163314610bda565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611b3d611fcc565b506080880196611b4e885151612022565b9660009960c081019a5b8a518051821015611bac57908c611b7f82611b7861168b82600197612080565b9251612080565b51611b8b6111626101cd565b6020820152611b9a828d612080565b52611ba5818c612080565b5001611b58565b50509194985091949850611beb611bfc9396611bcd61014084015160801c90565b835190611bd86101dc565b9a8b5260208b015260408a0152826126b9565b936040602082015191015191612735565b94611889611d49565b6040517f4d756c74694f726465722875696e74363420706172746e65725f69642c75696e60208201527f74323536206578706972792c616464726573732074616b65725f61646472657360408201527f732c61646472657373206d616b65725f616464726573732c75696e743235362060608201527f6d616b65725f6e6f6e63652c616464726573735b5d2074616b65725f746f6b6560808201527f6e732c616464726573735b5d206d616b65725f746f6b656e732c75696e74323560a08201527f365b5d2074616b65725f616d6f756e74732c75696e743235365b5d206d616b6560c08201527f725f616d6f756e74732c616464726573732072656365697665722c627974657360e08201527f20636f6d6d616e64732c6279746573333220686f6f6b7348617368290000000061010082015260fc8152610eb261011c82610199565b6033610eb2611d56611c05565b610f7a6040519384927f4d756c74694f72646572207769746e65737329000000000000000000000000006020850152610f278151809260208588019101610eb5565b611da0610d6e565b6020815191012090565b9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a08801526001600160a01b031660c087015260e08601611e18916001600160a01b03169052565b6101008501526101208401526001600160a01b03166101408301526101608201526101800152565b909161014082015160401c611e5c9067ffffffffffffffff1690565b93611e65611d98565b918351936020810151611e7e906001600160a01b031690565b956040820151611e94906001600160a01b031690565b926080830151611eaa906001600160a01b031690565b60a08401516001600160a01b03169060c085015192610100860151611ed5906001600160a01b031690565b956101200151966040519b8c9b60208d019e8f9c611ef29d611daa565b03601f1981018252611f049082610199565b51902090565b9060006064926020956001600160a01b03839681604051967f23b872dd00000000000000000000000000000000000000000000000000000000885216600487015216602485015260448401525af13d15601f3d1160016000511416171615611f6e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b60405190611fd98261015c565b6000604083606081528260208201520152565b903590601e1981360301821215610141570180359067ffffffffffffffff821161014157602001918160051b3603831361014157565b9061202c82610599565b6120396040519182610199565b828152809261204a601f1991610599565b019060005b82811061205b57505050565b60209060405161206a8161017d565b600081526000838201528282850101520161204f565b805182101561107b5760209160051b010190565b9060e08201916120a76111078483611fec565b9360005b6120b58584611fec565b9050811015612113576001816120d66120b593611149610120880188611fec565b35604051906120e48261017d565b6001600160a01b038816825260208201526120ff828a612080565b5261210a8189612080565b500190506120ab565b5092505050565b611da061120f565b9060005b8181106121335750505090565b9091926020806001926001600160a01b03873561214f816101eb565b168152019401929101612126565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81116101415760051b809282370190565b61219961211a565b916121a382611080565b926121b060208401611080565b91604084013593606081013590608081013560a082016121cf90611080565b60c08301356121e160e0850185611fec565b9060405180916020820180946121f692612122565b03601f19810182526122089082610199565b5190209161221a610100860186611fec565b90604051809160208201809461222f92612122565b03601f19810182526122419082610199565b51902093612253610120870187611fec565b9060405180916020820180946122689261215d565b03601f198101825261227a9082610199565b51902095610140810161228c91611fec565b9060405180916020820180946122a19261215d565b03601f19810182526122b39082610199565b519020966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b634e487b7160e01b600052601160045260246000fd5b9190820180921161235e57565b61233b565b9061236d82610599565b61237a6040519182610199565b828152809261238b601f1991610599565b0190602036910137565b90815181101561107b570160200190565b600019811461235e5760010190565b9291906123c0611fcc565b506123cb8151612022565b9260005b825181101561242657806001600160a01b036123ed60019386612080565b51166123f98287612080565b516124056111626101cd565b60208201526124148288612080565b5261241f8187612080565b50016123cf565b509391505061243a61014082015160801c90565b9051906124456101dc565b9283526020830152604082015290565b906124608251612022565b9160005b81518110156124b5578061247a60019284612080565b51604051906124888261017d565b6001600160a01b038616825260208201526124a38287612080565b526124ae8186612080565b5001612464565b50505090565b611da06118b7565b805160209091019060005b8181106124db5750505090565b82516001600160a01b03168452602093840193909201916001016124ce565b805160209091019060005b8181106125125750505090565b8251845260209384019390920191600101612505565b909161014082015161253a9060401c90565b67ffffffffffffffff169361254d6124bb565b918351936020810151612566906001600160a01b031690565b9560408201516040518060208101928361257f916124c3565b03601f19810182526125919082610199565b51902092604051806020810192836125a8916124fa565b03601f19810182526125ba9082610199565b5190209060808301516125cc9061290b565b8051906020012060a08401516125e19061290b565b805190602001209060c08501516125f79061296b565b80519060200120926126089061296b565b8051906020012093610100860151612626906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a0152608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b919060808301926126cb845151612022565b9260005b85515181101561272557806126ea60019260c0860151612080565b51604051906126f88261017d565b6001600160a01b038716825260208201526127138288612080565b5261271e8187612080565b50016126cf565b509350505090565b611da0611c05565b906101408201516127469060401c90565b67ffffffffffffffff169361275961272d565b918351936020810151612772906001600160a01b031690565b956040820151612788906001600160a01b031690565b926080830151604051806020810192836127a1916124c3565b03601f19810182526127b39082610199565b51902060a0840151604051806020810192836127ce916124c3565b03601f19810182526127e09082610199565b5190209060c0850151604051806020810192836127fc916124fa565b03601f198101825261280e9082610199565b5190209260405180602081019283612825916124fa565b03601f19810182526128379082610199565b51902093610100860151612851906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b6020929190612903849282815194859201610eb5565b019081520190565b60609080516000905b8082106129215750505090565b909193926001906129616129358588612080565b5160405161294b81610f7a6020820180956124c3565b51902091610f7a604051938492602084016128ed565b9394920190612914565b60609080516000905b8082106129815750505090565b909193926001906129ab6129958588612080565b5160405161294b81610f7a6020820180956124fa565b939492019061297456fea264697066735822122090133a57e321b8c2b3310a805d062cbbf658583bcc121b2474df437f5235ceb564736f6c634300081b0033000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80632143d82c1461012b5780633644e51514610126578063416e6d5e146101215780634a0d98781461011c578063796f077b146101175780637c317e0f146101125780637eea39f21461010d57806384b0196e14610108578063971604c614610103578063a03f5274146100fe578063a5cdc8fc146100f9578063acb8cc49146100f4578063b06b61db146100ef578063b57f9fed146100ea578063c7977be7146100e5578063f0a5f8f2146100e05763f80b26e30361000e57611375565b611336565b61131b565b6111e7565b6111a3565b611187565b6110ba565b611020565b610fd4565b610f38565b610ea3565b610e61565b610e2d565b6103fb565b6103b7565b610394565b6102e3565b908161018091031261013f5790565b600080fd5b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020838186019501011161013f57565b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020808501948460051b01011161013f57565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff8211176101d557604052565b6101a3565b6040810190811067ffffffffffffffff8211176101d557604052565b6060810190811067ffffffffffffffff8211176101d557604052565b90601f8019910116810190811067ffffffffffffffff8211176101d557604052565b60405190610243604083610212565b565b6040519061024361016083610212565b60405190610243606083610212565b67ffffffffffffffff81116101d557601f01601f191660200190565b81601f8201121561013f5780359061029782610264565b926102a56040519485610212565b8284526020838301011161013f57816000926020809301838601378301015290565b6001600160a01b0381160361013f57565b3590610243826102c7565b60a036600319011261013f5760043567ffffffffffffffff811161013f5761030f903690600401610130565b60243567ffffffffffffffff811161013f5761032f903690600401610144565b919060443567ffffffffffffffff811161013f57610351903690600401610172565b906064359467ffffffffffffffff861161013f57610376610019963690600401610280565b9360843595610384876102c7565b6113be565b600091031261013f57565b3461013f57600036600319011261013f5760206103af611d8e565b604051908152f35b3461013f57600036600319011261013f5760206040516001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a168152f35b608036600319011261013f57600435610413816102c7565b602435600381101561013f5760443567ffffffffffffffff811161013f5761043f903690600401610280565b9160643567ffffffffffffffff811161013f57610460903690600401610280565b92610469613d76565b835115610d845761048360208551860101602086016118da565b935b5160009015610d7e575061049884613e3a565b905b8115159384610d45575b6104ad81611e2f565b8061081c5750806020806104c693518301019101612a48565b6001600160a01b03979396919495977f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f578760008a61053d8296604051998a97889687957f57c3af1e00000000000000000000000000000000000000000000000000000000875260048701612c0c565b03925af19081156107b75761056c926001600160a01b0392610807575b50166001600160a01b03166040860152565b806107bc575b50608083019061059861058c83516001600160a01b031690565b6001600160a01b031690565b916001600160a01b0360c08601936105d58551917f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f928391614be3565b16803b1561013f578460009161061c94836040518097819582947f1a4990260000000000000000000000000000000000000000000000000000000084528d60048501612c6f565b03925af180156107b7577fca180a308256a6e9607c256dd145d700f18b1ee21e9bfa2919258b31a211bb8a936001600160a01b039361072c9261079c575b5061068261066d61014089015160801c90565b6fffffffffffffffffffffffffffffffff1690565b966106a961069b6101008301516001600160a01b031690565b94516001600160a01b031690565b610120820151909790600216156107885773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee925b51916106dd8251151590565b1561077c575060200151915b6fffffffffffffffffffffffffffffffff6040519687961699169785909493926001600160a01b0360609381608085019816845216602083015260408201520152565b0390a35b61073f575b6100196001600055565b61077160206107769201517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b611d5d565b38610735565b60e091500151916106e9565b60a08201516001600160a01b0316926106d1565b806107ab60006107b193610212565b80610389565b3861065a565b611a91565b61014084016108006107df6107d2835160401c90565b67ffffffffffffffff1690565b67ffffffffffffffff6107f86107d26107d28760401c90565b911614612568565b5238610572565b806107ab600061081693610212565b3861055a565b61082881949394611e2f565b60018103610acb57508060208061084493518301019101612840565b6001600160a01b0399959693979194997f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f57886000896108bc8296604051998a97889687957ffbfa3c5b00000000000000000000000000000000000000000000000000000000875260048701612995565b03925af19081156107b7576108eb926001600160a01b0392610ab6575b50166001600160a01b03166040850152565b80610a99575b5091927f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f929060005b6080840151805182101561096757906109618661094c61058c61093f856001976125af565b516001600160a01b031690565b61095a8460c08a01516125af565b5190614be3565b0161091a565b505093926001600160a01b039095919516803b1561013f57836000916109be93836040518096819582947fefe34fe60000000000000000000000000000000000000000000000000000000084528a600485016129cc565b03925af180156107b757610a84575b507fa3f15217206817f5e14f76307e5f65cfdc211516553c6638ef4fc79c4d6a0f0a6001600160a01b03610a0961066d61014085015160801c90565b93610a70610a226101008601516001600160a01b031690565b91608086015195610a3281614cff565b9160c082015191610a438251151590565b15610a78575060200151915b6fffffffffffffffffffffffffffffffff604051968796169916978561268b565b0390a3610730565b60e09150015191610a4f565b806107ab6000610a9393610212565b386109cd565b6101408301610aaf6107df6107d2835160401c90565b52386108f1565b806107ab6000610ac593610212565b386108d9565b80610ada600292979697611e2f565b03610d1b5780602080610af29351830101910161214b565b6001600160a01b0397949592969193977f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f5787600088610b6a8296604051988997889687957f77c19c1f00000000000000000000000000000000000000000000000000000000875260048701612518565b03925af180156107b757610d06575b5080610ce9575b50610b8e8383959495614721565b9590926000947f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f955b8551811015610be85780610be2888b61095a84610bdc61058c61093f6001998f6125af565b926125af565b01610bb7565b50929690946001600160a01b039096929616803b1561013f5782600091610c4095836040518098819582947f14e7a7ab0000000000000000000000000000000000000000000000000000000084528d600485016125df565b03925af19283156107b757610c896001600160a01b0393610a70927f85272ea7cbfb5ccba50d6cfaad14ff2ea471614d48c96ed5ecef53f11e56657996610cd4575b5087614977565b9092610cb2610100610ca361066d6101408c015160801c90565b9901516001600160a01b031690565b936fffffffffffffffffffffffffffffffff604051968796169916978561268b565b806107ab6000610ce393610212565b38610c82565b6101408301610cff6107df6107d2835160401c90565b5238610b80565b806107ab6000610d1593610212565b38610b79565b7f7082a8de0000000000000000000000000000000000000000000000000000000060005260046000fd5b610d79610d7487517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b611953565b6104a4565b9061049a565b610d8c611737565b610d94611737565b610d9c610234565b918252602082015293610485565b60405190610db9604083610212565b600d82527f4a616d536574746c656d656e74000000000000000000000000000000000000006020830152565b60005b838110610df85750506000910152565b8181015183820152602001610de8565b90602091610e2181518092818552858086019101610de5565b601f01601f1916010190565b3461013f57600036600319011261013f57610e5d610e49610daa565b604051918291602083526020830190610e08565b0390f35b3461013f57604036600319011261013f576100196000808080600435610e86816102c7565b6001600160a01b0360243591165af1610e9d612ce3565b50612d13565b3461013f57604036600319011261013f57600160ff600435610ec4816102c7565b6001600160a01b036024359116600052600260205260406000208160081c600052602052161b604060002054161560405180916020820190151582520390f35b906020808351928381520192019060005b818110610f225750505090565b8251845260209384019390920191600101610f15565b3461013f57600036600319011261013f57610fa5610f54610daa565b610e5d610f5f61114c565b610fb3610f6a612d44565b916040519586957f0f00000000000000000000000000000000000000000000000000000000000000875260e0602088015260e0870190610e08565b908582036040870152610e08565b90466060850152306080850152600060a085015283820360c0850152610f04565b3461013f57606036600319011261013f57600435610ff1816102c7565b6024356044359167ffffffffffffffff831161013f57611018610019933690600401610144565b929091612e33565b608036600319011261013f5760043567ffffffffffffffff811161013f5761104c903690600401610130565b60243567ffffffffffffffff811161013f5761106c903690600401610144565b60449291923567ffffffffffffffff811161013f5761108f903690600401610172565b916064359467ffffffffffffffff861161013f576110b4610019963690600401610280565b94613089565b3461013f57602036600319011261013f5760043580156111225761111f600160ff8360081c93161b91336000526002602052604060002092816000528360205260406000205461110e828083161415615051565b179290600052602052604060002090565b55005b7f150b14ee0000000000000000000000000000000000000000000000000000000060005260046000fd5b6040519061115b604083610212565b600182527f32000000000000000000000000000000000000000000000000000000000000006020830152565b3461013f57600036600319011261013f57610e5d610e4961114c565b3461013f57600036600319011261013f5760206040516001600160a01b037f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f168152f35b60a036600319011261013f5760043567ffffffffffffffff811161013f57611213903690600401610172565b9060243567ffffffffffffffff811161013f57611234903690600401610172565b9260443567ffffffffffffffff811161013f57611255903690600401610172565b906064359567ffffffffffffffff871161013f5761127a610019973690600401610172565b9590946084359761128a896102c7565b613697565b60405160208101907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672082527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060408201527f766572696679696e67436f6e7472616374290000000000000000000000000000606082015260528152611315607282610212565b51902090565b3461013f57600036600319011261013f5760206103af61128f565b3461013f57604036600319011261013f5760043567ffffffffffffffff811161013f576103af61136c6020923690600401610130565b60243590613c33565b3461013f57602036600319011261013f5760043567ffffffffffffffff811161013f576040600319823603011261013f576103af6113b96020923690600401613bbd565b613e3a565b9290959193956113cc613d76565b8551156116f9576113e660208751880101602088016118da565b955b51600090156116f457506113fb86613e3a565b61140781878488613f5e565b80151595866116c0575b61141e6101608701611984565b15611608576001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a1690813b1561013f576000809461147a604051988996879586946332910d0160e11b86528d60048701611afe565b03925af19081156107b7576114c2926114bd926115f3575b505b7f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9687916141fd565b611c63565b6101408101907f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b036115056114fe858561198e565b3691611c94565b92611549846115446101008401976115296115208a8761198e565b9190928761198e565b602088019591611538876119c4565b9360c08a013595614310565b6119c4565b821630146115cc575b6115a0608082013594611564836119c4565b9261158161158f61157860e084018461198e565b92909a8461198e565b91909361012081019061198e565b939092604051988998169b88611d11565b0390a36115b4575b50506102436001600055565b6115c591602061077192015161412f565b38806115a8565b6115ee6115e96115e56115df888561198e565b90614683565b1590565b611ce0565b611552565b806107ab600061160293610212565b38611492565b5050506001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a1661164260e085018561198e565b93909161165361012087018761198e565b95909261165f886119c4565b94833b1561013f5761168d6000969287936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19081156107b7576114c2926114bd926116ab575b50611494565b806107ab60006116ba93610212565b386116a5565b6116ef610d7489517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b611411565b6113fb565b611701611737565b611709611737565b611711610234565b9182526020820152956113e8565b67ffffffffffffffff81116101d55760051b60200190565b60405190611746602083610212565b6000825281601f19611758600061171f565b019060005b82811061176957505050565b602090604051611778816101b9565b60008152600083820152600060408201526060808201528282850101520161175d565b8015150361013f57565b5190610243826102c7565b81601f8201121561013f5780516117c681610264565b926117d46040519485610212565b8184526020828401011161013f576117f29160208085019101610de5565b90565b9080601f8301121561013f5781519161180d8361171f565b9261181b6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b83831061184757505050505090565b825167ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190611876826101b9565b60208301516118848161179b565b82526040830151611894816102c7565b60208301526060830151604083015260808301519167ffffffffffffffff831161013f576118ca886020809695819601016117b0565b6060820152815201920191611838565b60208183031261013f5780519067ffffffffffffffff821161013f570160408183031261013f576040519161190e836101da565b815167ffffffffffffffff811161013f578161192b9184016117f5565b8352602082015167ffffffffffffffff811161013f5761194b92016117f5565b602082015290565b1561195a57565b7f08f0f0fa0000000000000000000000000000000000000000000000000000000060005260046000fd5b356117f28161179b565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f57602001918160051b3603831361013f57565b356117f2816102c7565b9160209082815201919060005b8181106119e85750505090565b9091926020806001926001600160a01b038735611a04816102c7565b1681520194019291016119db565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161013f5760209260051b809284830137010190565b949695916001600160a01b0393606095611a768694611a849460808b5260808b01916119ce565b9188830360208a0152611a12565b9616604085015216910152565b6040513d6000823e3d90fd5b9035601e198236030181121561013f57016020813591019167ffffffffffffffff821161013f578160051b3603831361013f57565b35906102438261179b565b908060209392818452848401376000828201840152601f01601f1916010190565b90611c4e906102439597969460609460808552611b2e60808601611b21856102d8565b6001600160a01b03169052565b611b4d611b3d602085016102d8565b6001600160a01b031660a0870152565b604083013560c08601528583013560e08601526080830135610100860152611b8b611b7a60a085016102d8565b6001600160a01b0316610120870152565b60c0830135610140860152611c41611c37610160611c30611c0f611bee611bcd8b610200611bbc60e08d018d611a9d565b9190926101808982015201916119ce565b611bdb6101008b018b611a9d565b8d8303607f19016101808f0152906119ce565b611bfc6101208a018a611a9d565b8c8303607f19016101a08e015290611a12565b611c1d610140890189611a9d565b8b8303607f19016101c08d015290611a12565b9501611ad2565b15156101e0870152565b8483036020860152611add565b95604082015201906001600160a01b03169052565b15611c6a57565b7fff774c530000000000000000000000000000000000000000000000000000000060005260046000fd5b929190611ca08161171f565b93611cae6040519586610212565b602085838152019160051b810192831161013f57905b828210611cd057505050565b8135815260209182019101611cc4565b15611ce757565b7f7a745d4b0000000000000000000000000000000000000000000000000000000060005260046000fd5b959192611d4f94611d33611d41936117f29a989660808b5260808b01916119ce565b9188830360208a01526119ce565b918583036040870152611a12565b916060818403910152610f04565b15611d6457565b7fe70c1fc90000000000000000000000000000000000000000000000000000000060005260046000fd5b467f0000000000000000000000000000000000000000000000000000000000028c5803611dd9577f3b5143daea1dc0453cc708354ef2cd7a878c077cbb2da3339ce3e7099cdcdf4490565b611de161128f565b611de9610daa565b60208151910120611df861114c565b602081519101206040519160208301938452604083015260608201524660808201523060a082015260a0815261131560c082610212565b60031115611e3957565b634e487b7160e01b600052602160045260246000fd5b9080601f8301121561013f578151611e668161171f565b92611e746040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611e9c5750505090565b602080918351611eab816102c7565b815201910190611e8f565b9080601f8301121561013f578151611ecd8161171f565b92611edb6040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611f035750505090565b8151815260209182019101611ef6565b9080601f8301121561013f578151611f2a8161171f565b92611f386040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611f6457505050505090565b815167ffffffffffffffff811161013f57602091611f8787848094880101611e4f565b815201910190611f55565b9080601f8301121561013f578151611fa98161171f565b92611fb76040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611fe357505050505090565b815167ffffffffffffffff811161013f5760209161200687848094880101611eb6565b815201910190611fd4565b91909160408184031261013f576040519061202b826101da565b819381519167ffffffffffffffff831161013f5761204f60209392849383016117b0565b84520151910152565b9080601f8301121561013f57815161206f8161171f565b9261207d6040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b8382106120a957505050505090565b815167ffffffffffffffff811161013f576020916120cc87848094880101612011565b81520191019061209a565b919060608382031261013f57604051906120f0826101f6565b819380516120fd8161179b565b8352602081015167ffffffffffffffff811161013f578261211f918301611f92565b602084015260408101519167ffffffffffffffff831161013f576040926121469201611eb6565b910152565b91909160a08184031261013f57805167ffffffffffffffff811161013f5781016101608185031261013f5761217e610245565b908051825261218f602082016117a5565b6020830152604081015167ffffffffffffffff811161013f57856121b4918301611e4f565b6040830152606081015167ffffffffffffffff811161013f57856121d9918301611eb6565b6060830152608081015167ffffffffffffffff811161013f57856121fe918301611f13565b608083015260a081015167ffffffffffffffff811161013f5785612223918301611f13565b60a083015260c081015167ffffffffffffffff811161013f5785612248918301611f92565b60c083015260e081015167ffffffffffffffff811161013f578561226d918301611f92565b60e083015261227f61010082016117a5565b6101008301526101208101519067ffffffffffffffff821161013f576122aa866101409383016117b0565b610120840152015161014082015292602082015167ffffffffffffffff811161013f57816122d9918401612058565b92604083015167ffffffffffffffff811161013f57826122fa9185016120d7565b92606081015192608082015167ffffffffffffffff811161013f576117f292016117b0565b906020808351928381520192019060005b81811061233d5750505090565b82516001600160a01b0316845260209384019390920191600101612330565b9080602083519182815201916020808360051b8301019401926000915b83831061238857505050505090565b90919293946020806123a6600193601f19868203018752895161231f565b97019301930191939290612379565b9080602083519182815201916020808360051b8301019401926000915b8383106123e157505050505090565b90919293946020806123ff600193601f198682030187528951610f04565b970193019301919392906123d2565b805182526020808201516001600160a01b03169083015290610140806124d96124b161249f61248d61247b61246961245760408b015161016060408c01526101608b019061231f565b60608b01518a820360608c0152610f04565b60808a015189820360808b015261235c565b60a089015188820360a08a015261235c565b60c088015187820360c08901526123b5565b60e087015186820360e08801526123b5565b610100868101516001600160a01b031690860152610120860151858203610120870152610e08565b93015191015290565b6117f291815115158152604061250760208401516060602085015260608401906123b5565b920151906040818403910152610f04565b9160809361254f61255d926125416001600160a01b03959a99989a60a0885260a088019061240e565b9086820360208801526124e2565b908482036040860152610e08565b951660608201520152565b1561256f57565b7fe823bd5a0000000000000000000000000000000000000000000000000000000060005260046000fd5b634e487b7160e01b600052603260045260246000fd5b80518210156125c35760209160051b010190565b612599565b906020806124d98451604085526040850190610e08565b92906125f39060a0855260a085019061240e565b8381036020850152825180825260208201916020808360051b8301019501926000915b83831061265e575050505050829161263f91600060406117f296015283820360608501526124e2565b9060808183039101526040906002815261060f60f31b60208201520190565b909192939560208061267c600193601f198682030187528a516125c8565b98019301930191939290612616565b926126b76117f295936126a9611d4f9460808852608088019061231f565b90868203602088015261231f565b908482036040860152610f04565b91906101608382031261013f576126da610245565b92805184526126eb602082016117a5565b60208501526126fc604082016117a5565b604085015260608101516060850152608081015167ffffffffffffffff811161013f578261272b918301611e4f565b608085015260a081015167ffffffffffffffff811161013f5782612750918301611e4f565b60a085015260c081015167ffffffffffffffff811161013f5782612775918301611eb6565b60c085015260e081015167ffffffffffffffff811161013f578261279a918301611eb6565b60e08501526127ac61010082016117a5565b61010085015261012081015167ffffffffffffffff811161013f57610140926127d69183016117b0565b6101208501520151610140830152565b91909160608184031261013f5760405190612800826101f6565b8193815161280d8161179b565b835260208201519167ffffffffffffffff831161013f576128346040939284938301611eb6565b60208501520151910152565b9160c08383031261013f57825167ffffffffffffffff811161013f57826128689185016126c5565b92602081015167ffffffffffffffff811161013f5783612889918301612011565b92604082015167ffffffffffffffff811161013f57816128aa9184016127e6565b926128b7606084016117a5565b9260808101519260a082015167ffffffffffffffff811161013f576117f292016117b0565b805182526020808201516001600160a01b031690830152906040828101516001600160a01b03169082015260608201516060820152610140806124d96124b161296061294e61293c608089015161016060808a015261016089019061231f565b60a089015188820360a08a015261231f565b60c088015187820360c0890152610f04565b60e087015186820360e0880152610f04565b908151151581526040806124d96020850151606060208601526060850190610f04565b9160809361254f61255d926129be6001600160a01b03959a99989a60a0885260a08801906128dc565b908682036020880152612972565b91926129f86117f2946129ea61263f9460a0875260a08701906128dc565b9085820360208701526125c8565b90600060408501528382036060850152612972565b919082606091031261013f57604051612a25816101f6565b60408082948051612a358161179b565b8452602081015160208501520151910152565b91828203610240811261013f576101601361013f57612a65610245565b83518152612a75602085016117a5565b6020820152612a86604085016117a5565b604082015260608401516060820152612aa1608085016117a5565b6080820152612ab260a085016117a5565b60a082015260c084015160c082015260e084015160e0820152612ad861010085016117a5565b6101008201526101208401516101208201526101408401516101408201529261016081015167ffffffffffffffff811161013f5783612b18918301612011565b92612b27816101808401612a0d565b92612b356101e084016117a5565b926102008101519261022082015167ffffffffffffffff811161013f576117f292016117b0565b610140809180518452612b7f602082015160208601906001600160a01b03169052565b6040818101516001600160a01b03169085015260608101516060850152612bb6608082015160808601906001600160a01b03169052565b60a0818101516001600160a01b03169085015260c081015160c085015260e081015160e0850152612bf96101008201516101008601906001600160a01b03169052565b6101208101516101208501520151910152565b9161020093612c4f612c6392612c2e866001600160a01b03969b9a999b612b5c565b805115156101608701526020810151610180870152604001516101a0860152565b6102206101c0850152610220840190610e08565b95166101e08201520152565b90612c996117f29493612c8584612cc494612b5c565b6102206101608501526102208401906125c8565b6000610180840152835115156101a084015260208401516101c08401526040909301516101e0830152565b6102008183039101526040906002815261060f60f31b60208201520190565b3d15612d0e573d90612cf482610264565b91612d026040519384610212565b82523d6000602084013e565b606090565b15612d1a57565b7ffe8a94f40000000000000000000000000000000000000000000000000000000060005260046000fd5b60405190612d53602083610212565b6000808352366020840137565b90612d6a8261171f565b612d776040519182610212565b8281528092612d88601f199161171f565b0190602036910137565b9081602091031261013f57517fffffffff000000000000000000000000000000000000000000000000000000008116810361013f5790565b6040906117f2949281528160208201520191611add565b919082604091031261013f576020823592013590565b634e487b7160e01b600052601160045260246000fd5b60ff601b9116019060ff8211612e1f57565b612df7565b90604010156125c35760400190565b929091906000843b612fbd5760418203612f30575090602092612eab83612e83612e7d612e6f612e67600098880188612de1565b949097612e24565b356001600160f81b03191690565b60f81c90565b935b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156107b7576001600160a01b0360005116908115612f06576001600160a01b031603612edc57565b7f815e1d640000000000000000000000000000000000000000000000000000000060005260046000fd5b7f8baa579f0000000000000000000000000000000000000000000000000000000060005260046000fd5b60408203612f955750602092612f4e83612eab936000950190612de1565b929092612f8f612f8a612f847f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c90565b60ff1690565b612e0d565b93612e85565b807f4be6321b0000000000000000000000000000000000000000000000000000000060049252fd5b936020926001600160a01b03612fea9560405196879586948593630b135d3f60e11b855260048501612dca565b0392165afa9081156107b757630b135d3f60e11b917fffffffff0000000000000000000000000000000000000000000000000000000091849161305a575b5016036130325750565b807fb0669cbc0000000000000000000000000000000000000000000000000000000060049252fd5b61307c915060203d602011613082575b6130748183610212565b810190612d92565b38613028565b503d61306a565b9291939093613096613d76565b8551156135f0576130b060208751880101602088016118da565b955b51600090156135ea57506130c586613e3a565b945b6130d386838388613f5e565b85151595866135b6575b6130ea6101608701611984565b15613508576001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f57869360008094613148604051978896879586946332910d0160e11b8652339360048701611afe565b03925af180156107b7576134f3575b505b60c0830135806132d4575061317e9161317661014085018561198e565b929091614fde565b6001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a166101008401936131b8858261198e565b90926131c6602084016119c4565b90803b1561013f5786600080946131f78995604051998a9788968795635abff4df60e01b8752339360048801611a4f565b03925af180156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd936001600160a01b0393613273926132bf575b50608083013595613245846119c4565b9361158161326261325960e084018461198e565b92909b8461198e565b939092604051998a99169c8961364b565b0390a35b613287575b506102436001600055565b61077160206132b99201517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b3861327c565b806107ab60006132ce93610212565b38613235565b906132ef926132e761014086018661198e565b929091614e3d565b9193906001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a169061010083019561332d878561198e565b613339602087016119c4565b853b1561013f576000916133658a926040519586948594635abff4df60e01b8652339260048701613616565b038183885af180156107b7576134de575b508051613460575b5080516133ce575b50507f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd91506001600160a01b03906133c6608082013594611564836119c4565b0390a3613277565b6133d8868461198e565b929091813b1561013f576000809461340860405198899687958694635abff4df60e01b8652339260048701613616565b03925af19081156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd926001600160a01b039261344b575b819250613386565b806107ab600061345a93610212565b38613443565b61346a878561198e565b9190843b1561013f576000916134b86040519485938493635abff4df60e01b85527f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d92339260048701613616565b038183875af180156107b7571561337e57806107ab60006134d893610212565b3861337e565b806107ab60006134ed93610212565b38613376565b806107ab600061350293610212565b38613157565b5050506001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a1661354260e085018561198e565b909161355261012087018761198e565b919061355d886119c4565b94823b1561013f5760009461358c869260405198899788968795635abff4df60e01b8752339460048801611a4f565b03925af180156107b7576135a1575b50613159565b806107ab60006135b093610212565b3861359b565b6135e5610d7489517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b6130dd565b946130c7565b6135f8611737565b613600611737565b613608610234565b9182526020820152956130b2565b93959490611a8460609461363d6001600160a01b039593869460808a5260808a01916119ce565b908782036020890152610f04565b9694926136899461366d61367b936117f29b999560808c5260808c01916119ce565b9189830360208b01526119ce565b918683036040880152611a12565b926060818503910152611a12565b92979097969495969391936136aa613d76565b6136b88186888b8d89615157565b851515948860005b878c8210613855575050505050506114bd6136fe917f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9687916141fd565b60005b86811061371957505050505050506102436001600055565b808388613729818660019661525d565b61378f818761374761373c888784613a67565b61010081019061198e565b6137636137588a8986979597613a67565b61014081019061198e565b9160c06137878c8b613781602061377b84848d613a67565b016119c4565b98613a67565b013595614532565b7f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b0360806137c587868b613a67565b01359261381d6137d961154489888d613a67565b918a6137f36137e98b8a84613a67565b60e081019061198e565b909861158f6138128d61380a61373c828689613a67565b949096613a67565b61012081019061198e565b0390a361382b575b01613701565b6138506107718761384a613840858a8d613a45565b602081019061198e565b906141fd565b613825565b6139ff575b8b61387261016061386c84848c613a67565b01611984565b1561394957896138ad836001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16938b613a67565b91836138ba818989613abd565b9390968d60009060001461393f57506138df926113b9926138da92613a45565b613c19565b945b813b1561013f576000809461390d8b604051998a97889687956332910d0160e11b875260048701611afe565b03925af19182156107b75760019261392a575b505b0189906136c0565b806107ab600061393993610212565b38613920565b92505050946138e1565b91506001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16876139846137e9848684613a67565b6139a46115448661399c613812828b899a989a613a67565b999096613a67565b823b1561013f576000946139d18b87936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19182156107b7576001926139ea575b50613922565b806107ab60006139f993610212565b386139e4565b613a40610d74613a19613a13848d87613a45565b8061198e565b7f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a916141fd565b61385a565b91908110156125c35760051b81013590603e198136030182121561013f570190565b91908110156125c35760051b8101359061017e198136030182121561013f570190565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f5760200191813603831361013f57565b908210156125c357613ad49160051b810190613a8a565b9091565b9080601f8301121561013f57813591613af08361171f565b92613afe6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b838310613b2a57505050505090565b823567ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190613b59826101b9565b6020830135613b678161179b565b82526040830135613b77816102c7565b60208301526060830135604083015260808301359167ffffffffffffffff831161013f57613bad88602080969581960101610280565b6060820152815201920191613b1b565b919060408382031261013f5760405190613bd6826101da565b8193803567ffffffffffffffff811161013f5782613bf5918301613ad8565b835260208101359167ffffffffffffffff831161013f576020926121469201613ad8565b6117f2903690613bbd565b9081602091031261013f575190565b613c406101608201611984565b15613d5d57604051917f3644e5150000000000000000000000000000000000000000000000000000000083526020836004816001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3165afa9283156107b757600093613d1e575b50613ce9613d1092611315926001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a169161592f565b604051928391602083019586909160429261190160f01b8352600283015260228201520190565b03601f198101835282610212565b611315919350613d1092613d4c613ce99260203d602011613d56575b613d448183610212565b810190613c24565b9492509250613cad565b503d613d3a565b90611315613ce9613d1092613d70611d8e565b946156b3565b600260005414613d87576002600055565b7f3ee5aeb50000000000000000000000000000000000000000000000000000000060005260046000fd5b9080602083519182815201916020808360051b8301019401926000915b838310613ddd57505050505090565b9091929394602080613e2b600193601f19868203018752608060608b518051151584526001600160a01b03868201511686850152604081015160408501520151918160608201520190610e08565b97019301930191939290613dce565b602081018051511580613e90575b613e8957611315613d1091604051928391613e76602084019660208852516040808601526080850190613db1565b9051838203603f19016060850152613db1565b5050600090565b5081515115613e48565b15613ea157565b7f710c94970000000000000000000000000000000000000000000000000000000060005260046000fd5b15613ed257565b7f83dfb46e0000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f0357565b7fec7706630000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f3457565b7fc56873ba0000000000000000000000000000000000000000000000000000000060005260046000fd5b909260409261024394613f70846119c4565b6001600160a01b0316331415806140e8575b61408d575b505050613f9a6115e56101608301611984565b801561407c575b614055575b60a0810133613fb761058c836119c4565b1490811561403a575b50801561402d575b613fd190613e9a565b613ffb613fe261010083018361198e565b9050613ff261014084018461198e565b91905014613ecb565b61402461400b60e083018361198e565b905061401b61012084018461198e565b91905014613efc565b01354210613f2d565b5060608101354211613fc8565b6001600160a01b03915061404d906119c4565b161538613fc0565b614077614061826119c4565b60808301356402540be3ff858501351491615082565b613fa6565b506402540be3ff8282013514613fa1565b6140e092613d106140cf6140a96140a2611d8e565b93886156b3565b8851928391602083019586909160429261190160f01b8352600283015260228201520190565b5190206140db856119c4565b612e33565b388080613f87565b506140f96115e56101608601611984565b613f82565b1561410557565b7f9eb00a7e0000000000000000000000000000000000000000000000000000000060005260046000fd5b9060005b82518110156141c55761414681846125af565b5160008061417f61058c61058c6020860161093f61416b82516001600160a01b031690565b6001600160a01b03808c16911614156140fe565b604084015190606085015191602083519301915af161419c612ce3565b501590816141ba575b506141b257600101614133565b505050600090565b5115159050386141a5565b505050600190565b91908110156125c35760051b81013590607e198136030182121561013f570190565b908092918237016000815290565b91909160005b8381106142135750505050600190565b61421e8185846141cd565b60008061424e61058c61058c6020860161154461423a826119c4565b6001600160a01b03808d16911614156140fe565b60408401356142606060860186613a8a565b9190614271604051809481936141ef565b03925af161427d612ce3565b5015908161429c575b5061429357600101614203565b50505050600090565b6142a69150611984565b38614286565b91908110156125c35760051b0190565b91908203918211612e1f57565b156142d357505050565b6001600160a01b03907f875c683c000000000000000000000000000000000000000000000000000000006000521660045260245260445260646000fd5b909194929460005b838110614329575050505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61434f61058c6115448488886142ac565b60009291036144ca5760019150475b61436882896125af565b5288614484575b6143b761437c82896125af565b51614388838b876142ac565b35614397611544858a8a6142ac565b6143a2858d896142ac565b35916143ae868d6125af565b519310156142c9565b86818773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6143e061058c611544858c8c6142ac565b03614456576000808061440161440d956001600160a01b03839616976125af565b51865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061444c61443b848b6125af565b516040519081529081906020820190565b0390a25b01614318565b5061447f915061058c61154461446d9289896142ac565b87614478848b6125af565b5191615a8b565b614450565b6144ba6144aa6144986115448489896142ac565b6144a2848b6125af565b51908c615a0f565b6144b4838a6125af565b516142bc565b6144c482896125af565b5261436f565b6144de61058c61058c6115448489896142ac565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b75760019391614514575b5061435e565b61452c915060203d8111613d5657613d448183610212565b3861450e565b91909294939460005b84811061454c575050505050505050565b6001908861463e575b614595614562828a6125af565b518961456f8487896142ac565b3561457e611544868c8c6142ac565b906143ae8661458e818b8d6142ac565b35946125af565b87818873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6145be61058c611544858d8d6142ac565b0361461757600080806144016145df956001600160a01b03839616976125af565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061460d61443b848c6125af565b0390a25b0161453b565b50614639915061058c61154461462e928a8a6142ac565b88614478848c6125af565b614611565b61466661465c614652611544848a8a6142ac565b6144a2848c6125af565b6144b4838b6125af565b614670828a6125af565b52614555565b91908201809211612e1f57565b9060005b6000198201828111612e1f578110156141b25760018101808211612e1f575b8281106146b65750600101614687565b6146c382848694966142ac565b356146cd816102c7565b6001600160a01b036146e661058c6115448588886142ac565b9116146146f8576001019290926146a6565b50505050600190565b9081518110156125c3570160200190565b6000198114612e1f5760010190565b6000929150825b604082015151841015614759576147516001916147498660808601516125af565b515190614676565b930192614728565b92509061476e61476884612d60565b93612d60565b60009384805b60408601515187101561496b57614793906147498860a08901516125af565b6147a18760808801516125af565b515160005b8181106147cb5750506147c36001916147498960808a01516125af565b960195614774565b7f08000000000000000000000000000000000000000000000000000000000000006001600160f81b031961481f6148116101208c015161480b8689614676565b90614701565b516001600160f81b03191690565b1614158015614963575b614836575b6001016147a6565b8761485461093f8361484e8d608060019601516125af565b516125af565b8a838b600160fa1b6001600160f81b031961487c6148118b61480b8761012088015192614676565b1614614947575b6148949260c061484e9201516125af565b519160005b8781106148ed575b509060019392916148b6575b5050905061482e565b6148d2906148c4888a6125af565b906001600160a01b03169052565b6148e56148de87614712565b96896125af565b5238806148ad565b896148fb61093f838c6125af565b6001600160a01b038086169116146149165750600101614899565b849392506149346001969561492e8461493b946125af565b51614676565b918b6125af565b526000909192936148a1565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614883565b506000614829565b50808252825293509150565b600092835b6040830151518510156149a55761499d6001916147498760a08701516125af565b94019361497c565b935090916149bb6149b585612d60565b94612d60565b6000916001918391829190825b604089015151871015614bd4576149e38760a08b01516125af565b5151855b818110614a26575050614a1e600191614a188b6147498b6080614a0e8260a08601516125af565b51519301516125af565b90614676565b9601956149c8565b868b89614b89575b50614a3c575b6001016149e7565b60018b8a83614a5661093f8261484e8560a08801516125af565b92600160fa1b6001600160f81b0319614a7c6148118b61480b8761012088015192614676565b1614614b6d575b885115614b4f575061484e614a9c9260208a01516125af565b519088908f9493945b8b5b838110614aed575b50600195614ac3575b505050509050614a34565b614ad0926148c4916125af565b614ae3614adc89614712565b98886125af565b523887818f614ab8565b9193949592908a614b0161093f85846125af565b6001600160a01b03808816911614614b2557505050600101918f8a92959493614aa7565b8391929450614b408761492e60019a999896614b47946125af565b918c6125af565b528b95614aaf565b614b609260e061484e9201516125af565b519088908f949394614aa5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614a83565b7f07000000000000000000000000000000000000000000000000000000000000009150614bcb6148116101206001600160f81b031993015161480b8689614676565b1614158b614a2e565b50509550925050508084528252565b91906040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03831660248201526020816044816001600160a01b0388165afa9081156107b757600091614ce0575b5010614c4b575050565b6014526000196034526f095ea7b3000000000000000000000000600052602060006044601082855af13d15600160005114171615614c8c575b506000603452565b60006044601082602094816034526f095ea7b300000000000000000000000082528138858583855af15081196034525af13d15600160005114171615614cd25738614c84565b633e3f8f736000526004601cfd5b614cf9915060203d602011613d5657613d448183610212565b38614c41565b9060a08201614d0f815151612d60565b9060005b815151811015614d9a5780600160fa1b6001600160f81b0319614d3d6001946101208a0151614701565b511614600090600014614d7d575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03614d7383876125af565b9116905201614d13565b6001600160a01b0390614d918386516125af565b90505116614d61565b50509150565b15614da757565b7f692f31020000000000000000000000000000000000000000000000000000000060005260046000fd5b81810292918115918404141715612e1f57565b8115614dee570490565b634e487b7160e01b600052601260045260246000fd5b15614e0d575050565b7f871cbeab0000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b92949190606095614e4e8796615b5b565b94919690614e5d858514614da0565b61ffff614e6986612d60565b961680614f7f575b5061ffff1680614ed5575b505060005b838110614e92575050505093929190565b80614ecf614ea2600193886125af565b51614eae8387876142ac565b35614eba8488886142ac565b3590614ec6858b6125af565b51921015614e04565b01614e81565b909750614ee184612d60565b9760005b858110614ef25750614e7c565b80614f15614f0d85614f076001958b886142ac565b35614dd1565b612710900490565b614f1f828d6125af565b52614f2a81896125af565b51614f6157614f508b614f4983614f42818c896142ac565b35926125af565b51906142bc565b614f5a828a6125af565b5201614ee5565b614f7a8b614f4983614f73818d6125af565b51926125af565b614f50565b9950614f8a85612d60565b9960005b8b87808310614f9f57505050614e71565b90614fb983610bdc614f0d87614f0784600199988d6142ac565b52614fcd8d614f4983614f42818d8b6142ac565b614fd7828b6125af565b5201614f8e565b91909392841561504957614ff3818614614da0565b60005b858110615004575050509190565b8061504361501560019389886142ac565b356150218386886142ac565b3561502d8487896142ac565b359061503a858c8b6142ac565b35921015614e04565b01614ff6565b935090509190565b1561505857565b7f756688fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b908015611122576150d891600160ff8360081c93161b936000906000146150db57506001600160a01b031660005260026020526040600020925b816000528360205260406000205461110e828083161415615051565b55565b6001600160a01b03604092168152600160205220926150bc565b156150fc57565b7fa18792da0000000000000000000000000000000000000000000000000000000060005260046000fd5b1561512d57565b7fb82564ab0000000000000000000000000000000000000000000000000000000060005260046000fd5b939295948615918181036152025787811480156151fb575b615178906150f5565b60005b81811061518d57505050505050509050565b6001906151ae306151a761058c602061377b86898f613a67565b1415615126565b6151de6151bc82858b613a67565b828c6151c982898d613abd565b9290918b8b156151e457505050600092613f5e565b0161517b565b6151f5926113b9926138da92613a45565b92613f5e565b508261516f565b7f6e3779d80000000000000000000000000000000000000000000000000000000060005260046000fd5b1561523357565b7fadfbc6fc0000000000000000000000000000000000000000000000000000000060005260046000fd5b929161526a848284613a67565b93610100850161528461527d828861198e565b9050612d60565b9361014087019360005b615298848a61198e565b90508110156154e357600090855b8381106153f5575089878973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6152e061058c611544876152da8d8961198e565b906142ac565b14886000916000146153635750506152da8261533086809461532060019a61531b8a615314866152da6153379d479461198e565b3590614dd1565b614de4565b61532a83836125af565b526125af565b519461198e565b3511615344575b0161528e565b615352816152da898d61198e565b3561535d828a6125af565b5261533e565b61537f935061058c9250856152da6115449261058c949761198e565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b7576152da8a6153308f958e61532060019a61531b8a6153148d6152da8a6153379e839e849b916153d7575b509461198e565b6153ef915060203d8111613d5657613d448183610212565b386153d0565b95909860009a989294979a9593955b61541261373c89898c613a67565b90508110156154cd57896001600160a01b0361545161058c6115448f6152da8f8f8f8a8f9361373c61544b94611544946152da93613a67565b9761198e565b911614615461575b600101615404565b948561546e89898c613a67565b610140810161547c9161198e565b61548692916142ac565b3561549091614676565b9461549e60c08b0135615c0e565b6154a989898c613a67565b60c001356154b690615c0e565b61ffff166154c89161ffff161461522c565b615459565b509890956001909a979492989a959395016152a6565b509496505050505050565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec81526117f261010c82610212565b61563a6154ee565b6020815191012090565b9060005b8181106156555750505090565b9091926020806001926001600160a01b038735615671816102c7565b168152019401929101615648565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811161013f5760051b809282370190565b6156bb615632565b916156c5826119c4565b926156d2602084016119c4565b91604084013593606081013590608081013560a082016156f1906119c4565b60c083013561570360e085018561198e565b90604051809160208201809461571892615644565b03601f198101825261572a9082610212565b5190209161573c61010086018661198e565b90604051809160208201809461575192615644565b03601f19810182526157639082610212565b5190209361577561012087018761198e565b90604051809160208201809461578a9261567f565b03601f198101825261579c9082610212565b5190209561014081016157ae9161198e565b9060405180916020820180946157c39261567f565b03601f19810182526157d59082610212565b519020966040519b8c9b60208d019e8f9c61585d9d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b03601f19810182526113159082610212565b9061588260209282815194859201610de5565b0190565b61588e6154ee565b6117f2602e603160405180947f4a616d4f72646572207769746e6573732900000000000000000000000000000060208301526158d38151809260208686019101610de5565b81017f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75838201527f696e7432353620616d6f756e742900000000000000000000000000000000000060518201520301600e810184520182610212565b9091615939615c22565b5060e0820161595261594b828561198e565b9050615c42565b9461012084019260005b615966848761198e565b90508110156159cd57806159836115446001936152da888b61198e565b615991826152da898b61198e565b356159ac61599d610234565b6001600160a01b039093168352565b60208201526159bb828b6125af565b526159c6818a6125af565b500161595c565b50936117f29591969350615a01925060808101356040820135906159ef610255565b958652602086015260408501526156b3565b615a09615886565b91615d7b565b9190615a1c600093615b5b565b919061ffff8116615a76575b505061ffff8116615a3a575b50505090565b615a65927f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d92615e57565b8101809111612e1f57388080615a34565b615a839295508484615e57565b923880615a28565b600091826044926020956001600160a01b03604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d1160016000511416171615615ae757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b9061ffff8091169116019061ffff8211612e1f57565b9061ffff8216906001600160a01b0361ffff8460101c169360201c1661271061ffff615b878587615b45565b161015615be457831580801591615bce575b5015615ba457929190565b7fb7273bd50000000000000000000000000000000000000000000000000000000060005260046000fd5b905080615bdc575b38615b99565b508015615bd6565b7f721dbfea0000000000000000000000000000000000000000000000000000000060005260046000fd5b6117f29061ffff808260101c169116615b45565b60405190615c2f826101f6565b6000604083606081528260208201520152565b90615c4c8261171f565b615c596040519182610212565b8281528092615c6a601f199161171f565b019060005b828110615c7b57505050565b602090604051615c8a816101da565b6000815260008382015282828501015201615c6f565b60405190615caf60a083610212565b606b82527f3620646561646c696e652c0000000000000000000000000000000000000000006080837f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208201527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c6164647260408201527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608201520152565b805160209091019060005b818110615d655750505090565b8251845260209384019390920191600101615d58565b909291613d10615da7615d8c615ca0565b92604051928391615da160208401809761586f565b9061586f565b51902092815151615db781612d60565b9060005b818110615e2f5750506113159291613d1091604051615de281613d10602082018095615d4d565b51902092604060208201519101519060405196879560208701998a926001600160a01b039060a095929897969360c086019986526020860152166040840152606083015260808201520152565b80615e46615e4060019388516125af565b51615ee9565b615e5082866125af565b5201615dbb565b90615e736127109161ffff6001600160a01b0396951690614dd1565b049283911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103615edf5750506001600160a01b0316615eb2600080808086865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b66206020604051848152a290565b916117f292615a8b565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a184526001600160a01b038151166040840152015160608201526060815261131560808261021256fea2646970667358221220da6c85282a2cc6cde7c75dcde65f8361cd5c7c90ecba328016a401e28804a3c364736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d
-----Decoded View---------------
Arg [0] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [1] : _bebopBlend (address): 0xbbbbbBB520d69a9775E85b458C58c648259FAD5F
Arg [2] : _treasuryAddress (address): 0x1af49c826Ea0A8F29ea448f2171D1BCb716cB22D
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [1] : 000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f
Arg [2] : 0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.