Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BatchSignedERC721OrdersFeature
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 Element.Market Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.17;
import "../../storage/LibCommonNftOrdersStorage.sol";
import "../../storage/LibERC721OrdersStorage.sol";
import "../libs/LibSignature.sol";
import "../libs/LibOracleSignature.sol";
import "../interfaces/IBatchSignedERC721OrdersFeature.sol";
contract BatchSignedERC721OrdersFeature is IBatchSignedERC721OrdersFeature {
uint256 internal constant MASK_192 = (1 << 192) - 1;
uint256 internal constant MASK_160 = (1 << 160) - 1;
uint256 internal constant MASK_64 = (1 << 64) - 1;
uint256 internal constant MASK_40 = (1 << 40) - 1;
uint256 internal constant MASK_32 = (1 << 32) - 1;
uint256 internal constant MASK_16 = (1 << 16) - 1;
uint256 internal constant MASK_INDEX_LIST_PART1 = ((1 << 96) - 1) << 160;
uint256 internal constant MASK_INDEX_LIST_PART2 = ((1 << 32) - 1) << 128;
uint256 internal constant NONCE_RANGE_LIMIT = 1 << 248;
uint256 internal constant MAX_ERC20_AMOUNT = (1 << 224) - 1;
// Storage ID.
uint256 constant STORAGE_ID_COMMON_NFT_ORDERS = 4 << 128;
uint256 constant STORAGE_ID_ERC721_ORDERS = 5 << 128;
// Topic for ERC721SellOrderFilled.
bytes32 internal constant _TOPIC_SELL_ORDER_FILLED = 0x9c248aa1a265aa616f707b979d57f4529bb63a4fc34dc7fc61fdddc18410f74e;
// keccak256("")
bytes32 internal constant _EMPTY_ARRAY_KECCAK256 = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// keccak256(abi.encodePacked(
// "BatchSignedERC721Orders(address maker,uint256 listingTime,uint256 expiryTime,uint256 startNonce,address erc20Token,address platformFeeRecipient,BasicCollection[] basicCollections,Collection[] collections,uint256 hashNonce)",
// "BasicCollection(address nftAddress,bytes32 fee,bytes32[] items)",
// "Collection(address nftAddress,bytes32 fee,OrderItem[] items)",
// "OrderItem(uint256 erc20TokenAmount,uint256 nftId)"
// ))
bytes32 internal constant _BATCH_SIGNED_ERC721_ORDERS_TYPE_HASH = 0x2d8cbbbc696e7292c3b5beb38e1363d34ff11beb8c3456c14cb938854597b9ed;
// keccak256("BasicCollection(address nftAddress,bytes32 fee,bytes32[] items)")
bytes32 internal constant _BASIC_COLLECTION_TYPE_HASH = 0x12ad29288fd70022f26997a9958d9eceb6e840ceaa79b72ea5945ba87e4d33b0;
// keccak256(abi.encodePacked(
// "Collection(address nftAddress,bytes32 fee,OrderItem[] items)",
// "OrderItem(uint256 erc20TokenAmount,uint256 nftId)"
// ))
bytes32 internal constant _COLLECTION_TYPE_HASH = 0xb9f488d48cec782be9ecdb74330c9c6a33c236a8022d8a91a4e4df4e81b51620;
// keccak256("OrderItem(uint256 erc20TokenAmount,uint256 nftId)")
bytes32 internal constant _ORDER_ITEM_TYPE_HASH = 0x5f93394997caa49a9382d44a75e3ce6a460f32b39870464866ac994f8be97afe;
// keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
bytes32 internal constant DOMAIN = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
// keccak256("ElementEx")
bytes32 internal constant NAME = 0x27b14c20196091d9cd90ca9c473d3ad1523b00ddf487a9b7452a8a119a16b98c;
// keccak256("1.0.0")
bytes32 internal constant VERSION = 0x06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c;
/// @dev The implementation address of this feature.
address internal immutable _IMPL;
/// @dev The WETH token contract.
address internal immutable _WETH;
constructor(address weth) {
require(address(weth) != address(0), "INVALID_WETH_ADDRESS");
_WETH = weth;
_IMPL = address(this);
}
function fillBatchSignedERC721Order(BatchSignedERC721OrderParameter calldata /* parameter */, bytes calldata collections) external override payable {
uint256 ethBalanceBefore = address(this).balance - msg.value;
uint256 offsetCollectionsBytes;
assembly {
offsetCollectionsBytes := collections.offset
}
// Validate order.
(bytes32 orderHash, uint256 ptrEnd) = _validateOrder(offsetCollectionsBytes);
assembly {
// memory[0x0 - 0x20] orderHash
mstore(0, orderHash)
/////////////////////////// memory[0x380 - 0x420] for delegateCall ///////////
// memory[0x380 - 0x3a0] erc20TokenFromDelegateCall
// memory[0x3a0 - 0x3c0] platformFeeRecipientFromDelegateCall
// memory[0x3c0 - 0x3e0] royaltyFeeRecipientFromDelegateCall
mstore(0x380, 0)
mstore(0x3a0, 0)
mstore(0x3c0, 0)
}
// Fill order.
_fillBatchSignedERC721Order(offsetCollectionsBytes, ptrEnd);
// Refund ETH.
assembly {
if eq(selfbalance(), ethBalanceBefore) {
return(0, 0)
}
if gt(selfbalance(), ethBalanceBefore) {
if iszero(call(gas(), caller(), sub(selfbalance(), ethBalanceBefore), 0, 0, 0, 0)) {
_revertRefundETHFailed()
}
return(0, 0)
}
_revertRefundETHFailed()
function _revertRefundETHFailed() {
// revert("fillBatchSignedERC721Order: failed to refund ETH.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003166696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x6661696c656420746f20726566756e64204554482e0000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
}
}
/// @param additional1 [96 bits(withdrawETHAmount) + 160 bits(erc20Token)]
/// @param additional2 [8 bits(revertIfIncomplete) + 88 bits(unused) + 160 bits(royaltyFeeRecipient)]
function fillBatchSignedERC721Orders(
BatchSignedERC721OrderParameters[] calldata parameters,
uint256 additional1,
uint256 additional2
) external override payable {
require(parameters.length > 0, "fillBatchSignedERC721Orders: invalid parameters.");
uint256 ethBalanceBefore = address(this).balance - msg.value;
uint256 platformFeeRecipient = parameters[0].data3 & MASK_160;
address impl = _IMPL;
address weth = _WETH;
assembly {
let withdrawETHAmount := shr(160, additional1)
let erc20Token := and(additional1, MASK_160)
let royaltyFeeRecipient := and(additional2, MASK_160)
let platformFeeGlobalAccum
let royaltyFeeGlobalAccum
let someSuccess
// Withdraw ETH if needed.
if withdrawETHAmount {
// Step1: transfer WETH from msg.sender to address(this).
_transferERC20(weth, address(), withdrawETHAmount)
// Step2: withdraw ETH.
// selector for `withdraw(uint256)`.
mstore(0, 0x2e1a7d4d)
mstore(0x20, withdrawETHAmount)
if iszero(call(gas(), weth, 0, 0x1c, 0x24, 0, 0)) {
_revertWithdrawETHFailed()
}
}
/////////////////////////// memory[0 - 0x40] for delegatecall output /////////////
// memory[0 - 0x20] output [platformFeeGlobal]
// memory[0x20 - 0x40] output [royaltyFeeGlobal]
/////////////////////////// memory[0x40 - ] for delegatecall input /////////////
// memory[0x40 - 0x60] selector for `delegateCallFillBatchSignedERC721Order(BatchSignedERC721OrderParameter,address,address,address,bytes)`
mstore(0x40, 0xdc055ecc)
// memory[0x60 - 0x100] parameter
// memory[0x100 - 0x120] erc20Token
mstore(0x100, erc20Token)
// memory[0x120 - 0x140] platformFeeRecipient
mstore(0x120, platformFeeRecipient)
// memory[0x140 - 0x160] royaltyFeeRecipient
mstore(0x140, royaltyFeeRecipient)
// memory[0x160 - 0x180] collections.offset
mstore(0x160, 0x120)
// memory[0x180 - 0x1a0] collections.length
// memory[0x1a0 - ] collections.data
let ptrEnd := add(parameters.offset, mul(parameters.length, 0x20))
for { let ptr := parameters.offset } lt(ptr, ptrEnd) { ptr := add(ptr, 0x20) } {
let ptrData := add(parameters.offset, calldataload(ptr))
// memory[0x40 - 0x60] selector for `delegateCallFillBatchSignedERC721Order`
// memory[0x60 - 0x100] parameter
calldatacopy(0x60, ptrData, 0xa0 /* 5 * 32*/)
// memory[0x100 - 0x120] erc20Token
// memory[0x120 - 0x140] platformFeeRecipient
// memory[0x140 - 0x160] royaltyFeeRecipient
// memory[0x160 - 0x180] collections.offset
// memory[0x180 - 0x1a0] collections.length
let collectionsLength := calldataload(add(ptrData, 0xc0))
mstore(0x180, collectionsLength)
// memory[0x1a0 - ] collections.data
calldatacopy(0x1a0, add(ptrData, 0xe0), collectionsLength)
// 0x144 = 0x4(selector) + 0xa0(parameter) + 0x20(erc20Token) + 0x20(platformFeeRecipient) + 0x20(royaltyFeeRecipient) + 0x20(collections.offset) + 0x20(collections.length)
switch delegatecall(gas(), impl, 0x5c, add(0x144, collectionsLength), 0, 0x40)
case 0 {
// Check revertIfIncomplete flag if failed.
if byte(0, additional2) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
default {
// Success.
someSuccess := 1
// memory[0 - 0x20] output [platformFeeGlobal]
// memory[0x20 - 0x40] output [royaltyFeeGlobal]
platformFeeGlobalAccum := add(platformFeeGlobalAccum, mload(0))
royaltyFeeGlobalAccum := add(royaltyFeeGlobalAccum, mload(0x20))
}
} // end for
if platformFeeGlobalAccum {
_transferERC20(erc20Token, platformFeeRecipient, platformFeeGlobalAccum)
}
if royaltyFeeGlobalAccum {
_transferERC20(erc20Token, royaltyFeeRecipient, royaltyFeeGlobalAccum)
}
if iszero(someSuccess) {
_revertNoOrderFilled()
}
// Refund ETH.
if eq(selfbalance(), ethBalanceBefore) {
return(0, 0)
}
if gt(selfbalance(), ethBalanceBefore) {
if iszero(call(gas(), caller(), sub(selfbalance(), ethBalanceBefore), 0, 0, 0, 0)) {
_revertRefundETHFailed()
}
return(0, 0)
}
_revertRefundETHFailed()
///////////////////////////////// functions /////////////////////////////////
function _transferERC20(_erc20Token, _to, _amount) {
switch _erc20Token
case 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE {
if iszero(call(gas(), _to, _amount, 0, 0, 0, 0)) {
_revertTransferETHFailed()
}
}
default {
if iszero(extcodesize(_erc20Token)) {
_revertInvalidERC20Token()
}
// selector for `transferFrom(address,address,uint256)`
mstore(0, 0x23b872dd)
mstore(0x20, caller())
mstore(0x40, _to)
mstore(0x60, _amount)
if iszero(call(gas(), _erc20Token, 0, 0x1c, 0x64, 0, 0x20)) {
_revertTransferERC20Failed()
}
// Check for ERC20 success. ERC20 tokens should return a boolean, but some don't.
// We accept 0-length return data as success, or at least 32 bytes that starts with
// a 32-byte boolean true.
if returndatasize() {
if lt(returndatasize(), 0x20) {
_revertTransferERC20Failed()
}
if iszero(eq(mload(0), 1)) {
_revertTransferERC20Failed()
}
}
}
}
function _revertTransferETHFailed() {
// revert("fillBatchSignedERC721Orders: failed to transfer ETH.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003466696c6c42617463685369676e65644552433732314f72646572733a)
mstore(0x60, 0x206661696c656420746f207472616e73666572204554482e0000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertTransferERC20Failed() {
// revert("fillBatchSignedERC721Orders: failed to transfer ERC20.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003666696c6c42617463685369676e65644552433732314f72646572733a)
mstore(0x60, 0x206661696c656420746f207472616e736665722045524332302e000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertWithdrawETHFailed() {
// revert("fillBatchSignedERC721Orders: failed to withdraw ETH.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003466696c6c42617463685369676e65644552433732314f72646572733a)
mstore(0x60, 0x206661696c656420746f207769746864726177204554482e0000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertNoOrderFilled() {
// revert("fillBatchSignedERC721Orders: no order filled.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002d66696c6c42617463685369676e65644552433732314f72646572733a)
mstore(0x60, 0x206e6f206f726465722066696c6c65642e000000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertRefundETHFailed() {
// revert("fillBatchSignedERC721Orders: failed to refund ETH.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003266696c6c42617463685369676e65644552433732314f72646572733a)
mstore(0x60, 0x206661696c656420746f20726566756e64204554482e00000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidERC20Token() {
// revert("invalid erc20 token")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x00000013696e76616c696420657263323020746f6b656e000000000000000000)
mstore(0x60, 0)
revert(0, 0x64)
}
}
}
// @Note `delegateCallFillBatchSignedERC721Order` is a external function, but must delegatecall from an external exchange,
// and should not be registered in the external exchange.
function delegateCallFillBatchSignedERC721Order(
BatchSignedERC721OrderParameter calldata /* parameter */,
address erc20TokenFromDelegateCall,
address platformFeeRecipientFromDelegateCall,
address royaltyFeeRecipientFromDelegateCall,
bytes calldata collections
) external payable {
address impl = _IMPL;
uint256 offsetCollectionsBytes;
assembly {
if eq(impl, address()) {
// revert("delegateCallFillBatchSignedERC721Order: must delegateCall from an external exchange.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000005464656c656761746543616c6c46696c6c42617463685369676e656445)
mstore(0x60, 0x52433732314f726465723a206d7573742064656c656761746543616c6c206672)
mstore(0x80, 0x6f6d20616e2065787465726e616c2065786368616e67652e0000000000000000)
mstore(0xa0, 0)
revert(0, 0xa4)
}
offsetCollectionsBytes := collections.offset
}
// Validate order.
(bytes32 orderHash, uint256 ptrEnd) = _validateOrder(offsetCollectionsBytes);
assembly {
// memory[0x0 - 0x20] orderHash
mstore(0, orderHash)
/////////////////////////// memory[0x380 - 0x420] for delegateCall ///////////
// memory[0x380 - 0x3a0] erc20TokenFromDelegateCall
// memory[0x3a0 - 0x3c0] platformFeeRecipientFromDelegateCall
// memory[0x3c0 - 0x3e0] royaltyFeeRecipientFromDelegateCall
mstore(0x380, erc20TokenFromDelegateCall)
mstore(0x3a0, platformFeeRecipientFromDelegateCall)
mstore(0x3c0, royaltyFeeRecipientFromDelegateCall)
}
// Fill order.
_fillBatchSignedERC721Order(offsetCollectionsBytes, ptrEnd);
assembly {
// Return platformFeeGlobal and royaltyFeeGlobal.
// memory[0x3e0 - 0x400] platformFeeGlobal
// memory[0x400 - 0x420] royaltyFeeGlobal
return(0x3e0, 0x40)
}
}
/// data1 [[8 bits(signatureType) + 8 bits(reserved) + 40 bits(startNonce) + 8 bits(v) + 32 bits(listingTime) + 160 bits(maker)]
/// data2 [64 bits(taker part1) + 32 bits(expiryTime) + 160 bits(erc20Token)]
/// data3 [96 bits(taker part2) + 160 bits(platformFeeRecipient)]
function _fillBatchSignedERC721Order(uint256 offsetCollectionsBytes, uint256 ptrEnd) internal {
assembly {
/////////////////////////// memory[0x0 - 0x1c0] for emitEvent data ////////////////////////
// memory[0x0 - 0x20] orderHash
// memory[0x20 - 0x40] maker
mstore(0x20, and(calldataload(0x4), MASK_160)) // maker = data1 & MASK_160
// memory[0x40 - 0x60] taker
mstore(0x40, or(shl(96, shr(192, calldataload(0x24))), shr(160, calldataload(0x44)))) // taker = ((data2 >> 192) << 96) | (data3 >> 160)
if iszero(mload(0x40)) {
mstore(0x40, caller())
}
// memory[0x60 - 0x80] nonce
// memory[0x80 - 0xa0] erc20Token
mstore(0x80, and(calldataload(0x24), MASK_160)) // erc20Token = data2 & MASK_160
// memory[0xa0 - 0xc0] erc20TokenAmount
// memory[0xc0 - 0xe0] fees.offset
mstore(0xc0, 0x120 /* 9 * 32 */)
// memory[0xe0 - 0x100] nftAddress
// memory[0x100 - 0x120] nftId
// memory[0x120 - 0x140] fees.length
// memory[0x140 - 0x1c0] fees.data
/////////////////////////// memory[0x1c0 - 0x240] for transferERC721 //////////
// memory[0x1c0 - 0x1e0] selector for `transferFrom(address,address,uint256)`
mstore(0x1c0, 0x23b872dd)
// memory[0x1e0 - 0x200] maker
mstore(0x1e0, mload(0x20))
// memory[0x200 - 0x220] taker
mstore(0x200, mload(0x40))
// memory[0x220 - 0x240] nftId
/////////////////////////// memory[0x240 - 0x300] for nonceVector /////////////
// Note: nonceRange = nonce >> 8
// Note: nonceVector = LibERC721OrdersStorage.orderStatusByMaker[maker][nonceRange]
// Note: nonceVector.slot = keccak256(nonceRange, keccak256(maker, LibERC721OrdersStorage.storageId))
// memory[0x240 - 0x260] shouldStoreNonceVectorToStorage flag
mstore(0x240, 0)
// memory[0x260 - 0x280] nonceMask
// memory[0x280 - 0x2a0] nonceVector.slot
// memory[0x2a0 - 0x2c0] nonceVector
// memory[0x2c0 - 0x2e0] nonceRange
mstore(0x2c0, NONCE_RANGE_LIMIT)
// memory[0x2e0 - 0x300] keccak256(maker, LibERC721OrdersStorage.storageId)
mstore(0x2e0, mload(0x20))
mstore(0x300, STORAGE_ID_ERC721_ORDERS)
mstore(0x2e0, keccak256(0x2e0, 0x40))
/////////////////////////// memory[0x300 - 0x380] for collection //////////////
// memory[0x300 - 0x320] collection.head2
// memory[0x320 - 0x340] collection.platformFeePercentage
// memory[0x340 - 0x360] collection.royaltyFeePercentage
// memory[0x360 - 0x380] someSuccess flag
mstore(0x360, 0)
/////////////////////////// memory[0x380 - 0x420] for delegateCall ///////////
// memory[0x380 - 0x3a0] erc20TokenFromDelegateCall
// memory[0x3a0 - 0x3c0] platformFeeRecipientFromDelegateCall
// memory[0x3c0 - 0x3e0] royaltyFeeRecipientFromDelegateCall
// memory[0x3e0 - 0x400] platformFeeGlobal
mstore(0x3e0, 0)
// memory[0x400 - 0x420] royaltyFeeGlobal
mstore(0x400, 0)
/////////////////////////// memory[0x420 - 0x4a0] for transferERC20 ///////////
// memory[0x420 - 0x440] selector for `transferFrom(address,address,uint256)`
mstore(0x420, 0x23b872dd)
// memory[0x440 - 0x460] msg.sender
mstore(0x440, caller())
// memory[0x460 - 0x480] to
// memory[0x480 - 0x4a0] amount
/////////////////////////// memory[0x4a0 - 0x4e0] for transferERC20 ///////////
// memory[0x4a0 - 0x4c0] selector for `ownerOf(uint256)`
mstore(0x4a0, 0x6352211e)
// memory[0x4c0 - 0x4e0] nftId
/////////////////////////// global variables /////////////////////////////////
let nonceVectorForCheckingNonReentrant
// collectionStartNonce = (data1 >> 200) & MASK_40
let collectionStartNonce := and(shr(200, calldataload(0x4)), MASK_40)
// platformFeeRecipient = data3 & MASK_160
let platformFeeRecipient := and(calldataload(0x44), MASK_160)
// Total erc20 amount.
let totalERC20AmountToPlatform
let totalERC20AmountToMaker
for { let offsetCollection := offsetCollectionsBytes } lt(offsetCollection, ptrEnd) {} {
// memory[0xe0 - 0x100] nftAddress
// head1 [96 bits(filledIndexList part1) + 160 bits(nftAddress)]
mstore(0xe0, and(calldataload(offsetCollection), MASK_160)) // nftAddress = head1 & MASK_160
// memory[0x300 - 0x320] collection.head2
// collectionType: 0 - basicCollection, 1 - collection
// head2 [8 bits(collectionType) + 8 bits(itemsCount) + 8 bits(filledCount) + 8 bits(unused) + 32 bits(filledIndexList part2)
// + 16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)]
mstore(0x300, calldataload(add(offsetCollection, 0x20)))
// filledIndexList [96 bits(filledIndexList part1) + 32 bits(filledIndexList part2) + 128 bits(unused)]
// filledIndexList = (head1 & MASK_INDEX_LIST_PART1) | ((head2 >> 64) & MASK_INDEX_LIST_PART2)
let filledIndexList := or(and(calldataload(offsetCollection), MASK_INDEX_LIST_PART1), and(shr(64, mload(0x300)), MASK_INDEX_LIST_PART2))
let filledCount := byte(2, mload(0x300))
let itemsCount := byte(1, mload(0x300))
if filledCount {
if gt(filledCount, itemsCount) {
_revertInvalidFilledIndex()
}
if gt(filledCount, 128) {
_revertInvalidFilledIndex()
}
if iszero(extcodesize(mload(0xe0))) {
_revertInvalidERC721Token()
}
}
// memory[0x140 - 0x160] platformFeeRecipient
mstore(0x140, platformFeeRecipient)
// memory[0x320 - 0x340] collection.platformFeePercentage
switch platformFeeRecipient
// if (platformFeeRecipient == address(0) platformFeePercentage = 0
case 0 { mstore(0x320, 0) }
// else platformFeePercentage = collection.platformFeePercentage
default { mstore(0x320, and(shr(176, mload(0x300)), MASK_16)) }
// memory[0x180 - 0x1a0] royaltyFeeRecipient
mstore(0x180, and(mload(0x300), MASK_160))
// memory[0x340 - 0x360] collection.royaltyFeePercentage
switch mload(0x180)
// if (royaltyFeeRecipient == address(0) royaltyFeePercentage = 0
case 0 { mstore(0x340, 0) }
// else royaltyFeePercentage = collection.royaltyFeePercentage
default { mstore(0x340, and(shr(160, mload(0x300)), MASK_16)) }
// Check fees.
if gt(add(mload(0x320), mload(0x340)), 10000) {
revertFeesPercentageExceedsLimit()
}
let totalERC20AmountToRoyalty
// switch collectionType
switch byte(0, mload(0x300))
// basicCollection
case 0 {
for { } filledCount { } {
filledCount := sub(filledCount, 1)
let filledIndex := byte(filledCount, filledIndexList)
if iszero(lt(filledIndex, itemsCount)) {
_revertInvalidFilledIndex()
}
// memory[0x60 - 0x80] nonce
// memory[0x240 - 0x260] shouldStoreNonceVectorToStorage flag
// memory[0x260 - 0x280] nonceMask
// memory[0x280 - 0x2a0] nonceVector.slot
// memory[0x2a0 - 0x2c0] nonceVector
// memory[0x2c0 - 0x2e0] nonceRange
// memory[0x2e0 - 0x300] keccak256(maker, LibERC721OrdersStorage.storageId)
// nonce = add(collectionStartNonce, filledIndex)
mstore(0x60, add(collectionStartNonce, filledIndex))
// if (nonceRange != newNonceRange)
if iszero(eq(mload(0x2c0), shr(8, mload(0x60)))) {
// Store nonce to storage if needed.
if mload(0x240) {
// Revert if reentrant.
if iszero(eq(nonceVectorForCheckingNonReentrant, sload(mload(0x280)))) {
_revertReentrantCall()
}
// Store nonce to storage at one time.
sstore(mload(0x280), mload(0x2a0))
// Clear store nonceVector flag.
mstore(0x240, 0)
}
// nonceRange = nonce >> 8
mstore(0x2c0, shr(8, mload(0x60)))
// Calculate nonceVector.slot and store to memory.
mstore(0x280, keccak256(0x2c0, 0x40))
// Load nonceVector from storage.
nonceVectorForCheckingNonReentrant := sload(mload(0x280))
// Store nonceVector to memory.
mstore(0x2a0, nonceVectorForCheckingNonReentrant)
}
// memory[0x260 - 0x280] nonceMask
// nonceMask = 1 << (nonce & 0xff)
mstore(0x260, shl(and(mload(0x60), 0xff), 1))
// if order is not filled.
// if (nonceVector & nonceMask == 0)
if iszero(and(mload(0x2a0), mload(0x260))) {
// orderItem [96 bits(erc20TokenAmount) + 160 bits(nftId)]
let orderItem := calldataload(add(add(offsetCollection, 0x40), mul(filledIndex, 0x20)))
// nftAddress := mload(0xe0)
// nftId := and(orderItem, MASK_160)
if _transferERC721(mload(0xe0), and(orderItem, MASK_160)) {
// Set store nonceVector flag.
mstore(0x240, 1)
// Update nonceVector.
// nonceVector |= nonceMask
mstore(0x2a0, or(mload(0x2a0), mload(0x260)))
// Calculate fees.
// memory[0xa0 - 0xc0] erc20TokenAmount
mstore(0xa0, shr(160, orderItem)) // erc20TokenAmount = orderItem >> 160
// memory[0x140 - 0x1c0] fees.data
// memory[0x140 - 0x160] platformFeeRecipient
// memory[0x160 - 0x180] platformFeeAmount
// memory[0x180 - 0x1a0] royaltyFeeRecipient
// memory[0x1a0 - 0x1c0] royaltyFeeAmount
// memory[0x320 - 0x340] platformFeePercentage
// platformFeeAmount = erc20TokenAmount * platformFeePercentage / 10000
mstore(0x160, div(mul(mload(0xa0), mload(0x320)), 10000))
// memory[0x340 - 0x360] royaltyFeePercentage
// royaltyFeeAmount = erc20TokenAmount * royaltyFeePercentage / 10000
mstore(0x1a0, div(mul(mload(0xa0), mload(0x340)), 10000))
// Update total erc20 amount.
// totalERC20AmountToMaker += erc20TokenAmount - (platformFeeAmount + royaltyFeeAmount)
totalERC20AmountToMaker := add(totalERC20AmountToMaker, sub(mload(0xa0), add(mload(0x160), mload(0x1a0))))
// totalERC20AmountToPlatform += platformFeeAmount
totalERC20AmountToPlatform := add(totalERC20AmountToPlatform, mload(0x160))
// totalERC20AmountToRoyalty += royaltyFeeAmount
totalERC20AmountToRoyalty := add(totalERC20AmountToRoyalty, mload(0x1a0))
// Emit event
// memory[0 - 0x20] orderHash
// memory[0x20 - 0x40] maker
// memory[0x40 - 0x60] taker
// memory[0x60 - 0x80] nonce
// memory[0x80 - 0xa0] erc20Token
// memory[0xa0 - 0xc0] erc20TokenAmount
// memory[0xc0 - 0xe0] fees.offset
// memory[0xe0 - 0x100] nftAddress
// memory[0x100 - 0x120] nftId
mstore(0x100, mload(0x220))
// fees
switch platformFeeRecipient
case 0 {
// memory[0x180 - 0x1a0] royaltyFeeRecipient
switch mload(0x180)
case 0 {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 0)
// emit event
log1(0, 320 /* 10 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
default {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 1)
// Copy royaltyFeeRecipient to memory[0x140 - 0x160]
mstore(0x140, mload(0x180))
// Copy royaltyFeeAmount to memory[0x160 - 0x180]
mstore(0x160, mload(0x1a0))
// emit event
log1(0, 384 /* 12 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
}
default {
// memory[0x180 - 0x1a0] royaltyFeeRecipient
switch mload(0x180)
case 0 {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 1)
// emit event
log1(0, 384 /* 12 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
default {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 2)
// emit event
log1(0, 448 /* 14 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
}
// Set someSuccess flag.
mstore(0x360, 1)
}
}
} // end for
// Update offsetCollection.
offsetCollection := add(add(offsetCollection, 0x40), mul(itemsCount, 0x20))
} // end basicCollection
// collection
default {
for { } filledCount { } {
filledCount := sub(filledCount, 1)
let filledIndex := byte(filledCount, filledIndexList)
if iszero(lt(filledIndex, itemsCount)) {
_revertInvalidFilledIndex()
}
// memory[0x60 - 0x80] nonce
// memory[0x240 - 0x260] shouldStoreNonceVectorToStorage flag
// memory[0x260 - 0x280] nonceMask
// memory[0x280 - 0x2a0] nonceVector.slot
// memory[0x2a0 - 0x2c0] nonceVector
// memory[0x2c0 - 0x2e0] nonceRange
// memory[0x2e0 - 0x300] keccak256(maker, LibERC721OrdersStorage.storageId)
// nonce = add(collectionStartNonce, filledIndex)
mstore(0x60, add(collectionStartNonce, filledIndex))
// if (nonceRange != newNonceRange)
if iszero(eq(mload(0x2c0), shr(8, mload(0x60)))) {
// Store nonce to storage if needed.
if mload(0x240) {
// Revert if reentrant.
if iszero(eq(nonceVectorForCheckingNonReentrant, sload(mload(0x280)))) {
_revertReentrantCall()
}
// Store nonce to storage at one time.
sstore(mload(0x280), mload(0x2a0))
// Clear store nonceVector flag.
mstore(0x240, 0)
}
// nonceRange = nonce >> 8
mstore(0x2c0, shr(8, mload(0x60)))
// Calculate nonceVector.slot and store to memory.
mstore(0x280, keccak256(0x2c0, 0x40))
// Load nonceVector from storage.
nonceVectorForCheckingNonReentrant := sload(mload(0x280))
// Store nonceVector to memory.
mstore(0x2a0, nonceVectorForCheckingNonReentrant)
}
// memory[0x260 - 0x280] nonceMask
// nonceMask = 1 << (nonce & 0xff)
mstore(0x260, shl(and(mload(0x60), 0xff), 1))
// if order is not filled.
// if (nonceVector & nonceMask == 0)
if iszero(and(mload(0x2a0), mload(0x260))) {
// struct OrderItem {
// uint256 erc20TokenAmount;
// uint256 nftId;
// }
let offsetOrderItem := add(add(offsetCollection, 0x40), mul(filledIndex, 0x40))
if gt(calldataload(offsetOrderItem), MAX_ERC20_AMOUNT) {
_revertERC20AmountExceedsLimit()
}
// nftAddress := mload(0xe0)
// nftId := calldataload(add(offsetOrderItem, 0x20))
if _transferERC721(mload(0xe0), calldataload(add(offsetOrderItem, 0x20))) {
// Set store nonceVector flag.
mstore(0x240, 1)
// Update nonceVector.
// nonceVector |= nonceMask
mstore(0x2a0, or(mload(0x2a0), mload(0x260)))
// Calculate fees.
// memory[0xa0 - 0xc0] erc20TokenAmount
mstore(0xa0, calldataload(offsetOrderItem))
// memory[0x140 - 0x1c0] fees.data
// memory[0x140 - 0x160] platformFeeRecipient
// memory[0x160 - 0x180] platformFeeAmount
// memory[0x180 - 0x1a0] royaltyFeeRecipient
// memory[0x1a0 - 0x1c0] royaltyFeeAmount
// memory[0x320 - 0x340] platformFeePercentage
// platformFeeAmount = erc20TokenAmount * platformFeePercentage / 10000
mstore(0x160, div(mul(mload(0xa0), mload(0x320)), 10000))
// memory[0x340 - 0x360] royaltyFeePercentage
// royaltyFeeAmount = erc20TokenAmount * royaltyFeePercentage / 10000
mstore(0x1a0, div(mul(mload(0xa0), mload(0x340)), 10000))
// Update total erc20 amount.
// totalERC20AmountToMaker += erc20TokenAmount - (platformFeeAmount + royaltyFeeAmount)
totalERC20AmountToMaker := add(totalERC20AmountToMaker, sub(mload(0xa0), add(mload(0x160), mload(0x1a0))))
// totalERC20AmountToPlatform += platformFeeAmount
totalERC20AmountToPlatform := add(totalERC20AmountToPlatform, mload(0x160))
// totalERC20AmountToRoyalty += royaltyFeeAmount
totalERC20AmountToRoyalty := add(totalERC20AmountToRoyalty, mload(0x1a0))
// Emit event
// memory[0 - 0x20] orderHash
// memory[0x20 - 0x40] maker
// memory[0x40 - 0x60] taker
// memory[0x60 - 0x80] nonce
// memory[0x80 - 0xa0] erc20Token
// memory[0xa0 - 0xc0] erc20TokenAmount
// memory[0xc0 - 0xe0] fees.offset
// memory[0xe0 - 0x100] nftAddress
// memory[0x100 - 0x120] nftId
mstore(0x100, mload(0x220))
// fees
switch platformFeeRecipient
case 0 {
// memory[0x180 - 0x1a0] royaltyFeeRecipient
switch mload(0x180)
case 0 {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 0)
// emit event
log1(0, 320 /* 10 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
default {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 1)
// Copy royaltyFeeRecipient to memory[0x140 - 0x160]
mstore(0x140, mload(0x180))
// Copy royaltyFeeAmount to memory[0x160 - 0x180]
mstore(0x160, mload(0x1a0))
// emit event
log1(0, 384 /* 12 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
}
default {
// memory[0x180 - 0x1a0] royaltyFeeRecipient
switch mload(0x180)
case 0 {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 1)
// emit event
log1(0, 384 /* 12 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
default {
// memory[0x120 - 0x140] fees.length
mstore(0x120, 2)
// emit event
log1(0, 448 /* 14 * 32 */, _TOPIC_SELL_ORDER_FILLED)
}
}
// Set someSuccess flag.
mstore(0x360, 1)
}
}
} // end for
// Update offsetCollection.
offsetCollection := add(add(offsetCollection, 0x40), mul(itemsCount, 0x40))
} // end collection
// Update collectionStartNonce.
// collectionStartNonce += itemsCount
// memory[0x300 - 0x320] collection.head2
collectionStartNonce := add(collectionStartNonce, itemsCount)
// Pay royaltyFee together.
if totalERC20AmountToRoyalty {
// memory[0x80 - 0xa0] erc20Token
// memory[0x180 - 0x1a0] royaltyFeeRecipient
// memory[0x380 - 0x3a0] erc20TokenFromDelegateCall
// memory[0x3c0 - 0x3e0] royaltyFeeRecipientFromDelegateCall
switch and(eq(mload(0x80), mload(0x380)), eq(mload(0x180), mload(0x3c0)))
case 1 {
// memory[0x400 - 0x420] royaltyFeeGlobal
mstore(0x400, add(mload(0x400), totalERC20AmountToRoyalty))
}
default {
_transferERC20(mload(0x180), totalERC20AmountToRoyalty)
}
}
} // end for
// Store nonce to storage if needed.
if mload(0x240) {
// Revert if reentrant.
if iszero(eq(nonceVectorForCheckingNonReentrant, sload(mload(0x280)))) {
_revertReentrantCall()
}
// Store nonce to storage at one time.
// memory[0x280 - 0x2a0] nonceVector.slot
// memory[0x2a0 - 0x2c0] nonceVector
sstore(mload(0x280), mload(0x2a0))
}
// Pay to maker at one time.
if totalERC20AmountToMaker {
// memory[0x20 - 0x40] maker
_transferERC20(mload(0x20), totalERC20AmountToMaker)
}
// Pay to platform at one time.
if totalERC20AmountToPlatform {
// memory[0x80 - 0xa0] erc20Token
// memory[0x380 - 0x3a0] erc20TokenFromDelegateCall
// memory[0x3a0 - 0x3c0] platformFeeRecipientFromDelegateCall
switch and(eq(mload(0x80), mload(0x380)), eq(platformFeeRecipient, mload(0x3a0)))
case 1 {
// memory[0x3e0 - 0x400] platformFeeGlobal
mstore(0x3e0, add(mload(0x3e0), totalERC20AmountToPlatform))
}
default {
_transferERC20(platformFeeRecipient, totalERC20AmountToPlatform)
}
}
// Revert if none of the orders is filled.
// memory[0x360 - 0x380] someSuccess flag
if iszero(mload(0x360)) {
_revertNoOrderFilled()
}
///////////////////////////////// functions /////////////////////////////////
function _transferERC721(token, nftId) -> success {
// memory[0x1dc - 0x1e0] selector for `transferFrom(address,address,uint256)`
// memory[0x1e0 - 0x200] maker
// memory[0x200 - 0x220] taker
// memory[0x220 - 0x240] nftId
mstore(0x220, nftId)
if call(gas(), token, 0, 0x1dc, 0x64, 0, 0) {
// memory[0x4bc - 0x4c0] selector for `ownerOf(uint256)`
// memory[0x4c0 - 0x4e0] nftId
mstore(0x4c0, nftId)
if staticcall(gas(), token, 0x4bc, 0x24, 0x4c0, 0x20) {
if eq(returndatasize(), 0x20) {
if eq(mload(0x4c0), mload(0x200)) {
success := 1
}
}
}
}
}
function _transferERC20(_to, _amount) {
// memory[0x80 - 0xa0] erc20Token
switch mload(0x80)
case 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE {
if iszero(call(gas(), _to, _amount, 0, 0, 0, 0)) {
_revertTransferETHFailed()
}
}
default {
if iszero(extcodesize(mload(0x80))) {
_revertInvalidERC20Token()
}
// memory[0x43c - 0x440] selector for `transferFrom(address,address,uint256)`
// memory[0x440 - 0x460] msg.sender
// memory[0x460 - 0x480] to
mstore(0x460, _to)
// memory[0x480 - 0x4a0] amount
mstore(0x480, _amount)
// memory[0x80 - 0xa0] erc20Token
if iszero(call(gas(), mload(0x80), 0, 0x43c, 0x64, 0x480, 0x20)) {
_revertTransferERC20Failed()
}
// Check for ERC20 success. ERC20 tokens should return a boolean, but some don't.
// We accept 0-length return data as success, or at least 32 bytes that starts with
// a 32-byte boolean true.
if returndatasize() {
if lt(returndatasize(), 0x20) {
_revertTransferERC20Failed()
}
if iszero(eq(mload(0x480), 1)) {
_revertTransferERC20Failed()
}
}
}
}
function revertFeesPercentageExceedsLimit() {
// revert("fillBatchSignedERC721Order: total fees percentage exceeds the limit.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000004466696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x746f74616c20666565732070657263656e746167652065786365656473207468)
mstore(0x80, 0x65206c696d69742e000000000000000000000000000000000000000000000000)
mstore(0xa0, 0)
revert(0, 0xa4)
}
function _revertInvalidFilledIndex() {
// revert("fillBatchSignedERC721Order: invalid filledIndex.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003066696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c69642066696c6c6564496e6465782e000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertReentrantCall() {
// revert("fillBatchSignedERC721Order: reentrant call.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002b66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x7265656e7472616e742063616c6c2e0000000000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertERC20AmountExceedsLimit() {
// revert("fillBatchSignedERC721Order: erc20TokenAmount exceeds limit.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003b66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x6572633230546f6b656e416d6f756e742065786365656473206c696d69742e00)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertNoOrderFilled() {
// revert("fillBatchSignedERC721Order: no order filled.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002c66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x6e6f206f726465722066696c6c65642e00000000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertTransferETHFailed() {
// revert("fillBatchSignedERC721Order: failed to transfer ETH.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003366696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x6661696c656420746f207472616e73666572204554482e000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertTransferERC20Failed() {
// revert("fillBatchSignedERC721Order: failed to transfer ERC20.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003566696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x6661696c656420746f207472616e736665722045524332302e00000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidERC20Token() {
// revert("invalid erc20 token")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x00000013696e76616c696420657263323020746f6b656e000000000000000000)
mstore(0x60, 0)
revert(0, 0x64)
}
function _revertInvalidERC721Token() {
// revert("invalid erc271 token")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x00000014696e76616c69642065726337323120746f6b656e0000000000000000)
mstore(0x60, 0)
revert(0, 0x64)
}
}
}
/// data1 [[8 bits(signatureType) + 8 bits(reserved) + 40 bits(startNonce) + 8 bits(v) + 32 bits(listingTime) + 160 bits(maker)]
/// data2 [64 bits(taker part1) + 32 bits(expiryTime) + 160 bits(erc20Token)]
/// data3 [96 bits(taker part2) + 160 bits(platformFeeRecipient)]
function _validateOrder(uint256 offsetCollectionsBytes) internal view returns (bytes32 orderHash, uint256 ptrEnd) {
uint256 extraDataLength;
bool needValidateOracleSignature;
address maker;
assembly {
let bytesLength := calldataload(sub(offsetCollectionsBytes, 0x20))
ptrEnd := add(offsetCollectionsBytes, bytesLength)
let data1 := calldataload(0x4)
let data2 := calldataload(0x24)
// reserved = 1bits[extraDataFlag] + 6bits[unused] + 1bits[needValidateOracleSignature]
let reserved := byte(1, data1)
needValidateOracleSignature := and(reserved, 0x1)
// If has extraData
if shr(7, reserved) {
// data = [collectionsBytes] + [extraData] + 4bytes[extraDataLength]
extraDataLength := and(calldataload(sub(ptrEnd, 0x20)), 0xffffffff)
if gt(add(extraDataLength, 4), bytesLength) {
_revertInvalidExtraData()
}
ptrEnd := sub(ptrEnd, add(extraDataLength, 4))
}
// Check for listingTime.
// if ((data1 >> 160) & MASK_32 > block.timestamp)
if gt(and(shr(160, data1), MASK_32), timestamp()) {
_revertNotStarted()
}
// Check for expiryTime.
// if ((data2 >> 160) & MASK_32 <= block.timestamp)
if iszero(gt(and(shr(160, data2), MASK_32), timestamp())) {
_revertExpired()
}
// Check for erc20Token.
if iszero(and(data2, MASK_160)) {
_revertInvalidERC20Token()
}
// Check maker.
maker := and(data1, MASK_160)
if iszero(maker) {
_revertInvalidMaker()
}
function _revertInvalidExtraData() {
// revert("fillBatchSignedERC721Order: invalid extraData.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002e66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c6964206578747261446174612e0000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertNotStarted() {
// revert("fillBatchSignedERC721Order: not started.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002866696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x6e6f7420737461727465642e0000000000000000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertExpired() {
// revert("fillBatchSignedERC721Order: expired.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002466696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x657870697265642e000000000000000000000000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidERC20Token() {
// revert("fillBatchSignedERC721Order: invalid erc20Token.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002f66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c6964206572633230546f6b656e2e00000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidMaker() {
// revert("fillBatchSignedERC721Order: invalid maker.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002a66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c6964206d616b65722e000000000000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
}
// Get order hash.
orderHash = _getEIP712Hash(_getStructHash(offsetCollectionsBytes, ptrEnd));
// Validate signature.
{
bytes32 r;
bytes32 s;
uint8 v;
LibSignature.SignatureType signatureType;
assembly {
// Reset the memory status.
mstore(0x40, 0x80)
mstore(0x60, 0)
let data1 := calldataload(0x4)
signatureType := byte(0, data1)
v := byte(7, data1)
r := calldataload(0x64)
s := calldataload(0x84)
}
if (signatureType == LibSignature.SignatureType.EIP712) {
require(maker == ecrecover(orderHash, v, r, s), "Failed to validate signature");
} else if (signatureType == LibSignature.SignatureType.EIP712_1271) {
require(
LibSignature.isValidSignature1271(maker, orderHash, v, r, s),
"Failed to validate signature"
);
} else if (signatureType == LibSignature.SignatureType.ETHEREUM_PERSONAL_SIGN_1271) {
require(LibCommonNftOrdersStorage.isEnableEthereumPersonalSign(), "EthereumPersonalSign is disabled");
bytes32 validateHash = LibSignature.toEthereumPersonalSignHash(orderHash);
require(
LibSignature.isValidSignature1271(maker, validateHash, v, r, s),
"Failed to validate signature"
);
}else if (signatureType == LibSignature.SignatureType.BITCOIN_PERSONAL_SIGN_1271) {
require(LibCommonNftOrdersStorage.isEnableBitcoinPersonalSign(), "BitcoinPersonalSign is disabled");
bytes32 validateHash = LibSignature.toBitcoinPersonalSignHash(orderHash);
require(
LibSignature.isValidSignature1271(maker, validateHash, v, r, s),
"Failed to validate signature"
);
} else if (signatureType == LibSignature.SignatureType.BITCOIN_PERSONAL_SIGN_173) {
require(LibCommonNftOrdersStorage.isEnableBitcoinPersonalSign173(), "BitcoinPersonalSign173 is disabled");
bytes32 validateHash = LibSignature.toBitcoinPersonalSignHash(orderHash);
require(
LibSignature.isValidSignature173(maker, validateHash, v, r, s),
"Failed to validate signature"
);
} else {
revert("Invalid signatureType.");
}
}
// Validate the oracle signature if needed.
if (needValidateOracleSignature) {
// Get the taker.
address taker;
assembly {
// taker = ((data2 >> 192) << 96) | (data3 >> 160)
taker := or(shl(96, shr(192, calldataload(0x24))), shr(160, calldataload(0x44)))
if iszero(taker) {
taker := caller()
}
}
// Get the extraData;
bytes memory extraData = new bytes(extraDataLength);
if (extraDataLength > 0) {
assembly {
calldatacopy(add(extraData, 0x20), ptrEnd, extraDataLength)
}
}
// Validate the oracle signature.
LibOracleSignature.validateOracleSignature(orderHash, taker, extraData);
}
}
function _getEIP712Hash(bytes32 structHash) internal view returns (bytes32 eip712Hash) {
assembly {
// EIP712_DOMAIN_SEPARATOR = keccak256(abi.encode(
// DOMAIN,
// NAME,
// VERSION,
// block.chainid,
// address(this)
// ));
mstore(0, DOMAIN)
mstore(0x20, NAME)
mstore(0x40, VERSION)
mstore(0x60, chainid())
mstore(0x80, address())
// eip712Hash = keccak256(abi.encodePacked(
// hex"1901",
// EIP712_DOMAIN_SEPARATOR,
// structHash
// ));
mstore(0xa0, 0x1901000000000000000000000000000000000000000000000000000000000000)
mstore(0xa2, keccak256(0, 0xa0))
mstore(0xc2, structHash)
eip712Hash := keccak256(0xa0, 0x42)
}
}
/// data1 [[8 bits(signatureType) + 8 bits(reserved) + 40 bits(startNonce) + 8 bits(v) + 32 bits(listingTime) + 160 bits(maker)]
/// data2 [64 bits(taker part1) + 32 bits(expiryTime) + 160 bits(erc20Token)]
/// data3 [96 bits(taker part2) + 160 bits(platformFeeRecipient)]
function _getStructHash(uint256 offsetCollectionsBytes, uint256 ptrEnd) internal view returns (bytes32 structHash) {
// structHash = keccak256(abi.encode(
// _BATCH_SIGNED_ERC721_ORDERS_TYPE_HASH, // offset: 0x0
// maker, // offset: 0x20
// listingTime, // offset: 0x40
// expiryTime, // offset: 0x60
// startNonce, // offset: 0x80
// erc20Token, // offset: 0xa0
// platformFeeRecipient, // offset: 0xc0
// basicCollectionsHash, // offset: 0xe0
// collectionsHash, // offset: 0x100
// hashNonce // offset: 0x120
// ));
// Store basicCollectionsHash to memory[0xe0] and store collectionsHash to memory[0x100].
_storeCollectionsHashToMemory(offsetCollectionsBytes, ptrEnd);
assembly {
let data1 := calldataload(0x4)
let data2 := calldataload(0x24)
let data3 := calldataload(0x44)
let maker := and(data1, MASK_160)
// _BATCH_SIGNED_ERC721_ORDERS_TYPE_HASH
mstore(0, _BATCH_SIGNED_ERC721_ORDERS_TYPE_HASH)
// maker
mstore(0x20, maker)
// listingTime = (data1 >> 160) & MASK_32
mstore(0x40, and(shr(160, data1), MASK_32))
// expiry = (needValidateOracleSignature << 248) | expiryTime
let needValidateOracleSignature := and(byte(1, data1), 0x1)
let expiryTime := and(shr(160, data2), MASK_32)
mstore(0x60, or(shl(248, needValidateOracleSignature), expiryTime))
// startNonce = (data1 >> 200) & MASK_40
mstore(0x80, and(shr(200, data1), MASK_40))
// erc20Token = data2 & MASK_160
mstore(0xa0, and(data2, MASK_160))
// platformFeeRecipient = data3 & MASK_160
mstore(0xc0, and(data3, MASK_160))
// 0xe0 basicCollectionsHash
// 0x100 collectionsHash
// 0x120 hashNonce
// hashNonce.slot = keccak256(abi.encode(maker, STORAGE_ID_COMMON_NFT_ORDERS))
// hashNonce = sload(hashNonce.slot)
mstore(0x120, maker)
mstore(0x140, STORAGE_ID_COMMON_NFT_ORDERS)
mstore(0x120, sload(keccak256(0x120, 0x40)))
structHash := keccak256(0, 0x140 /* 10 * 32 */)
}
}
function _storeCollectionsHashToMemory(uint256 offsetCollectionsBytes, uint256 ptrEnd) internal pure {
assembly {
let isBasicCollectionsEnded
let basicCollectionsHash
let ptrCollectionHash
let offsetCollection := offsetCollectionsBytes
for {} lt(offsetCollection, ptrEnd) {} {
// head1 [96 bits(filledIndexList part1) + 160 bits(nftAddress)]
// nftAddress = head1 & MASK_160
let nftAddress := and(calldataload(offsetCollection), MASK_160)
if iszero(nftAddress) {
_revertInvalidNftAddress()
}
// collectionType: 0 - basicCollection, 1 - collection
// head2 [8 bits(collectionType) + 8 bits(itemsCount) + 8 bits(filledCount) + 8 bits(unused) + 32 bits(filledIndexList part2)
// + 16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)]
let head2 := calldataload(add(offsetCollection, 0x20))
let itemsCount := byte(1, head2)
if iszero(itemsCount) {
_revertInvalidItemCount()
}
let filledCount := byte(2, head2)
if or(gt(filledCount, itemsCount), gt(filledCount, 16)) {
_revertInvalidFilledCount()
}
// basicCollection
if iszero(byte(0, head2)) {
if isBasicCollectionsEnded {
_revertInvalidCollectionsBytes()
}
// typeHash = _BASIC_COLLECTION_TYPE_HASH
mstore(ptrCollectionHash, _BASIC_COLLECTION_TYPE_HASH)
// nftAddress
mstore(add(ptrCollectionHash, 0x20), nftAddress)
// fee = head2 & MASK_192
mstore(add(ptrCollectionHash, 0x40), and(head2, MASK_192))
// itemsHash
let ptrItemsHash := add(ptrCollectionHash, 0x60)
let itemsBytesLength := mul(itemsCount, 0x20)
// offset: 0x0 - head1
// 0x20 - head2
// 0x40 - items.data
let offsetItems := add(offsetCollection, 0x40)
calldatacopy(ptrItemsHash, offsetItems, itemsBytesLength)
// Calculate and store itemsHash.
mstore(ptrItemsHash, keccak256(ptrItemsHash, itemsBytesLength))
// keccak256(abi.encode(_BASIC_COLLECTION_TYPE_HASH, nftAddress, fee, itemsHash))
mstore(ptrCollectionHash, keccak256(ptrCollectionHash, 0x80))
// Update offset.
ptrCollectionHash := add(ptrCollectionHash, 0x20)
offsetCollection := add(offsetItems, itemsBytesLength)
continue
}
// Get basicCollectionsHash.
if iszero(isBasicCollectionsEnded) {
// Set flag.
isBasicCollectionsEnded := 1
switch ptrCollectionHash
case 0 {
// basicCollections is empty.
basicCollectionsHash := _EMPTY_ARRAY_KECCAK256
}
default {
// Calculate basicCollectionsHash.
basicCollectionsHash := keccak256(0, ptrCollectionHash)
ptrCollectionHash := 0
}
}
// collection
// typeHash = _COLLECTION_TYPE_HASH
mstore(ptrCollectionHash, _COLLECTION_TYPE_HASH)
// nftAddress
mstore(add(ptrCollectionHash, 0x20), nftAddress)
// fee = head2 & MASK_192
mstore(add(ptrCollectionHash, 0x40), and(head2, MASK_192))
// itemsHash
let ptrItemsHash := add(ptrCollectionHash, 0x60)
let itemsBytesLength := mul(itemsCount, 0x40)
// offset: 0x0 - head1
// 0x20 - head2
// 0x40 - items.data
let offsetItems := add(offsetCollection, 0x40)
// Copy items to memory [ptrItemsHash + 0x20].
// Reserve a slot(0x20) to store _ORDER_ITEM_TYPE_HASH.
calldatacopy(add(ptrItemsHash, 0x20), offsetItems, itemsBytesLength)
let ptrItemHashData := ptrItemsHash
let ptrItemEnd := add(ptrItemsHash, mul(itemsCount, 0x20))
for { let ptrItem := ptrItemsHash } lt(ptrItem, ptrItemEnd) {} {
mstore(ptrItemHashData, _ORDER_ITEM_TYPE_HASH)
mstore(ptrItem, keccak256(ptrItemHashData, 0x60))
ptrItem := add(ptrItem, 0x20)
ptrItemHashData := add(ptrItemHashData, 0x40)
}
// Calculate and store itemsHash.
mstore(ptrItemsHash, keccak256(ptrItemsHash, mul(itemsCount, 0x20)))
// keccak256(abi.encode(_COLLECTION_TYPE_HASH, nftAddress, fee, itemsHash))
mstore(ptrCollectionHash, keccak256(ptrCollectionHash, 0x80))
// Update offset.
ptrCollectionHash := add(ptrCollectionHash, 0x20)
offsetCollection := add(offsetItems, itemsBytesLength)
}
// if (offsetCollection != ptrEnd) revert()
if iszero(eq(offsetCollection, ptrEnd)) {
_revertInvalidCollectionsBytes()
}
switch isBasicCollectionsEnded
// Order.collections is empty.
case 0 {
// Order.basicCollections is empty.
if iszero(ptrCollectionHash) {
_revertInvalidCollectionsBytes()
}
// Store basicCollectionsHash to memory[0xe0].
mstore(0xe0, keccak256(0, ptrCollectionHash))
// Store collectionsHash to memory[0x100].
mstore(0x100, _EMPTY_ARRAY_KECCAK256)
}
// Order.collections is not empty.
default {
// Store basicCollectionsHash to memory[0xe0].
mstore(0xe0, basicCollectionsHash)
// Store collectionsHash to memory[0x100].
mstore(0x100, keccak256(0, ptrCollectionHash))
}
///////////////////////////////// functions /////////////////////////////////
function _revertInvalidNftAddress() {
// revert("fillBatchSignedERC721Order: invalid nftAddress.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002f66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c6964206e6674416464726573732e00000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidItemCount() {
// revert("fillBatchSignedERC721Order: invalid itemCount.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000002e66696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c6964206974656d436f756e742e0000000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidFilledCount() {
// revert("fillBatchSignedERC721Order: invalid filledCount.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003066696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c69642066696c6c6564436f756e742e000000000000000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
function _revertInvalidCollectionsBytes() {
// revert("fillBatchSignedERC721Order: invalid collectionsBytes.")
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003566696c6c42617463685369676e65644552433732314f726465723a20)
mstore(0x60, 0x696e76616c696420636f6c6c656374696f6e7342797465732e00000000000000)
mstore(0x80, 0)
revert(0, 0x84)
}
}
}
}// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 Element.Market Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.17;
interface IBatchSignedERC721OrdersFeature {
/// @param fee [16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)].
/// @param items [96 bits(erc20TokenAmount) + 160 bits(nftId)].
/// struct BasicCollection {
/// address nftAddress;
/// bytes32 fee;
/// bytes32[] items;
/// }
///
/// struct OrderItem {
/// uint256 erc20TokenAmount;
/// uint256 nftId;
/// }
///
/// @param fee [16 bits(platformFeePercentage) + 16 bits(royaltyFeePercentage) + 160 bits(royaltyFeeRecipient)].
/// struct Collection {
/// address nftAddress;
/// bytes32 fee;
/// OrderItem[] items;
/// }
///
/// struct BatchSignedERC721Orders {
/// address maker;
/// uint256 listingTime;
/// uint256 expiryTime;
/// uint256 startNonce;
/// address erc20Token;
/// address platformFeeRecipient;
/// BasicCollection[] basicCollections;
/// Collection[] collections;
/// uint256 hashNonce;
/// }
/// @param data1 [8 bits(signatureType) + 8 bits(reserved) + 40 bits(startNonce) + 8 bits(v) + 32 bits(listingTime) + 160 bits(maker)]
/// @param data2 [64 bits(taker part1) + 32 bits(expiryTime) + 160 bits(erc20Token)]
/// @param data3 [96 bits(taker part2) + 160 bits(platformFeeRecipient)]
struct BatchSignedERC721OrderParameter {
uint256 data1;
uint256 data2;
uint256 data3;
bytes32 r;
bytes32 s;
}
function fillBatchSignedERC721Order(BatchSignedERC721OrderParameter calldata parameter, bytes calldata collections) external payable;
/// @param data1 [8 bits(signatureType) + 8 bits(reserved) + 40 bits(startNonce) + 8 bits(v) + 32 bits(listingTime) + 160 bits(maker)]
/// @param data2 [64 bits(taker part1) + 32 bits(expiryTime) + 160 bits(erc20Token)]
/// @param data3 [96 bits(taker part2) + 160 bits(platformFeeRecipient)]
struct BatchSignedERC721OrderParameters {
uint256 data1;
uint256 data2;
uint256 data3;
bytes32 r;
bytes32 s;
bytes collections;
}
/// @param additional1 [96 bits(withdrawETHAmount) + 160 bits(erc20Token)]
/// @param additional2 [8 bits(revertIfIncomplete) + 88 bits(unused) + 160 bits(royaltyFeeRecipient)]
function fillBatchSignedERC721Orders(
BatchSignedERC721OrderParameters[] calldata parameters,
uint256 additional1,
uint256 additional2
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "../../storage/LibCommonNftOrdersStorage.sol";
library LibOracleSignature {
function isNeedValidateOracleSignature(uint256 expiry) internal pure returns(bool) {
return (expiry >> 248) & 0x1 == 1;
}
function validateOracleSignature(
bytes32 orderHash,
address taker,
bytes memory data
) internal view returns(bytes memory childData) {
uint256 dataLength = data.length;
require(dataLength >= 69, "Oracle signature error");
address oracleSigner = LibCommonNftOrdersStorage.getOracleSigner();
if (oracleSigner == address(0)) {
assembly {
// 32bytes[dataLength] + 4bytes[deadline] + 65bytes[signature] + [childData]
childData := add(data, 69)
mstore(childData, sub(dataLength, 69))
}
return childData;
}
uint8 v;
bytes32 r;
bytes32 s;
uint256 deadline;
bytes32 hash;
assembly {
// 32bytes[dataLength] + 4bytes[deadline] + 65bytes[signature] + [childData]
deadline := and(mload(add(data, 0x4)), 0xffffffff)
r := mload(add(data, 0x24))
s := mload(add(data, 0x44))
v := and(mload(add(data, 0x45)), 0xff)
let ptr := mload(0x40)
mstore(ptr, chainid())
mstore(add(ptr, 0x20), address())
mstore(add(ptr, 0x40), orderHash)
mstore(add(ptr, 0x60), taker)
mstore(add(ptr, 0x80), deadline)
hash := keccak256(ptr, 0xa0)
childData := add(data, 69)
mstore(childData, sub(dataLength, 69))
}
require(block.timestamp < deadline, "Oracle deadline reached");
require(ecrecover(hash, v, r, s) == oracleSigner, "Invalid oracle signature");
return childData;
}
}// SPDX-License-Identifier: Apache-2.0
/*
Modifications Copyright 2022 Element.Market
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.17;
/// @dev A library for validating signatures.
library LibSignature {
/// @dev Allowed signature types.
enum SignatureType {
EIP712, // 0
PRESIGNED, // 1
EIP712_BULK,// 2
EIP712_1271,// 3
EIP712_BULK_1271, // 4
ETHEREUM_PERSONAL_SIGN_1271, // 5
ETHEREUM_PERSONAL_SIGN_BULK_1271,// 6
BITCOIN_PERSONAL_SIGN_1271, // 7
BITCOIN_PERSONAL_SIGN_BULK_1271, // 8
BITCOIN_PERSONAL_SIGN_173, // 9
BITCOIN_PERSONAL_SIGN_BULK_173 // 10
}
/// @dev Encoded EC signature.
struct Signature {
// How to validate the signature.
SignatureType signatureType;
// EC Signature data.
uint8 v;
// EC Signature data.
bytes32 r;
// EC Signature data.
bytes32 s;
}
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
function bytes32ToHexBuffer(bytes32 data) internal pure returns(bytes memory buffer) {
uint256 localValue = uint256(data);
buffer = new bytes(66);
buffer[0] = "0";
buffer[1] = "x";
unchecked {
for (uint256 i = 65; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
}
return buffer;
}
function toEthereumPersonalSignHash(bytes32 hash) internal pure returns(bytes32) {
return keccak256(
bytes.concat(
"\x19Ethereum Signed Message:\n101Element.market listing/offer hash:\n",
bytes32ToHexBuffer(hash)
)
);
}
function toBitcoinPersonalSignHash(bytes32 hash) internal pure returns(bytes32) {
bytes32 tempHash = sha256(
bytes.concat(
"\x18Bitcoin Signed Message:\n\x65Element.market listing/offer hash:\n",
bytes32ToHexBuffer(hash)
)
);
// Convert bytes32 to bytes.
bytes memory buffer = new bytes(32);
assembly {
mstore(add(buffer, 32), tempHash)
}
return sha256(buffer);
}
function isValidSignature1271(
address aa,
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal view returns(bool) {
bool isValid;
assembly {
if extcodesize(aa) {
let ptr := mload(0x40) // free memory pointer
// selector for `isValidSignature(bytes32,bytes)`
mstore(ptr, 0x1626ba7e)
mstore(add(ptr, 0x20), hash)
mstore(add(ptr, 0x40), 0x40)
mstore(add(ptr, 0x60), 0x41)
mstore(add(ptr, 0x80), r)
mstore(add(ptr, 0xa0), s)
mstore(add(ptr, 0xc0), shl(248, v))
if staticcall(gas(), aa, add(ptr, 0x1c), 0xa5, ptr, 0x20) {
if eq(mload(ptr), 0x1626ba7e00000000000000000000000000000000000000000000000000000000) {
isValid := 1
}
}
}
}
return isValid;
}
uint256 constant private ADDRESS_LIMIT = 1 << 160;
function isValidSignature173(
address aa,
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal view returns(bool) {
address owner;
assembly {
if extcodesize(aa) {
let ptr := mload(0x40) // free memory pointer
// selector for `owner()`
mstore(ptr, 0x8da5cb5b)
if staticcall(gas(), aa, add(ptr, 0x1c), 0x4, ptr, 0x20) {
if lt(mload(ptr), ADDRESS_LIMIT) {
owner := mload(ptr)
}
}
}
}
return owner != address(0) && owner == ecrecover(hash, v, r, s);
}
}// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2022 Element.Market
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.17;
import "./LibStorage.sol";
library LibCommonNftOrdersStorage {
uint256 internal constant MASK_160 = (1 << 160) - 1;
/// @dev Storage bucket for this feature.
struct Storage {
/* Track per-maker nonces that can be incremented by the maker to cancel orders in bulk. */
// The current nonce for the maker represents the only valid nonce that can be signed by the maker
// If a signature was signed with a nonce that's different from the one stored in nonces, it
// will fail validation.
mapping(address => uint256) hashNonces;
// The personal sign state.
uint256 personalSignState;
// The oracle sign state.
bytes32 oracleSignState;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.STORAGE_ID_COMMON_NFT_ORDERS;
// Dip into assembly to change the slot pointed to by the local
// variable `stor`.
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
assembly { stor.slot := storageSlot }
}
function isEnableEthereumPersonalSign() internal view returns(bool) {
return (getStorage().personalSignState & 0x1) != 0;
}
function isEnableBitcoinPersonalSign() internal view returns(bool) {
return (getStorage().personalSignState & 0x2) != 0;
}
function isEnableBitcoinPersonalSign173() internal view returns(bool) {
return (getStorage().personalSignState & 0x4) != 0;
}
function getOracleSigner() internal view returns(address signer) {
bytes32 oracleSignState = getStorage().oracleSignState;
assembly {
signer := and(oracleSignState, MASK_160)
}
}
}// SPDX-License-Identifier: Apache-2.0
/*
Modifications Copyright 2022 Element.Market
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.17;
import "./LibStorage.sol";
/// @dev Storage helpers for `ERC721OrdersFeature`.
library LibERC721OrdersStorage {
/// @dev Storage bucket for this feature.
struct Storage {
// maker => nonce range => order status bit vector
mapping(address => mapping(uint248 => uint256)) orderStatusByMaker;
// order hash => preSigned
mapping(bytes32 => uint256) preSigned;
// order hash => filledAmount
mapping(bytes32 => uint128) filledAmount;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.STORAGE_ID_ERC721_ORDERS;
// Dip into assembly to change the slot pointed to by the local
// variable `stor`.
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
assembly { stor.slot := storageSlot }
}
}// SPDX-License-Identifier: Apache-2.0
/*
Modifications Copyright 2022 Element.Market
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.17;
/// @dev Common storage helpers
library LibStorage {
/// @dev What to bit-shift a storage ID by to get its slot.
/// This gives us a maximum of 2**128 inline fields in each bucket.
uint256 constant STORAGE_ID_PROXY = 1 << 128;
uint256 constant STORAGE_ID_SIMPLE_FUNCTION_REGISTRY = 2 << 128;
uint256 constant STORAGE_ID_OWNABLE = 3 << 128;
uint256 constant STORAGE_ID_COMMON_NFT_ORDERS = 4 << 128;
uint256 constant STORAGE_ID_ERC721_ORDERS = 5 << 128;
uint256 constant STORAGE_ID_ERC1155_ORDERS = 6 << 128;
uint256 constant STORAGE_ID_REENTRANCY_GUARD = 7 << 128;
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"uint256","name":"data1","type":"uint256"},{"internalType":"uint256","name":"data2","type":"uint256"},{"internalType":"uint256","name":"data3","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IBatchSignedERC721OrdersFeature.BatchSignedERC721OrderParameter","name":"","type":"tuple"},{"internalType":"address","name":"erc20TokenFromDelegateCall","type":"address"},{"internalType":"address","name":"platformFeeRecipientFromDelegateCall","type":"address"},{"internalType":"address","name":"royaltyFeeRecipientFromDelegateCall","type":"address"},{"internalType":"bytes","name":"collections","type":"bytes"}],"name":"delegateCallFillBatchSignedERC721Order","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"data1","type":"uint256"},{"internalType":"uint256","name":"data2","type":"uint256"},{"internalType":"uint256","name":"data3","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IBatchSignedERC721OrdersFeature.BatchSignedERC721OrderParameter","name":"","type":"tuple"},{"internalType":"bytes","name":"collections","type":"bytes"}],"name":"fillBatchSignedERC721Order","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"data1","type":"uint256"},{"internalType":"uint256","name":"data2","type":"uint256"},{"internalType":"uint256","name":"data3","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"bytes","name":"collections","type":"bytes"}],"internalType":"struct IBatchSignedERC721OrdersFeature.BatchSignedERC721OrderParameters[]","name":"parameters","type":"tuple[]"},{"internalType":"uint256","name":"additional1","type":"uint256"},{"internalType":"uint256","name":"additional2","type":"uint256"}],"name":"fillBatchSignedERC721Orders","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b50604051620026f1380380620026f18339810160408190526200003491620000a5565b6001600160a01b0381166200008f5760405162461bcd60e51b815260206004820152601460248201527f494e56414c49445f574554485f41444452455353000000000000000000000000604482015260640160405180910390fd5b6001600160a01b031660a05230608052620000d7565b600060208284031215620000b857600080fd5b81516001600160a01b0381168114620000d057600080fd5b9392505050565b60805160a0516125ed620001046000396000610146015260008181610125015261064d01526125ed6000f3fe6080604052600436106100345760003560e01c8063149b8ce614610039578063a4d730411461004e578063dc055ecc14610061575b600080fd5b61004c6100473660046121fc565b610074565b005b61004c61005c3660046122df565b610573565b61004c61006f36600461234f565b61064b565b826100df5760405162461bcd60e51b815260206004820152603060248201527f66696c6c42617463685369676e65644552433732314f72646572733a20696e7660448201526f30b634b2103830b930b6b2ba32b9399760811b60648201526084015b60405180910390fd5b60006100eb34476123d8565b905060006001600160a01b038686600081811061010a5761010a6123f9565b905060200281019061011c919061240f565b604001351690507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060a086901c6001600160a01b038088169087166000808085156101b15761018d8630896102b3565b632e1a7d4d600052856020526000806024601c60008b5af16101b1576101b1610418565b63dc055ecc6040528461010052886101205283610140526101206101605260208d028e0195508d5b868110156102475780358f0160a08160603760c081013580610180528060e083016101a037604060008261014401605c8e5af480156102295760019450600051870196506020518601955061023c565b8e60001a1561023c573d6000803e3d6000fd5b5050506020016101d9565b50821561025957610259838a876102b3565b811561026a5761026a8285876102b3565b806102775761027761047a565b50505050505083470361028657005b834711156102a657600080600080874703335af161004c5761004c6104d0565b6102ae6104d0565b610569565b8073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee811461033857813b6102dd576102dd61052b565b6323b872dd600052336020528260405283606052602060006064601c6000865af161030a5761030a6103b6565b3d156103335760203d1015610321576103216103b6565b600160005114610333576103336103b6565b61034e565b60008060008087875af161034e5761034e610354565b50505050565b62461bcd60e51b600052600160e51b6020527c3466696c6c42617463685369676e65644552433732314f72646572733a6040527f206661696c656420746f207472616e73666572204554482e0000000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3666696c6c42617463685369676e65644552433732314f72646572733a6040527f206661696c656420746f207472616e736665722045524332302e000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3466696c6c42617463685369676e65644552433732314f72646572733a6040527f206661696c656420746f207769746864726177204554482e0000000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2d66696c6c42617463685369676e65644552433732314f72646572733a604052701037379037b93232b9103334b63632b21760791b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3266696c6c42617463685369676e65644552433732314f72646572733a60405275103330b4b632b2103a37903932b33ab7321022aa241760511b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c13696e76616c696420657263323020746f6b656e000000000000000000604052600060605260646000fd5b5050505050505050565b600061057f34476123d8565b90508260008061058e83610731565b915091508160005260006103805260006103a05260006103c0526105b28382610dd9565b8347036105bb57005b834711156105db57600080600080874703335af161004c5761004c6105e8565b6105e36105e8565b610642565b62461bcd60e51b600052600160e51b6020527c3166696c6c42617463685369676e65644552433732314f726465723a20604052743330b4b632b2103a37903932b33ab7321022aa241760591b606052600060805260846000fd5b50505050505050565b7f000000000000000000000000000000000000000000000000000000000000000060003082036106fb5762461bcd60e51b600052600160e51b6020527c5464656c656761746543616c6c46696c6c42617463685369676e6564456040527f52433732314f726465723a206d7573742064656c656761746543616c6c2066726060527f6f6d20616e2065787465726e616c2065786368616e67652e0000000000000000608052600060a05260a46000fd5b508260008061070983610731565b91509150816000528861038052876103a052866103c05261072a8382610dd9565b60406103e0f35b6000806000806000602086033580870194506004356024358160011a6001811695508060071c156107855763ffffffff60208903351696508360048801111561077c5761077c6107ed565b60048701880397505b504263ffffffff8360a01c16111561079f5761079f610844565b4263ffffffff8260a01c16116107b7576107b7610895565b6001600160a01b0381166107cd576107cd6108e2565b506001600160a01b031691508190506107e8576107e861093a565b61098d565b62461bcd60e51b600052600160e51b6020527c2e66696c6c42617463685369676e65644552433732314f726465723a206040527134b73b30b634b21032bc3a3930a230ba309760711b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2866696c6c42617463685369676e65644552433732314f726465723a206040526b3737ba1039ba30b93a32b21760a11b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2466696c6c42617463685369676e65644552433732314f726465723a206040526732bc3834b932b21760c11b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2f66696c6c42617463685369676e65644552433732314f726465723a206040527234b73b30b634b21032b93199182a37b5b2b71760691b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2a66696c6c42617463685369676e65644552433732314f726465723a206040526d34b73b30b634b21036b0b5b2b91760911b606052600060805260846000fd5b610a3161099a8786611831565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000527f27b14c20196091d9cd90ca9c473d3ad1523b00ddf487a9b7452a8a119a16b98c6020527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c604052466060523060805261190160f01b60a05260a060002060a2528160c252604260a0209050919050565b6080604052600060608190529095506064359060843590600435600781901a9190811a9081600a811115610a6757610a6761242f565b03610afe576040805160008152602081018083528b905260ff841691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015610abf573d6000803e3d6000fd5b505050602060405103516001600160a01b0316856001600160a01b031614610af95760405162461bcd60e51b81526004016100d690612445565b610d40565b600381600a811115610b1257610b1261242f565b03610b4057610b24858a8487876118f4565b610af95760405162461bcd60e51b81526004016100d690612445565b600581600a811115610b5457610b5461242f565b03610bed576001600160821b0154600116610bb15760405162461bcd60e51b815260206004820181905260248201527f457468657265756d506572736f6e616c5369676e2069732064697361626c656460448201526064016100d6565b6000610bbc8a611961565b9050610bcb86828588886118f4565b610be75760405162461bcd60e51b81526004016100d690612445565b50610d40565b600781600a811115610c0157610c0161242f565b03610c69576001600160821b0154600216610c5e5760405162461bcd60e51b815260206004820152601f60248201527f426974636f696e506572736f6e616c5369676e2069732064697361626c65640060448201526064016100d6565b6000610bbc8a611999565b600981600a811115610c7d57610c7d61242f565b03610cff576001600160821b0154600416610ce55760405162461bcd60e51b815260206004820152602260248201527f426974636f696e506572736f6e616c5369676e3137332069732064697361626c604482015261195960f21b60648201526084016100d6565b6000610cf08a611999565b9050610bcb8682858888611a94565b60405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21039b4b3b730ba3ab932aa3cb8329760511b60448201526064016100d6565b505050508115610dd15767ffffffffffffffff60601b60243560601c1660443560a01c1780610d6c5750335b60008467ffffffffffffffff811115610d8757610d8761247c565b6040519080825280601f01601f191660200182016040528015610db1576020820181803683370190505b5090508415610dc257848660208301375b610dcd878383611b5d565b5050505b505050915091565b6001600160a01b036004351660205260443560a01c60243560c01c60601b17604052604051610e0757336040525b6001600160a01b036024351660805261012060c0526323b872dd6101c0526020516101e05260405161020052600061024052600160f81b6102c0526020516102e052600560801b6103005260406102e0206102e05260006103605260006103e0526000610400526323b872dd610420523361044052636352211e6104a052600064ffffffffff60043560c81c166001600160a01b0360443516600080865b868110156113e6576001600160a01b0381351660e05260208101356103005263ffffffff60801b6103005160401c166001600160a01b0319823516176103005160021a6103005160011a8115610f265780821115610f0557610f056115cb565b6080821115610f1657610f166115cb565b60e0513b610f2657610f266117f3565b86610140528660008114610f485761ffff6103005160b01c1661032052610f4f565b6000610320525b50610300516001600160a01b03166101808190528015610f7d5761ffff6103005160a01c1661034052610f84565b6000610340525b506127106103405161032051011115610f9f57610f9f61155a565b60006103005160001a600081146111af575b831561119f5760018403935084841a838110610fcf57610fcf6115cb565b808b0160605260605160081c6102c051146110315761024051156110105761028051548c1461100057611000611624565b6102a05161028051556000610240525b60605160081c6102c05260406102c0206102805261028051549b508b6102a0525b600160ff606051161b61026052610260516102a05116611199576040810260408801016001600160e01b038135111561106c5761106c611678565b61107c602082013560e051611471565b1561119757600161024052610260516102a051176102a052803560a0526127106103205160a0510204610160526127106103405160a05102046101a0526101a051610160510160a0510389019850610160518a0199506101a0518401935061022051610100528a6000811461113757610180518015611115576002610120526000805160206125988339815191526101c06000a1611131565b6001610120526000805160206125988339815191526101806000a15b5061118f565b6101805180156111715760016101205261018051610140526101a051610160526000805160206125988339815191526101806000a161118d565b6000610120526000805160206125988339815191526101406000a15b505b506001610360525b505b50610fb1565b6040830260408701019550611399565b831561138d5760018403935084841a8381106111cd576111cd6115cb565b808b0160605260605160081c6102c0511461122f57610240511561120e5761028051548c146111fe576111fe611624565b6102a05161028051556000610240525b60605160081c6102c05260406102c0206102805261028051549b508b6102a0525b600160ff606051161b61026052610260516102a0511661138757602081026040880101356112686001600160a01b03821660e051611471565b1561138557600161024052610260516102a051176102a0528060a01c60a0526127106103205160a0510204610160526127106103405160a05102046101a0526101a051610160510160a0510389019850610160518a0199506101a0518401935061022051610100528a6000811461132557610180518015611303576002610120526000805160206125988339815191526101c06000a161131f565b6001610120526000805160206125988339815191526101806000a15b5061137d565b61018051801561135f5760016101205261018051610140526101a051610160526000805160206125988339815191526101806000a161137b565b6000610120526000805160206125988339815191526101406000a15b505b506001610360525b505b506111af565b60208302604087010195505b509781019780156113dd576103c0516101805114610380516080511416600181146113d0576113cb82610180516114c0565b6113db565b816104005101610400525b505b50505050610ea5565b50610240511561140d576102805154851461140357611403611624565b6102a05161028051555b801561141f5761141f816020516114c0565b508015611459576103a05182146103805160805114166001811461144c5761144782846114c0565b611457565b816103e051016103e0525b505b505050506103605161146d5761146d6116da565b5050565b8161022052600080600060646101dc6000865af1156114ba57826104c05260206104c060246104bc855afa156114ba5760203d036114ba57610200516104c051036114ba575060015b92915050565b60805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8114611544576080513b6114ee576114ee61052b565b816104605282610480526020610480606461043c60006080515af161151557611515611791565b3d1561153f5760203d101561152c5761152c611791565b6001610480511461153f5761153f611791565b505050565b60008060008086865af161153f5761153f61172f565b62461bcd60e51b600052600160e51b6020527c4466696c6c42617463685369676e65644552433732314f726465723a206040527f746f74616c20666565732070657263656e7461676520657863656564732074686060526732903634b6b4ba1760c11b608052600060a05260a46000fd5b62461bcd60e51b600052600160e51b6020527c3066696c6c42617463685369676e65644552433732314f726465723a206040527334b73b30b634b2103334b63632b224b73232bc1760611b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2b66696c6c42617463685369676e65644552433732314f726465723a206040526e3932b2b73a3930b73a1031b0b6361760891b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3b66696c6c42617463685369676e65644552433732314f726465723a206040527f6572633230546f6b656e416d6f756e742065786365656473206c696d69742e00606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2c66696c6c42617463685369676e65644552433732314f726465723a206040526f37379037b93232b9103334b63632b21760811b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3366696c6c42617463685369676e65644552433732314f726465723a206040527f6661696c656420746f207472616e73666572204554482e000000000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3566696c6c42617463685369676e65644552433732314f726465723a206040527f6661696c656420746f207472616e736665722045524332302e00000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c14696e76616c69642065726337323120746f6b656e0000000000000000604052600060605260646000fd5b600061183d8383611d61565b6004356024356044356001600160a01b0383167f2d8cbbbc696e7292c3b5beb38e1363d34ff11beb8c3456c14cb938854597b9ed6000528060205263ffffffff8460a01c1660405260018460011a1663ffffffff8460a01c16808260f81b17606052505064ffffffffff8460c81c166080526001600160a01b03831660a0526001600160a01b03821660c052806101205250505050600160821b610140526040610120205461012052610140600020905092915050565b600080863b1561195757604051631626ba7e8152866020820152604080820152604160608201528460808201528360a08201528560f81b60c082015260208160a5601c84018b5afa1561195557630b135d3f60e11b81510361195557600191505b505b9695505050505050565b600061196c82612101565b60405160200161197c91906124c2565b604051602081830303815290604052805190602001209050919050565b60008060026119a784612101565b6040516020016119b7919061251a565b60408051601f19818403018152908290526119d191612572565b602060405180830381855afa1580156119ee573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611a11919061257e565b60408051602080825281830190925291925060009190602082018180368337019050509050816020820152600281604051611a4c9190612572565b602060405180830381855afa158015611a69573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611a8c919061257e565b949350505050565b600080863b15611acd57604051638da5cb5b81526020816004601c84018b5afa15611acb57600160a01b81511015611acb57805191505b505b6001600160a01b03811615801590611b52575060408051600081526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015611b33573d6000803e3d6000fd5b505050602060405103516001600160a01b0316816001600160a01b0316145b979650505050505050565b80516060906045811015611bac5760405162461bcd60e51b815260206004820152601660248201527527b930b1b6329039b4b3b730ba3ab9329032b93937b960511b60448201526064016100d6565b6000611bd0700400000000000000000000000000000002546001600160a01b031690565b90506001600160a01b038116611bf3575060441901604583019081529050611d5a565b600484015160248501516044860151604587018051604080514681523060208201529081018c9052606081018b905263ffffffff9095166080860181905260a09095206044198801835291975060ff169390428211611c945760405162461bcd60e51b815260206004820152601760248201527f4f7261636c6520646561646c696e65207265616368656400000000000000000060448201526064016100d6565b60408051600081526020810180835283905260ff87169181019190915260608101859052608081018490526001600160a01b0387169060019060a0016020604051602081039080840390855afa158015611cf2573d6000803e3d6000fd5b505050602060405103516001600160a01b031614611d525760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206f7261636c65207369676e6174757265000000000000000060448201526064016100d6565b505050505050505b9392505050565b6000806000845b84811015611f2d576001600160a01b0381351680611d8857611d88611f97565b60208201358060011a80611d9e57611d9e611fef565b8160021a601081118282111715611db757611db7612046565b508160001a611e34578615611dce57611dce61209f565b7f12ad29288fd70022f26997a9958d9eceb6e840ceaa79b72ea5945ba87e4d33b085528260208601526001600160c01b038216604086015260608501602082026040860181818437818320909252608087208752602090960195019350611d6892505050565b86611e765760019650848015611e505760009586209650611e74565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47096505b505b7fb9f488d48cec782be9ecdb74330c9c6a33c236a8022d8a91a4e4df4e81b5162085528260208601526001600160c01b0382166040860152606085019250604081029150604084018281602086013783602083028501855b81811015611f0d577f5f93394997caa49a9382d44a75e3ce6a460f32b39870464866ac994f8be97afe8352606083208152604090920191602001611ece565b505050602091820284209093526080852085529390930192019050611d68565b848114611f3c57611f3c61209f565b50828015611f55578260e0528160002061010052611f8f565b81611f6257611f6261209f565b8160002060e0527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470610100525b505050505050565b62461bcd60e51b600052600160e51b6020527c2f66696c6c42617463685369676e65644552433732314f726465723a206040527234b73b30b634b21037333a20b2323932b9b99760691b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2e66696c6c42617463685369676e65644552433732314f726465723a206040527134b73b30b634b21034ba32b6a1b7bab73a1760711b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3066696c6c42617463685369676e65644552433732314f726465723a206040527334b73b30b634b2103334b63632b221b7bab73a1760611b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3566696c6c42617463685369676e65644552433732314f726465723a206040527f696e76616c696420636f6c6c656374696f6e7342797465732e00000000000000606052600060805260846000fd5b60408051604280825260808201909252606091839190602082018180368337019050509150600360fc1b8260008151811061213e5761213e6123f9565b60200101906001600160f81b031916908160001a905350600f60fb1b8260018151811061216d5761216d6123f9565b60200101906001600160f81b031916908160001a90535060415b60018111156121f5576f181899199a1a9b1b9c1cb0b131b232b360811b82600f16601081106121b8576121b86123f9565b1a60f81b8382815181106121ce576121ce6123f9565b60200101906001600160f81b031916908160001a90535060049190911c9060001901612187565b5050919050565b6000806000806060858703121561221257600080fd5b843567ffffffffffffffff8082111561222a57600080fd5b818701915087601f83011261223e57600080fd5b81358181111561224d57600080fd5b8860208260051b850101111561226257600080fd5b6020928301999098509187013596604001359550909350505050565b600060a0828403121561229057600080fd5b50919050565b60008083601f8401126122a857600080fd5b50813567ffffffffffffffff8111156122c057600080fd5b6020830191508360208285010111156122d857600080fd5b9250929050565b600080600060c084860312156122f457600080fd5b6122fe858561227e565b925060a084013567ffffffffffffffff81111561231a57600080fd5b61232686828701612296565b9497909650939450505050565b80356001600160a01b038116811461234a57600080fd5b919050565b600080600080600080610120878903121561236957600080fd5b612373888861227e565b955061238160a08801612333565b945061238f60c08801612333565b935061239d60e08801612333565b925061010087013567ffffffffffffffff8111156123ba57600080fd5b6123c689828a01612296565b979a9699509497509295939492505050565b818103818111156114ba57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000823560be1983360301811261242557600080fd5b9190910192915050565b634e487b7160e01b600052602160045260246000fd5b6020808252601c908201527f4661696c656420746f2076616c6964617465207369676e617475726500000000604082015260600190565b634e487b7160e01b600052604160045260246000fd5b6000815160005b818110156124b35760208185018101518683015201612499565b50600093019283525090919050565b7f19457468657265756d205369676e6564204d6573736167653a0a313031456c6581527f6d656e742e6d61726b6574206c697374696e672f6f6666657220686173683a0a60208201526000611d5a6040830184612492565b7f18426974636f696e205369676e6564204d6573736167653a0a65456c656d656e81527f742e6d61726b6574206c697374696e672f6f6666657220686173683a0a00000060208201526000611d5a603d830184612492565b6000611d5a8284612492565b60006020828403121561259057600080fd5b505191905056fe9c248aa1a265aa616f707b979d57f4529bb63a4fc34dc7fc61fdddc18410f74ea2646970667358221220d953c6e0cc64f42e83a6e8e4b0a8c33b313010f7f7e55474dfc8217874a939bc64736f6c634300081100330000000000000000000000004300000000000000000000000000000000000004
Deployed Bytecode
0x6080604052600436106100345760003560e01c8063149b8ce614610039578063a4d730411461004e578063dc055ecc14610061575b600080fd5b61004c6100473660046121fc565b610074565b005b61004c61005c3660046122df565b610573565b61004c61006f36600461234f565b61064b565b826100df5760405162461bcd60e51b815260206004820152603060248201527f66696c6c42617463685369676e65644552433732314f72646572733a20696e7660448201526f30b634b2103830b930b6b2ba32b9399760811b60648201526084015b60405180910390fd5b60006100eb34476123d8565b905060006001600160a01b038686600081811061010a5761010a6123f9565b905060200281019061011c919061240f565b604001351690507f00000000000000000000000065f490dfe809dc0cc363c306b675c3e79e118fd77f000000000000000000000000430000000000000000000000000000000000000460a086901c6001600160a01b038088169087166000808085156101b15761018d8630896102b3565b632e1a7d4d600052856020526000806024601c60008b5af16101b1576101b1610418565b63dc055ecc6040528461010052886101205283610140526101206101605260208d028e0195508d5b868110156102475780358f0160a08160603760c081013580610180528060e083016101a037604060008261014401605c8e5af480156102295760019450600051870196506020518601955061023c565b8e60001a1561023c573d6000803e3d6000fd5b5050506020016101d9565b50821561025957610259838a876102b3565b811561026a5761026a8285876102b3565b806102775761027761047a565b50505050505083470361028657005b834711156102a657600080600080874703335af161004c5761004c6104d0565b6102ae6104d0565b610569565b8073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee811461033857813b6102dd576102dd61052b565b6323b872dd600052336020528260405283606052602060006064601c6000865af161030a5761030a6103b6565b3d156103335760203d1015610321576103216103b6565b600160005114610333576103336103b6565b61034e565b60008060008087875af161034e5761034e610354565b50505050565b62461bcd60e51b600052600160e51b6020527c3466696c6c42617463685369676e65644552433732314f72646572733a6040527f206661696c656420746f207472616e73666572204554482e0000000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3666696c6c42617463685369676e65644552433732314f72646572733a6040527f206661696c656420746f207472616e736665722045524332302e000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3466696c6c42617463685369676e65644552433732314f72646572733a6040527f206661696c656420746f207769746864726177204554482e0000000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2d66696c6c42617463685369676e65644552433732314f72646572733a604052701037379037b93232b9103334b63632b21760791b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3266696c6c42617463685369676e65644552433732314f72646572733a60405275103330b4b632b2103a37903932b33ab7321022aa241760511b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c13696e76616c696420657263323020746f6b656e000000000000000000604052600060605260646000fd5b5050505050505050565b600061057f34476123d8565b90508260008061058e83610731565b915091508160005260006103805260006103a05260006103c0526105b28382610dd9565b8347036105bb57005b834711156105db57600080600080874703335af161004c5761004c6105e8565b6105e36105e8565b610642565b62461bcd60e51b600052600160e51b6020527c3166696c6c42617463685369676e65644552433732314f726465723a20604052743330b4b632b2103a37903932b33ab7321022aa241760591b606052600060805260846000fd5b50505050505050565b7f00000000000000000000000065f490dfe809dc0cc363c306b675c3e79e118fd760003082036106fb5762461bcd60e51b600052600160e51b6020527c5464656c656761746543616c6c46696c6c42617463685369676e6564456040527f52433732314f726465723a206d7573742064656c656761746543616c6c2066726060527f6f6d20616e2065787465726e616c2065786368616e67652e0000000000000000608052600060a05260a46000fd5b508260008061070983610731565b91509150816000528861038052876103a052866103c05261072a8382610dd9565b60406103e0f35b6000806000806000602086033580870194506004356024358160011a6001811695508060071c156107855763ffffffff60208903351696508360048801111561077c5761077c6107ed565b60048701880397505b504263ffffffff8360a01c16111561079f5761079f610844565b4263ffffffff8260a01c16116107b7576107b7610895565b6001600160a01b0381166107cd576107cd6108e2565b506001600160a01b031691508190506107e8576107e861093a565b61098d565b62461bcd60e51b600052600160e51b6020527c2e66696c6c42617463685369676e65644552433732314f726465723a206040527134b73b30b634b21032bc3a3930a230ba309760711b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2866696c6c42617463685369676e65644552433732314f726465723a206040526b3737ba1039ba30b93a32b21760a11b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2466696c6c42617463685369676e65644552433732314f726465723a206040526732bc3834b932b21760c11b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2f66696c6c42617463685369676e65644552433732314f726465723a206040527234b73b30b634b21032b93199182a37b5b2b71760691b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2a66696c6c42617463685369676e65644552433732314f726465723a206040526d34b73b30b634b21036b0b5b2b91760911b606052600060805260846000fd5b610a3161099a8786611831565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000527f27b14c20196091d9cd90ca9c473d3ad1523b00ddf487a9b7452a8a119a16b98c6020527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c604052466060523060805261190160f01b60a05260a060002060a2528160c252604260a0209050919050565b6080604052600060608190529095506064359060843590600435600781901a9190811a9081600a811115610a6757610a6761242f565b03610afe576040805160008152602081018083528b905260ff841691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015610abf573d6000803e3d6000fd5b505050602060405103516001600160a01b0316856001600160a01b031614610af95760405162461bcd60e51b81526004016100d690612445565b610d40565b600381600a811115610b1257610b1261242f565b03610b4057610b24858a8487876118f4565b610af95760405162461bcd60e51b81526004016100d690612445565b600581600a811115610b5457610b5461242f565b03610bed576001600160821b0154600116610bb15760405162461bcd60e51b815260206004820181905260248201527f457468657265756d506572736f6e616c5369676e2069732064697361626c656460448201526064016100d6565b6000610bbc8a611961565b9050610bcb86828588886118f4565b610be75760405162461bcd60e51b81526004016100d690612445565b50610d40565b600781600a811115610c0157610c0161242f565b03610c69576001600160821b0154600216610c5e5760405162461bcd60e51b815260206004820152601f60248201527f426974636f696e506572736f6e616c5369676e2069732064697361626c65640060448201526064016100d6565b6000610bbc8a611999565b600981600a811115610c7d57610c7d61242f565b03610cff576001600160821b0154600416610ce55760405162461bcd60e51b815260206004820152602260248201527f426974636f696e506572736f6e616c5369676e3137332069732064697361626c604482015261195960f21b60648201526084016100d6565b6000610cf08a611999565b9050610bcb8682858888611a94565b60405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21039b4b3b730ba3ab932aa3cb8329760511b60448201526064016100d6565b505050508115610dd15767ffffffffffffffff60601b60243560601c1660443560a01c1780610d6c5750335b60008467ffffffffffffffff811115610d8757610d8761247c565b6040519080825280601f01601f191660200182016040528015610db1576020820181803683370190505b5090508415610dc257848660208301375b610dcd878383611b5d565b5050505b505050915091565b6001600160a01b036004351660205260443560a01c60243560c01c60601b17604052604051610e0757336040525b6001600160a01b036024351660805261012060c0526323b872dd6101c0526020516101e05260405161020052600061024052600160f81b6102c0526020516102e052600560801b6103005260406102e0206102e05260006103605260006103e0526000610400526323b872dd610420523361044052636352211e6104a052600064ffffffffff60043560c81c166001600160a01b0360443516600080865b868110156113e6576001600160a01b0381351660e05260208101356103005263ffffffff60801b6103005160401c166001600160a01b0319823516176103005160021a6103005160011a8115610f265780821115610f0557610f056115cb565b6080821115610f1657610f166115cb565b60e0513b610f2657610f266117f3565b86610140528660008114610f485761ffff6103005160b01c1661032052610f4f565b6000610320525b50610300516001600160a01b03166101808190528015610f7d5761ffff6103005160a01c1661034052610f84565b6000610340525b506127106103405161032051011115610f9f57610f9f61155a565b60006103005160001a600081146111af575b831561119f5760018403935084841a838110610fcf57610fcf6115cb565b808b0160605260605160081c6102c051146110315761024051156110105761028051548c1461100057611000611624565b6102a05161028051556000610240525b60605160081c6102c05260406102c0206102805261028051549b508b6102a0525b600160ff606051161b61026052610260516102a05116611199576040810260408801016001600160e01b038135111561106c5761106c611678565b61107c602082013560e051611471565b1561119757600161024052610260516102a051176102a052803560a0526127106103205160a0510204610160526127106103405160a05102046101a0526101a051610160510160a0510389019850610160518a0199506101a0518401935061022051610100528a6000811461113757610180518015611115576002610120526000805160206125988339815191526101c06000a1611131565b6001610120526000805160206125988339815191526101806000a15b5061118f565b6101805180156111715760016101205261018051610140526101a051610160526000805160206125988339815191526101806000a161118d565b6000610120526000805160206125988339815191526101406000a15b505b506001610360525b505b50610fb1565b6040830260408701019550611399565b831561138d5760018403935084841a8381106111cd576111cd6115cb565b808b0160605260605160081c6102c0511461122f57610240511561120e5761028051548c146111fe576111fe611624565b6102a05161028051556000610240525b60605160081c6102c05260406102c0206102805261028051549b508b6102a0525b600160ff606051161b61026052610260516102a0511661138757602081026040880101356112686001600160a01b03821660e051611471565b1561138557600161024052610260516102a051176102a0528060a01c60a0526127106103205160a0510204610160526127106103405160a05102046101a0526101a051610160510160a0510389019850610160518a0199506101a0518401935061022051610100528a6000811461132557610180518015611303576002610120526000805160206125988339815191526101c06000a161131f565b6001610120526000805160206125988339815191526101806000a15b5061137d565b61018051801561135f5760016101205261018051610140526101a051610160526000805160206125988339815191526101806000a161137b565b6000610120526000805160206125988339815191526101406000a15b505b506001610360525b505b506111af565b60208302604087010195505b509781019780156113dd576103c0516101805114610380516080511416600181146113d0576113cb82610180516114c0565b6113db565b816104005101610400525b505b50505050610ea5565b50610240511561140d576102805154851461140357611403611624565b6102a05161028051555b801561141f5761141f816020516114c0565b508015611459576103a05182146103805160805114166001811461144c5761144782846114c0565b611457565b816103e051016103e0525b505b505050506103605161146d5761146d6116da565b5050565b8161022052600080600060646101dc6000865af1156114ba57826104c05260206104c060246104bc855afa156114ba5760203d036114ba57610200516104c051036114ba575060015b92915050565b60805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8114611544576080513b6114ee576114ee61052b565b816104605282610480526020610480606461043c60006080515af161151557611515611791565b3d1561153f5760203d101561152c5761152c611791565b6001610480511461153f5761153f611791565b505050565b60008060008086865af161153f5761153f61172f565b62461bcd60e51b600052600160e51b6020527c4466696c6c42617463685369676e65644552433732314f726465723a206040527f746f74616c20666565732070657263656e7461676520657863656564732074686060526732903634b6b4ba1760c11b608052600060a05260a46000fd5b62461bcd60e51b600052600160e51b6020527c3066696c6c42617463685369676e65644552433732314f726465723a206040527334b73b30b634b2103334b63632b224b73232bc1760611b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2b66696c6c42617463685369676e65644552433732314f726465723a206040526e3932b2b73a3930b73a1031b0b6361760891b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3b66696c6c42617463685369676e65644552433732314f726465723a206040527f6572633230546f6b656e416d6f756e742065786365656473206c696d69742e00606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2c66696c6c42617463685369676e65644552433732314f726465723a206040526f37379037b93232b9103334b63632b21760811b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3366696c6c42617463685369676e65644552433732314f726465723a206040527f6661696c656420746f207472616e73666572204554482e000000000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3566696c6c42617463685369676e65644552433732314f726465723a206040527f6661696c656420746f207472616e736665722045524332302e00000000000000606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c14696e76616c69642065726337323120746f6b656e0000000000000000604052600060605260646000fd5b600061183d8383611d61565b6004356024356044356001600160a01b0383167f2d8cbbbc696e7292c3b5beb38e1363d34ff11beb8c3456c14cb938854597b9ed6000528060205263ffffffff8460a01c1660405260018460011a1663ffffffff8460a01c16808260f81b17606052505064ffffffffff8460c81c166080526001600160a01b03831660a0526001600160a01b03821660c052806101205250505050600160821b610140526040610120205461012052610140600020905092915050565b600080863b1561195757604051631626ba7e8152866020820152604080820152604160608201528460808201528360a08201528560f81b60c082015260208160a5601c84018b5afa1561195557630b135d3f60e11b81510361195557600191505b505b9695505050505050565b600061196c82612101565b60405160200161197c91906124c2565b604051602081830303815290604052805190602001209050919050565b60008060026119a784612101565b6040516020016119b7919061251a565b60408051601f19818403018152908290526119d191612572565b602060405180830381855afa1580156119ee573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611a11919061257e565b60408051602080825281830190925291925060009190602082018180368337019050509050816020820152600281604051611a4c9190612572565b602060405180830381855afa158015611a69573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611a8c919061257e565b949350505050565b600080863b15611acd57604051638da5cb5b81526020816004601c84018b5afa15611acb57600160a01b81511015611acb57805191505b505b6001600160a01b03811615801590611b52575060408051600081526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015611b33573d6000803e3d6000fd5b505050602060405103516001600160a01b0316816001600160a01b0316145b979650505050505050565b80516060906045811015611bac5760405162461bcd60e51b815260206004820152601660248201527527b930b1b6329039b4b3b730ba3ab9329032b93937b960511b60448201526064016100d6565b6000611bd0700400000000000000000000000000000002546001600160a01b031690565b90506001600160a01b038116611bf3575060441901604583019081529050611d5a565b600484015160248501516044860151604587018051604080514681523060208201529081018c9052606081018b905263ffffffff9095166080860181905260a09095206044198801835291975060ff169390428211611c945760405162461bcd60e51b815260206004820152601760248201527f4f7261636c6520646561646c696e65207265616368656400000000000000000060448201526064016100d6565b60408051600081526020810180835283905260ff87169181019190915260608101859052608081018490526001600160a01b0387169060019060a0016020604051602081039080840390855afa158015611cf2573d6000803e3d6000fd5b505050602060405103516001600160a01b031614611d525760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206f7261636c65207369676e6174757265000000000000000060448201526064016100d6565b505050505050505b9392505050565b6000806000845b84811015611f2d576001600160a01b0381351680611d8857611d88611f97565b60208201358060011a80611d9e57611d9e611fef565b8160021a601081118282111715611db757611db7612046565b508160001a611e34578615611dce57611dce61209f565b7f12ad29288fd70022f26997a9958d9eceb6e840ceaa79b72ea5945ba87e4d33b085528260208601526001600160c01b038216604086015260608501602082026040860181818437818320909252608087208752602090960195019350611d6892505050565b86611e765760019650848015611e505760009586209650611e74565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47096505b505b7fb9f488d48cec782be9ecdb74330c9c6a33c236a8022d8a91a4e4df4e81b5162085528260208601526001600160c01b0382166040860152606085019250604081029150604084018281602086013783602083028501855b81811015611f0d577f5f93394997caa49a9382d44a75e3ce6a460f32b39870464866ac994f8be97afe8352606083208152604090920191602001611ece565b505050602091820284209093526080852085529390930192019050611d68565b848114611f3c57611f3c61209f565b50828015611f55578260e0528160002061010052611f8f565b81611f6257611f6261209f565b8160002060e0527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470610100525b505050505050565b62461bcd60e51b600052600160e51b6020527c2f66696c6c42617463685369676e65644552433732314f726465723a206040527234b73b30b634b21037333a20b2323932b9b99760691b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c2e66696c6c42617463685369676e65644552433732314f726465723a206040527134b73b30b634b21034ba32b6a1b7bab73a1760711b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3066696c6c42617463685369676e65644552433732314f726465723a206040527334b73b30b634b2103334b63632b221b7bab73a1760611b606052600060805260846000fd5b62461bcd60e51b600052600160e51b6020527c3566696c6c42617463685369676e65644552433732314f726465723a206040527f696e76616c696420636f6c6c656374696f6e7342797465732e00000000000000606052600060805260846000fd5b60408051604280825260808201909252606091839190602082018180368337019050509150600360fc1b8260008151811061213e5761213e6123f9565b60200101906001600160f81b031916908160001a905350600f60fb1b8260018151811061216d5761216d6123f9565b60200101906001600160f81b031916908160001a90535060415b60018111156121f5576f181899199a1a9b1b9c1cb0b131b232b360811b82600f16601081106121b8576121b86123f9565b1a60f81b8382815181106121ce576121ce6123f9565b60200101906001600160f81b031916908160001a90535060049190911c9060001901612187565b5050919050565b6000806000806060858703121561221257600080fd5b843567ffffffffffffffff8082111561222a57600080fd5b818701915087601f83011261223e57600080fd5b81358181111561224d57600080fd5b8860208260051b850101111561226257600080fd5b6020928301999098509187013596604001359550909350505050565b600060a0828403121561229057600080fd5b50919050565b60008083601f8401126122a857600080fd5b50813567ffffffffffffffff8111156122c057600080fd5b6020830191508360208285010111156122d857600080fd5b9250929050565b600080600060c084860312156122f457600080fd5b6122fe858561227e565b925060a084013567ffffffffffffffff81111561231a57600080fd5b61232686828701612296565b9497909650939450505050565b80356001600160a01b038116811461234a57600080fd5b919050565b600080600080600080610120878903121561236957600080fd5b612373888861227e565b955061238160a08801612333565b945061238f60c08801612333565b935061239d60e08801612333565b925061010087013567ffffffffffffffff8111156123ba57600080fd5b6123c689828a01612296565b979a9699509497509295939492505050565b818103818111156114ba57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000823560be1983360301811261242557600080fd5b9190910192915050565b634e487b7160e01b600052602160045260246000fd5b6020808252601c908201527f4661696c656420746f2076616c6964617465207369676e617475726500000000604082015260600190565b634e487b7160e01b600052604160045260246000fd5b6000815160005b818110156124b35760208185018101518683015201612499565b50600093019283525090919050565b7f19457468657265756d205369676e6564204d6573736167653a0a313031456c6581527f6d656e742e6d61726b6574206c697374696e672f6f6666657220686173683a0a60208201526000611d5a6040830184612492565b7f18426974636f696e205369676e6564204d6573736167653a0a65456c656d656e81527f742e6d61726b6574206c697374696e672f6f6666657220686173683a0a00000060208201526000611d5a603d830184612492565b6000611d5a8284612492565b60006020828403121561259057600080fd5b505191905056fe9c248aa1a265aa616f707b979d57f4529bb63a4fc34dc7fc61fdddc18410f74ea2646970667358221220d953c6e0cc64f42e83a6e8e4b0a8c33b313010f7f7e55474dfc8217874a939bc64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004300000000000000000000000000000000000004
-----Decoded View---------------
Arg [0] : weth (address): 0x4300000000000000000000000000000000000004
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004300000000000000000000000000000000000004
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.