编译器
0.8.17+commit.8df45f5f
文件 1 的 14:CollectionType.sol
pragma solidity 0.8.17;
enum CollectionType {
ERC721,
ERC1155
}
文件 2 的 14:GenericErrors.sol
pragma solidity ^0.8.17;
error NotAContract();
文件 3 的 14:IERC1155.sol
pragma solidity ^0.8.17;
interface IERC1155 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
文件 4 的 14:IERC721.sol
pragma solidity ^0.8.17;
interface IERC721 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 5 的 14:IOwnableTwoSteps.sol
pragma solidity ^0.8.17;
interface IOwnableTwoSteps {
enum Status {
NoOngoingTransfer,
TransferInProgress,
RenouncementInProgress
}
error NoOngoingTransferInProgress();
error NotOwner();
error RenouncementNotInProgress();
error TransferAlreadyInProgress();
error TransferNotInProgress();
error WrongPotentialOwner();
event CancelOwnershipTransfer();
event InitiateOwnershipRenouncement();
event InitiateOwnershipTransfer(address previousOwner, address potentialOwner);
event NewOwner(address newOwner);
}
文件 6 的 14:ITransferManager.sol
pragma solidity 0.8.17;
import {OrderStructs} from "../libraries/OrderStructs.sol";
import {CollectionType} from "../enums/CollectionType.sol";
interface ITransferManager {
struct BatchTransferItem {
address collection;
CollectionType collectionType;
uint256[] itemIds;
uint256[] amounts;
}
event ApprovalsGranted(address user, address[] operators);
event ApprovalsRemoved(address user, address[] operators);
event OperatorAllowed(address operator);
event OperatorRemoved(address operator);
error OperatorAlreadyApprovedByUser();
error OperatorNotApprovedByUser();
error OperatorAlreadyAllowed();
error OperatorNotAllowed();
error TransferCallerInvalid();
}
文件 7 的 14:LowLevelERC1155Transfer.sol
pragma solidity ^0.8.17;
import {IERC1155} from "../interfaces/generic/IERC1155.sol";
import {ERC1155SafeTransferFromFail, ERC1155SafeBatchTransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";
contract LowLevelERC1155Transfer {
function _executeERC1155SafeTransferFrom(
address collection,
address from,
address to,
uint256 tokenId,
uint256 amount
) internal {
if (collection.code.length == 0) {
revert NotAContract();
}
(bool status, ) = collection.call(abi.encodeCall(IERC1155.safeTransferFrom, (from, to, tokenId, amount, "")));
if (!status) {
revert ERC1155SafeTransferFromFail();
}
}
function _executeERC1155SafeBatchTransferFrom(
address collection,
address from,
address to,
uint256[] calldata tokenIds,
uint256[] calldata amounts
) internal {
if (collection.code.length == 0) {
revert NotAContract();
}
(bool status, ) = collection.call(
abi.encodeCall(IERC1155.safeBatchTransferFrom, (from, to, tokenIds, amounts, ""))
);
if (!status) {
revert ERC1155SafeBatchTransferFromFail();
}
}
}
文件 8 的 14:LowLevelERC721Transfer.sol
pragma solidity ^0.8.17;
import {IERC721} from "../interfaces/generic/IERC721.sol";
import {ERC721TransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";
contract LowLevelERC721Transfer {
function _executeERC721TransferFrom(address collection, address from, address to, uint256 tokenId) internal {
if (collection.code.length == 0) {
revert NotAContract();
}
(bool status, ) = collection.call(abi.encodeCall(IERC721.transferFrom, (from, to, tokenId)));
if (!status) {
revert ERC721TransferFromFail();
}
}
}
文件 9 的 14:LowLevelErrors.sol
pragma solidity ^0.8.17;
error ETHTransferFail();
error ERC20ApprovalFail();
error ERC20TransferFail();
error ERC20TransferFromFail();
error ERC721TransferFromFail();
error ERC1155SafeTransferFromFail();
error ERC1155SafeBatchTransferFromFail();
文件 10 的 14:OrderStructs.sol
pragma solidity 0.8.17;
import {CollectionType} from "../enums/CollectionType.sol";
import {QuoteType} from "../enums/QuoteType.sol";
library OrderStructs {
struct Maker {
QuoteType quoteType;
uint256 globalNonce;
uint256 subsetNonce;
uint256 orderNonce;
uint256 strategyId;
CollectionType collectionType;
address collection;
address currency;
address signer;
uint256 startTime;
uint256 endTime;
uint256 price;
uint256[] itemIds;
uint256[] amounts;
bytes additionalParameters;
}
struct Taker {
address recipient;
bytes additionalParameters;
}
enum MerkleTreeNodePosition { Left, Right }
struct MerkleTreeNode {
bytes32 value;
MerkleTreeNodePosition position;
}
struct MerkleTree {
bytes32 root;
MerkleTreeNode[] proof;
}
bytes32 internal constant _MAKER_TYPEHASH =
keccak256(
"Maker("
"uint8 quoteType,"
"uint256 globalNonce,"
"uint256 subsetNonce,"
"uint256 orderNonce,"
"uint256 strategyId,"
"uint8 collectionType,"
"address collection,"
"address currency,"
"address signer,"
"uint256 startTime,"
"uint256 endTime,"
"uint256 price,"
"uint256[] itemIds,"
"uint256[] amounts,"
"bytes additionalParameters"
")"
);
function hash(Maker memory maker) internal pure returns (bytes32) {
return
keccak256(
bytes.concat(
abi.encode(
_MAKER_TYPEHASH,
maker.quoteType,
maker.globalNonce,
maker.subsetNonce,
maker.orderNonce,
maker.strategyId,
maker.collectionType,
maker.collection,
maker.currency
),
abi.encode(
maker.signer,
maker.startTime,
maker.endTime,
maker.price,
keccak256(abi.encodePacked(maker.itemIds)),
keccak256(abi.encodePacked(maker.amounts)),
keccak256(maker.additionalParameters)
)
)
);
}
}
文件 11 的 14:OwnableTwoSteps.sol
pragma solidity ^0.8.17;
import {IOwnableTwoSteps} from "./interfaces/IOwnableTwoSteps.sol";
abstract contract OwnableTwoSteps is IOwnableTwoSteps {
address public owner;
address public potentialOwner;
Status public ownershipStatus;
modifier onlyOwner() {
_onlyOwner();
_;
}
constructor(address _owner) {
owner = _owner;
emit NewOwner(_owner);
}
function cancelOwnershipTransfer() external onlyOwner {
Status _ownershipStatus = ownershipStatus;
if (_ownershipStatus == Status.NoOngoingTransfer) {
revert NoOngoingTransferInProgress();
}
if (_ownershipStatus == Status.TransferInProgress) {
delete potentialOwner;
}
delete ownershipStatus;
emit CancelOwnershipTransfer();
}
function confirmOwnershipRenouncement() external onlyOwner {
if (ownershipStatus != Status.RenouncementInProgress) {
revert RenouncementNotInProgress();
}
delete owner;
delete ownershipStatus;
emit NewOwner(address(0));
}
function confirmOwnershipTransfer() external {
if (ownershipStatus != Status.TransferInProgress) {
revert TransferNotInProgress();
}
if (msg.sender != potentialOwner) {
revert WrongPotentialOwner();
}
owner = msg.sender;
delete ownershipStatus;
delete potentialOwner;
emit NewOwner(msg.sender);
}
function initiateOwnershipTransfer(address newPotentialOwner) external onlyOwner {
if (ownershipStatus != Status.NoOngoingTransfer) {
revert TransferAlreadyInProgress();
}
ownershipStatus = Status.TransferInProgress;
potentialOwner = newPotentialOwner;
emit InitiateOwnershipTransfer(msg.sender, newPotentialOwner);
}
function initiateOwnershipRenouncement() external onlyOwner {
if (ownershipStatus != Status.NoOngoingTransfer) {
revert TransferAlreadyInProgress();
}
ownershipStatus = Status.RenouncementInProgress;
emit InitiateOwnershipRenouncement();
}
function _onlyOwner() private view {
if (msg.sender != owner) revert NotOwner();
}
}
文件 12 的 14:QuoteType.sol
pragma solidity 0.8.17;
enum QuoteType {
Bid,
Ask
}
文件 13 的 14:SharedErrors.sol
pragma solidity 0.8.17;
error AmountInvalid();
error AskTooHigh();
error BidTooLow();
error CallerInvalid();
error CurrencyInvalid();
error FunctionSelectorInvalid();
error LengthsInvalid();
error MerkleProofInvalid();
error MerkleProofTooLarge(uint256 length);
error OrderInvalid();
error QuoteTypeInvalid();
文件 14 的 14:TransferManager.sol
pragma solidity 0.8.17;
import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol";
import {LowLevelERC721Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC721Transfer.sol";
import {LowLevelERC1155Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC1155Transfer.sol";
import {ITransferManager} from "./interfaces/ITransferManager.sol";
import {AmountInvalid, LengthsInvalid} from "./errors/SharedErrors.sol";
import {OrderStructs} from "./libraries/OrderStructs.sol";
import {CollectionType} from "./enums/CollectionType.sol";
contract TransferManager is ITransferManager, LowLevelERC721Transfer, LowLevelERC1155Transfer, OwnableTwoSteps {
mapping(address => mapping(address => bool)) public hasUserApprovedOperator;
mapping(address => bool) public isOperatorAllowed;
constructor(address _owner) OwnableTwoSteps(_owner) {}
function transferItemsERC721(
address collection,
address from,
address to,
uint256[] calldata itemIds,
uint256[] calldata amounts
) external {
uint256 length = itemIds.length;
if (length == 0) {
revert LengthsInvalid();
}
_isOperatorValidForTransfer(from, msg.sender);
for (uint256 i; i < length; ) {
if (amounts[i] != 1) {
revert AmountInvalid();
}
_executeERC721TransferFrom(collection, from, to, itemIds[i]);
unchecked {
++i;
}
}
}
function transferItemsERC1155(
address collection,
address from,
address to,
uint256[] calldata itemIds,
uint256[] calldata amounts
) external {
uint256 length = itemIds.length;
if (length == 0 || amounts.length != length) {
revert LengthsInvalid();
}
_isOperatorValidForTransfer(from, msg.sender);
if (length == 1) {
if (amounts[0] == 0) {
revert AmountInvalid();
}
_executeERC1155SafeTransferFrom(collection, from, to, itemIds[0], amounts[0]);
} else {
for (uint256 i; i < length; ) {
if (amounts[i] == 0) {
revert AmountInvalid();
}
unchecked {
++i;
}
}
_executeERC1155SafeBatchTransferFrom(collection, from, to, itemIds, amounts);
}
}
function transferBatchItemsAcrossCollections(
BatchTransferItem[] calldata items,
address from,
address to
) external {
uint256 itemsLength = items.length;
if (itemsLength == 0) {
revert LengthsInvalid();
}
if (from != msg.sender) {
_isOperatorValidForTransfer(from, msg.sender);
}
for (uint256 i; i < itemsLength; ) {
uint256[] calldata itemIds = items[i].itemIds;
uint256 itemIdsLengthForSingleCollection = itemIds.length;
uint256[] calldata amounts = items[i].amounts;
if (itemIdsLengthForSingleCollection == 0 || amounts.length != itemIdsLengthForSingleCollection) {
revert LengthsInvalid();
}
CollectionType collectionType = items[i].collectionType;
if (collectionType == CollectionType.ERC721) {
for (uint256 j; j < itemIdsLengthForSingleCollection; ) {
if (amounts[j] != 1) {
revert AmountInvalid();
}
_executeERC721TransferFrom(items[i].collection, from, to, itemIds[j]);
unchecked {
++j;
}
}
} else if (collectionType == CollectionType.ERC1155) {
for (uint256 j; j < itemIdsLengthForSingleCollection; ) {
if (amounts[j] == 0) {
revert AmountInvalid();
}
unchecked {
++j;
}
}
_executeERC1155SafeBatchTransferFrom(items[i].collection, from, to, itemIds, amounts);
}
unchecked {
++i;
}
}
}
function grantApprovals(address[] calldata operators) external {
uint256 length = operators.length;
if (length == 0) {
revert LengthsInvalid();
}
for (uint256 i; i < length; ) {
address operator = operators[i];
if (!isOperatorAllowed[operator]) {
revert OperatorNotAllowed();
}
if (hasUserApprovedOperator[msg.sender][operator]) {
revert OperatorAlreadyApprovedByUser();
}
hasUserApprovedOperator[msg.sender][operator] = true;
unchecked {
++i;
}
}
emit ApprovalsGranted(msg.sender, operators);
}
function revokeApprovals(address[] calldata operators) external {
uint256 length = operators.length;
if (length == 0) {
revert LengthsInvalid();
}
for (uint256 i; i < length; ) {
address operator = operators[i];
if (!hasUserApprovedOperator[msg.sender][operator]) {
revert OperatorNotApprovedByUser();
}
delete hasUserApprovedOperator[msg.sender][operator];
unchecked {
++i;
}
}
emit ApprovalsRemoved(msg.sender, operators);
}
function allowOperator(address operator) external onlyOwner {
if (isOperatorAllowed[operator]) {
revert OperatorAlreadyAllowed();
}
isOperatorAllowed[operator] = true;
emit OperatorAllowed(operator);
}
function removeOperator(address operator) external onlyOwner {
if (!isOperatorAllowed[operator]) {
revert OperatorNotAllowed();
}
delete isOperatorAllowed[operator];
emit OperatorRemoved(operator);
}
function _isOperatorValidForTransfer(address user, address operator) private view {
if (isOperatorAllowed[operator] && hasUserApprovedOperator[user][operator]) {
return;
}
revert TransferCallerInvalid();
}
}
{
"compilationTarget": {
"contracts/TransferManager.sol": "TransferManager"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 888888
},
"remappings": [
":@chainlink/=node_modules/@chainlink/",
":@ensdomains/=node_modules/@ensdomains/",
":@eth-optimism/=node_modules/@eth-optimism/",
":@looksrare/=node_modules/@looksrare/",
":@openzeppelin/=node_modules/@openzeppelin/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":eth-gas-reporter/=node_modules/eth-gas-reporter/",
":forge-std/=lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":murky/=lib/murky/src/",
":openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",
":solmate/=node_modules/solmate/"
]
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountInvalid","type":"error"},{"inputs":[],"name":"ERC1155SafeBatchTransferFromFail","type":"error"},{"inputs":[],"name":"ERC1155SafeTransferFromFail","type":"error"},{"inputs":[],"name":"ERC721TransferFromFail","type":"error"},{"inputs":[],"name":"LengthsInvalid","type":"error"},{"inputs":[],"name":"NoOngoingTransferInProgress","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"OperatorAlreadyAllowed","type":"error"},{"inputs":[],"name":"OperatorAlreadyApprovedByUser","type":"error"},{"inputs":[],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"OperatorNotApprovedByUser","type":"error"},{"inputs":[],"name":"RenouncementNotInProgress","type":"error"},{"inputs":[],"name":"TransferAlreadyInProgress","type":"error"},{"inputs":[],"name":"TransferCallerInvalid","type":"error"},{"inputs":[],"name":"TransferNotInProgress","type":"error"},{"inputs":[],"name":"WrongPotentialOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address[]","name":"operators","type":"address[]"}],"name":"ApprovalsGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address[]","name":"operators","type":"address[]"}],"name":"ApprovalsRemoved","type":"event"},{"anonymous":false,"inputs":[],"name":"CancelOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[],"name":"InitiateOwnershipRenouncement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"potentialOwner","type":"address"}],"name":"InitiateOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"allowOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"operators","type":"address[]"}],"name":"grantApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"hasUserApprovedOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initiateOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"initiateOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isOperatorAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipStatus","outputs":[{"internalType":"enum IOwnableTwoSteps.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"potentialOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"removeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"operators","type":"address[]"}],"name":"revokeApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct ITransferManager.BatchTransferItem[]","name":"items","type":"tuple[]"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"transferBatchItemsAcrossCollections","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"transferItemsERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"transferItemsERC721","outputs":[],"stateMutability":"nonpayable","type":"function"}]