Overview
ETH Balance
1 wei
Eth Value
Less Than $0.01 (@ $3,350.25/ETH)Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 28,902 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Execute Multiple... | 20175182 | 6 hrs ago | IN | 0.0749 ETH | 0.0039208 | ||||
Increment Bid As... | 20174797 | 8 hrs ago | IN | 0 ETH | 0.000314 | ||||
Execute Taker Bi... | 20174511 | 8 hrs ago | IN | 0.0019 ETH | 0.00026852 | ||||
Cancel Order Non... | 20173999 | 10 hrs ago | IN | 0 ETH | 0.00009787 | ||||
Execute Taker Bi... | 20173818 | 11 hrs ago | IN | 0.01 ETH | 0.00062031 | ||||
Cancel Order Non... | 20172583 | 15 hrs ago | IN | 0 ETH | 0.00013293 | ||||
Cancel Order Non... | 20171562 | 18 hrs ago | IN | 0 ETH | 0.00021388 | ||||
Execute Multiple... | 20171236 | 19 hrs ago | IN | 0.1609 ETH | 0.00420164 | ||||
Execute Taker Bi... | 20165689 | 38 hrs ago | IN | 0.0176 ETH | 0.00079033 | ||||
Execute Taker Bi... | 20165671 | 38 hrs ago | IN | 0.0175 ETH | 0.00051413 | ||||
Execute Taker Bi... | 20164658 | 42 hrs ago | IN | 0.089 ETH | 0.00049908 | ||||
Execute Taker Bi... | 20161517 | 2 days ago | IN | 0.2 ETH | 0.00091175 | ||||
Execute Taker Bi... | 20159151 | 2 days ago | IN | 0.08 ETH | 0.00049545 | ||||
Execute Taker As... | 20159046 | 2 days ago | IN | 0 ETH | 0.00053085 | ||||
Cancel Order Non... | 20157949 | 2 days ago | IN | 0 ETH | 0.00005635 | ||||
Cancel Order Non... | 20157946 | 2 days ago | IN | 0 ETH | 0.00008475 | ||||
Cancel Order Non... | 20157115 | 2 days ago | IN | 0 ETH | 0.00013127 | ||||
Cancel Order Non... | 20157110 | 2 days ago | IN | 0 ETH | 0.00013461 | ||||
Cancel Order Non... | 20157104 | 2 days ago | IN | 0 ETH | 0.00013419 | ||||
Cancel Order Non... | 20157096 | 2 days ago | IN | 0 ETH | 0.00014993 | ||||
Cancel Order Non... | 20157089 | 2 days ago | IN | 0 ETH | 0.00014433 | ||||
Cancel Order Non... | 20157071 | 2 days ago | IN | 0 ETH | 0.00014353 | ||||
Cancel Order Non... | 20157066 | 2 days ago | IN | 0 ETH | 0.0001395 | ||||
Cancel Order Non... | 20157046 | 2 days ago | IN | 0 ETH | 0.00016614 | ||||
Cancel Order Non... | 20157035 | 2 days ago | IN | 0 ETH | 0.00016809 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
20175182 | 6 hrs ago | 0.006 ETH | ||||
20175182 | 6 hrs ago | 0.035 ETH | ||||
20175182 | 6 hrs ago | 0.012 ETH | ||||
20175182 | 6 hrs ago | 0.0074 ETH | ||||
20175182 | 6 hrs ago | 0.0067 ETH | ||||
20175182 | 6 hrs ago | 0.0078 ETH | ||||
20174511 | 8 hrs ago | 0.0019 ETH | ||||
20173818 | 11 hrs ago | 0.01 ETH | ||||
20171236 | 19 hrs ago | 0.022 ETH | ||||
20171236 | 19 hrs ago | 0.022 ETH | ||||
20171236 | 19 hrs ago | 0.02 ETH | ||||
20171236 | 19 hrs ago | 0.02 ETH | ||||
20171236 | 19 hrs ago | 0.02 ETH | ||||
20171236 | 19 hrs ago | 0.02 ETH | ||||
20171236 | 19 hrs ago | 0.02 ETH | ||||
20171236 | 19 hrs ago | 0.0169 ETH | ||||
20168521 | 29 hrs ago | 0.1434449 ETH | ||||
20168521 | 29 hrs ago | 0.1434449 ETH | ||||
20165689 | 38 hrs ago | 0.0176 ETH | ||||
20165671 | 38 hrs ago | 0.0175 ETH | ||||
20165460 | 39 hrs ago | 0.01 ETH | ||||
20165460 | 39 hrs ago | 0.01 ETH | ||||
20165460 | 39 hrs ago | 0.01 ETH | ||||
20165460 | 39 hrs ago | 0.01 ETH | ||||
20164658 | 42 hrs ago | 0.089 ETH |
Loading...
Loading
Contract Name:
LooksRareProtocol
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 888888 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // LooksRare unopinionated libraries import {SignatureCheckerCalldata} from "@looksrare/contracts-libs/contracts/SignatureCheckerCalldata.sol"; import {LowLevelETHReturnETHIfAnyExceptOneWei} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelETHReturnETHIfAnyExceptOneWei.sol"; import {LowLevelWETH} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelWETH.sol"; import {LowLevelERC20Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC20Transfer.sol"; // OpenZeppelin's library (adjusted) for verifying Merkle proofs import {MerkleProofCalldataWithNodes} from "./libraries/OpenZeppelin/MerkleProofCalldataWithNodes.sol"; // Libraries import {OrderStructs} from "./libraries/OrderStructs.sol"; // Interfaces import {ILooksRareProtocol} from "./interfaces/ILooksRareProtocol.sol"; // Shared errors import {CallerInvalid, CurrencyInvalid, LengthsInvalid, MerkleProofInvalid, MerkleProofTooLarge, QuoteTypeInvalid} from "./errors/SharedErrors.sol"; // Direct dependencies import {TransferSelectorNFT} from "./TransferSelectorNFT.sol"; import {BatchOrderTypehashRegistry} from "./BatchOrderTypehashRegistry.sol"; // Constants import {MAX_CALLDATA_PROOF_LENGTH, ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol"; // Enums import {QuoteType} from "./enums/QuoteType.sol"; /** * @title LooksRareProtocol * @notice This contract is the core smart contract of the LooksRare protocol ("v2"). * It is the main entry point for users to initiate transactions with taker orders * and manage the cancellation of maker orders, which exist off-chain. LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRAR'''''''''''''''''''''''''''''''''''OOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKS:. .;OOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOO,. .,KSRARELOOKSRARELOOKSR LOOKSRARELOOKSRAREL' ..',;:LOOKS::;,'.. 'RARELOOKSRARELOOKSR LOOKSRARELOOKSRAR. .,:LOOKSRARELOOKSRARELO:,. .RELOOKSRARELOOKSR LOOKSRARELOOKS:. .;RARELOOKSRARELOOKSRARELOOKSl;. .:OOKSRARELOOKSR LOOKSRARELOO;. .'OKSRARELOOKSRARELOOKSRARELOOKSRARE'. .;KSRARELOOKSR LOOKSRAREL,. .,LOOKSRARELOOK:;;:"""":;;;lELOOKSRARELO,. .,RARELOOKSR LOOKSRAR. .;okLOOKSRAREx:. .;OOKSRARELOOK;. .RELOOKSR LOOKS:. .:dOOOLOOKSRARE' .''''.. .OKSRARELOOKSR:. .LOOKSR LOx;. .cKSRARELOOKSRAR' 'LOOKSRAR' .KSRARELOOKSRARc.. .OKSR L;. .cxOKSRARELOOKSRAR. .LOOKS.RARE' ;kRARELOOKSRARExc. .;R LO' .;oOKSRARELOOKSRAl. .LOOKS.RARE. :kRARELOOKSRAREo;. 'SR LOOK;. .,KSRARELOOKSRAx, .;LOOKSR;. .oSRARELOOKSRAo,. .;OKSR LOOKSk:. .'RARELOOKSRARd;. .... 'oOOOOOOOOOOxc'. .:LOOKSR LOOKSRARc. .:dLOOKSRAREko;. .,lxOOOOOOOOOd:. .ARELOOKSR LOOKSRARELo' .;oOKSRARELOOxoc;,....,;:ldkOOOOOOOOkd;. 'SRARELOOKSR LOOKSRARELOOd,. .,lSRARELOOKSRARELOOKSRARELOOKSRkl,. .,OKSRARELOOKSR LOOKSRARELOOKSx;. ..;oxELOOKSRARELOOKSRARELOkxl:.. .:LOOKSRARELOOKSR LOOKSRARELOOKSRARc. .':cOKSRARELOOKSRALOc;'. .ARELOOKSRARELOOKSR LOOKSRARELOOKSRARELl' ...'',,,,''... 'SRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOo,. .,OKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSx;. .;xOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLO:. .:SRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKl. .lOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRo'. .'oWENV2?LOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRARd;. .;xRELOOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRARELO:. .:kRARELOOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKl. .cOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRo' 'oLOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARE,. .,dRELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR * @author LooksRare protocol team (👀,💎) */ contract LooksRareProtocol is ILooksRareProtocol, TransferSelectorNFT, LowLevelETHReturnETHIfAnyExceptOneWei, LowLevelWETH, LowLevelERC20Transfer, BatchOrderTypehashRegistry { using OrderStructs for OrderStructs.Maker; /** * @notice Wrapped ETH. */ address public immutable WETH; /** * @notice Current chainId. */ uint256 public chainId; /** * @notice Current domain separator. */ bytes32 public domainSeparator; /** * @notice This variable is used as the gas limit for a ETH transfer. * If a standard ETH transfer fails within this gas limit, ETH will get wrapped to WETH * and transferred to the initial recipient. */ uint256 private _gasLimitETHTransfer = 2_300; /** * @notice Constructor * @param _owner Owner address * @param _protocolFeeRecipient Protocol fee recipient address * @param _transferManager Transfer manager address * @param _weth Wrapped ETH address */ constructor( address _owner, address _protocolFeeRecipient, address _transferManager, address _weth ) TransferSelectorNFT(_owner, _protocolFeeRecipient, _transferManager) { _updateDomainSeparator(); WETH = _weth; } /** * @inheritdoc ILooksRareProtocol */ function executeTakerAsk( OrderStructs.Taker calldata takerAsk, OrderStructs.Maker calldata makerBid, bytes calldata makerSignature, OrderStructs.MerkleTree calldata merkleTree, address affiliate ) external nonReentrant { address currency = makerBid.currency; // Verify whether the currency is allowed and is not ETH (address(0)) if (!isCurrencyAllowed[currency] || currency == address(0)) { revert CurrencyInvalid(); } address signer = makerBid.signer; bytes32 orderHash = makerBid.hash(); _verifyMerkleProofOrOrderHash(merkleTree, orderHash, makerSignature, signer); // Execute the transaction and fetch protocol fee amount uint256 totalProtocolFeeAmount = _executeTakerAsk(takerAsk, makerBid, orderHash); // Pay protocol fee (and affiliate fee if any) _payProtocolFeeAndAffiliateFee(currency, signer, affiliate, totalProtocolFeeAmount); } /** * @inheritdoc ILooksRareProtocol */ function executeTakerBid( OrderStructs.Taker calldata takerBid, OrderStructs.Maker calldata makerAsk, bytes calldata makerSignature, OrderStructs.MerkleTree calldata merkleTree, address affiliate ) external payable nonReentrant { address currency = makerAsk.currency; // Verify whether the currency is allowed for trading. if (!isCurrencyAllowed[currency]) { revert CurrencyInvalid(); } bytes32 orderHash = makerAsk.hash(); _verifyMerkleProofOrOrderHash(merkleTree, orderHash, makerSignature, makerAsk.signer); // Execute the transaction and fetch protocol fee amount uint256 totalProtocolFeeAmount = _executeTakerBid(takerBid, makerAsk, msg.sender, orderHash); // Pay protocol fee amount (and affiliate fee if any) _payProtocolFeeAndAffiliateFee(currency, msg.sender, affiliate, totalProtocolFeeAmount); // Return ETH if any _returnETHIfAnyWithOneWeiLeft(); } /** * @inheritdoc ILooksRareProtocol */ function executeMultipleTakerBids( OrderStructs.Taker[] calldata takerBids, OrderStructs.Maker[] calldata makerAsks, bytes[] calldata makerSignatures, OrderStructs.MerkleTree[] calldata merkleTrees, address affiliate, bool isAtomic ) external payable nonReentrant { uint256 length = takerBids.length; if ( length == 0 || (makerAsks.length ^ length) | (makerSignatures.length ^ length) | (merkleTrees.length ^ length) != 0 ) { revert LengthsInvalid(); } // Verify whether the currency at index = 0 is allowed for trading address currency = makerAsks[0].currency; if (!isCurrencyAllowed[currency]) { revert CurrencyInvalid(); } { // Initialize protocol fee amount uint256 totalProtocolFeeAmount; // If atomic, it uses the executeTakerBid function. // If not atomic, it uses a catch/revert pattern with external function. if (isAtomic) { for (uint256 i; i < length; ) { OrderStructs.Maker calldata makerAsk = makerAsks[i]; // Verify the currency is the same if (i != 0) { if (makerAsk.currency != currency) { revert CurrencyInvalid(); } } OrderStructs.Taker calldata takerBid = takerBids[i]; bytes32 orderHash = makerAsk.hash(); { _verifyMerkleProofOrOrderHash(merkleTrees[i], orderHash, makerSignatures[i], makerAsk.signer); // Execute the transaction and add protocol fee totalProtocolFeeAmount += _executeTakerBid(takerBid, makerAsk, msg.sender, orderHash); unchecked { ++i; } } } } else { for (uint256 i; i < length; ) { OrderStructs.Maker calldata makerAsk = makerAsks[i]; // Verify the currency is the same if (i != 0) { if (makerAsk.currency != currency) { revert CurrencyInvalid(); } } OrderStructs.Taker calldata takerBid = takerBids[i]; bytes32 orderHash = makerAsk.hash(); { _verifyMerkleProofOrOrderHash(merkleTrees[i], orderHash, makerSignatures[i], makerAsk.signer); try this.restrictedExecuteTakerBid(takerBid, makerAsk, msg.sender, orderHash) returns ( uint256 protocolFeeAmount ) { totalProtocolFeeAmount += protocolFeeAmount; } catch {} unchecked { ++i; } } } } // Pay protocol fee (and affiliate fee if any) _payProtocolFeeAndAffiliateFee(currency, msg.sender, affiliate, totalProtocolFeeAmount); } // Return ETH if any _returnETHIfAnyWithOneWeiLeft(); } /** * @notice This function is used to do a non-atomic matching in the context of a batch taker bid. * @param takerBid Taker bid struct * @param makerAsk Maker ask struct * @param sender Sender address (i.e. the initial msg sender) * @param orderHash Hash of the maker ask order * @return protocolFeeAmount Protocol fee amount * @dev This function is only callable by this contract. It is used for non-atomic batch order matching. */ function restrictedExecuteTakerBid( OrderStructs.Taker calldata takerBid, OrderStructs.Maker calldata makerAsk, address sender, bytes32 orderHash ) external returns (uint256 protocolFeeAmount) { if (msg.sender != address(this)) { revert CallerInvalid(); } protocolFeeAmount = _executeTakerBid(takerBid, makerAsk, sender, orderHash); } /** * @notice This function allows the owner to update the domain separator (if possible). * @dev Only callable by owner. If there is a fork of the network with a new chainId, * it allows the owner to reset the domain separator for the new chain id. */ function updateDomainSeparator() external onlyOwner { if (block.chainid != chainId) { _updateDomainSeparator(); emit NewDomainSeparator(); } else { revert SameDomainSeparator(); } } /** * @notice This function allows the owner to update the maximum ETH gas limit for a standard transfer. * @param newGasLimitETHTransfer New gas limit for ETH transfer * @dev Only callable by owner. */ function updateETHGasLimitForTransfer(uint256 newGasLimitETHTransfer) external onlyOwner { if (newGasLimitETHTransfer < 2_300) { revert NewGasLimitETHTransferTooLow(); } _gasLimitETHTransfer = newGasLimitETHTransfer; emit NewGasLimitETHTransfer(newGasLimitETHTransfer); } /** * @notice This function is internal and is used to execute a taker ask (against a maker bid). * @param takerAsk Taker ask order struct * @param makerBid Maker bid order struct * @param orderHash Hash of the maker bid order * @return protocolFeeAmount Protocol fee amount */ function _executeTakerAsk( OrderStructs.Taker calldata takerAsk, OrderStructs.Maker calldata makerBid, bytes32 orderHash ) internal returns (uint256) { if (makerBid.quoteType != QuoteType.Bid) { revert QuoteTypeInvalid(); } address signer = makerBid.signer; { bytes32 userOrderNonceStatus = userOrderNonce[signer][makerBid.orderNonce]; // Verify nonces if ( userBidAskNonces[signer].bidNonce != makerBid.globalNonce || userSubsetNonce[signer][makerBid.subsetNonce] || (userOrderNonceStatus != bytes32(0) && userOrderNonceStatus != orderHash) ) { revert NoncesInvalid(); } } ( uint256[] memory itemIds, uint256[] memory amounts, address[2] memory recipients, uint256[3] memory feeAmounts, bool isNonceInvalidated ) = _executeStrategyForTakerOrder(takerAsk, makerBid, msg.sender); // Order nonce status is updated _updateUserOrderNonce(isNonceInvalidated, signer, makerBid.orderNonce, orderHash); // Taker action goes first _transferNFT(makerBid.collection, makerBid.collectionType, msg.sender, signer, itemIds, amounts); // Maker action goes second _transferToAskRecipientAndCreatorIfAny(recipients, feeAmounts, makerBid.currency, signer); emit TakerAsk( NonceInvalidationParameters({ orderHash: orderHash, orderNonce: makerBid.orderNonce, isNonceInvalidated: isNonceInvalidated }), msg.sender, signer, makerBid.strategyId, makerBid.currency, makerBid.collection, itemIds, amounts, recipients, feeAmounts ); // It returns the protocol fee amount return feeAmounts[2]; } /** * @notice This function is internal and is used to execute a taker bid (against a maker ask). * @param takerBid Taker bid order struct * @param makerAsk Maker ask order struct * @param sender Sender of the transaction (i.e. msg.sender) * @param orderHash Hash of the maker ask order * @return protocolFeeAmount Protocol fee amount */ function _executeTakerBid( OrderStructs.Taker calldata takerBid, OrderStructs.Maker calldata makerAsk, address sender, bytes32 orderHash ) internal returns (uint256) { if (makerAsk.quoteType != QuoteType.Ask) { revert QuoteTypeInvalid(); } address signer = makerAsk.signer; { // Verify nonces bytes32 userOrderNonceStatus = userOrderNonce[signer][makerAsk.orderNonce]; if ( userBidAskNonces[signer].askNonce != makerAsk.globalNonce || userSubsetNonce[signer][makerAsk.subsetNonce] || (userOrderNonceStatus != bytes32(0) && userOrderNonceStatus != orderHash) ) { revert NoncesInvalid(); } } ( uint256[] memory itemIds, uint256[] memory amounts, address[2] memory recipients, uint256[3] memory feeAmounts, bool isNonceInvalidated ) = _executeStrategyForTakerOrder(takerBid, makerAsk, msg.sender); // Order nonce status is updated _updateUserOrderNonce(isNonceInvalidated, signer, makerAsk.orderNonce, orderHash); // Taker action goes first _transferToAskRecipientAndCreatorIfAny(recipients, feeAmounts, makerAsk.currency, sender); // Maker action goes second _transferNFT( makerAsk.collection, makerAsk.collectionType, signer, takerBid.recipient == address(0) ? sender : takerBid.recipient, itemIds, amounts ); emit TakerBid( NonceInvalidationParameters({ orderHash: orderHash, orderNonce: makerAsk.orderNonce, isNonceInvalidated: isNonceInvalidated }), sender, takerBid.recipient == address(0) ? sender : takerBid.recipient, makerAsk.strategyId, makerAsk.currency, makerAsk.collection, itemIds, amounts, recipients, feeAmounts ); // It returns the protocol fee amount return feeAmounts[2]; } /** * @notice This function is internal and is used to pay the protocol fee and affiliate fee (if any). * @param currency Currency address to transfer (address(0) is ETH) * @param bidUser Bid user address * @param affiliate Affiliate address (address(0) if none) * @param totalProtocolFeeAmount Total protocol fee amount (denominated in the currency) */ function _payProtocolFeeAndAffiliateFee( address currency, address bidUser, address affiliate, uint256 totalProtocolFeeAmount ) internal { if (totalProtocolFeeAmount != 0) { if (affiliate != address(0)) { // Check whether affiliate program is active and whether to execute a affiliate logic // If so, it adjusts the protocol fee downward. if (isAffiliateProgramActive) { uint256 totalAffiliateFeeAmount = (totalProtocolFeeAmount * affiliateRates[affiliate]) / ONE_HUNDRED_PERCENT_IN_BP; if (totalAffiliateFeeAmount != 0) { totalProtocolFeeAmount -= totalAffiliateFeeAmount; // If bid user isn't the affiliate, pay the affiliate. // If currency is ETH, funds are returned to sender at the end of the execution. // If currency is ERC20, funds are not transferred from bidder to bidder // (since it uses transferFrom). if (bidUser != affiliate) { _transferFungibleTokens(currency, bidUser, affiliate, totalAffiliateFeeAmount); } emit AffiliatePayment(affiliate, currency, totalAffiliateFeeAmount); } } } // Transfer remaining protocol fee to the protocol fee recipient _transferFungibleTokens(currency, bidUser, protocolFeeRecipient, totalProtocolFeeAmount); } } /** * @notice This function is internal and is used to transfer fungible tokens. * @param currency Currency address * @param sender Sender address * @param recipient Recipient address * @param amount Amount (in fungible tokens) */ function _transferFungibleTokens(address currency, address sender, address recipient, uint256 amount) internal { if (currency == address(0)) { _transferETHAndWrapIfFailWithGasLimit(WETH, recipient, amount, _gasLimitETHTransfer); } else { _executeERC20TransferFrom(currency, sender, recipient, amount); } } /** * @notice This function is private and used to transfer funds to * (1) creator recipient (if any) * (2) ask recipient. * @param recipients Recipient addresses * @param feeAmounts Fees * @param currency Currency address * @param bidUser Bid user address * @dev It does not send to the 0-th element in the array since it is the protocol fee, * which is paid later in the execution flow. */ function _transferToAskRecipientAndCreatorIfAny( address[2] memory recipients, uint256[3] memory feeAmounts, address currency, address bidUser ) private { // @dev There is no check for address(0) since the ask recipient can never be address(0) // If ask recipient is the maker --> the signer cannot be the null address // If ask is the taker --> either it is the sender address or // if the recipient (in TakerAsk) is set to address(0), it is adjusted to the original taker address uint256 sellerProceed = feeAmounts[0]; if (sellerProceed != 0) { _transferFungibleTokens(currency, bidUser, recipients[0], sellerProceed); } // @dev There is no check for address(0), if the creator recipient is address(0), the fee is set to 0 uint256 creatorFeeAmount = feeAmounts[1]; if (creatorFeeAmount != 0) { _transferFungibleTokens(currency, bidUser, recipients[1], creatorFeeAmount); } } /** * @notice This function is private and used to compute the domain separator and store the current chain id. */ function _updateDomainSeparator() private { domainSeparator = keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256("LooksRareProtocol"), keccak256(bytes("2")), block.chainid, address(this) ) ); chainId = block.chainid; } /** * @notice This function is internal and is called during the execution of a transaction to decide * how to map the user's order nonce. * @param isNonceInvalidated Whether the nonce is being invalidated * @param signer Signer address * @param orderNonce Maker user order nonce * @param orderHash Hash of the order struct * @dev If isNonceInvalidated is true, this function invalidates the user order nonce for future execution. * If it is equal to false, this function maps the order hash for this user order nonce * to prevent other order structs sharing the same order nonce to be executed. */ function _updateUserOrderNonce( bool isNonceInvalidated, address signer, uint256 orderNonce, bytes32 orderHash ) private { userOrderNonce[signer][orderNonce] = (isNonceInvalidated ? MAGIC_VALUE_ORDER_NONCE_EXECUTED : orderHash); } /** * @notice This function is private and used to verify the chain id, compute the digest, and verify the signature. * @dev If chainId is not equal to the cached chain id, it would revert. * @param computedHash Hash of order (maker bid or maker ask) or merkle root * @param makerSignature Signature of the maker * @param signer Signer address */ function _computeDigestAndVerify(bytes32 computedHash, bytes calldata makerSignature, address signer) private view { if (chainId == block.chainid) { // \x19\x01 is the standard encoding prefix SignatureCheckerCalldata.verify( keccak256(abi.encodePacked("\x19\x01", domainSeparator, computedHash)), signer, makerSignature ); } else { revert ChainIdInvalid(); } } /** * @notice This function is private and called to verify whether the merkle proofs provided for the order hash * are correct or verify the order hash if the order is not part of a merkle tree. * @param merkleTree Merkle tree * @param orderHash Order hash (can be maker bid hash or maker ask hash) * @param signature Maker order signature * @param signer Maker address * @dev It verifies (1) merkle proof (if necessary) (2) signature is from the expected signer */ function _verifyMerkleProofOrOrderHash( OrderStructs.MerkleTree calldata merkleTree, bytes32 orderHash, bytes calldata signature, address signer ) private view { uint256 proofLength = merkleTree.proof.length; if (proofLength != 0) { if (proofLength > MAX_CALLDATA_PROOF_LENGTH) { revert MerkleProofTooLarge(proofLength); } if (!MerkleProofCalldataWithNodes.verifyCalldata(merkleTree.proof, merkleTree.root, orderHash)) { revert MerkleProofInvalid(); } orderHash = hashBatchOrder(merkleTree.root, proofLength); } _computeDigestAndVerify(orderHash, signature, signer); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // LooksRare unopinionated libraries import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol"; // Interfaces import {IAffiliateManager} from "./interfaces/IAffiliateManager.sol"; // Constants import {ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol"; /** * @title AffiliateManager * @notice This contract handles the management of affiliates for the LooksRare protocol. * @author LooksRare protocol team (👀,💎) */ contract AffiliateManager is IAffiliateManager, OwnableTwoSteps { /** * @notice Whether the affiliate program is active. */ bool public isAffiliateProgramActive; /** * @notice Address of the affiliate controller. */ address public affiliateController; /** * @notice It tracks the affiliate rate (in basis point) for a given affiliate address. * The basis point represents how much of the protocol fee will be shared to the affiliate. */ mapping(address => uint256) public affiliateRates; /** * @notice Constructor * @param _owner Owner address */ constructor(address _owner) OwnableTwoSteps(_owner) {} /** * @notice This function allows the affiliate controller to update the affiliate rate (in basis point). * @param affiliate Affiliate address * @param bp Rate (in basis point) to collect (e.g. 100 = 1%) per referred transaction */ function updateAffiliateRate(address affiliate, uint256 bp) external { if (msg.sender != affiliateController) { revert NotAffiliateController(); } if (bp > ONE_HUNDRED_PERCENT_IN_BP) { revert PercentageTooHigh(); } affiliateRates[affiliate] = bp; emit NewAffiliateRate(affiliate, bp); } /** * @notice This function allows the owner to update the affiliate controller address. * @param newAffiliateController New affiliate controller address * @dev Only callable by owner. */ function updateAffiliateController(address newAffiliateController) external onlyOwner { affiliateController = newAffiliateController; emit NewAffiliateController(newAffiliateController); } /** * @notice This function allows the owner to update the affiliate program status. * @param isActive Whether the affiliate program is active * @dev Only callable by owner. */ function updateAffiliateProgramStatus(bool isActive) external onlyOwner { isAffiliateProgramActive = isActive; emit NewAffiliateProgramStatus(isActive); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Shared errors import {MerkleProofTooLarge} from "./errors/SharedErrors.sol"; /** * @title BatchOrderTypehashRegistry * @notice The contract generates the batch order hash that is used to compute the digest for signature verification. * @author LooksRare protocol team (👀,💎) */ contract BatchOrderTypehashRegistry { /** * @notice This function returns the hash of the concatenation of batch order type hash and merkle root. * @param root Merkle root * @param proofLength Merkle proof length * @return batchOrderHash The batch order hash */ function hashBatchOrder(bytes32 root, uint256 proofLength) public pure returns (bytes32 batchOrderHash) { batchOrderHash = keccak256(abi.encode(_getBatchOrderTypehash(proofLength), root)); } /** * @dev It looks like this for each height * height == 1: BatchOrder(Maker[2] tree)Maker(uint8 quoteType,uint256 globalNonce,uint256 subsetNonce,uint256 orderNonce,uint256 strategyId,uint8 collectionType,address collection,address currency,address signer,uint256 startTime,uint256 endTime,uint256 price,uint256[] itemIds,uint256[] amounts,bytes additionalParameters) * height == 2: BatchOrder(Maker[2][2] tree)Maker(uint8 quoteType,uint256 globalNonce,uint256 subsetNonce,uint256 orderNonce,uint256 strategyId,uint8 collectionType,address collection,address currency,address signer,uint256 startTime,uint256 endTime,uint256 price,uint256[] itemIds,uint256[] amounts,bytes additionalParameters) * height == n: BatchOrder(Maker[2]...[2] tree)Maker(uint8 quoteType,uint256 globalNonce,uint256 subsetNonce,uint256 orderNonce,uint256 strategyId,uint8 collectionType,address collection,address currency,address signer,uint256 startTime,uint256 endTime,uint256 price,uint256[] itemIds,uint256[] amounts,bytes additionalParameters) */ function _getBatchOrderTypehash(uint256 height) internal pure returns (bytes32 typehash) { if (height == 1) { typehash = hex"9661287f7a4aa4867db46a2453ee15bebac4e8fc25667a58718da658f15de643"; } else if (height == 2) { typehash = hex"a54ab330ea9e1dfccee2b86f3666989e7fbd479704416c757c8de8e820142a08"; } else if (height == 3) { typehash = hex"93390f5d45ede9dea305f16aec86b2472af4f823851637f1b7019ad0775cea49"; } else if (height == 4) { typehash = hex"9dda2c8358da895e43d574bb15954ce5727b22e923a2d8f28261f297bce42f0b"; } else if (height == 5) { typehash = hex"92dc717124e161262f9d10c7079e7d54dc51271893fba54aa4a0f270fecdcc98"; } else if (height == 6) { typehash = hex"ce02aee5a7a35d40d974463c4c6e5534954fb07a7e7bc966fee268a15337bfd8"; } else if (height == 7) { typehash = hex"f7a65efd167a18f7091b2bb929d687dd94503cf0a43620487055ed7d6b727559"; } else if (height == 8) { typehash = hex"def24acacad1318b664520f7c10e8bc6d1e7f6f6f7c8b031e70624ceb42266a6"; } else if (height == 9) { typehash = hex"4cb4080dc4e7bae88b4dc4307ad5117fa4f26195998a1b5f40368809d7f4c7f2"; } else if (height == 10) { typehash = hex"f8b1f864164d8d6e0b45f1399bd711223117a4ab0b057a9c2d7779e86a7c88db"; } else { revert MerkleProofTooLarge(height); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Interfaces import {ICurrencyManager} from "./interfaces/ICurrencyManager.sol"; // Dependencies import {AffiliateManager} from "./AffiliateManager.sol"; /** * @title CurrencyManager * @notice This contract manages the list of valid fungible currencies. * @author LooksRare protocol team (👀,💎) */ contract CurrencyManager is ICurrencyManager, AffiliateManager { /** * @notice It checks whether the currency is allowed for transacting. */ mapping(address => bool) public isCurrencyAllowed; /** * @notice Constructor * @param _owner Owner address */ constructor(address _owner) AffiliateManager(_owner) {} /** * @notice This function allows the owner to update the status of a currency. * @param currency Currency address (address(0) for ETH) * @param isAllowed Whether the currency should be allowed for trading * @dev Only callable by owner. */ function updateCurrencyStatus(address currency, bool isAllowed) external onlyOwner { isCurrencyAllowed[currency] = isAllowed; emit CurrencyStatusUpdated(currency, isAllowed); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Libraries import {OrderStructs} from "./libraries/OrderStructs.sol"; // Interfaces import {IExecutionManager} from "./interfaces/IExecutionManager.sol"; import {ICreatorFeeManager} from "./interfaces/ICreatorFeeManager.sol"; // Direct dependencies import {InheritedStrategy} from "./InheritedStrategy.sol"; import {NonceManager} from "./NonceManager.sol"; import {StrategyManager} from "./StrategyManager.sol"; // Assembly import {NoSelectorForStrategy_error_selector, NoSelectorForStrategy_error_length, OutsideOfTimeRange_error_selector, OutsideOfTimeRange_error_length, Error_selector_offset} from "./constants/AssemblyConstants.sol"; // Constants import {ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol"; // Enums import {QuoteType} from "./enums/QuoteType.sol"; /** * @title ExecutionManager * @notice This contract handles the execution and resolution of transactions. A transaction is executed on-chain * when an off-chain maker order is matched by on-chain taker order of a different kind. * For instance, a taker ask is executed against a maker bid (or a taker bid against a maker ask). * @author LooksRare protocol team (👀,💎) */ contract ExecutionManager is InheritedStrategy, NonceManager, StrategyManager, IExecutionManager { /** * @notice Protocol fee recipient. */ address public protocolFeeRecipient; /** * @notice Maximum creator fee (in basis point). */ uint16 public maxCreatorFeeBp = 1_000; /** * @notice Creator fee manager. */ ICreatorFeeManager public creatorFeeManager; /** * @notice Constructor * @param _owner Owner address * @param _protocolFeeRecipient Protocol fee recipient address */ constructor(address _owner, address _protocolFeeRecipient) StrategyManager(_owner) { _updateProtocolFeeRecipient(_protocolFeeRecipient); } /** * @notice This function allows the owner to update the creator fee manager address. * @param newCreatorFeeManager Address of the creator fee manager * @dev Only callable by owner. */ function updateCreatorFeeManager(address newCreatorFeeManager) external onlyOwner { creatorFeeManager = ICreatorFeeManager(newCreatorFeeManager); emit NewCreatorFeeManager(newCreatorFeeManager); } /** * @notice This function allows the owner to update the maximum creator fee (in basis point). * @param newMaxCreatorFeeBp New maximum creator fee (in basis point) * @dev The maximum value that can be set is 25%. * Only callable by owner. */ function updateMaxCreatorFeeBp(uint16 newMaxCreatorFeeBp) external onlyOwner { if (newMaxCreatorFeeBp > 2_500) { revert CreatorFeeBpTooHigh(); } maxCreatorFeeBp = newMaxCreatorFeeBp; emit NewMaxCreatorFeeBp(newMaxCreatorFeeBp); } /** * @notice This function allows the owner to update the protocol fee recipient. * @param newProtocolFeeRecipient New protocol fee recipient address * @dev Only callable by owner. */ function updateProtocolFeeRecipient(address newProtocolFeeRecipient) external onlyOwner { _updateProtocolFeeRecipient(newProtocolFeeRecipient); } /** * @notice This function is internal and is used to execute a transaction initiated by a taker order. * @param takerOrder Taker order struct (taker specific parameters for the execution) * @param makerOrder Maker order struct (maker specific parameter for the execution) * @param sender The address that sent the transaction * @return itemIds Array of item ids to be traded * @return amounts Array of amounts for each item id * @return recipients Array of recipient addresses * @return feeAmounts Array of fee amounts * @return isNonceInvalidated Whether the order's nonce will be invalidated after executing the order */ function _executeStrategyForTakerOrder( OrderStructs.Taker calldata takerOrder, OrderStructs.Maker calldata makerOrder, address sender ) internal returns ( uint256[] memory itemIds, uint256[] memory amounts, address[2] memory recipients, uint256[3] memory feeAmounts, bool isNonceInvalidated ) { uint256 price; // Verify the order validity for timestamps _verifyOrderTimestampValidity(makerOrder.startTime, makerOrder.endTime); if (makerOrder.strategyId == 0) { _verifyItemIdsAndAmountsEqualLengthsAndValidAmounts(makerOrder.amounts, makerOrder.itemIds); (price, itemIds, amounts) = (makerOrder.price, makerOrder.itemIds, makerOrder.amounts); isNonceInvalidated = true; } else { if (strategyInfo[makerOrder.strategyId].isActive) { /** * @dev This is equivalent to * * if (makerOrder.quoteType == QuoteType.Bid) { * if (!strategyInfo[makerOrder.strategyId].isMakerBid) { * revert NoSelectorForStrategy(); * } * } else { * if (strategyInfo[makerOrder.strategyId].isMakerBid) { * revert NoSelectorForStrategy(); * } * } * * because one must be 0 and another must be 1 for the function * to not revert. * * Both quoteType (an enum with 2 values) and isMakerBid (a bool) * can only be 0 or 1. */ QuoteType quoteType = makerOrder.quoteType; bool isMakerBid = strategyInfo[makerOrder.strategyId].isMakerBid; assembly { if eq(quoteType, isMakerBid) { mstore(0x00, NoSelectorForStrategy_error_selector) revert(Error_selector_offset, NoSelectorForStrategy_error_length) } } (bool status, bytes memory data) = strategyInfo[makerOrder.strategyId].implementation.call( abi.encodeWithSelector(strategyInfo[makerOrder.strategyId].selector, takerOrder, makerOrder) ); if (!status) { // @dev It forwards the revertion message from the low-level call assembly { revert(add(data, 32), mload(data)) } } (price, itemIds, amounts, isNonceInvalidated) = abi.decode(data, (uint256, uint256[], uint256[], bool)); } else { revert StrategyNotAvailable(makerOrder.strategyId); } } // Creator fee and adjustment of protocol fee (recipients[1], feeAmounts[1]) = _getCreatorRecipientAndCalculateFeeAmount( makerOrder.collection, price, itemIds ); if (makerOrder.quoteType == QuoteType.Bid) { _setTheRestOfFeeAmountsAndRecipients( makerOrder.strategyId, price, takerOrder.recipient == address(0) ? sender : takerOrder.recipient, feeAmounts, recipients ); } else { _setTheRestOfFeeAmountsAndRecipients( makerOrder.strategyId, price, makerOrder.signer, feeAmounts, recipients ); } } /** * @notice This private function updates the protocol fee recipient. * @param newProtocolFeeRecipient New protocol fee recipient address */ function _updateProtocolFeeRecipient(address newProtocolFeeRecipient) private { if (newProtocolFeeRecipient == address(0)) { revert NewProtocolFeeRecipientCannotBeNullAddress(); } protocolFeeRecipient = newProtocolFeeRecipient; emit NewProtocolFeeRecipient(newProtocolFeeRecipient); } /** * @notice This function is internal and is used to calculate * the protocol fee amount for a set of fee amounts. * @param price Transaction price * @param strategyId Strategy id * @param creatorFeeAmount Creator fee amount * @param minTotalFeeAmount Min total fee amount * @return protocolFeeAmount Protocol fee amount */ function _calculateProtocolFeeAmount( uint256 price, uint256 strategyId, uint256 creatorFeeAmount, uint256 minTotalFeeAmount ) private view returns (uint256 protocolFeeAmount) { protocolFeeAmount = (price * strategyInfo[strategyId].standardProtocolFeeBp) / ONE_HUNDRED_PERCENT_IN_BP; if (protocolFeeAmount + creatorFeeAmount < minTotalFeeAmount) { protocolFeeAmount = minTotalFeeAmount - creatorFeeAmount; } } /** * @notice This function is internal and is used to get the creator fee address * and calculate the creator fee amount. * @param collection Collection address * @param price Transaction price * @param itemIds Array of item ids * @return creator Creator recipient * @return creatorFeeAmount Creator fee amount */ function _getCreatorRecipientAndCalculateFeeAmount( address collection, uint256 price, uint256[] memory itemIds ) private view returns (address creator, uint256 creatorFeeAmount) { if (address(creatorFeeManager) != address(0)) { (creator, creatorFeeAmount) = creatorFeeManager.viewCreatorFeeInfo(collection, price, itemIds); if (creator == address(0)) { // If recipient is null address, creator fee is set to 0 creatorFeeAmount = 0; } else if (creatorFeeAmount * ONE_HUNDRED_PERCENT_IN_BP > (price * uint256(maxCreatorFeeBp))) { // If creator fee is higher than tolerated, it reverts revert CreatorFeeBpTooHigh(); } } } /** * @dev This function does not need to return feeAmounts and recipients as they are modified * in memory. */ function _setTheRestOfFeeAmountsAndRecipients( uint256 strategyId, uint256 price, address askRecipient, uint256[3] memory feeAmounts, address[2] memory recipients ) private view { // Compute minimum total fee amount uint256 minTotalFeeAmount = (price * strategyInfo[strategyId].minTotalFeeBp) / ONE_HUNDRED_PERCENT_IN_BP; if (feeAmounts[1] == 0) { // If creator fee is null, protocol fee is set as the minimum total fee amount feeAmounts[2] = minTotalFeeAmount; // Net fee amount for seller feeAmounts[0] = price - feeAmounts[2]; } else { // If there is a creator fee information, the protocol fee amount can be calculated feeAmounts[2] = _calculateProtocolFeeAmount(price, strategyId, feeAmounts[1], minTotalFeeAmount); // Net fee amount for seller feeAmounts[0] = price - feeAmounts[1] - feeAmounts[2]; } recipients[0] = askRecipient; } /** * @notice This function is internal and is used to verify the validity of an order * in the context of the current block timestamps. * @param startTime Start timestamp * @param endTime End timestamp */ function _verifyOrderTimestampValidity(uint256 startTime, uint256 endTime) private view { // if (startTime > block.timestamp || endTime < block.timestamp) revert OutsideOfTimeRange(); assembly { if or(gt(startTime, timestamp()), lt(endTime, timestamp())) { mstore(0x00, OutsideOfTimeRange_error_selector) revert(Error_selector_offset, OutsideOfTimeRange_error_length) } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Libraries import {OrderStructs} from "./libraries/OrderStructs.sol"; // Shared errors import {OrderInvalid} from "./errors/SharedErrors.sol"; // Assembly import {OrderInvalid_error_selector, OrderInvalid_error_length, Error_selector_offset, OneWord} from "./constants/AssemblyConstants.sol"; /** * @title InheritedStrategy * @notice This contract handles the verification of parameters for standard transactions. * It does not verify the taker struct's itemIds and amounts array as well as * minPrice (taker ask) / maxPrice (taker bid) because before the taker executes the * transaction and the maker itemIds/amounts/price should have already been confirmed off-chain. * @dev A standard transaction (bid or ask) is mapped to strategyId = 0. * @author LooksRare protocol team (👀,💎) */ contract InheritedStrategy { /** * @notice This function is internal and is used to validate the parameters for a standard sale strategy * when the standard transaction is initiated by a taker bid. * @param amounts Array of amounts * @param itemIds Array of item ids */ function _verifyItemIdsAndAmountsEqualLengthsAndValidAmounts( uint256[] calldata amounts, uint256[] calldata itemIds ) internal pure { assembly { let end { /* * @dev If A == B, then A XOR B == 0. * * if (amountsLength == 0 || amountsLength != itemIdsLength) { * revert OrderInvalid(); * } */ let amountsLength := amounts.length let itemIdsLength := itemIds.length if or(iszero(amountsLength), xor(amountsLength, itemIdsLength)) { mstore(0x00, OrderInvalid_error_selector) revert(Error_selector_offset, OrderInvalid_error_length) } /** * @dev Shifting left 5 times is equivalent to amountsLength * 32 bytes */ end := shl(5, amountsLength) } let amountsOffset := amounts.offset for { } end { } { /** * @dev Starting from the end of the array minus 32 bytes to load the last item, * ending with `end` equal to 0 to load the first item * * uint256 end = amountsLength; * * for (uint256 i = end - 1; i >= 0; i--) { * uint256 amount = amounts[i]; * if (amount == 0) { * revert OrderInvalid(); * } * } */ end := sub(end, OneWord) let amount := calldataload(add(amountsOffset, end)) if iszero(amount) { mstore(0x00, OrderInvalid_error_selector) revert(Error_selector_offset, OrderInvalid_error_length) } } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Interfaces and errors import {INonceManager} from "./interfaces/INonceManager.sol"; import {LengthsInvalid} from "./errors/SharedErrors.sol"; /** * @title NonceManager * @notice This contract handles the nonce logic that is used for invalidating maker orders that exist off-chain. * The nonce logic revolves around three parts at the user level: * - order nonce (orders sharing an order nonce are conditional, OCO-like) * - subset (orders can be grouped under a same subset) * - bid/ask (all orders can be executed only if the bid/ask nonce matches the user's one on-chain) * Only the order nonce is invalidated at the time of the execution of a maker order that contains it. * @author LooksRare protocol team (👀,💎) */ contract NonceManager is INonceManager { /** * @notice Magic value nonce returned if executed (or cancelled). */ bytes32 public constant MAGIC_VALUE_ORDER_NONCE_EXECUTED = keccak256("ORDER_NONCE_EXECUTED"); /** * @notice This tracks the bid and ask nonces for a user address. */ mapping(address => UserBidAskNonces) public userBidAskNonces; /** * @notice This checks whether the order nonce for a user was executed or cancelled. */ mapping(address => mapping(uint256 => bytes32)) public userOrderNonce; /** * @notice This checks whether the subset nonce for a user was cancelled. */ mapping(address => mapping(uint256 => bool)) public userSubsetNonce; /** * @notice This function allows a user to cancel an array of order nonces. * @param orderNonces Array of order nonces * @dev It does not check the status of the nonces to save gas * and to prevent revertion if one of the orders is filled in the same * block. */ function cancelOrderNonces(uint256[] calldata orderNonces) external { uint256 length = orderNonces.length; if (length == 0) { revert LengthsInvalid(); } for (uint256 i; i < length; ) { userOrderNonce[msg.sender][orderNonces[i]] = MAGIC_VALUE_ORDER_NONCE_EXECUTED; unchecked { ++i; } } emit OrderNoncesCancelled(msg.sender, orderNonces); } /** * @notice This function allows a user to cancel an array of subset nonces. * @param subsetNonces Array of subset nonces * @dev It does not check the status of the nonces to save gas. */ function cancelSubsetNonces(uint256[] calldata subsetNonces) external { uint256 length = subsetNonces.length; if (length == 0) { revert LengthsInvalid(); } for (uint256 i; i < length; ) { userSubsetNonce[msg.sender][subsetNonces[i]] = true; unchecked { ++i; } } emit SubsetNoncesCancelled(msg.sender, subsetNonces); } /** * @notice This function increments a user's bid/ask nonces. * @param bid Whether to increment the user bid nonce * @param ask Whether to increment the user ask nonce * @dev The logic for computing the quasi-random number is inspired by Seaport v1.2. * The pseudo-randomness allows non-deterministic computation of the next ask/bid nonce. * A deterministic increment would make the cancel-all process non-effective in certain cases * (orders signed with a greater ask/bid nonce). * The same quasi-random number is used for incrementing both the bid and ask nonces if both values * are incremented in the same transaction. * If this function is used twice in the same block, it will return the same quasiRandomNumber * but this will not impact the overall business logic. */ function incrementBidAskNonces(bool bid, bool ask) external { // Use second half of the previous block hash as a quasi-random number uint256 quasiRandomNumber = uint256(blockhash(block.number - 1) >> 128); uint256 newBidNonce = userBidAskNonces[msg.sender].bidNonce; uint256 newAskNonce = userBidAskNonces[msg.sender].askNonce; if (bid) { newBidNonce += quasiRandomNumber; userBidAskNonces[msg.sender].bidNonce = newBidNonce; } if (ask) { newAskNonce += quasiRandomNumber; userBidAskNonces[msg.sender].askNonce = newAskNonce; } emit NewBidAskNonces(msg.sender, newBidNonce, newAskNonce); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // LooksRare unopinionated libraries import {CurrencyManager} from "./CurrencyManager.sol"; // Interfaces import {IStrategy} from "./interfaces/IStrategy.sol"; import {IStrategyManager} from "./interfaces/IStrategyManager.sol"; /** * @title StrategyManager * @notice This contract handles the addition and the update of execution strategies. * @author LooksRare protocol team (👀,💎) */ contract StrategyManager is IStrategyManager, CurrencyManager { /** * @notice This variable keeps the count of how many strategies exist. * It includes strategies that have been removed. */ uint256 private _countStrategies = 1; /** * @notice This returns the strategy information for a strategy id. */ mapping(uint256 => Strategy) public strategyInfo; /** * @notice Constructor * @param _owner Owner address */ constructor(address _owner) CurrencyManager(_owner) { strategyInfo[0] = Strategy({ isActive: true, standardProtocolFeeBp: 50, minTotalFeeBp: 50, maxProtocolFeeBp: 200, selector: bytes4(0), isMakerBid: false, implementation: address(0) }); emit NewStrategy(0, 50, 50, 200, bytes4(0), false, address(0)); } /** * @notice This function allows the owner to add a new execution strategy to the protocol. * @param standardProtocolFeeBp Standard protocol fee (in basis point) * @param minTotalFeeBp Minimum total fee (in basis point) * @param maxProtocolFeeBp Maximum protocol fee (in basis point) * @param selector Function selector for the strategy * @param isMakerBid Whether the function selector is for maker bid * @param implementation Implementation address * @dev Strategies have an id that is incremental. * Only callable by owner. */ function addStrategy( uint16 standardProtocolFeeBp, uint16 minTotalFeeBp, uint16 maxProtocolFeeBp, bytes4 selector, bool isMakerBid, address implementation ) external onlyOwner { if (minTotalFeeBp > maxProtocolFeeBp || standardProtocolFeeBp > minTotalFeeBp || maxProtocolFeeBp > 500) { revert StrategyProtocolFeeTooHigh(); } if (selector == bytes4(0)) { revert StrategyHasNoSelector(); } if (!IStrategy(implementation).isLooksRareV2Strategy()) { revert NotV2Strategy(); } strategyInfo[_countStrategies] = Strategy({ isActive: true, standardProtocolFeeBp: standardProtocolFeeBp, minTotalFeeBp: minTotalFeeBp, maxProtocolFeeBp: maxProtocolFeeBp, selector: selector, isMakerBid: isMakerBid, implementation: implementation }); emit NewStrategy( _countStrategies++, standardProtocolFeeBp, minTotalFeeBp, maxProtocolFeeBp, selector, isMakerBid, implementation ); } /** * @notice This function allows the owner to update parameters for an existing execution strategy. * @param strategyId Strategy id * @param isActive Whether the strategy must be active * @param newStandardProtocolFee New standard protocol fee (in basis point) * @param newMinTotalFee New minimum total fee (in basis point) * @dev Only callable by owner. */ function updateStrategy( uint256 strategyId, bool isActive, uint16 newStandardProtocolFee, uint16 newMinTotalFee ) external onlyOwner { if (strategyId >= _countStrategies) { revert StrategyNotUsed(); } if (newMinTotalFee > strategyInfo[strategyId].maxProtocolFeeBp || newStandardProtocolFee > newMinTotalFee) { revert StrategyProtocolFeeTooHigh(); } strategyInfo[strategyId].isActive = isActive; strategyInfo[strategyId].standardProtocolFeeBp = newStandardProtocolFee; strategyInfo[strategyId].minTotalFeeBp = newMinTotalFee; emit StrategyUpdated(strategyId, isActive, newStandardProtocolFee, newMinTotalFee); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // LooksRare unopinionated libraries import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol"; import {LowLevelERC721Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC721Transfer.sol"; import {LowLevelERC1155Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC1155Transfer.sol"; // Interfaces and errors import {ITransferManager} from "./interfaces/ITransferManager.sol"; import {AmountInvalid, LengthsInvalid} from "./errors/SharedErrors.sol"; // Libraries import {OrderStructs} from "./libraries/OrderStructs.sol"; // Enums import {CollectionType} from "./enums/CollectionType.sol"; /** * @title TransferManager * @notice This contract provides the transfer functions for ERC721/ERC1155 for contracts that require them. * Collection type "0" refers to ERC721 transfer functions. * Collection type "1" refers to ERC1155 transfer functions. * @dev "Safe" transfer functions for ERC721 are not implemented since they come with added gas costs * to verify if the recipient is a contract as it requires verifying the receiver interface is valid. * @author LooksRare protocol team (👀,💎) */ contract TransferManager is ITransferManager, LowLevelERC721Transfer, LowLevelERC1155Transfer, OwnableTwoSteps { /** * @notice This returns whether the user has approved the operator address. * The first address is the user and the second address is the operator (e.g. LooksRareProtocol). */ mapping(address => mapping(address => bool)) public hasUserApprovedOperator; /** * @notice This returns whether the operator address is allowed by this contract's owner. */ mapping(address => bool) public isOperatorAllowed; /** * @notice Constructor * @param _owner Owner address */ constructor(address _owner) OwnableTwoSteps(_owner) {} /** * @notice This function transfers items for a single ERC721 collection. * @param collection Collection address * @param from Sender address * @param to Recipient address * @param itemIds Array of itemIds * @param amounts Array of amounts */ function transferItemsERC721( address collection, address from, address to, uint256[] calldata itemIds, uint256[] calldata amounts ) external { uint256 length = itemIds.length; if (length == 0) { revert LengthsInvalid(); } _isOperatorValidForTransfer(from, msg.sender); for (uint256 i; i < length; ) { if (amounts[i] != 1) { revert AmountInvalid(); } _executeERC721TransferFrom(collection, from, to, itemIds[i]); unchecked { ++i; } } } /** * @notice This function transfers items for a single ERC1155 collection. * @param collection Collection address * @param from Sender address * @param to Recipient address * @param itemIds Array of itemIds * @param amounts Array of amounts * @dev It does not allow batch transferring if from = msg.sender since native function should be used. */ function transferItemsERC1155( address collection, address from, address to, uint256[] calldata itemIds, uint256[] calldata amounts ) external { uint256 length = itemIds.length; if (length == 0 || amounts.length != length) { revert LengthsInvalid(); } _isOperatorValidForTransfer(from, msg.sender); if (length == 1) { if (amounts[0] == 0) { revert AmountInvalid(); } _executeERC1155SafeTransferFrom(collection, from, to, itemIds[0], amounts[0]); } else { for (uint256 i; i < length; ) { if (amounts[i] == 0) { revert AmountInvalid(); } unchecked { ++i; } } _executeERC1155SafeBatchTransferFrom(collection, from, to, itemIds, amounts); } } /** * @notice This function transfers items across an array of collections that can be both ERC721 and ERC1155. * @param items Array of BatchTransferItem * @param from Sender address * @param to Recipient address */ function transferBatchItemsAcrossCollections( BatchTransferItem[] calldata items, address from, address to ) external { uint256 itemsLength = items.length; if (itemsLength == 0) { revert LengthsInvalid(); } if (from != msg.sender) { _isOperatorValidForTransfer(from, msg.sender); } for (uint256 i; i < itemsLength; ) { uint256[] calldata itemIds = items[i].itemIds; uint256 itemIdsLengthForSingleCollection = itemIds.length; uint256[] calldata amounts = items[i].amounts; if (itemIdsLengthForSingleCollection == 0 || amounts.length != itemIdsLengthForSingleCollection) { revert LengthsInvalid(); } CollectionType collectionType = items[i].collectionType; if (collectionType == CollectionType.ERC721) { for (uint256 j; j < itemIdsLengthForSingleCollection; ) { if (amounts[j] != 1) { revert AmountInvalid(); } _executeERC721TransferFrom(items[i].collection, from, to, itemIds[j]); unchecked { ++j; } } } else if (collectionType == CollectionType.ERC1155) { for (uint256 j; j < itemIdsLengthForSingleCollection; ) { if (amounts[j] == 0) { revert AmountInvalid(); } unchecked { ++j; } } _executeERC1155SafeBatchTransferFrom(items[i].collection, from, to, itemIds, amounts); } unchecked { ++i; } } } /** * @notice This function allows a user to grant approvals for an array of operators. * Users cannot grant approvals if the operator is not allowed by this contract's owner. * @param operators Array of operator addresses * @dev Each operator address must be globally allowed to be approved. */ function grantApprovals(address[] calldata operators) external { uint256 length = operators.length; if (length == 0) { revert LengthsInvalid(); } for (uint256 i; i < length; ) { address operator = operators[i]; if (!isOperatorAllowed[operator]) { revert OperatorNotAllowed(); } if (hasUserApprovedOperator[msg.sender][operator]) { revert OperatorAlreadyApprovedByUser(); } hasUserApprovedOperator[msg.sender][operator] = true; unchecked { ++i; } } emit ApprovalsGranted(msg.sender, operators); } /** * @notice This function allows a user to revoke existing approvals for an array of operators. * @param operators Array of operator addresses * @dev Each operator address must be approved at the user level to be revoked. */ function revokeApprovals(address[] calldata operators) external { uint256 length = operators.length; if (length == 0) { revert LengthsInvalid(); } for (uint256 i; i < length; ) { address operator = operators[i]; if (!hasUserApprovedOperator[msg.sender][operator]) { revert OperatorNotApprovedByUser(); } delete hasUserApprovedOperator[msg.sender][operator]; unchecked { ++i; } } emit ApprovalsRemoved(msg.sender, operators); } /** * @notice This function allows an operator to be added for the shared transfer system. * Once the operator is allowed, users can grant NFT approvals to this operator. * @param operator Operator address to allow * @dev Only callable by owner. */ function allowOperator(address operator) external onlyOwner { if (isOperatorAllowed[operator]) { revert OperatorAlreadyAllowed(); } isOperatorAllowed[operator] = true; emit OperatorAllowed(operator); } /** * @notice This function allows the user to remove an operator for the shared transfer system. * @param operator Operator address to remove * @dev Only callable by owner. */ function removeOperator(address operator) external onlyOwner { if (!isOperatorAllowed[operator]) { revert OperatorNotAllowed(); } delete isOperatorAllowed[operator]; emit OperatorRemoved(operator); } /** * @notice This function is internal and verifies whether the transfer * (by an operator on behalf of a user) is valid. If not, it reverts. * @param user User address * @param operator Operator address */ function _isOperatorValidForTransfer(address user, address operator) private view { if (isOperatorAllowed[operator] && hasUserApprovedOperator[user][operator]) { return; } revert TransferCallerInvalid(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Direct dependencies import {PackableReentrancyGuard} from "@looksrare/contracts-libs/contracts/PackableReentrancyGuard.sol"; import {ExecutionManager} from "./ExecutionManager.sol"; import {TransferManager} from "./TransferManager.sol"; // Libraries import {OrderStructs} from "./libraries/OrderStructs.sol"; // Enums import {CollectionType} from "./enums/CollectionType.sol"; /** * @title TransferSelectorNFT * @notice This contract handles the logic for transferring non-fungible items. * @author LooksRare protocol team (👀,💎) */ contract TransferSelectorNFT is ExecutionManager, PackableReentrancyGuard { /** * @notice Transfer manager for ERC721 and ERC1155. */ TransferManager public immutable transferManager; /** * @notice Constructor * @param _owner Owner address * @param _protocolFeeRecipient Protocol fee recipient address * @param _transferManager Address of the transfer manager for ERC721/ERC1155 */ constructor( address _owner, address _protocolFeeRecipient, address _transferManager ) ExecutionManager(_owner, _protocolFeeRecipient) { transferManager = TransferManager(_transferManager); } /** * @notice This function is internal and used to transfer non-fungible tokens. * @param collection Collection address * @param collectionType Collection type (e.g. 0 = ERC721, 1 = ERC1155) * @param sender Sender address * @param recipient Recipient address * @param itemIds Array of itemIds * @param amounts Array of amounts */ function _transferNFT( address collection, CollectionType collectionType, address sender, address recipient, uint256[] memory itemIds, uint256[] memory amounts ) internal { if (collectionType == CollectionType.ERC721) { transferManager.transferItemsERC721(collection, sender, recipient, itemIds, amounts); } else if (collectionType == CollectionType.ERC1155) { transferManager.transferItemsERC1155(collection, sender, recipient, itemIds, amounts); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /* * @dev error OrderInvalid() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant OrderInvalid_error_selector = 0x2e0c0f71; uint256 constant OrderInvalid_error_length = 0x04; /* * @dev error CurrencyInvalid() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant CurrencyInvalid_error_selector = 0x4f795487; uint256 constant CurrencyInvalid_error_length = 0x04; /* * @dev error OutsideOfTimeRange() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant OutsideOfTimeRange_error_selector = 0x7476320f; uint256 constant OutsideOfTimeRange_error_length = 0x04; /* * @dev error NoSelectorForStrategy() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NoSelectorForStrategy_error_selector = 0xab984846; uint256 constant NoSelectorForStrategy_error_length = 0x04; uint256 constant Error_selector_offset = 0x1c; uint256 constant OneWord = 0x20;
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @dev 100% represented in basis point is 10_000. */ uint256 constant ONE_HUNDRED_PERCENT_IN_BP = 10_000; /** * @dev The maximum length of a proof for a batch order is 10. * The maximum merkle tree that can used for signing has a height of * 2**10 = 1_024. */ uint256 constant MAX_CALLDATA_PROOF_LENGTH = 10;
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @notice CollectionType is used in OrderStructs.Maker's collectionType to determine the collection type being traded. */ enum CollectionType { ERC721, ERC1155 }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @notice QuoteType is used in OrderStructs.Maker's quoteType to determine whether the maker order is a bid or an ask. */ enum QuoteType { Bid, Ask }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @notice It is returned if the amount is invalid. * For ERC721, any number that is not 1. For ERC1155, if amount is 0. */ error AmountInvalid(); /** * @notice It is returned if the ask price is too high for the bid user. */ error AskTooHigh(); /** * @notice It is returned if the bid price is too low for the ask user. */ error BidTooLow(); /** * @notice It is returned if the function cannot be called by the sender. */ error CallerInvalid(); /** * @notice It is returned if the currency is invalid. */ error CurrencyInvalid(); /** * @notice The function selector is invalid for this strategy implementation. */ error FunctionSelectorInvalid(); /** * @notice It is returned if there is either a mismatch or an error in the length of the array(s). */ error LengthsInvalid(); /** * @notice It is returned if the merkle proof provided is invalid. */ error MerkleProofInvalid(); /** * @notice It is returned if the length of the merkle proof provided is greater than tolerated. * @param length Proof length */ error MerkleProofTooLarge(uint256 length); /** * @notice It is returned if the order is permanently invalid. * There may be an issue with the order formatting. */ error OrderInvalid(); /** * @notice It is returned if the maker quote type is invalid. */ error QuoteTypeInvalid();
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title IAffiliateManager * @author LooksRare protocol team (👀,💎) */ interface IAffiliateManager { /** * @notice It is emitted when there is an update of affliate controller. * @param affiliateController Address of the new affiliate controller */ event NewAffiliateController(address affiliateController); /** * @notice It is emitted if the affiliate program is activated or deactivated. * @param isActive Whether the affiliate program is active after the update */ event NewAffiliateProgramStatus(bool isActive); /** * @notice It is emitted if there is a new affiliate and its associated rate (in basis point). * @param affiliate Address of the affiliate * @param rate Affiliate rate (in basis point) */ event NewAffiliateRate(address affiliate, uint256 rate); /** * @notice It is returned if the function is called by another address than the affiliate controller. */ error NotAffiliateController(); /** * @notice It is returned if the affiliate controller is trying to set an affiliate rate higher than 10,000. */ error PercentageTooHigh(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Interfaces import {IRoyaltyFeeRegistry} from "./IRoyaltyFeeRegistry.sol"; /** * @title ICreatorFeeManager * @author LooksRare protocol team (👀,💎) */ interface ICreatorFeeManager { /** * @notice It is returned if the bundle contains multiple itemIds with different creator fee structure. */ error BundleEIP2981NotAllowed(address collection); /** * @notice It returns the royalty fee registry address/interface. * @return royaltyFeeRegistry Interface of the royalty fee registry */ function royaltyFeeRegistry() external view returns (IRoyaltyFeeRegistry royaltyFeeRegistry); /** * @notice This function returns the creator address and calculates the creator fee amount. * @param collection Collection address * @param price Transaction price * @param itemIds Array of item ids * @return creator Creator address * @return creatorFeeAmount Creator fee amount */ function viewCreatorFeeInfo( address collection, uint256 price, uint256[] memory itemIds ) external view returns (address creator, uint256 creatorFeeAmount); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title ICurrencyManager * @author LooksRare protocol team (👀,💎) */ interface ICurrencyManager { /** * @notice It is emitted if the currency status in the allowlist is updated. * @param currency Currency address (address(0) = ETH) * @param isAllowed Whether the currency is allowed */ event CurrencyStatusUpdated(address currency, bool isAllowed); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title IExecutionManager * @author LooksRare protocol team (👀,💎) */ interface IExecutionManager { /** * @notice It is issued when there is a new creator fee manager. * @param creatorFeeManager Address of the new creator fee manager */ event NewCreatorFeeManager(address creatorFeeManager); /** * @notice It is issued when there is a new maximum creator fee (in basis point). * @param maxCreatorFeeBp New maximum creator fee (in basis point) */ event NewMaxCreatorFeeBp(uint256 maxCreatorFeeBp); /** * @notice It is issued when there is a new protocol fee recipient address. * @param protocolFeeRecipient Address of the new protocol fee recipient */ event NewProtocolFeeRecipient(address protocolFeeRecipient); /** * @notice It is returned if the creator fee (in basis point) is too high. */ error CreatorFeeBpTooHigh(); /** * @notice It is returned if the new protocol fee recipient is set to address(0). */ error NewProtocolFeeRecipientCannotBeNullAddress(); /** * @notice It is returned if there is no selector for maker ask/bid for a given strategyId, * depending on the quote type. */ error NoSelectorForStrategy(); /** * @notice It is returned if the current block timestamp is not between start and end times in the maker order. */ error OutsideOfTimeRange(); /** * @notice It is returned if the strategy id has no implementation. * @dev It is returned if there is no implementation address and the strategyId is strictly greater than 0. */ error StrategyNotAvailable(uint256 strategyId); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Libraries import {OrderStructs} from "../libraries/OrderStructs.sol"; /** * @title ILooksRareProtocol * @author LooksRare protocol team (👀,💎) */ interface ILooksRareProtocol { /** * @notice This struct contains an order nonce's invalidation status * and the order hash that triggered the status change. * @param orderHash Maker order hash * @param orderNonce Order nonce * @param isNonceInvalidated Whether this transaction invalidated the maker user's order nonce at the protocol level */ struct NonceInvalidationParameters { bytes32 orderHash; uint256 orderNonce; bool isNonceInvalidated; } /** * @notice It is emitted when there is an affiliate fee paid. * @param affiliate Affiliate address * @param currency Address of the currency * @param affiliateFee Affiliate fee (in the currency) */ event AffiliatePayment(address affiliate, address currency, uint256 affiliateFee); /** * @notice It is emitted if there is a change in the domain separator. */ event NewDomainSeparator(); /** * @notice It is emitted when there is a new gas limit for a ETH transfer (before it is wrapped to WETH). * @param gasLimitETHTransfer Gas limit for an ETH transfer */ event NewGasLimitETHTransfer(uint256 gasLimitETHTransfer); /** * @notice It is emitted when a taker ask transaction is completed. * @param nonceInvalidationParameters Struct about nonce invalidation parameters * @param askUser Address of the ask user * @param bidUser Address of the bid user * @param strategyId Id of the strategy * @param currency Address of the currency * @param collection Address of the collection * @param itemIds Array of item ids * @param amounts Array of amounts (for item ids) * @param feeRecipients Array of fee recipients * feeRecipients[0] User who receives the proceeds of the sale (it can be the taker ask user or different) * feeRecipients[1] Creator fee recipient (if none, address(0)) * @param feeAmounts Array of fee amounts * feeAmounts[0] Fee amount for the user receiving sale proceeds * feeAmounts[1] Creator fee amount * feeAmounts[2] Protocol fee amount prior to adjustment for a potential affiliate payment */ event TakerAsk( NonceInvalidationParameters nonceInvalidationParameters, address askUser, // taker (initiates the transaction) address bidUser, // maker (receives the NFT) uint256 strategyId, address currency, address collection, uint256[] itemIds, uint256[] amounts, address[2] feeRecipients, uint256[3] feeAmounts ); /** * @notice It is emitted when a taker bid transaction is completed. * @param nonceInvalidationParameters Struct about nonce invalidation parameters * @param bidUser Address of the bid user * @param bidRecipient Address of the recipient of the bid * @param strategyId Id of the strategy * @param currency Address of the currency * @param collection Address of the collection * @param itemIds Array of item ids * @param amounts Array of amounts (for item ids) * @param feeRecipients Array of fee recipients * feeRecipients[0] User who receives the proceeds of the sale (it is the maker ask user) * feeRecipients[1] Creator fee recipient (if none, address(0)) * @param feeAmounts Array of fee amounts * feeAmounts[0] Fee amount for the user receiving sale proceeds * feeAmounts[1] Creator fee amount * feeAmounts[2] Protocol fee amount prior to adjustment for a potential affiliate payment */ event TakerBid( NonceInvalidationParameters nonceInvalidationParameters, address bidUser, // taker (initiates the transaction) address bidRecipient, // taker (receives the NFT) uint256 strategyId, address currency, address collection, uint256[] itemIds, uint256[] amounts, address[2] feeRecipients, uint256[3] feeAmounts ); /** * @notice It is returned if the gas limit for a standard ETH transfer is too low. */ error NewGasLimitETHTransferTooLow(); /** * @notice It is returned if the domain separator cannot be updated (i.e. the chainId is the same). */ error SameDomainSeparator(); /** * @notice It is returned if the domain separator should change. */ error ChainIdInvalid(); /** * @notice It is returned if the nonces are invalid. */ error NoncesInvalid(); /** * @notice This function allows a user to execute a taker ask (against a maker bid). * @param takerAsk Taker ask struct * @param makerBid Maker bid struct * @param makerSignature Maker signature * @param merkleTree Merkle tree struct (if the signature contains multiple maker orders) * @param affiliate Affiliate address */ function executeTakerAsk( OrderStructs.Taker calldata takerAsk, OrderStructs.Maker calldata makerBid, bytes calldata makerSignature, OrderStructs.MerkleTree calldata merkleTree, address affiliate ) external; /** * @notice This function allows a user to execute a taker bid (against a maker ask). * @param takerBid Taker bid struct * @param makerAsk Maker ask struct * @param makerSignature Maker signature * @param merkleTree Merkle tree struct (if the signature contains multiple maker orders) * @param affiliate Affiliate address */ function executeTakerBid( OrderStructs.Taker calldata takerBid, OrderStructs.Maker calldata makerAsk, bytes calldata makerSignature, OrderStructs.MerkleTree calldata merkleTree, address affiliate ) external payable; /** * @notice This function allows a user to batch buy with an array of taker bids (against an array of maker asks). * @param takerBids Array of taker bid structs * @param makerAsks Array of maker ask structs * @param makerSignatures Array of maker signatures * @param merkleTrees Array of merkle tree structs if the signature contains multiple maker orders * @param affiliate Affiliate address * @param isAtomic Whether the execution should be atomic * i.e. whether it should revert if 1 or more transactions fail */ function executeMultipleTakerBids( OrderStructs.Taker[] calldata takerBids, OrderStructs.Maker[] calldata makerAsks, bytes[] calldata makerSignatures, OrderStructs.MerkleTree[] calldata merkleTrees, address affiliate, bool isAtomic ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title INonceManager * @author LooksRare protocol team (👀,💎) */ interface INonceManager { /** * @notice This struct contains the global bid and ask nonces of a user. * @param bidNonce Bid nonce * @param askNonce Ask nonce */ struct UserBidAskNonces { uint256 bidNonce; uint256 askNonce; } /** * @notice It is emitted when there is an update of the global bid/ask nonces for a user. * @param user Address of the user * @param bidNonce New bid nonce * @param askNonce New ask nonce */ event NewBidAskNonces(address user, uint256 bidNonce, uint256 askNonce); /** * @notice It is emitted when order nonces are cancelled for a user. * @param user Address of the user * @param orderNonces Array of order nonces cancelled */ event OrderNoncesCancelled(address user, uint256[] orderNonces); /** * @notice It is emitted when subset nonces are cancelled for a user. * @param user Address of the user * @param subsetNonces Array of subset nonces cancelled */ event SubsetNoncesCancelled(address user, uint256[] subsetNonces); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title IRoyaltyFeeRegistry * @author LooksRare protocol team (👀,💎) */ interface IRoyaltyFeeRegistry { /** * @notice This function returns the royalty information for a collection at a given transaction price. * @param collection Collection address * @param price Transaction price * @return receiver Receiver address * @return royaltyFee Royalty fee amount */ function royaltyInfo( address collection, uint256 price ) external view returns (address receiver, uint256 royaltyFee); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Libraries import {OrderStructs} from "../libraries/OrderStructs.sol"; /** * @title IStrategy * @author LooksRare protocol team (👀,💎) */ interface IStrategy { /** * @notice Validate *only the maker* order under the context of the chosen strategy. It does not revert if * the maker order is invalid. Instead it returns false and the error's 4 bytes selector. * @param makerOrder Maker struct (maker specific parameters for the execution) * @param functionSelector Function selector for the strategy * @return isValid Whether the maker struct is valid * @return errorSelector If isValid is false, it returns the error's 4 bytes selector */ function isMakerOrderValid( OrderStructs.Maker calldata makerOrder, bytes4 functionSelector ) external view returns (bool isValid, bytes4 errorSelector); /** * @notice This function acts as a safety check for the protocol's owner when adding new execution strategies. * @return isStrategy Whether it is a LooksRare V2 protocol strategy */ function isLooksRareV2Strategy() external pure returns (bool isStrategy); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title IStrategyManager * @author LooksRare protocol team (👀,💎) */ interface IStrategyManager { /** * @notice This struct contains the parameter of an execution strategy. * @param strategyId Id of the new strategy * @param standardProtocolFeeBp Standard protocol fee (in basis point) * @param minTotalFeeBp Minimum total fee (in basis point) * @param maxProtocolFeeBp Maximum protocol fee (in basis point) * @param selector Function selector for the transaction to be executed * @param isMakerBid Whether the strategyId is for maker bid * @param implementation Address of the implementation of the strategy */ struct Strategy { bool isActive; uint16 standardProtocolFeeBp; uint16 minTotalFeeBp; uint16 maxProtocolFeeBp; bytes4 selector; bool isMakerBid; address implementation; } /** * @notice It is emitted when a new strategy is added. * @param strategyId Id of the new strategy * @param standardProtocolFeeBp Standard protocol fee (in basis point) * @param minTotalFeeBp Minimum total fee (in basis point) * @param maxProtocolFeeBp Maximum protocol fee (in basis point) * @param selector Function selector for the transaction to be executed * @param isMakerBid Whether the strategyId is for maker bid * @param implementation Address of the implementation of the strategy */ event NewStrategy( uint256 strategyId, uint16 standardProtocolFeeBp, uint16 minTotalFeeBp, uint16 maxProtocolFeeBp, bytes4 selector, bool isMakerBid, address implementation ); /** * @notice It is emitted when an existing strategy is updated. * @param strategyId Id of the strategy * @param isActive Whether the strategy is active (or not) after the update * @param standardProtocolFeeBp Standard protocol fee (in basis point) * @param minTotalFeeBp Minimum total fee (in basis point) */ event StrategyUpdated(uint256 strategyId, bool isActive, uint16 standardProtocolFeeBp, uint16 minTotalFeeBp); /** * @notice If the strategy has not set properly its implementation contract. * @dev It can only be returned for owner operations. */ error NotV2Strategy(); /** * @notice It is returned if the strategy has no selector. * @dev It can only be returned for owner operations. */ error StrategyHasNoSelector(); /** * @notice It is returned if the strategyId is invalid. */ error StrategyNotUsed(); /** * @notice It is returned if the strategy's protocol fee is too high. * @dev It can only be returned for owner operations. */ error StrategyProtocolFeeTooHigh(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Libraries import {OrderStructs} from "../libraries/OrderStructs.sol"; // Enums import {CollectionType} from "../enums/CollectionType.sol"; /** * @title ITransferManager * @author LooksRare protocol team (👀,💎) */ interface ITransferManager { /** * @notice This struct is only used for transferBatchItemsAcrossCollections. * @param collection Collection address * @param collectionType 0 for ERC721, 1 for ERC1155 * @param itemIds Array of item ids to transfer * @param amounts Array of amounts to transfer */ struct BatchTransferItem { address collection; CollectionType collectionType; uint256[] itemIds; uint256[] amounts; } /** * @notice It is emitted if operators' approvals to transfer NFTs are granted by a user. * @param user Address of the user * @param operators Array of operator addresses */ event ApprovalsGranted(address user, address[] operators); /** * @notice It is emitted if operators' approvals to transfer NFTs are revoked by a user. * @param user Address of the user * @param operators Array of operator addresses */ event ApprovalsRemoved(address user, address[] operators); /** * @notice It is emitted if a new operator is added to the global allowlist. * @param operator Operator address */ event OperatorAllowed(address operator); /** * @notice It is emitted if an operator is removed from the global allowlist. * @param operator Operator address */ event OperatorRemoved(address operator); /** * @notice It is returned if the operator to approve has already been approved by the user. */ error OperatorAlreadyApprovedByUser(); /** * @notice It is returned if the operator to revoke has not been previously approved by the user. */ error OperatorNotApprovedByUser(); /** * @notice It is returned if the transfer caller is already allowed by the owner. * @dev This error can only be returned for owner operations. */ error OperatorAlreadyAllowed(); /** * @notice It is returned if the operator to approve is not in the global allowlist defined by the owner. * @dev This error can be returned if the user tries to grant approval to an operator address not in the * allowlist or if the owner tries to remove the operator from the global allowlist. */ error OperatorNotAllowed(); /** * @notice It is returned if the transfer caller is invalid. * For a transfer called to be valid, the operator must be in the global allowlist and * approved by the 'from' user. */ error TransferCallerInvalid(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Libraries import {OrderStructs} from "../../libraries/OrderStructs.sol"; /** * @title MerkleProofCalldataWithNodes * @notice This library is adjusted from the work of OpenZeppelin. * It is based on the 4.7.0 (utils/cryptography/MerkleProof.sol). * @author OpenZeppelin (adjusted by LooksRare) */ library MerkleProofCalldataWithNodes { /** * @notice This returns true if a `leaf` can be proved to be a part of a Merkle tree defined by `root`. * For this, a `proof` must be provided, containing sibling hashes on the branch from the leaf to the * root of the tree. Each pair of leaves and each pair of pre-images are assumed to be sorted. */ function verifyCalldata( OrderStructs.MerkleTreeNode[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @notice This returns the rebuilt hash obtained by traversing a Merkle tree up from `leaf` using `proof`. * A `proof` is valid if and only if the rebuilt hash matches the root of the tree. * When processing the proof, the pairs of leafs & pre-images are assumed to be sorted. */ function processProofCalldata( OrderStructs.MerkleTreeNode[] calldata proof, bytes32 leaf ) internal pure returns (bytes32) { bytes32 computedHash = leaf; uint256 length = proof.length; for (uint256 i = 0; i < length; ) { if (proof[i].position == OrderStructs.MerkleTreeNodePosition.Left) { computedHash = _efficientHash(proof[i].value, computedHash); } else { computedHash = _efficientHash(computedHash, proof[i].value); } unchecked { ++i; } } return computedHash; } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Enums import {CollectionType} from "../enums/CollectionType.sol"; import {QuoteType} from "../enums/QuoteType.sol"; /** * @title OrderStructs * @notice This library contains all order struct types for the LooksRare protocol (v2). * @author LooksRare protocol team (👀,💎) */ library OrderStructs { /** * 1. Maker struct */ /** * @notice Maker is the struct for a maker order. * @param quoteType Quote type (i.e. 0 = BID, 1 = ASK) * @param globalNonce Global user order nonce for maker orders * @param subsetNonce Subset nonce (shared across bid/ask maker orders) * @param orderNonce Order nonce (it can be shared across bid/ask maker orders) * @param strategyId Strategy id * @param collectionType Collection type (i.e. 0 = ERC721, 1 = ERC1155) * @param collection Collection address * @param currency Currency address (@dev address(0) = ETH) * @param signer Signer address * @param startTime Start timestamp * @param endTime End timestamp * @param price Minimum price for maker ask, maximum price for maker bid * @param itemIds Array of itemIds * @param amounts Array of amounts * @param additionalParameters Extra data specific for the order */ struct Maker { QuoteType quoteType; uint256 globalNonce; uint256 subsetNonce; uint256 orderNonce; uint256 strategyId; CollectionType collectionType; address collection; address currency; address signer; uint256 startTime; uint256 endTime; uint256 price; uint256[] itemIds; uint256[] amounts; bytes additionalParameters; } /** * 2. Taker struct */ /** * @notice Taker is the struct for a taker ask/bid order. It contains the parameters required for a direct purchase. * @dev Taker struct is matched against MakerAsk/MakerBid structs at the protocol level. * @param recipient Recipient address (to receive NFTs or non-fungible tokens) * @param additionalParameters Extra data specific for the order */ struct Taker { address recipient; bytes additionalParameters; } /** * 3. Merkle tree struct */ enum MerkleTreeNodePosition { Left, Right } /** * @notice MerkleTreeNode is a MerkleTree's node. * @param value It can be an order hash or a proof * @param position The node's position in its branch. * It can be left or right or none * (before the tree is sorted). */ struct MerkleTreeNode { bytes32 value; MerkleTreeNodePosition position; } /** * @notice MerkleTree is the struct for a merkle tree of order hashes. * @dev A Merkle tree can be computed with order hashes. * It can contain order hashes from both maker bid and maker ask structs. * @param root Merkle root * @param proof Array containing the merkle proof */ struct MerkleTree { bytes32 root; MerkleTreeNode[] proof; } /** * 4. Constants */ /** * @notice This is the type hash constant used to compute the maker order hash. */ bytes32 internal constant _MAKER_TYPEHASH = keccak256( "Maker(" "uint8 quoteType," "uint256 globalNonce," "uint256 subsetNonce," "uint256 orderNonce," "uint256 strategyId," "uint8 collectionType," "address collection," "address currency," "address signer," "uint256 startTime," "uint256 endTime," "uint256 price," "uint256[] itemIds," "uint256[] amounts," "bytes additionalParameters" ")" ); /** * 5. Hash functions */ /** * @notice This function is used to compute the order hash for a maker struct. * @param maker Maker order struct * @return makerHash Hash of the maker struct */ function hash(Maker memory maker) internal pure returns (bytes32) { // Encoding is done into two parts to avoid stack too deep issues return keccak256( bytes.concat( abi.encode( _MAKER_TYPEHASH, maker.quoteType, maker.globalNonce, maker.subsetNonce, maker.orderNonce, maker.strategyId, maker.collectionType, maker.collection, maker.currency ), abi.encode( maker.signer, maker.startTime, maker.endTime, maker.price, keccak256(abi.encodePacked(maker.itemIds)), keccak256(abi.encodePacked(maker.amounts)), keccak256(maker.additionalParameters) ) ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IOwnableTwoSteps} from "./interfaces/IOwnableTwoSteps.sol"; /** * @title OwnableTwoSteps * @notice This contract offers transfer of ownership in two steps with potential owner * having to confirm the transaction to become the owner. * Renouncement of the ownership is also a two-step process since the next potential owner is the address(0). * @author LooksRare protocol team (👀,💎) */ abstract contract OwnableTwoSteps is IOwnableTwoSteps { /** * @notice Address of the current owner. */ address public owner; /** * @notice Address of the potential owner. */ address public potentialOwner; /** * @notice Ownership status. */ Status public ownershipStatus; /** * @notice Modifier to wrap functions for contracts that inherit this contract. */ modifier onlyOwner() { _onlyOwner(); _; } /** * @notice Constructor * @param _owner The contract's owner */ constructor(address _owner) { owner = _owner; emit NewOwner(_owner); } /** * @notice This function is used to cancel the ownership transfer. * @dev This function can be used for both cancelling a transfer to a new owner and * cancelling the renouncement of the ownership. */ function cancelOwnershipTransfer() external onlyOwner { Status _ownershipStatus = ownershipStatus; if (_ownershipStatus == Status.NoOngoingTransfer) { revert NoOngoingTransferInProgress(); } if (_ownershipStatus == Status.TransferInProgress) { delete potentialOwner; } delete ownershipStatus; emit CancelOwnershipTransfer(); } /** * @notice This function is used to confirm the ownership renouncement. */ function confirmOwnershipRenouncement() external onlyOwner { if (ownershipStatus != Status.RenouncementInProgress) { revert RenouncementNotInProgress(); } delete owner; delete ownershipStatus; emit NewOwner(address(0)); } /** * @notice This function is used to confirm the ownership transfer. * @dev This function can only be called by the current potential owner. */ function confirmOwnershipTransfer() external { if (ownershipStatus != Status.TransferInProgress) { revert TransferNotInProgress(); } if (msg.sender != potentialOwner) { revert WrongPotentialOwner(); } owner = msg.sender; delete ownershipStatus; delete potentialOwner; emit NewOwner(msg.sender); } /** * @notice This function is used to initiate the transfer of ownership to a new owner. * @param newPotentialOwner New potential owner address */ function initiateOwnershipTransfer(address newPotentialOwner) external onlyOwner { if (ownershipStatus != Status.NoOngoingTransfer) { revert TransferAlreadyInProgress(); } ownershipStatus = Status.TransferInProgress; potentialOwner = newPotentialOwner; /** * @dev This function can only be called by the owner, so msg.sender is the owner. * We don't have to SLOAD the owner again. */ emit InitiateOwnershipTransfer(msg.sender, newPotentialOwner); } /** * @notice This function is used to initiate the ownership renouncement. */ function initiateOwnershipRenouncement() external onlyOwner { if (ownershipStatus != Status.NoOngoingTransfer) { revert TransferAlreadyInProgress(); } ownershipStatus = Status.RenouncementInProgress; emit InitiateOwnershipRenouncement(); } function _onlyOwner() private view { if (msg.sender != owner) revert NotOwner(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IReentrancyGuard} from "./interfaces/IReentrancyGuard.sol"; /** * @title PackableReentrancyGuard * @notice This contract protects against reentrancy attacks. * It is adjusted from OpenZeppelin. * The only difference between this contract and ReentrancyGuard * is that _status is uint8 instead of uint256 so that it can be * packed with other contracts' storage variables. * @author LooksRare protocol team (👀,💎) */ abstract contract PackableReentrancyGuard is IReentrancyGuard { uint8 private _status; /** * @notice Modifier to wrap functions to prevent reentrancy calls. */ modifier nonReentrant() { if (_status == 2) { revert ReentrancyFail(); } _status = 2; _; _status = 1; } constructor() { _status = 1; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC1271} from "./interfaces/generic/IERC1271.sol"; // Constants import {ERC1271_MAGIC_VALUE} from "./constants/StandardConstants.sol"; // Errors import {SignatureParameterSInvalid, SignatureParameterVInvalid, SignatureERC1271Invalid, SignatureEOAInvalid, NullSignerAddress, SignatureLengthInvalid} from "./errors/SignatureCheckerErrors.sol"; /** * @title SignatureCheckerCalldata * @notice This library is used to verify signatures for EOAs (with lengths of both 65 and 64 bytes) * and contracts (ERC1271). * @author LooksRare protocol team (👀,💎) */ library SignatureCheckerCalldata { /** * @notice This function verifies whether the signer is valid for a hash and raw signature. * @param hash Data hash * @param signer Signer address (to confirm message validity) * @param signature Signature parameters encoded (v, r, s) * @dev For EIP-712 signatures, the hash must be the digest (computed with signature hash and domain separator) */ function verify(bytes32 hash, address signer, bytes calldata signature) internal view { if (signer.code.length == 0) { if (_recoverEOASigner(hash, signature) == signer) return; revert SignatureEOAInvalid(); } else { if (IERC1271(signer).isValidSignature(hash, signature) == ERC1271_MAGIC_VALUE) return; revert SignatureERC1271Invalid(); } } /** * @notice This function is internal and splits a signature into r, s, v outputs. * @param signature A 64 or 65 bytes signature * @return r The r output of the signature * @return s The s output of the signature * @return v The recovery identifier, must be 27 or 28 */ function splitSignature(bytes calldata signature) internal pure returns (bytes32 r, bytes32 s, uint8 v) { uint256 length = signature.length; if (length == 65) { assembly { r := calldataload(signature.offset) s := calldataload(add(signature.offset, 0x20)) v := byte(0, calldataload(add(signature.offset, 0x40))) } } else if (length == 64) { assembly { r := calldataload(signature.offset) let vs := calldataload(add(signature.offset, 0x20)) s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } } else { revert SignatureLengthInvalid(length); } if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert SignatureParameterSInvalid(); } if (v != 27 && v != 28) { revert SignatureParameterVInvalid(v); } } /** * @notice This function is private and recovers the signer of a signature (for EOA only). * @param hash Hash of the signed message * @param signature Bytes containing the signature (64 or 65 bytes) * @return signer The address that signed the signature */ function _recoverEOASigner(bytes32 hash, bytes calldata signature) private pure returns (address signer) { (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature); // If the signature is valid (and not malleable), return the signer's address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { revert NullSignerAddress(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /* * @dev error ETHTransferFail() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ETHTransferFail_error_selector = 0x07246cf4; uint256 constant ETHTransferFail_error_length = 0x04; uint256 constant Error_selector_offset = 0x1c;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @dev ERC1271's magic value (bytes4(keccak256("isValidSignature(bytes32,bytes)")) */ bytes4 constant ERC1271_MAGIC_VALUE = 0x1626ba7e;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the call recipient is not a contract. */ error NotAContract();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the ETH transfer fails. */ error ETHTransferFail(); /** * @notice It is emitted if the ERC20 approval fails. */ error ERC20ApprovalFail(); /** * @notice It is emitted if the ERC20 transfer fails. */ error ERC20TransferFail(); /** * @notice It is emitted if the ERC20 transferFrom fails. */ error ERC20TransferFromFail(); /** * @notice It is emitted if the ERC721 transferFrom fails. */ error ERC721TransferFromFail(); /** * @notice It is emitted if the ERC1155 safeTransferFrom fails. */ error ERC1155SafeTransferFromFail(); /** * @notice It is emitted if the ERC1155 safeBatchTransferFrom fails. */ error ERC1155SafeBatchTransferFromFail();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the signer is null. */ error NullSignerAddress(); /** * @notice It is emitted if the signature is invalid for an EOA (the address recovered is not the expected one). */ error SignatureEOAInvalid(); /** * @notice It is emitted if the signature is invalid for a ERC1271 contract signer. */ error SignatureERC1271Invalid(); /** * @notice It is emitted if the signature's length is neither 64 nor 65 bytes. */ error SignatureLengthInvalid(uint256 length); /** * @notice It is emitted if the signature is invalid due to S parameter. */ error SignatureParameterSInvalid(); /** * @notice It is emitted if the signature is invalid due to V parameter. */ error SignatureParameterVInvalid(uint8 v);
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @title IOwnableTwoSteps * @author LooksRare protocol team (👀,💎) */ interface IOwnableTwoSteps { /** * @notice This enum keeps track of the ownership status. * @param NoOngoingTransfer The default status when the owner is set * @param TransferInProgress The status when a transfer to a new owner is initialized * @param RenouncementInProgress The status when a transfer to address(0) is initialized */ enum Status { NoOngoingTransfer, TransferInProgress, RenouncementInProgress } /** * @notice This is returned when there is no transfer of ownership in progress. */ error NoOngoingTransferInProgress(); /** * @notice This is returned when the caller is not the owner. */ error NotOwner(); /** * @notice This is returned when there is no renouncement in progress but * the owner tries to validate the ownership renouncement. */ error RenouncementNotInProgress(); /** * @notice This is returned when the transfer is already in progress but the owner tries * initiate a new ownership transfer. */ error TransferAlreadyInProgress(); /** * @notice This is returned when there is no ownership transfer in progress but the * ownership change tries to be approved. */ error TransferNotInProgress(); /** * @notice This is returned when the ownership transfer is attempted to be validated by the * a caller that is not the potential owner. */ error WrongPotentialOwner(); /** * @notice This is emitted if the ownership transfer is cancelled. */ event CancelOwnershipTransfer(); /** * @notice This is emitted if the ownership renouncement is initiated. */ event InitiateOwnershipRenouncement(); /** * @notice This is emitted if the ownership transfer is initiated. * @param previousOwner Previous/current owner * @param potentialOwner Potential/future owner */ event InitiateOwnershipTransfer(address previousOwner, address potentialOwner); /** * @notice This is emitted when there is a new owner. */ event NewOwner(address newOwner); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @title IReentrancyGuard * @author LooksRare protocol team (👀,💎) */ interface IReentrancyGuard { /** * @notice This is returned when there is a reentrant call. */ error ReentrancyFail(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC1155 { event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); event ApprovalForAll(address indexed account, address indexed operator, bool approved); event URI(string value, uint256 indexed id); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch( address[] calldata accounts, uint256[] calldata ids ) external view returns (uint256[] memory); function setApprovalForAll(address operator, bool approved) external; function isApprovedForAll(address account, address operator) external view returns (bool); function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC1271 { function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC721 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); function balanceOf(address owner) external view returns (uint256 balance); function ownerOf(uint256 tokenId) external view returns (address owner); function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; function safeTransferFrom(address from, address to, uint256 tokenId) external; function transferFrom(address from, address to, uint256 tokenId) external; function approve(address to, uint256 tokenId) external; function setApprovalForAll(address operator, bool _approved) external; function getApproved(uint256 tokenId) external view returns (address operator); function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IWETH { function deposit() external payable; function transfer(address dst, uint256 wad) external returns (bool); function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC1155} from "../interfaces/generic/IERC1155.sol"; // Errors import {ERC1155SafeTransferFromFail, ERC1155SafeBatchTransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC1155Transfer * @notice This contract contains low-level calls to transfer ERC1155 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC1155Transfer { /** * @notice Execute ERC1155 safeTransferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenId tokenId to transfer * @param amount Amount to transfer */ function _executeERC1155SafeTransferFrom( address collection, address from, address to, uint256 tokenId, uint256 amount ) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call(abi.encodeCall(IERC1155.safeTransferFrom, (from, to, tokenId, amount, ""))); if (!status) { revert ERC1155SafeTransferFromFail(); } } /** * @notice Execute ERC1155 safeBatchTransferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenIds Array of tokenIds to transfer * @param amounts Array of amounts to transfer */ function _executeERC1155SafeBatchTransferFrom( address collection, address from, address to, uint256[] calldata tokenIds, uint256[] calldata amounts ) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call( abi.encodeCall(IERC1155.safeBatchTransferFrom, (from, to, tokenIds, amounts, "")) ); if (!status) { revert ERC1155SafeBatchTransferFromFail(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC20} from "../interfaces/generic/IERC20.sol"; // Errors import {ERC20TransferFail, ERC20TransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC20Transfer * @notice This contract contains low-level calls to transfer ERC20 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC20Transfer { /** * @notice Execute ERC20 transferFrom * @param currency Currency address * @param from Sender address * @param to Recipient address * @param amount Amount to transfer */ function _executeERC20TransferFrom(address currency, address from, address to, uint256 amount) internal { if (currency.code.length == 0) { revert NotAContract(); } (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transferFrom, (from, to, amount))); if (!status) { revert ERC20TransferFromFail(); } if (data.length > 0) { if (!abi.decode(data, (bool))) { revert ERC20TransferFromFail(); } } } /** * @notice Execute ERC20 (direct) transfer * @param currency Currency address * @param to Recipient address * @param amount Amount to transfer */ function _executeERC20DirectTransfer(address currency, address to, uint256 amount) internal { if (currency.code.length == 0) { revert NotAContract(); } (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transfer, (to, amount))); if (!status) { revert ERC20TransferFail(); } if (data.length > 0) { if (!abi.decode(data, (bool))) { revert ERC20TransferFail(); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC721} from "../interfaces/generic/IERC721.sol"; // Errors import {ERC721TransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC721Transfer * @notice This contract contains low-level calls to transfer ERC721 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC721Transfer { /** * @notice Execute ERC721 transferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenId tokenId to transfer */ function _executeERC721TransferFrom(address collection, address from, address to, uint256 tokenId) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call(abi.encodeCall(IERC721.transferFrom, (from, to, tokenId))); if (!status) { revert ERC721TransferFromFail(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Assembly constants import {ETHTransferFail_error_selector, ETHTransferFail_error_length, Error_selector_offset} from "../constants/AssemblyConstants.sol"; /** * @title LowLevelETHReturnETHIfAnyExceptOneWei * @notice This contract contains a function to return all ETH except 1 wei held. * @author LooksRare protocol team (👀,💎) */ contract LowLevelETHReturnETHIfAnyExceptOneWei { /** * @notice It returns ETH to the original sender if any is left in the payable call * but this leaves 1 wei of ETH in the contract. * @dev It does not revert if self balance is equal to 1 or 0. */ function _returnETHIfAnyWithOneWeiLeft() internal { assembly { let selfBalance := selfbalance() if gt(selfBalance, 1) { let status := call(gas(), caller(), sub(selfBalance, 1), 0, 0, 0, 0) if iszero(status) { mstore(0x00, ETHTransferFail_error_selector) revert(Error_selector_offset, ETHTransferFail_error_length) } } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IWETH} from "../interfaces/generic/IWETH.sol"; /** * @title LowLevelWETH * @notice This contract contains a function to transfer ETH with an option to wrap to WETH. * If the ETH transfer fails within a gas limit, the amount in ETH is wrapped to WETH and then transferred. * @author LooksRare protocol team (👀,💎) */ contract LowLevelWETH { /** * @notice It transfers ETH to a recipient with a specified gas limit. * If the original transfers fails, it wraps to WETH and transfers the WETH to recipient. * @param _WETH WETH address * @param _to Recipient address * @param _amount Amount to transfer * @param _gasLimit Gas limit to perform the ETH transfer */ function _transferETHAndWrapIfFailWithGasLimit( address _WETH, address _to, uint256 _amount, uint256 _gasLimit ) internal { bool status; assembly { status := call(_gasLimit, _to, _amount, 0, 0, 0, 0) } if (!status) { IWETH(_WETH).deposit{value: _amount}(); IWETH(_WETH).transfer(_to, _amount); } } }
{ "remappings": [ "@chainlink/=node_modules/@chainlink/", "@ensdomains/=node_modules/@ensdomains/", "@eth-optimism/=node_modules/@eth-optimism/", "@looksrare/=node_modules/@looksrare/", "@openzeppelin/=node_modules/@openzeppelin/", "ds-test/=lib/forge-std/lib/ds-test/src/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "murky/=lib/murky/src/", "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/", "solmate/=node_modules/solmate/" ], "optimizer": { "enabled": true, "runs": 888888 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_protocolFeeRecipient","type":"address"},{"internalType":"address","name":"_transferManager","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerInvalid","type":"error"},{"inputs":[],"name":"ChainIdInvalid","type":"error"},{"inputs":[],"name":"CreatorFeeBpTooHigh","type":"error"},{"inputs":[],"name":"CurrencyInvalid","type":"error"},{"inputs":[],"name":"ERC20TransferFromFail","type":"error"},{"inputs":[],"name":"LengthsInvalid","type":"error"},{"inputs":[],"name":"MerkleProofInvalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"MerkleProofTooLarge","type":"error"},{"inputs":[],"name":"NewGasLimitETHTransferTooLow","type":"error"},{"inputs":[],"name":"NewProtocolFeeRecipientCannotBeNullAddress","type":"error"},{"inputs":[],"name":"NoOngoingTransferInProgress","type":"error"},{"inputs":[],"name":"NoSelectorForStrategy","type":"error"},{"inputs":[],"name":"NoncesInvalid","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotAffiliateController","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotV2Strategy","type":"error"},{"inputs":[],"name":"NullSignerAddress","type":"error"},{"inputs":[],"name":"OutsideOfTimeRange","type":"error"},{"inputs":[],"name":"PercentageTooHigh","type":"error"},{"inputs":[],"name":"QuoteTypeInvalid","type":"error"},{"inputs":[],"name":"ReentrancyFail","type":"error"},{"inputs":[],"name":"RenouncementNotInProgress","type":"error"},{"inputs":[],"name":"SameDomainSeparator","type":"error"},{"inputs":[],"name":"SignatureEOAInvalid","type":"error"},{"inputs":[],"name":"SignatureERC1271Invalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"SignatureLengthInvalid","type":"error"},{"inputs":[],"name":"SignatureParameterSInvalid","type":"error"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"}],"name":"SignatureParameterVInvalid","type":"error"},{"inputs":[],"name":"StrategyHasNoSelector","type":"error"},{"inputs":[{"internalType":"uint256","name":"strategyId","type":"uint256"}],"name":"StrategyNotAvailable","type":"error"},{"inputs":[],"name":"StrategyNotUsed","type":"error"},{"inputs":[],"name":"StrategyProtocolFeeTooHigh","type":"error"},{"inputs":[],"name":"TransferAlreadyInProgress","type":"error"},{"inputs":[],"name":"TransferNotInProgress","type":"error"},{"inputs":[],"name":"WrongPotentialOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"affiliateFee","type":"uint256"}],"name":"AffiliatePayment","type":"event"},{"anonymous":false,"inputs":[],"name":"CancelOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"CurrencyStatusUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"InitiateOwnershipRenouncement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"potentialOwner","type":"address"}],"name":"InitiateOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"affiliateController","type":"address"}],"name":"NewAffiliateController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"NewAffiliateProgramStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"NewAffiliateRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidNonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"askNonce","type":"uint256"}],"name":"NewBidAskNonces","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"creatorFeeManager","type":"address"}],"name":"NewCreatorFeeManager","type":"event"},{"anonymous":false,"inputs":[],"name":"NewDomainSeparator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasLimitETHTransfer","type":"uint256"}],"name":"NewGasLimitETHTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxCreatorFeeBp","type":"uint256"}],"name":"NewMaxCreatorFeeBp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolFeeRecipient","type":"address"}],"name":"NewProtocolFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"maxProtocolFeeBp","type":"uint16"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"isMakerBid","type":"bool"},{"indexed":false,"internalType":"address","name":"implementation","type":"address"}],"name":"NewStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"orderNonces","type":"uint256[]"}],"name":"OrderNoncesCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"},{"indexed":false,"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"}],"name":"StrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"subsetNonces","type":"uint256[]"}],"name":"SubsetNoncesCancelled","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"bool","name":"isNonceInvalidated","type":"bool"}],"indexed":false,"internalType":"struct ILooksRareProtocol.NonceInvalidationParameters","name":"nonceInvalidationParameters","type":"tuple"},{"indexed":false,"internalType":"address","name":"askUser","type":"address"},{"indexed":false,"internalType":"address","name":"bidUser","type":"address"},{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"address[2]","name":"feeRecipients","type":"address[2]"},{"indexed":false,"internalType":"uint256[3]","name":"feeAmounts","type":"uint256[3]"}],"name":"TakerAsk","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"bool","name":"isNonceInvalidated","type":"bool"}],"indexed":false,"internalType":"struct ILooksRareProtocol.NonceInvalidationParameters","name":"nonceInvalidationParameters","type":"tuple"},{"indexed":false,"internalType":"address","name":"bidUser","type":"address"},{"indexed":false,"internalType":"address","name":"bidRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"address[2]","name":"feeRecipients","type":"address[2]"},{"indexed":false,"internalType":"uint256[3]","name":"feeAmounts","type":"uint256[3]"}],"name":"TakerBid","type":"event"},{"inputs":[],"name":"MAGIC_VALUE_ORDER_NONCE_EXECUTED","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"},{"internalType":"uint16","name":"maxProtocolFeeBp","type":"uint16"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bool","name":"isMakerBid","type":"bool"},{"internalType":"address","name":"implementation","type":"address"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"affiliateController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"affiliateRates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderNonces","type":"uint256[]"}],"name":"cancelOrderNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"subsetNonces","type":"uint256[]"}],"name":"cancelSubsetNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"confirmOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creatorFeeManager","outputs":[{"internalType":"contract ICreatorFeeManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker[]","name":"takerBids","type":"tuple[]"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker[]","name":"makerAsks","type":"tuple[]"},{"internalType":"bytes[]","name":"makerSignatures","type":"bytes[]"},{"components":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"value","type":"bytes32"},{"internalType":"enum OrderStructs.MerkleTreeNodePosition","name":"position","type":"uint8"}],"internalType":"struct OrderStructs.MerkleTreeNode[]","name":"proof","type":"tuple[]"}],"internalType":"struct OrderStructs.MerkleTree[]","name":"merkleTrees","type":"tuple[]"},{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bool","name":"isAtomic","type":"bool"}],"name":"executeMultipleTakerBids","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker","name":"takerAsk","type":"tuple"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker","name":"makerBid","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"components":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"value","type":"bytes32"},{"internalType":"enum OrderStructs.MerkleTreeNodePosition","name":"position","type":"uint8"}],"internalType":"struct OrderStructs.MerkleTreeNode[]","name":"proof","type":"tuple[]"}],"internalType":"struct OrderStructs.MerkleTree","name":"merkleTree","type":"tuple"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"executeTakerAsk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker","name":"takerBid","type":"tuple"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker","name":"makerAsk","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"components":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"value","type":"bytes32"},{"internalType":"enum OrderStructs.MerkleTreeNodePosition","name":"position","type":"uint8"}],"internalType":"struct OrderStructs.MerkleTreeNode[]","name":"proof","type":"tuple[]"}],"internalType":"struct OrderStructs.MerkleTree","name":"merkleTree","type":"tuple"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"executeTakerBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"uint256","name":"proofLength","type":"uint256"}],"name":"hashBatchOrder","outputs":[{"internalType":"bytes32","name":"batchOrderHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bool","name":"bid","type":"bool"},{"internalType":"bool","name":"ask","type":"bool"}],"name":"incrementBidAskNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initiateOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"initiateOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAffiliateProgramActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isCurrencyAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxCreatorFeeBp","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipStatus","outputs":[{"internalType":"enum IOwnableTwoSteps.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"potentialOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker","name":"takerBid","type":"tuple"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker","name":"makerAsk","type":"tuple"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"restrictedExecuteTakerBid","outputs":[{"internalType":"uint256","name":"protocolFeeAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"strategyInfo","outputs":[{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"},{"internalType":"uint16","name":"maxProtocolFeeBp","type":"uint16"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bool","name":"isMakerBid","type":"bool"},{"internalType":"address","name":"implementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferManager","outputs":[{"internalType":"contract TransferManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAffiliateController","type":"address"}],"name":"updateAffiliateController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isActive","type":"bool"}],"name":"updateAffiliateProgramStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"uint256","name":"bp","type":"uint256"}],"name":"updateAffiliateRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCreatorFeeManager","type":"address"}],"name":"updateCreatorFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"updateCurrencyStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasLimitETHTransfer","type":"uint256"}],"name":"updateETHGasLimitForTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMaxCreatorFeeBp","type":"uint16"}],"name":"updateMaxCreatorFeeBp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProtocolFeeRecipient","type":"address"}],"name":"updateProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint16","name":"newStandardProtocolFee","type":"uint16"},{"internalType":"uint16","name":"newMinTotalFee","type":"uint16"}],"name":"updateStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBidAskNonces","outputs":[{"internalType":"uint256","name":"bidNonce","type":"uint256"},{"internalType":"uint256","name":"askNonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userOrderNonce","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userSubsetNonce","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040526001600855600a805461ffff60a01b1916607d60a31b1790556108fc600e553480156200003057600080fd5b5060405162005dc838038062005dc8833981016040819052620000539162000417565b600380546001600160a01b0319166001600160a01b0386169081179091556040519081528490849084908390839082908190819081907f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc9060200160405180910390a150506040805160e08082018352600182526032602080840182815284860183815260c86060870181815260006080890181815260a08a0182815260c08b01838152838052600990985299517fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b805497519651945192519b5198516001600160a01b03166c01000000000000000000000000026001600160601b039915156b0100000000000000000000000260ff60581b199d909c1c670100000000000000029c909c1664ffffffffff60381b1961ffff948516650100000000000261ffff60281b199786166301000000029790971666ffffffff00000019999095166101000262ffff00199415159490941662ffffff19909a1699909917929092179690961691909117929092179490941617959095179290921694909417905592517f5290475107686ff8d28cd104943b127d453b23622ac55346373fa25c0c8957a29450620002719391829184908190819096875261ffff958616602088015293851660408701529190931660608501526001600160e01b031992909216608084015290151560a08301526001600160a01b031660c082015260e00190565b60405180910390a15062000285816200037e565b5050600b805460ff60a01b1916600160a01b1790556001600160a01b03166080525062000368905060408051808201825260018152601960f91b60209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f9e6bc51ef68b436657c5fe7a273ea9121a02b234cc81ad1e04892649c9168c6a818401527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5606082015246608082018190523060a0808401919091528451808403909101815260c09092019093528051910120600d55600c55565b6001600160a01b031660a0525062000474915050565b6001600160a01b038116620003a657604051630f966bcb60e41b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0383169081179091556040519081527f8cffb07faa2874440346743bdc0a86b06c3335cc47dc49b327d10e77b73ceb109060200160405180910390a150565b80516001600160a01b03811681146200041257600080fd5b919050565b600080600080608085870312156200042e57600080fd5b6200043985620003fa565b93506200044960208601620003fa565b92506200045960408601620003fa565b91506200046960608601620003fa565b905092959194509250565b60805160a051615919620004af600039600081816107ee0152613a2501526000818161045d015281816138c4015261398e01526159196000f3fe6080604052600436106102dc5760003560e01c8063838b8f5c11610184578063ae1cce5a116100d6578063d5b010f51161008a578063ea179b7611610064578063ea179b7614610a05578063f4288a2114610a40578063f698da2514610a5357600080fd5b8063d5b010f5146109a5578063d5b7f065146109c5578063e72853e1146109e557600080fd5b8063bb91c339116100bb578063bb91c33914610850578063c0b6f56114610965578063d5a06adf1461098557600080fd5b8063ae1cce5a14610810578063b647a4041461083057600080fd5b806391be136011610138578063a02bab5711610112578063a02bab5714610773578063a39bf29f14610793578063ad5c4648146107dc57600080fd5b806391be13601461071d578063974e7c9f1461073d5780639a8a05921461075d57600080fd5b806386c076421161016957806386c07642146106bb57806389ccfe89146106db5780638da5cb5b146106f057600080fd5b8063838b8f5c1461067b5780638585ae03146106a857600080fd5b80634cbac9dc1161023d57806367d9dd79116101f15780637762df25116101cb5780637762df251461060157806379ed31d41461062e5780637a7d88511461064e57600080fd5b806367d9dd79146105735780636e90c014146105a65780637200b829146105ec57600080fd5b80635a195d19116102225780635a195d19146104f15780635b6ac0111461053157806364df049e1461054657600080fd5b80634cbac9dc146104a457806354878876146104d157600080fd5b80632bb5a9e611610294578063463357ec11610279578063463357ec146103f757806346b625bc1461042b57806346ea25521461044b57600080fd5b80632bb5a9e6146103a35780633e567539146103e257600080fd5b80631df47f80116102c55780631df47f801461032357806320cd05c71461034357806323452b9c1461038e57600080fd5b8063134849a6146102e15780631d3c426814610303575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614520565b610a69565b005b34801561030f57600080fd5b5061030161031e3660046145a8565b610b63565b34801561032f57600080fd5b5061030161033e3660046145e1565b610bfa565b34801561034f57600080fd5b5061037b61035e366004614605565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561039a57600080fd5b50610301610c0e565b3480156103af57600080fd5b506004546103d59074010000000000000000000000000000000000000000900460ff1681565b6040516103859190614660565b3480156103ee57600080fd5b50610301610d15565b34801561040357600080fd5b5061037b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db81565b34801561043757600080fd5b5061030161044636600461468c565b610e0c565b34801561045757600080fd5b5061047f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610385565b3480156104b057600080fd5b5060055461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104dd57600080fd5b506103016104ec3660046146a7565b610ed6565b3480156104fd57600080fd5b5061052161050c3660046145e1565b60076020526000908152604090205460ff1681565b6040519015158152602001610385565b34801561053d57600080fd5b50610301610f58565b34801561055257600080fd5b50600a5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b50600454610521907501000000000000000000000000000000000000000000900460ff1681565b3480156105b257600080fd5b50600a546105d99074010000000000000000000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610385565b3480156105f857600080fd5b50610301611032565b34801561060d57600080fd5b5060045461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561063a57600080fd5b50610301610649366004614520565b611170565b34801561065a57600080fd5b5061037b6106693660046145e1565b60066020526000908152604090205481565b34801561068757600080fd5b50600b5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b6103016106b63660046146ef565b611250565b3480156106c757600080fd5b5061037b6106d63660046147df565b6113fc565b3480156106e757600080fd5b50610301611439565b3480156106fc57600080fd5b5060035461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561072957600080fd5b5061030161073836600461482f565b611583565b34801561074957600080fd5b506103016107583660046148ab565b611996565b34801561076957600080fd5b5061037b600c5481565b34801561077f57600080fd5b5061030161078e3660046145e1565b611a0f565b34801561079f57600080fd5b506107c76107ae3660046145e1565b6000602081905290815260409020805460019091015482565b60408051928352602083019190915201610385565b3480156107e857600080fd5b5061047f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561081c57600080fd5b5061030161082b366004614605565b611a8a565b34801561083c57600080fd5b5061030161084b3660046145e1565b611b75565b34801561085c57600080fd5b506108ec61086b3660046148ab565b60096020526000908152604090205460ff8082169161ffff61010082048116926301000000830482169265010000000000810490921691670100000000000000810460e01b916b0100000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009091041687565b60408051971515885261ffff9687166020890152948616948701949094529390911660608501527fffffffff0000000000000000000000000000000000000000000000000000000016608084015290151560a083015273ffffffffffffffffffffffffffffffffffffffff1660c082015260e001610385565b34801561097157600080fd5b506103016109803660046145e1565b611bf0565b34801561099157600080fd5b506103016109a03660046148c4565b611cf2565b3480156109b157600080fd5b506103016109c0366004614913565b611e89565b3480156109d157600080fd5b5061037b6109e0366004614931565b611f4b565b3480156109f157600080fd5b50610301610a003660046146ef565b611f9b565b348015610a1157600080fd5b50610521610a20366004614605565b600260209081526000928352604080842090915290825290205460ff1681565b610301610a4e3660046149af565b612160565b348015610a5f57600080fd5b5061037b600d5481565b806000819003610aa5576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610b2257336000908152600260205260408120600191868685818110610ad457610ad4614a94565b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610aa8565b507fe8036d6fb143373f3ff63e551373f5fffe4267f6809bf6d3934014a18a9b38f6338484604051610b5693929190614b0e565b60405180910390a1505050565b610b6b61266e565b73ffffffffffffffffffffffffffffffffffffffff821660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527fba28eda47a2e15b1dd3269e6d82f66730d20a5661aa40e9faf9f311c7872a54391015b60405180910390a15050565b610c0261266e565b610c0b816126bf565b50565b610c1661266e565b60045474010000000000000000000000000000000000000000900460ff166000816002811115610c4857610c48614631565b03610c7f576040517fccf69db700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001816002811115610c9357610c93614631565b03610cc157600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556040517f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae390600090a150565b610d1d61266e565b600260045474010000000000000000000000000000000000000000900460ff166002811115610d4e57610d4e614631565b14610d85576040517f045c512200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055604051600081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc906020015b60405180910390a1565b610e1461266e565b6109c48161ffff161115610e54576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000061ffff8416908102919091179091556040519081527fcaba16bb74e50491b14ebf4755083b43aaf56a765134681af613a2ef8d732f4f906020015b60405180910390a150565b610ede61266e565b600480548215157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9091161790556040517fdca612ba3556b7c2603089071be1feb2404df55dcabceee9d5fd852fdb39bc3490610ecb90831515815260200190565b610f6061266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115610f9157610f91614631565b14610fc8576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556040517f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec90600090a1565b600160045474010000000000000000000000000000000000000000900460ff16600281111561106357611063614631565b1461109a576040517f5e4f282600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045473ffffffffffffffffffffffffffffffffffffffff1633146110eb576040517fafdcfb9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633908117909155600480547fffffffffffffffffffffff0000000000000000000000000000000000000000001690556040519081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602001610e02565b8060008190036111ac576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561121c573360009081526001602052604081207f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db918686858181106111fa576111fa614a94565b60209081029290920135835250810191909152604001600020556001016111af565b507f0560c6093fba8a508d0e6ea3b4d7260d7afa9b152731f03a2d05dfe39b0ec425338484604051610b5693929190614b0e565b600b5474010000000000000000000000000000000000000000900460ff166002036112a7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560006112f9610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff1661135b576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061136e61136988614d1b565b61277f565b905061138e848288886113896101208d016101008e016145e1565b612934565b600061139c898933856129ff565b90506113aa83338684612d14565b6113b2612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050565b600061140782612ea1565b604080516020810192909252810184905260600160405160208183030381529060405280519060200120905092915050565b61144161266e565b600c54461461154f57611524604080518082018252600181527f320000000000000000000000000000000000000000000000000000000000000060209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f9e6bc51ef68b436657c5fe7a273ea9121a02b234cc81ad1e04892649c9168c6a818401527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5606082015246608082018190523060a0808401919091528451808403909101815260c09092019093528051910120600d55600c55565b6040517f5b2d1f36cd3ec425baab07b99853532e2ba6387a472ddbff437c5cc96f2f20ca90600090a1565b6040517fa69915e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b61158b61266e565b8361ffff168561ffff1611806115a857508461ffff168661ffff16115b806115b857506101f48461ffff16115b156115ef576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff000000000000000000000000000000000000000000000000000000008316611648576040517fc2d0709200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166345b2b3816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b79190614e57565b6116ed576040517fef8c37d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e080820183526001825261ffff808a1660208085019182528a83168587019081528a8416606087019081527fffffffff000000000000000000000000000000000000000000000000000000008b16608088019081528a151560a0890190815273ffffffffffffffffffffffffffffffffffffffff808c1660c08b0190815260088054600090815260099098529b87209a518b549851965195519451935191519092166c01000000000000000000000000026bffffffffffffffffffffffff9115156b010000000000000000000000027fffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff94909b1c67010000000000000002939093167fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff948a1665010000000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffff968b16630100000002969096167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff97909a16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff931515939093167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009099169890981791909117949094169690961791909117169290921793909317161790915581547f5290475107686ff8d28cd104943b127d453b23622ac55346373fa25c0c8957a292909161191483614ea3565b909155506040805191825261ffff898116602084015288811683830152871660608301527fffffffff000000000000000000000000000000000000000000000000000000008616608083015284151560a083015273ffffffffffffffffffffffffffffffffffffffff841660c0830152519081900360e00190a1505050505050565b61199e61266e565b6108fc8110156119da576040517fad6d14d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8190556040518181527ffc3a20d07f3d5bcc0b01a52011f630765611323fa9afa69f63ba2aa19f7364b690602001610ecb565b611a1761266e565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa92d85531a006d07fd0df4c61259b6dc18e4f492857e2454e5a20ee5e55cddcc90602001610ecb565b60055473ffffffffffffffffffffffffffffffffffffffff163314611adb576040517f9f63004300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612710811115611b17576040517f2242dac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815260066020908152604091829020849055815192835282018390527fa16126d9473196242b0784325b30642b89f34442dd178a852f5b88ee483a30d89101610bee565b611b7d61266e565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa7014d98341b07b23615cb6b4da7cca2a381932b46fb39ca4b8c3875c53aa76490602001610ecb565b611bf861266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115611c2957611c29614631565b14611c60576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffff000000000000000000000000000000000000000000909116811774010000000000000000000000000000000000000000179091556040805133815260208101929092527fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef9101610ecb565b611cfa61266e565b6008548410611d35576040517fbd7056c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526009602052604090205461ffff6501000000000090910481169082161180611d6957508061ffff168261ffff16115b15611da0576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020908152604091829020805461ffff858116630100000081027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff92891661010081027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff8c15159081167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009097169690961717939093161790935584518981529384019190915282840152606082015290517f3b25bf77fa688236b850bf89c87e353098688237aa18dc42593aff0f6387aea99181900360800190a150505050565b60006080611e98600143614edb565b3360009081526020819052604090208054600190910154914090921c92508415611edb57611ec68383614ef4565b33600090815260208190526040902081905591505b8315611f0357611eeb8382614ef4565b33600090815260208190526040902060010181905590505b60408051338152602081018490529081018290527fb738dd6073fae1a7128e3fcc6b4ca6e1356b7232f87cc98f8a2857bcd83dfc449060600160405180910390a15050505050565b6000333014611f86576040517fa78d09b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f92858585856129ff565b95945050505050565b600b5474010000000000000000000000000000000000000000900460ff16600203611ff2576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556000612044610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff161580612090575073ffffffffffffffffffffffffffffffffffffffff8116155b156120c7576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120db610120880161010089016145e1565b905060006120eb61136989614d1b565b90506120fa8582898986612934565b60006121078a8a846130b3565b905061211584848784612d14565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555050505050505050565b600b5474010000000000000000000000000000000000000000900460ff166002036121b7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790558880158061220d5750878118868218178482181715155b15612244576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008989600081811061225957612259614a94565b905060200281019061226b9190614f07565b61227d9061010081019060e0016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff166122df576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083156124555760005b8381101561244f57368c8c8381811061230557612305614a94565b90506020028101906123179190614f07565b905081156123945773ffffffffffffffffffffffffffffffffffffffff8416612347610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612394576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f848181106123a7576123a7614a94565b90506020028101906123b99190614f45565b905060006123c961136984614d1b565b90506124298b8b868181106123e0576123e0614a94565b90506020028101906123f29190614f45565b828f8f8881811061240557612405614a94565b90506020028101906124179190614f79565b61138961012089016101008a016145e1565b612435828433846129ff565b61243f9086614ef4565b94508360010193505050506122ea565b5061260c565b60005b8381101561260a57368c8c8381811061247357612473614a94565b90506020028101906124859190614f07565b905081156125025773ffffffffffffffffffffffffffffffffffffffff84166124b5610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612502576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f8481811061251557612515614a94565b90506020028101906125279190614f45565b9050600061253761136984614d1b565b905061254e8b8b868181106123e0576123e0614a94565b6040517fd5b7f065000000000000000000000000000000000000000000000000000000008152309063d5b7f065906125909085908790339087906004016152be565b6020604051808303816000875af19250505080156125e9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526125e69181019061530d565b60015b156125fc576125f88187614ef4565b9550505b836001019350505050612458565b505b61261882338784612d14565b50612621612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611581576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661270c576040517ff966bcb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8cffb07faa2874440346743bdc0a86b06c3335cc47dc49b327d10e77b73ceb1090602001610ecb565b60007e3c1bce41a2de73dfe64d6eeb2b3d7f15f1c0c382d9d963c2c6daeb75f0e539826000015183602001518460400151856060015186608001518760a001518860c001518960e001516040516020016127e199989796959493929190615326565b60405160208183030381529060405282610100015183610120015184610140015185610160015186610180015160405160200161281e9190615396565b60405160208183030381529060405280519060200120876101a0015160405160200161284a9190615396565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101c08c015180519083012073ffffffffffffffffffffffffffffffffffffffff90991691840191909152908201959095526060810193909352608083019190915260a082015260c081019190915260e081019190915261010001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261291792916020016153fc565b604051602081830303815290604052805190602001209050919050565b60006129436020870187615411565b91505080156129eb57600a81111561298f576040517febbd838a000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6129a761299f6020880188615411565b88358861330b565b6129dd576040517fc8ac23c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129e88635826113fc565b94505b6129f785858585613323565b505050505050565b60006001612a106020860186615479565b6001811115612a2157612a21614631565b14612a58576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a6c610120860161010087016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020818152604080842060608c013585528252808420549484528382529092200154929350909190870135141580612af5575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832089820135845290915290205460ff165b80612b0a57508015801590612b0a5750838114155b15612b41576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000806000806000612b558b8b336133c3565b94509450945094509450612b6f81878c606001358b6137d2565b612b8b8383612b856101008e0160e08f016145e1565b8c61383a565b612c16612b9e60e08c0160c08d016145e1565b612bae60c08d0160a08e01615479565b88600073ffffffffffffffffffffffffffffffffffffffff168f6000016020810190612bda91906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612c0d578e6000016020810190612c0891906145e1565b612c0f565b8c5b898961386e565b7f3ee3de4684413690dee6fff1a0a4f92916a1b97d1c5a83cdf24671844306b2e360405180606001604052808a81526020018c6060013581526020018315158152508a600073ffffffffffffffffffffffffffffffffffffffff168e6000016020810190612c8491906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612cb157612cac60208f018f6145e1565b612cb3565b8b5b8d608001358e60e0016020810190612ccb91906145e1565b8f60c0016020810190612cde91906145e1565b8b8b8b8b604051612cf89a9998979695949392919061552d565b60405180910390a150604001519450505050505b949350505050565b8015612e6d5773ffffffffffffffffffffffffffffffffffffffff821615612e46576004547501000000000000000000000000000000000000000000900460ff1615612e465773ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604081205461271090612d8e9084615624565b612d98919061563b565b90508015612e4457612daa8183614edb565b91508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614612deb57612deb85858584613a05565b6040805173ffffffffffffffffffffffffffffffffffffffff8086168252871660208201529081018290527f49e92b6b3114f7e128555cd58c568f7c2e0e56fe9b4c46b6125bc308184623b39060600160405180910390a15b505b600a54612e6d908590859073ffffffffffffffffffffffffffffffffffffffff1684613a05565b50505050565b476001811115610c0b5760008060008060018503335af180612e9d576307246cf46000526004601cfd5b5050565b600081600103612ed257507f9661287f7a4aa4867db46a2453ee15bebac4e8fc25667a58718da658f15de643919050565b81600203612f0157507fa54ab330ea9e1dfccee2b86f3666989e7fbd479704416c757c8de8e820142a08919050565b81600303612f3057507f93390f5d45ede9dea305f16aec86b2472af4f823851637f1b7019ad0775cea49919050565b81600403612f5f57507f9dda2c8358da895e43d574bb15954ce5727b22e923a2d8f28261f297bce42f0b919050565b81600503612f8e57507f92dc717124e161262f9d10c7079e7d54dc51271893fba54aa4a0f270fecdcc98919050565b81600603612fbd57507fce02aee5a7a35d40d974463c4c6e5534954fb07a7e7bc966fee268a15337bfd8919050565b81600703612fec57507ff7a65efd167a18f7091b2bb929d687dd94503cf0a43620487055ed7d6b727559919050565b8160080361301b57507fdef24acacad1318b664520f7c10e8bc6d1e7f6f6f7c8b031e70624ceb42266a6919050565b8160090361304a57507f4cb4080dc4e7bae88b4dc4307ad5117fa4f26195998a1b5f40368809d7f4c7f2919050565b81600a0361307957507ff8b1f864164d8d6e0b45f1399bd711223117a4ab0b057a9c2d7779e86a7c88db919050565b6040517febbd838a00000000000000000000000000000000000000000000000000000000815260048101839052602401612986565b919050565b6000806130c36020850185615479565b60018111156130d4576130d4614631565b1461310b576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061311f610120850161010086016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020908152604080832060608a01358452825280832054938352828252909120549293509091908601351415806131a7575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832088820135845290915290205460ff165b806131bc575080158015906131bc5750838114155b156131f3576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008060008060006132078a8a336133c3565b9450945094509450945061322181878b606001358b6137d2565b61324d61323460e08b0160c08c016145e1565b61324460c08c0160a08d01615479565b3389898961386e565b61326983836132636101008d0160e08e016145e1565b8961383a565b7f9aaa45d6db2ef74ead0751ea9113263d1dec1b50cea05f0ca2002cb8063564a460405180606001604052808a81526020018b60600135815260200183151581525033888c608001358d60e00160208101906132c591906145e1565b8e60c00160208101906132d891906145e1565b8b8b8b8b6040516132f29a9998979695949392919061552d565b60405180910390a1506040015198975050505050505050565b600082613319868685613a5a565b1495945050505050565b46600c540361339157600d546040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810185905261338c9060620160405160208183030381529060405280519060200120828585613b25565b612e6d565b6040517f6fd794c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060806133ce614498565b6133d66144b6565b6000806133ed886101200135896101400135613ca5565b87608001356000036134bf5761341d61340a6101a08a018a615676565b6134186101808c018c615676565b613cbf565b6101608801356134316101808a018a615676565b61343f6101a08c018c615676565b8383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080870282810182019093528682529498509596509394938693869350839250850190849080828437600092019190915250959c50919a50600197509495506136f3945050505050565b608088013560009081526009602052604090205460ff16156136bb5760006134ea60208a018a615479565b60808a01356000908152600960205260409020549091506b010000000000000000000000900460ff168082036135285763ab9848466000526004601cfd5b600080600960008d608001358152602001908152602001600020600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600960008e60800135815260200190815260200160002060000160079054906101000a900460e01b8e8e6040516024016135b79291906156de565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516136409190615703565b6000604051808303816000865af19150503d806000811461367d576040519150601f19603f3d011682016040523d82523d6000602084013e613682565b606091505b50915091508161369457805160208201fd5b808060200190518101906136a8919061576a565b919c509a50965094506136f39350505050565b6040517fd73c2c6a00000000000000000000000000000000000000000000000000000000815260808901356004820152602401612986565b61370d61370660e08a0160c08b016145e1565b8288613d0d565b60208581019190915273ffffffffffffffffffffffffffffffffffffffff9190911681860152600090613742908a018a615479565b600181111561375357613753614631565b036137ab576137a6608089013582600061377060208e018e6145e1565b73ffffffffffffffffffffffffffffffffffffffff161461379d5761379860208d018d6145e1565b61379f565b895b8688613e67565b6137c6565b6137c660808901358261379f6101208c016101008d016145e1565b50939792965093509350565b836137dd57806137ff565b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db5b73ffffffffffffffffffffffffffffffffffffffff909316600090815260016020908152604080832094835293905291909120919091555050565b825180156138565761385683838760005b602002015184613a05565b602084015180156129f7576129f7848488600161384b565b600085600181111561388257613882614631565b03613938576040517fa7bc96d300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a7bc96d39061390190899088908890889088906004016157ea565b600060405180830381600087803b15801561391b57600080fd5b505af115801561392f573d6000803e3d6000fd5b505050506129f7565b600185600181111561394c5761394c614631565b036129f7576040517fa0a406c600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a0a406c6906139cb90899088908890889088906004016157ea565b600060405180830381600087803b1580156139e557600080fd5b505af11580156139f9573d6000803e3d6000fd5b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416613a4e5761338c7f00000000000000000000000000000000000000000000000000000000000000008383600e54613f17565b612e6d8484848461402c565b60008183825b81811015613b1a576000878783818110613a7c57613a7c614a94565b9050604002016020016020810190613a949190615479565b6001811115613aa557613aa5614631565b03613ae057613ad9878783818110613abf57613abf614a94565b905060400201600001358460009182526020526040902090565b9250613b12565b613b0f83888884818110613af657613af6614a94565b9050604002016000013560009182526020526040902090565b92505b600101613a60565b509095945050505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003613bb3578273ffffffffffffffffffffffffffffffffffffffff16613b66858484614207565b73ffffffffffffffffffffffffffffffffffffffff1614612e6d576040517fd1085d1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff851690631626ba7e90613c0b90889087908790600401615849565b602060405180830381865afa158015613c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4c9190615863565b7fffffffff000000000000000000000000000000000000000000000000000000001614612e6d576040517ff6cd0e2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4281104283111715612e9d57637476320f6000526004601cfd5b6000838280821882151715613cdc57632e0c0f716000526004601cfd5b5060051b9050845b81156129f7576020820391508181013580613d0757632e0c0f716000526004601cfd5b50613ce4565b600b54600090819073ffffffffffffffffffffffffffffffffffffffff1615613e5f57600b546040517f70c1092100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906370c1092190613d8a90889088908890600401615880565b6040805180830381865afa158015613da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dca91906158b5565b909250905073ffffffffffffffffffffffffffffffffffffffff8216613df257506000613e5f565b600a54613e1b9074010000000000000000000000000000000000000000900461ffff1685615624565b613e2761271083615624565b1115613e5f576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935093915050565b60008581526009602052604081205461271090613e8f906301000000900461ffff1687615624565b613e99919061563b565b6020840151909150600003613ec05760408301819052613eb98186614edb565b8352613ef6565b613ed385878560016020020151846142f4565b604084018190526020840151613ee99087614edb565b613ef39190614edb565b83525b5073ffffffffffffffffffffffffffffffffffffffff909216909152505050565b6000806000806000868887f1905080614025578473ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f7257600080fd5b505af1158015613f86573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018890528916935063a9059cbb925060440190506020604051808303816000875af1158015614001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f79190614e57565b5050505050565b8373ffffffffffffffffffffffffffffffffffffffff163b60000361407d576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff84811660248301528381166044830152606482018390526000918291871690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052516141389190615703565b6000604051808303816000865af19150503d8060008114614175576040519150601f19603f3d011682016040523d82523d6000602084013e61417a565b606091505b5091509150816141b6576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051156129f757808060200190518101906141d19190614e57565b6129f7576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806142178686614341565b6040805160008152602081018083528c905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015614272573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff84166142ea576040517ff05a20c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050509392505050565b6000838152600960205260408120546127109061431a90610100900461ffff1687615624565b614324919061563b565b9050816143318483614ef4565b1015612d0c57611f928383614edb565b60008080836041819003614369578535935060208601359250604086013560001a91506143e2565b806040036143ad57853593507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6020870135908116935060ff1c601b0191506143e2565b6040517fd42b4bbd00000000000000000000000000000000000000000000000000000000815260048101829052602401612986565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561443c576040517fc185125200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff16601b1415801561445457508160ff16601c14155b15614490576040517f417893a400000000000000000000000000000000000000000000000000000000815260ff83166004820152602401612986565b509250925092565b60405180604001604052806002906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b60008083601f8401126144e657600080fd5b50813567ffffffffffffffff8111156144fe57600080fd5b6020830191508360208260051b850101111561451957600080fd5b9250929050565b6000806020838503121561453357600080fd5b823567ffffffffffffffff81111561454a57600080fd5b614556858286016144d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c0b57600080fd5b80356130ae81614562565b8015158114610c0b57600080fd5b80356130ae8161458f565b600080604083850312156145bb57600080fd5b82356145c681614562565b915060208301356145d68161458f565b809150509250929050565b6000602082840312156145f357600080fd5b81356145fe81614562565b9392505050565b6000806040838503121561461857600080fd5b823561462381614562565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061467457614674614631565b91905290565b803561ffff811681146130ae57600080fd5b60006020828403121561469e57600080fd5b6145fe8261467a565b6000602082840312156146b957600080fd5b81356145fe8161458f565b6000604082840312156146d657600080fd5b50919050565b60006101e082840312156146d657600080fd5b60008060008060008060a0878903121561470857600080fd5b863567ffffffffffffffff8082111561472057600080fd5b61472c8a838b016146c4565b9750602089013591508082111561474257600080fd5b61474e8a838b016146dc565b9650604089013591508082111561476457600080fd5b818901915089601f83011261477857600080fd5b81358181111561478757600080fd5b8a602082850101111561479957600080fd5b6020830196508095505060608901359150808211156147b757600080fd5b506147c489828a016146c4565b9250506147d360808801614584565b90509295509295509295565b600080604083850312156147f257600080fd5b50508035926020909101359150565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610c0b57600080fd5b60008060008060008060c0878903121561484857600080fd5b6148518761467a565b955061485f6020880161467a565b945061486d6040880161467a565b9350606087013561487d81614801565b9250608087013561488d8161458f565b915060a087013561489d81614562565b809150509295509295509295565b6000602082840312156148bd57600080fd5b5035919050565b600080600080608085870312156148da57600080fd5b8435935060208501356148ec8161458f565b92506148fa6040860161467a565b91506149086060860161467a565b905092959194509250565b6000806040838503121561492657600080fd5b82356145c68161458f565b6000806000806080858703121561494757600080fd5b843567ffffffffffffffff8082111561495f57600080fd5b61496b888389016146c4565b9550602087013591508082111561498157600080fd5b5061498e878288016146dc565b935050604085013561499f81614562565b9396929550929360600135925050565b60008060008060008060008060008060c08b8d0312156149ce57600080fd5b8a3567ffffffffffffffff808211156149e657600080fd5b6149f28e838f016144d4565b909c509a5060208d0135915080821115614a0b57600080fd5b614a178e838f016144d4565b909a50985060408d0135915080821115614a3057600080fd5b614a3c8e838f016144d4565b909850965060608d0135915080821115614a5557600080fd5b50614a628d828e016144d4565b9095509350614a75905060808c01614584565b9150614a8360a08c0161459d565b90509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614af557600080fd5b8260051b80836020870137939093016020019392505050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611f92604083018486614ac3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715614b9157614b91614b3e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614bde57614bde614b3e565b604052919050565b60028110610c0b57600080fd5b80356130ae81614be6565b600067ffffffffffffffff821115614c1857614c18614b3e565b5060051b60200190565b600082601f830112614c3357600080fd5b81356020614c48614c4383614bfe565b614b97565b82815260059290921b84018101918181019086841115614c6757600080fd5b8286015b84811015614c825780358352918301918301614c6b565b509695505050505050565b600082601f830112614c9e57600080fd5b813567ffffffffffffffff811115614cb857614cb8614b3e565b614ce960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b97565b818152846020838601011115614cfe57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101e08236031215614d2e57600080fd5b614d36614b6d565b614d3f83614bf3565b815260208301356020820152604083013560408201526060830135606082015260808301356080820152614d7560a08401614bf3565b60a0820152614d8660c08401614584565b60c0820152614d9760e08401614584565b60e0820152610100614daa818501614584565b908201526101208381013590820152610140808401359082015261016080840135908201526101808084013567ffffffffffffffff80821115614dec57600080fd5b614df836838801614c22565b838501526101a0925082860135915080821115614e1457600080fd5b614e2036838801614c22565b838501526101c0925082860135915080821115614e3c57600080fd5b50614e4936828701614c8d565b918301919091525092915050565b600060208284031215614e6957600080fd5b81516145fe8161458f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ed457614ed4614e74565b5060010190565b81810381811115614eee57614eee614e74565b92915050565b80820180821115614eee57614eee614e74565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe21833603018112614f3b57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112614f3b57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614fae57600080fd5b83018035915067ffffffffffffffff821115614fc957600080fd5b60200191503681900382131561451957600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261501357600080fd5b830160208101925035905067ffffffffffffffff81111561503357600080fd5b80360382131561451957600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6000813561509881614562565b73ffffffffffffffffffffffffffffffffffffffff1683526150bd6020830183614fde565b60406020860152611f92604086018284615042565b60028110610c0b57610c0b614631565b6150eb816150d2565b9052565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261512457600080fd5b830160208101925035905067ffffffffffffffff81111561514457600080fd5b8060051b360382131561451957600080fd5b60006101e061516d8461516885614bf3565b6150e2565b602083013560208501526040830135604085015260608301356060850152608083013560808501526151a160a08401614bf3565b6151ae60a08601826150e2565b506151bb60c08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660c08501526151e260e08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660e085015261010061520b848201614584565b73ffffffffffffffffffffffffffffffffffffffff1690850152610120838101359085015261014080840135908501526101608084013590850152610180615255818501856150ef565b83838801526152678488018284614ac3565b93505050506101a061527b818501856150ef565b8684038388015261528d848284614ac3565b93505050506101c06152a181850185614fde565b868403838801526152b3848284615042565b979650505050505050565b6080815260006152d1608083018761508b565b82810360208401526152e38187615156565b73ffffffffffffffffffffffffffffffffffffffff95909516604084015250506060015292915050565b60006020828403121561531f57600080fd5b5051919050565b89815261012081016153378a6150d2565b8960208301528860408301528760608301528660808301528560a083015261535e856150d2565b60c082019490945273ffffffffffffffffffffffffffffffffffffffff92831660e08201529116610100909101529695505050505050565b815160009082906020808601845b838110156153c0578151855293820193908201906001016153a4565b50929695505050505050565b6000815160005b818110156153ed57602081850181015186830152016153d3565b50600093019283525090919050565b6000612d0c61540b83866153cc565b846153cc565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261544657600080fd5b83018035915067ffffffffffffffff82111561546157600080fd5b6020019150600681901b360382131561451957600080fd5b60006020828403121561548b57600080fd5b81356145fe81614be6565b600081518084526020808501945080840160005b838110156154c6578151875295820195908201906001016154aa565b509495945050505050565b8060005b6002811015612e6d57815173ffffffffffffffffffffffffffffffffffffffff168452602093840193909101906001016154d5565b8060005b6003811015612e6d57815184526020938401939091019060010161550e565b60006101e08c51835260208d0151602084015260408d01511515604084015261556e606084018d73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff8b1660808401528960a08401526155b260c084018a73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff881660e0840152806101008401526155e181840188615496565b90508281036101208401526155f68187615496565b9150506156076101408301856154d1565b61561561018083018461550a565b9b9a5050505050505050505050565b8082028115828204841417614eee57614eee614e74565b600082615671577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126156ab57600080fd5b83018035915067ffffffffffffffff8211156156c657600080fd5b6020019150600581901b360382131561451957600080fd5b6040815260006156f1604083018561508b565b8281036020840152611f928185615156565b60006145fe82846153cc565b600082601f83011261572057600080fd5b81516020615730614c4383614bfe565b82815260059290921b8401810191818101908684111561574f57600080fd5b8286015b84811015614c825780518352918301918301615753565b6000806000806080858703121561578057600080fd5b84519350602085015167ffffffffffffffff8082111561579f57600080fd5b6157ab8883890161570f565b945060408701519150808211156157c157600080fd5b506157ce8782880161570f565b92505060608501516157df8161458f565b939692955090935050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060a0606083015261582b60a0830185615496565b828103608084015261583d8185615496565b98975050505050505050565b838152604060208201526000611f92604083018486615042565b60006020828403121561587557600080fd5b81516145fe81614801565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611f926060830184615496565b600080604083850312156158c857600080fd5b82516158d381614562565b602093909301519294929350505056fea2646970667358221220fda1aa391f9a90a5fa9e8cc21d3b32dd6362514c3103bfd1a99529e079bcb58264736f6c634300081100330000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a70000000000000000000000005924a28caaf1cc016617874a2f0c3710d881f3c1000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x6080604052600436106102dc5760003560e01c8063838b8f5c11610184578063ae1cce5a116100d6578063d5b010f51161008a578063ea179b7611610064578063ea179b7614610a05578063f4288a2114610a40578063f698da2514610a5357600080fd5b8063d5b010f5146109a5578063d5b7f065146109c5578063e72853e1146109e557600080fd5b8063bb91c339116100bb578063bb91c33914610850578063c0b6f56114610965578063d5a06adf1461098557600080fd5b8063ae1cce5a14610810578063b647a4041461083057600080fd5b806391be136011610138578063a02bab5711610112578063a02bab5714610773578063a39bf29f14610793578063ad5c4648146107dc57600080fd5b806391be13601461071d578063974e7c9f1461073d5780639a8a05921461075d57600080fd5b806386c076421161016957806386c07642146106bb57806389ccfe89146106db5780638da5cb5b146106f057600080fd5b8063838b8f5c1461067b5780638585ae03146106a857600080fd5b80634cbac9dc1161023d57806367d9dd79116101f15780637762df25116101cb5780637762df251461060157806379ed31d41461062e5780637a7d88511461064e57600080fd5b806367d9dd79146105735780636e90c014146105a65780637200b829146105ec57600080fd5b80635a195d19116102225780635a195d19146104f15780635b6ac0111461053157806364df049e1461054657600080fd5b80634cbac9dc146104a457806354878876146104d157600080fd5b80632bb5a9e611610294578063463357ec11610279578063463357ec146103f757806346b625bc1461042b57806346ea25521461044b57600080fd5b80632bb5a9e6146103a35780633e567539146103e257600080fd5b80631df47f80116102c55780631df47f801461032357806320cd05c71461034357806323452b9c1461038e57600080fd5b8063134849a6146102e15780631d3c426814610303575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614520565b610a69565b005b34801561030f57600080fd5b5061030161031e3660046145a8565b610b63565b34801561032f57600080fd5b5061030161033e3660046145e1565b610bfa565b34801561034f57600080fd5b5061037b61035e366004614605565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561039a57600080fd5b50610301610c0e565b3480156103af57600080fd5b506004546103d59074010000000000000000000000000000000000000000900460ff1681565b6040516103859190614660565b3480156103ee57600080fd5b50610301610d15565b34801561040357600080fd5b5061037b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db81565b34801561043757600080fd5b5061030161044636600461468c565b610e0c565b34801561045757600080fd5b5061047f7f000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610385565b3480156104b057600080fd5b5060055461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104dd57600080fd5b506103016104ec3660046146a7565b610ed6565b3480156104fd57600080fd5b5061052161050c3660046145e1565b60076020526000908152604090205460ff1681565b6040519015158152602001610385565b34801561053d57600080fd5b50610301610f58565b34801561055257600080fd5b50600a5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b50600454610521907501000000000000000000000000000000000000000000900460ff1681565b3480156105b257600080fd5b50600a546105d99074010000000000000000000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610385565b3480156105f857600080fd5b50610301611032565b34801561060d57600080fd5b5060045461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561063a57600080fd5b50610301610649366004614520565b611170565b34801561065a57600080fd5b5061037b6106693660046145e1565b60066020526000908152604090205481565b34801561068757600080fd5b50600b5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b6103016106b63660046146ef565b611250565b3480156106c757600080fd5b5061037b6106d63660046147df565b6113fc565b3480156106e757600080fd5b50610301611439565b3480156106fc57600080fd5b5060035461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561072957600080fd5b5061030161073836600461482f565b611583565b34801561074957600080fd5b506103016107583660046148ab565b611996565b34801561076957600080fd5b5061037b600c5481565b34801561077f57600080fd5b5061030161078e3660046145e1565b611a0f565b34801561079f57600080fd5b506107c76107ae3660046145e1565b6000602081905290815260409020805460019091015482565b60408051928352602083019190915201610385565b3480156107e857600080fd5b5061047f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561081c57600080fd5b5061030161082b366004614605565b611a8a565b34801561083c57600080fd5b5061030161084b3660046145e1565b611b75565b34801561085c57600080fd5b506108ec61086b3660046148ab565b60096020526000908152604090205460ff8082169161ffff61010082048116926301000000830482169265010000000000810490921691670100000000000000810460e01b916b0100000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009091041687565b60408051971515885261ffff9687166020890152948616948701949094529390911660608501527fffffffff0000000000000000000000000000000000000000000000000000000016608084015290151560a083015273ffffffffffffffffffffffffffffffffffffffff1660c082015260e001610385565b34801561097157600080fd5b506103016109803660046145e1565b611bf0565b34801561099157600080fd5b506103016109a03660046148c4565b611cf2565b3480156109b157600080fd5b506103016109c0366004614913565b611e89565b3480156109d157600080fd5b5061037b6109e0366004614931565b611f4b565b3480156109f157600080fd5b50610301610a003660046146ef565b611f9b565b348015610a1157600080fd5b50610521610a20366004614605565b600260209081526000928352604080842090915290825290205460ff1681565b610301610a4e3660046149af565b612160565b348015610a5f57600080fd5b5061037b600d5481565b806000819003610aa5576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610b2257336000908152600260205260408120600191868685818110610ad457610ad4614a94565b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610aa8565b507fe8036d6fb143373f3ff63e551373f5fffe4267f6809bf6d3934014a18a9b38f6338484604051610b5693929190614b0e565b60405180910390a1505050565b610b6b61266e565b73ffffffffffffffffffffffffffffffffffffffff821660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527fba28eda47a2e15b1dd3269e6d82f66730d20a5661aa40e9faf9f311c7872a54391015b60405180910390a15050565b610c0261266e565b610c0b816126bf565b50565b610c1661266e565b60045474010000000000000000000000000000000000000000900460ff166000816002811115610c4857610c48614631565b03610c7f576040517fccf69db700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001816002811115610c9357610c93614631565b03610cc157600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556040517f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae390600090a150565b610d1d61266e565b600260045474010000000000000000000000000000000000000000900460ff166002811115610d4e57610d4e614631565b14610d85576040517f045c512200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055604051600081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc906020015b60405180910390a1565b610e1461266e565b6109c48161ffff161115610e54576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000061ffff8416908102919091179091556040519081527fcaba16bb74e50491b14ebf4755083b43aaf56a765134681af613a2ef8d732f4f906020015b60405180910390a150565b610ede61266e565b600480548215157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9091161790556040517fdca612ba3556b7c2603089071be1feb2404df55dcabceee9d5fd852fdb39bc3490610ecb90831515815260200190565b610f6061266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115610f9157610f91614631565b14610fc8576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556040517f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec90600090a1565b600160045474010000000000000000000000000000000000000000900460ff16600281111561106357611063614631565b1461109a576040517f5e4f282600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045473ffffffffffffffffffffffffffffffffffffffff1633146110eb576040517fafdcfb9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633908117909155600480547fffffffffffffffffffffff0000000000000000000000000000000000000000001690556040519081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602001610e02565b8060008190036111ac576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561121c573360009081526001602052604081207f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db918686858181106111fa576111fa614a94565b60209081029290920135835250810191909152604001600020556001016111af565b507f0560c6093fba8a508d0e6ea3b4d7260d7afa9b152731f03a2d05dfe39b0ec425338484604051610b5693929190614b0e565b600b5474010000000000000000000000000000000000000000900460ff166002036112a7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560006112f9610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff1661135b576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061136e61136988614d1b565b61277f565b905061138e848288886113896101208d016101008e016145e1565b612934565b600061139c898933856129ff565b90506113aa83338684612d14565b6113b2612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050565b600061140782612ea1565b604080516020810192909252810184905260600160405160208183030381529060405280519060200120905092915050565b61144161266e565b600c54461461154f57611524604080518082018252600181527f320000000000000000000000000000000000000000000000000000000000000060209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f9e6bc51ef68b436657c5fe7a273ea9121a02b234cc81ad1e04892649c9168c6a818401527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5606082015246608082018190523060a0808401919091528451808403909101815260c09092019093528051910120600d55600c55565b6040517f5b2d1f36cd3ec425baab07b99853532e2ba6387a472ddbff437c5cc96f2f20ca90600090a1565b6040517fa69915e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b61158b61266e565b8361ffff168561ffff1611806115a857508461ffff168661ffff16115b806115b857506101f48461ffff16115b156115ef576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff000000000000000000000000000000000000000000000000000000008316611648576040517fc2d0709200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166345b2b3816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b79190614e57565b6116ed576040517fef8c37d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e080820183526001825261ffff808a1660208085019182528a83168587019081528a8416606087019081527fffffffff000000000000000000000000000000000000000000000000000000008b16608088019081528a151560a0890190815273ffffffffffffffffffffffffffffffffffffffff808c1660c08b0190815260088054600090815260099098529b87209a518b549851965195519451935191519092166c01000000000000000000000000026bffffffffffffffffffffffff9115156b010000000000000000000000027fffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff94909b1c67010000000000000002939093167fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff948a1665010000000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffff968b16630100000002969096167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff97909a16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff931515939093167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009099169890981791909117949094169690961791909117169290921793909317161790915581547f5290475107686ff8d28cd104943b127d453b23622ac55346373fa25c0c8957a292909161191483614ea3565b909155506040805191825261ffff898116602084015288811683830152871660608301527fffffffff000000000000000000000000000000000000000000000000000000008616608083015284151560a083015273ffffffffffffffffffffffffffffffffffffffff841660c0830152519081900360e00190a1505050505050565b61199e61266e565b6108fc8110156119da576040517fad6d14d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8190556040518181527ffc3a20d07f3d5bcc0b01a52011f630765611323fa9afa69f63ba2aa19f7364b690602001610ecb565b611a1761266e565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa92d85531a006d07fd0df4c61259b6dc18e4f492857e2454e5a20ee5e55cddcc90602001610ecb565b60055473ffffffffffffffffffffffffffffffffffffffff163314611adb576040517f9f63004300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612710811115611b17576040517f2242dac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815260066020908152604091829020849055815192835282018390527fa16126d9473196242b0784325b30642b89f34442dd178a852f5b88ee483a30d89101610bee565b611b7d61266e565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa7014d98341b07b23615cb6b4da7cca2a381932b46fb39ca4b8c3875c53aa76490602001610ecb565b611bf861266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115611c2957611c29614631565b14611c60576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffff000000000000000000000000000000000000000000909116811774010000000000000000000000000000000000000000179091556040805133815260208101929092527fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef9101610ecb565b611cfa61266e565b6008548410611d35576040517fbd7056c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526009602052604090205461ffff6501000000000090910481169082161180611d6957508061ffff168261ffff16115b15611da0576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020908152604091829020805461ffff858116630100000081027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff92891661010081027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff8c15159081167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009097169690961717939093161790935584518981529384019190915282840152606082015290517f3b25bf77fa688236b850bf89c87e353098688237aa18dc42593aff0f6387aea99181900360800190a150505050565b60006080611e98600143614edb565b3360009081526020819052604090208054600190910154914090921c92508415611edb57611ec68383614ef4565b33600090815260208190526040902081905591505b8315611f0357611eeb8382614ef4565b33600090815260208190526040902060010181905590505b60408051338152602081018490529081018290527fb738dd6073fae1a7128e3fcc6b4ca6e1356b7232f87cc98f8a2857bcd83dfc449060600160405180910390a15050505050565b6000333014611f86576040517fa78d09b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f92858585856129ff565b95945050505050565b600b5474010000000000000000000000000000000000000000900460ff16600203611ff2576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556000612044610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff161580612090575073ffffffffffffffffffffffffffffffffffffffff8116155b156120c7576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120db610120880161010089016145e1565b905060006120eb61136989614d1b565b90506120fa8582898986612934565b60006121078a8a846130b3565b905061211584848784612d14565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555050505050505050565b600b5474010000000000000000000000000000000000000000900460ff166002036121b7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790558880158061220d5750878118868218178482181715155b15612244576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008989600081811061225957612259614a94565b905060200281019061226b9190614f07565b61227d9061010081019060e0016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff166122df576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083156124555760005b8381101561244f57368c8c8381811061230557612305614a94565b90506020028101906123179190614f07565b905081156123945773ffffffffffffffffffffffffffffffffffffffff8416612347610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612394576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f848181106123a7576123a7614a94565b90506020028101906123b99190614f45565b905060006123c961136984614d1b565b90506124298b8b868181106123e0576123e0614a94565b90506020028101906123f29190614f45565b828f8f8881811061240557612405614a94565b90506020028101906124179190614f79565b61138961012089016101008a016145e1565b612435828433846129ff565b61243f9086614ef4565b94508360010193505050506122ea565b5061260c565b60005b8381101561260a57368c8c8381811061247357612473614a94565b90506020028101906124859190614f07565b905081156125025773ffffffffffffffffffffffffffffffffffffffff84166124b5610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612502576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f8481811061251557612515614a94565b90506020028101906125279190614f45565b9050600061253761136984614d1b565b905061254e8b8b868181106123e0576123e0614a94565b6040517fd5b7f065000000000000000000000000000000000000000000000000000000008152309063d5b7f065906125909085908790339087906004016152be565b6020604051808303816000875af19250505080156125e9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526125e69181019061530d565b60015b156125fc576125f88187614ef4565b9550505b836001019350505050612458565b505b61261882338784612d14565b50612621612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611581576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661270c576040517ff966bcb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8cffb07faa2874440346743bdc0a86b06c3335cc47dc49b327d10e77b73ceb1090602001610ecb565b60007e3c1bce41a2de73dfe64d6eeb2b3d7f15f1c0c382d9d963c2c6daeb75f0e539826000015183602001518460400151856060015186608001518760a001518860c001518960e001516040516020016127e199989796959493929190615326565b60405160208183030381529060405282610100015183610120015184610140015185610160015186610180015160405160200161281e9190615396565b60405160208183030381529060405280519060200120876101a0015160405160200161284a9190615396565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101c08c015180519083012073ffffffffffffffffffffffffffffffffffffffff90991691840191909152908201959095526060810193909352608083019190915260a082015260c081019190915260e081019190915261010001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261291792916020016153fc565b604051602081830303815290604052805190602001209050919050565b60006129436020870187615411565b91505080156129eb57600a81111561298f576040517febbd838a000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6129a761299f6020880188615411565b88358861330b565b6129dd576040517fc8ac23c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129e88635826113fc565b94505b6129f785858585613323565b505050505050565b60006001612a106020860186615479565b6001811115612a2157612a21614631565b14612a58576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a6c610120860161010087016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020818152604080842060608c013585528252808420549484528382529092200154929350909190870135141580612af5575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832089820135845290915290205460ff165b80612b0a57508015801590612b0a5750838114155b15612b41576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000806000806000612b558b8b336133c3565b94509450945094509450612b6f81878c606001358b6137d2565b612b8b8383612b856101008e0160e08f016145e1565b8c61383a565b612c16612b9e60e08c0160c08d016145e1565b612bae60c08d0160a08e01615479565b88600073ffffffffffffffffffffffffffffffffffffffff168f6000016020810190612bda91906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612c0d578e6000016020810190612c0891906145e1565b612c0f565b8c5b898961386e565b7f3ee3de4684413690dee6fff1a0a4f92916a1b97d1c5a83cdf24671844306b2e360405180606001604052808a81526020018c6060013581526020018315158152508a600073ffffffffffffffffffffffffffffffffffffffff168e6000016020810190612c8491906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612cb157612cac60208f018f6145e1565b612cb3565b8b5b8d608001358e60e0016020810190612ccb91906145e1565b8f60c0016020810190612cde91906145e1565b8b8b8b8b604051612cf89a9998979695949392919061552d565b60405180910390a150604001519450505050505b949350505050565b8015612e6d5773ffffffffffffffffffffffffffffffffffffffff821615612e46576004547501000000000000000000000000000000000000000000900460ff1615612e465773ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604081205461271090612d8e9084615624565b612d98919061563b565b90508015612e4457612daa8183614edb565b91508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614612deb57612deb85858584613a05565b6040805173ffffffffffffffffffffffffffffffffffffffff8086168252871660208201529081018290527f49e92b6b3114f7e128555cd58c568f7c2e0e56fe9b4c46b6125bc308184623b39060600160405180910390a15b505b600a54612e6d908590859073ffffffffffffffffffffffffffffffffffffffff1684613a05565b50505050565b476001811115610c0b5760008060008060018503335af180612e9d576307246cf46000526004601cfd5b5050565b600081600103612ed257507f9661287f7a4aa4867db46a2453ee15bebac4e8fc25667a58718da658f15de643919050565b81600203612f0157507fa54ab330ea9e1dfccee2b86f3666989e7fbd479704416c757c8de8e820142a08919050565b81600303612f3057507f93390f5d45ede9dea305f16aec86b2472af4f823851637f1b7019ad0775cea49919050565b81600403612f5f57507f9dda2c8358da895e43d574bb15954ce5727b22e923a2d8f28261f297bce42f0b919050565b81600503612f8e57507f92dc717124e161262f9d10c7079e7d54dc51271893fba54aa4a0f270fecdcc98919050565b81600603612fbd57507fce02aee5a7a35d40d974463c4c6e5534954fb07a7e7bc966fee268a15337bfd8919050565b81600703612fec57507ff7a65efd167a18f7091b2bb929d687dd94503cf0a43620487055ed7d6b727559919050565b8160080361301b57507fdef24acacad1318b664520f7c10e8bc6d1e7f6f6f7c8b031e70624ceb42266a6919050565b8160090361304a57507f4cb4080dc4e7bae88b4dc4307ad5117fa4f26195998a1b5f40368809d7f4c7f2919050565b81600a0361307957507ff8b1f864164d8d6e0b45f1399bd711223117a4ab0b057a9c2d7779e86a7c88db919050565b6040517febbd838a00000000000000000000000000000000000000000000000000000000815260048101839052602401612986565b919050565b6000806130c36020850185615479565b60018111156130d4576130d4614631565b1461310b576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061311f610120850161010086016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020908152604080832060608a01358452825280832054938352828252909120549293509091908601351415806131a7575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832088820135845290915290205460ff165b806131bc575080158015906131bc5750838114155b156131f3576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008060008060006132078a8a336133c3565b9450945094509450945061322181878b606001358b6137d2565b61324d61323460e08b0160c08c016145e1565b61324460c08c0160a08d01615479565b3389898961386e565b61326983836132636101008d0160e08e016145e1565b8961383a565b7f9aaa45d6db2ef74ead0751ea9113263d1dec1b50cea05f0ca2002cb8063564a460405180606001604052808a81526020018b60600135815260200183151581525033888c608001358d60e00160208101906132c591906145e1565b8e60c00160208101906132d891906145e1565b8b8b8b8b6040516132f29a9998979695949392919061552d565b60405180910390a1506040015198975050505050505050565b600082613319868685613a5a565b1495945050505050565b46600c540361339157600d546040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810185905261338c9060620160405160208183030381529060405280519060200120828585613b25565b612e6d565b6040517f6fd794c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060806133ce614498565b6133d66144b6565b6000806133ed886101200135896101400135613ca5565b87608001356000036134bf5761341d61340a6101a08a018a615676565b6134186101808c018c615676565b613cbf565b6101608801356134316101808a018a615676565b61343f6101a08c018c615676565b8383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080870282810182019093528682529498509596509394938693869350839250850190849080828437600092019190915250959c50919a50600197509495506136f3945050505050565b608088013560009081526009602052604090205460ff16156136bb5760006134ea60208a018a615479565b60808a01356000908152600960205260409020549091506b010000000000000000000000900460ff168082036135285763ab9848466000526004601cfd5b600080600960008d608001358152602001908152602001600020600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600960008e60800135815260200190815260200160002060000160079054906101000a900460e01b8e8e6040516024016135b79291906156de565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516136409190615703565b6000604051808303816000865af19150503d806000811461367d576040519150601f19603f3d011682016040523d82523d6000602084013e613682565b606091505b50915091508161369457805160208201fd5b808060200190518101906136a8919061576a565b919c509a50965094506136f39350505050565b6040517fd73c2c6a00000000000000000000000000000000000000000000000000000000815260808901356004820152602401612986565b61370d61370660e08a0160c08b016145e1565b8288613d0d565b60208581019190915273ffffffffffffffffffffffffffffffffffffffff9190911681860152600090613742908a018a615479565b600181111561375357613753614631565b036137ab576137a6608089013582600061377060208e018e6145e1565b73ffffffffffffffffffffffffffffffffffffffff161461379d5761379860208d018d6145e1565b61379f565b895b8688613e67565b6137c6565b6137c660808901358261379f6101208c016101008d016145e1565b50939792965093509350565b836137dd57806137ff565b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db5b73ffffffffffffffffffffffffffffffffffffffff909316600090815260016020908152604080832094835293905291909120919091555050565b825180156138565761385683838760005b602002015184613a05565b602084015180156129f7576129f7848488600161384b565b600085600181111561388257613882614631565b03613938576040517fa7bc96d300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d169063a7bc96d39061390190899088908890889088906004016157ea565b600060405180830381600087803b15801561391b57600080fd5b505af115801561392f573d6000803e3d6000fd5b505050506129f7565b600185600181111561394c5761394c614631565b036129f7576040517fa0a406c600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d169063a0a406c6906139cb90899088908890889088906004016157ea565b600060405180830381600087803b1580156139e557600080fd5b505af11580156139f9573d6000803e3d6000fd5b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416613a4e5761338c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28383600e54613f17565b612e6d8484848461402c565b60008183825b81811015613b1a576000878783818110613a7c57613a7c614a94565b9050604002016020016020810190613a949190615479565b6001811115613aa557613aa5614631565b03613ae057613ad9878783818110613abf57613abf614a94565b905060400201600001358460009182526020526040902090565b9250613b12565b613b0f83888884818110613af657613af6614a94565b9050604002016000013560009182526020526040902090565b92505b600101613a60565b509095945050505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003613bb3578273ffffffffffffffffffffffffffffffffffffffff16613b66858484614207565b73ffffffffffffffffffffffffffffffffffffffff1614612e6d576040517fd1085d1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff851690631626ba7e90613c0b90889087908790600401615849565b602060405180830381865afa158015613c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4c9190615863565b7fffffffff000000000000000000000000000000000000000000000000000000001614612e6d576040517ff6cd0e2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4281104283111715612e9d57637476320f6000526004601cfd5b6000838280821882151715613cdc57632e0c0f716000526004601cfd5b5060051b9050845b81156129f7576020820391508181013580613d0757632e0c0f716000526004601cfd5b50613ce4565b600b54600090819073ffffffffffffffffffffffffffffffffffffffff1615613e5f57600b546040517f70c1092100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906370c1092190613d8a90889088908890600401615880565b6040805180830381865afa158015613da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dca91906158b5565b909250905073ffffffffffffffffffffffffffffffffffffffff8216613df257506000613e5f565b600a54613e1b9074010000000000000000000000000000000000000000900461ffff1685615624565b613e2761271083615624565b1115613e5f576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935093915050565b60008581526009602052604081205461271090613e8f906301000000900461ffff1687615624565b613e99919061563b565b6020840151909150600003613ec05760408301819052613eb98186614edb565b8352613ef6565b613ed385878560016020020151846142f4565b604084018190526020840151613ee99087614edb565b613ef39190614edb565b83525b5073ffffffffffffffffffffffffffffffffffffffff909216909152505050565b6000806000806000868887f1905080614025578473ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f7257600080fd5b505af1158015613f86573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018890528916935063a9059cbb925060440190506020604051808303816000875af1158015614001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f79190614e57565b5050505050565b8373ffffffffffffffffffffffffffffffffffffffff163b60000361407d576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff84811660248301528381166044830152606482018390526000918291871690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052516141389190615703565b6000604051808303816000865af19150503d8060008114614175576040519150601f19603f3d011682016040523d82523d6000602084013e61417a565b606091505b5091509150816141b6576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051156129f757808060200190518101906141d19190614e57565b6129f7576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806142178686614341565b6040805160008152602081018083528c905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015614272573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff84166142ea576040517ff05a20c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050509392505050565b6000838152600960205260408120546127109061431a90610100900461ffff1687615624565b614324919061563b565b9050816143318483614ef4565b1015612d0c57611f928383614edb565b60008080836041819003614369578535935060208601359250604086013560001a91506143e2565b806040036143ad57853593507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6020870135908116935060ff1c601b0191506143e2565b6040517fd42b4bbd00000000000000000000000000000000000000000000000000000000815260048101829052602401612986565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561443c576040517fc185125200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff16601b1415801561445457508160ff16601c14155b15614490576040517f417893a400000000000000000000000000000000000000000000000000000000815260ff83166004820152602401612986565b509250925092565b60405180604001604052806002906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b60008083601f8401126144e657600080fd5b50813567ffffffffffffffff8111156144fe57600080fd5b6020830191508360208260051b850101111561451957600080fd5b9250929050565b6000806020838503121561453357600080fd5b823567ffffffffffffffff81111561454a57600080fd5b614556858286016144d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c0b57600080fd5b80356130ae81614562565b8015158114610c0b57600080fd5b80356130ae8161458f565b600080604083850312156145bb57600080fd5b82356145c681614562565b915060208301356145d68161458f565b809150509250929050565b6000602082840312156145f357600080fd5b81356145fe81614562565b9392505050565b6000806040838503121561461857600080fd5b823561462381614562565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061467457614674614631565b91905290565b803561ffff811681146130ae57600080fd5b60006020828403121561469e57600080fd5b6145fe8261467a565b6000602082840312156146b957600080fd5b81356145fe8161458f565b6000604082840312156146d657600080fd5b50919050565b60006101e082840312156146d657600080fd5b60008060008060008060a0878903121561470857600080fd5b863567ffffffffffffffff8082111561472057600080fd5b61472c8a838b016146c4565b9750602089013591508082111561474257600080fd5b61474e8a838b016146dc565b9650604089013591508082111561476457600080fd5b818901915089601f83011261477857600080fd5b81358181111561478757600080fd5b8a602082850101111561479957600080fd5b6020830196508095505060608901359150808211156147b757600080fd5b506147c489828a016146c4565b9250506147d360808801614584565b90509295509295509295565b600080604083850312156147f257600080fd5b50508035926020909101359150565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610c0b57600080fd5b60008060008060008060c0878903121561484857600080fd5b6148518761467a565b955061485f6020880161467a565b945061486d6040880161467a565b9350606087013561487d81614801565b9250608087013561488d8161458f565b915060a087013561489d81614562565b809150509295509295509295565b6000602082840312156148bd57600080fd5b5035919050565b600080600080608085870312156148da57600080fd5b8435935060208501356148ec8161458f565b92506148fa6040860161467a565b91506149086060860161467a565b905092959194509250565b6000806040838503121561492657600080fd5b82356145c68161458f565b6000806000806080858703121561494757600080fd5b843567ffffffffffffffff8082111561495f57600080fd5b61496b888389016146c4565b9550602087013591508082111561498157600080fd5b5061498e878288016146dc565b935050604085013561499f81614562565b9396929550929360600135925050565b60008060008060008060008060008060c08b8d0312156149ce57600080fd5b8a3567ffffffffffffffff808211156149e657600080fd5b6149f28e838f016144d4565b909c509a5060208d0135915080821115614a0b57600080fd5b614a178e838f016144d4565b909a50985060408d0135915080821115614a3057600080fd5b614a3c8e838f016144d4565b909850965060608d0135915080821115614a5557600080fd5b50614a628d828e016144d4565b9095509350614a75905060808c01614584565b9150614a8360a08c0161459d565b90509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614af557600080fd5b8260051b80836020870137939093016020019392505050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611f92604083018486614ac3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715614b9157614b91614b3e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614bde57614bde614b3e565b604052919050565b60028110610c0b57600080fd5b80356130ae81614be6565b600067ffffffffffffffff821115614c1857614c18614b3e565b5060051b60200190565b600082601f830112614c3357600080fd5b81356020614c48614c4383614bfe565b614b97565b82815260059290921b84018101918181019086841115614c6757600080fd5b8286015b84811015614c825780358352918301918301614c6b565b509695505050505050565b600082601f830112614c9e57600080fd5b813567ffffffffffffffff811115614cb857614cb8614b3e565b614ce960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b97565b818152846020838601011115614cfe57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101e08236031215614d2e57600080fd5b614d36614b6d565b614d3f83614bf3565b815260208301356020820152604083013560408201526060830135606082015260808301356080820152614d7560a08401614bf3565b60a0820152614d8660c08401614584565b60c0820152614d9760e08401614584565b60e0820152610100614daa818501614584565b908201526101208381013590820152610140808401359082015261016080840135908201526101808084013567ffffffffffffffff80821115614dec57600080fd5b614df836838801614c22565b838501526101a0925082860135915080821115614e1457600080fd5b614e2036838801614c22565b838501526101c0925082860135915080821115614e3c57600080fd5b50614e4936828701614c8d565b918301919091525092915050565b600060208284031215614e6957600080fd5b81516145fe8161458f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ed457614ed4614e74565b5060010190565b81810381811115614eee57614eee614e74565b92915050565b80820180821115614eee57614eee614e74565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe21833603018112614f3b57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112614f3b57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614fae57600080fd5b83018035915067ffffffffffffffff821115614fc957600080fd5b60200191503681900382131561451957600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261501357600080fd5b830160208101925035905067ffffffffffffffff81111561503357600080fd5b80360382131561451957600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6000813561509881614562565b73ffffffffffffffffffffffffffffffffffffffff1683526150bd6020830183614fde565b60406020860152611f92604086018284615042565b60028110610c0b57610c0b614631565b6150eb816150d2565b9052565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261512457600080fd5b830160208101925035905067ffffffffffffffff81111561514457600080fd5b8060051b360382131561451957600080fd5b60006101e061516d8461516885614bf3565b6150e2565b602083013560208501526040830135604085015260608301356060850152608083013560808501526151a160a08401614bf3565b6151ae60a08601826150e2565b506151bb60c08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660c08501526151e260e08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660e085015261010061520b848201614584565b73ffffffffffffffffffffffffffffffffffffffff1690850152610120838101359085015261014080840135908501526101608084013590850152610180615255818501856150ef565b83838801526152678488018284614ac3565b93505050506101a061527b818501856150ef565b8684038388015261528d848284614ac3565b93505050506101c06152a181850185614fde565b868403838801526152b3848284615042565b979650505050505050565b6080815260006152d1608083018761508b565b82810360208401526152e38187615156565b73ffffffffffffffffffffffffffffffffffffffff95909516604084015250506060015292915050565b60006020828403121561531f57600080fd5b5051919050565b89815261012081016153378a6150d2565b8960208301528860408301528760608301528660808301528560a083015261535e856150d2565b60c082019490945273ffffffffffffffffffffffffffffffffffffffff92831660e08201529116610100909101529695505050505050565b815160009082906020808601845b838110156153c0578151855293820193908201906001016153a4565b50929695505050505050565b6000815160005b818110156153ed57602081850181015186830152016153d3565b50600093019283525090919050565b6000612d0c61540b83866153cc565b846153cc565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261544657600080fd5b83018035915067ffffffffffffffff82111561546157600080fd5b6020019150600681901b360382131561451957600080fd5b60006020828403121561548b57600080fd5b81356145fe81614be6565b600081518084526020808501945080840160005b838110156154c6578151875295820195908201906001016154aa565b509495945050505050565b8060005b6002811015612e6d57815173ffffffffffffffffffffffffffffffffffffffff168452602093840193909101906001016154d5565b8060005b6003811015612e6d57815184526020938401939091019060010161550e565b60006101e08c51835260208d0151602084015260408d01511515604084015261556e606084018d73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff8b1660808401528960a08401526155b260c084018a73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff881660e0840152806101008401526155e181840188615496565b90508281036101208401526155f68187615496565b9150506156076101408301856154d1565b61561561018083018461550a565b9b9a5050505050505050505050565b8082028115828204841417614eee57614eee614e74565b600082615671577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126156ab57600080fd5b83018035915067ffffffffffffffff8211156156c657600080fd5b6020019150600581901b360382131561451957600080fd5b6040815260006156f1604083018561508b565b8281036020840152611f928185615156565b60006145fe82846153cc565b600082601f83011261572057600080fd5b81516020615730614c4383614bfe565b82815260059290921b8401810191818101908684111561574f57600080fd5b8286015b84811015614c825780518352918301918301615753565b6000806000806080858703121561578057600080fd5b84519350602085015167ffffffffffffffff8082111561579f57600080fd5b6157ab8883890161570f565b945060408701519150808211156157c157600080fd5b506157ce8782880161570f565b92505060608501516157df8161458f565b939692955090935050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060a0606083015261582b60a0830185615496565b828103608084015261583d8185615496565b98975050505050505050565b838152604060208201526000611f92604083018486615042565b60006020828403121561587557600080fd5b81516145fe81614801565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611f926060830184615496565b600080604083850312156158c857600080fd5b82516158d381614562565b602093909301519294929350505056fea2646970667358221220fda1aa391f9a90a5fa9e8cc21d3b32dd6362514c3103bfd1a99529e079bcb58264736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a70000000000000000000000005924a28caaf1cc016617874a2f0c3710d881f3c1000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : _owner (address): 0x3ab105F0e4A22ec4A96a9b0Ca90c5C534d21f3a7
Arg [1] : _protocolFeeRecipient (address): 0x5924A28caAF1cc016617874a2f0C3710d881f3c1
Arg [2] : _transferManager (address): 0x000000000060C4Ca14CfC4325359062ace33Fe3D
Arg [3] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7
Arg [1] : 0000000000000000000000005924a28caaf1cc016617874a2f0c3710d881f3c1
Arg [2] : 000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $3,351.33 | 0.000000000000000001 | <$0.000001 |
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.