Blockchain / Global / Address

Contract

0x002d5df82f997f945914b524E5e98103c7dB0730

Balance
0 SOMI
Transactions sent
1
Type
Contract · 6,247 bytes of code

KeyFarmMarketplaceV3 Verified

Compiler
solc 0.8.17+commit.8df45f5f
Language
Solidity
Optimization
Yes, 200 runs
EVM version
—
License
—
Verified
2026-10-12

KeyFarmMarketplaceV3.sol

Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC165 { function supportsInterface(bytes4 interfaceId) external view returns (bool); }
interface IERC721 is IERC165 {
    function ownerOf(uint256 tokenId) external view returns (address);
    function transferFrom(address from, address to, uint256 tokenId) external;
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
interface IERC1155 is IERC165 {
    function balanceOf(address account, uint256 id) external view returns (uint256);
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
    function isApprovedForAll(address account, address operator) external view returns (bool);
}
interface IERC2981 is IERC165 {
    function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount);
}

abstract contract ReentrancyGuard {
    uint256 private _status;
    constructor() { _status = 1; }
    modifier nonReentrant() {
        require(_status == 1, "ReentrancyGuard: reentrant call");
        _status = 2;
        _;
        _status = 1;
    }
}

abstract contract Ownable {
    address public owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    constructor() { owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); }
    modifier onlyOwner(){ require(msg.sender == owner, "Ownable: caller is not owner"); _; }
    function transferOwnership(address newOwner) external onlyOwner { require(newOwner!=address(0), "zero"); emit OwnershipTransferred(owner, newOwner); owner = newOwner; }
}

contract KeyFarmMarketplaceV3 is ReentrancyGuard, Ownable {
    enum TokenStandard { ERC721, ERC1155 }

    struct Order {
        address seller;
        address nftContract;
        uint256 tokenId;
        uint256 amount; // for ERC1155; for ERC721 must be 1
        uint256 price;  // wei
        TokenStandard std;
        bool skipRoyalties;
        uint256 expiry; // unix timestamp, 0 = no expiry
        uint256 nonce;  // to allow seller unique orders
    }

    // EIP-712 domain
    bytes32 public DOMAIN_SEPARATOR;
    bytes32 public constant ORDER_TYPEHASH = keccak256("Order(address seller,address nftContract,uint256 tokenId,uint256 amount,uint256 price,uint8 std,bool skipRoyalties,uint256 expiry,uint256 nonce)");

    // orders used or cancelled
    mapping(bytes32 => bool) public usedOrders;

    // platform fee
    uint16 public platformFeeBps;
    uint256 public accruedPlatformFees;

    // volume tracking
    uint256 public totalVolumeTraded;
    mapping(address => uint256) public volumeByCollection;
    mapping(address => uint256) public volumeBySeller;
    mapping(address => uint256) public volumeByBuyer;

    event OrderExecuted(bytes32 indexed orderHash, address indexed seller, address indexed buyer, uint256 price);
    event OrderCancelled(bytes32 indexed orderHash, address indexed seller);
    event PlatformFeeUpdated(uint16 newBps);
    event WithdrawnFees(address to, uint256 amount);

    constructor(string memory name, string memory version, uint16 _platformFeeBps) {
        require(_platformFeeBps <= 10000, "bps>10000");
        platformFeeBps = _platformFeeBps;
        uint256 chainId;
        assembly { chainId := chainid() }
        DOMAIN_SEPARATOR = keccak256(abi.encode(
            keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            keccak256(bytes(name)),
            keccak256(bytes(version)),
            chainId,
            address(this)
        ));
    }

    // owner functions
    function setPlatformFeeBps(uint16 bps) external onlyOwner { require(bps<=10000, "bps>10000"); platformFeeBps=bps; emit PlatformFeeUpdated(bps); }
    function withdrawFees(address payable to) external onlyOwner nonReentrant { require(to!=address(0),"zero"); uint256 amt = accruedPlatformFees; require(amt>0,"no fees"); accruedPlatformFees=0; (bool ok,) = to.call{value:amt}(""); require(ok,"transfer failed"); emit WithdrawnFees(to, amt); }

    // helper: supports ERC2981
    function _supportsRoyalty(address nft) internal view returns (bool) {
        try IERC165(nft).supportsInterface(type(IERC2981).interfaceId) returns (bool ok) { return ok; } catch { return false; }
    }

    // hash order
    function _hashOrder(Order memory o) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            ORDER_TYPEHASH,
            o.seller,
            o.nftContract,
            o.tokenId,
            o.amount,
            o.price,
            uint8(o.std),
            o.skipRoyalties,
            o.expiry,
            o.nonce
        ));
    }

    function _toTypedMessageHash(bytes32 structHash) internal view returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash));
    }

    // verify that signature was signed by seller
    function _recoverSigner(bytes32 digest, bytes memory signature) internal pure returns (address) {
        require(signature.length == 65, "invalid sig");
        bytes32 r; bytes32 s; uint8 v;
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }
        if (v < 27) v += 27;
        require(v==27 || v==28, "invalid v");
        return ecrecover(digest, v, r, s);
    }

    // public view to compute order hash (useful for UI)
    function orderHash(Order memory o) public view returns (bytes32) {
        return _toTypedMessageHash(_hashOrder(o));
    }

    // Internal helper: settle payments (royalty + platform fee), transfer NFT.
    // Separated out to avoid "stack too deep" in executeOrder.
    function _settleAndTransfer(
        address seller,
        address nftContract,
        uint256 tokenId,
        uint256 amount,
        uint256 salePrice,
        TokenStandard std,
        bool skipRoyalties,
        address buyer
    ) internal {
        // compute platform fee & remaining
        uint256 platformFee = (salePrice * platformFeeBps) / 10000;
        uint256 remaining = salePrice - platformFee;

        // royalty only for ERC721 (as per policy)
        if (std == TokenStandard.ERC721 && !skipRoyalties && _supportsRoyalty(nftContract)) {
            try IERC2981(nftContract).royaltyInfo(tokenId, salePrice) returns (address receiver, uint256 royaltyAmount) {
                if (receiver != address(0) && royaltyAmount > 0) {
                    if (royaltyAmount > remaining) royaltyAmount = remaining;
                    remaining -= royaltyAmount;
                    (bool okr,) = payable(receiver).call{value: royaltyAmount}("");
                    if (!okr) {
                        // fallback: add royalty to accrued platform fees
                        accruedPlatformFees += royaltyAmount;
                    }
                }
            } catch {
                // ignore royalty failures
            }
        }

        // transfer remaining to seller
        (bool okSeller,) = payable(seller).call{value: remaining}("");
        require(okSeller, "seller transfer failed");

        // accrue platform fee
        accruedPlatformFees += platformFee;

        // transfer NFT: ERC721 or ERC1155
        if (std == TokenStandard.ERC721) {
            IERC721(nftContract).transferFrom(seller, buyer, tokenId);
        } else {
            IERC1155(nftContract).safeTransferFrom(seller, buyer, tokenId, amount, "");
        }
    }

    // Execute an off-chain signed order. Buyer must send >= price (extra refunded).
    function executeOrder(Order calldata o, bytes calldata signature) external payable nonReentrant {
        bytes32 structHash = _hashOrder(o);
        bytes32 digest = _toTypedMessageHash(structHash);
        address signer = _recoverSigner(digest, signature);
        require(signer == o.seller, "invalid signature");
        require(msg.value >= o.price, "insufficient payment");
        if (o.expiry != 0) require(block.timestamp <= o.expiry, "order expired");

        bytes32 orderId = digest;
        require(!usedOrders[orderId], "order used");

        // validate ownership & approval depending on standard
        if (o.std == TokenStandard.ERC721) {
            address ownerOfToken = IERC721(o.nftContract).ownerOf(o.tokenId);
            require(ownerOfToken == o.seller, "seller not owner");
        } else {
            uint256 bal = IERC1155(o.nftContract).balanceOf(o.seller, o.tokenId);
            require(bal >= o.amount, "seller not balance");
        }

        // mark used immediately (prevents replays / reentrancy)
        usedOrders[orderId] = true;

        // settle payments and transfer NFT (moved to internal to reduce stack usage)
        _settleAndTransfer(
            o.seller,
            o.nftContract,
            o.tokenId,
            o.amount,
            o.price,
            o.std,
            o.skipRoyalties,
            msg.sender
        );

        // update volume
        _recordVolume(o.nftContract, o.seller, msg.sender, o.price);

        // refund extra if msg.value > price
        if (msg.value > o.price) {
            uint256 refund = msg.value - o.price;
            (bool okr,) = payable(msg.sender).call{value: refund}("");
            require(okr, "refund failed");
        }

        emit OrderExecuted(orderId, o.seller, msg.sender, o.price);
    }

    // seller can cancel order (prevents replay) by providing the same order fields
    function cancelOrder(Order calldata o) external nonReentrant {
        require(msg.sender == o.seller, "only seller");
        bytes32 id = _toTypedMessageHash(_hashOrder(o));
        require(!usedOrders[id], "already used/cancelled");
        usedOrders[id] = true;
        emit OrderCancelled(id, o.seller);
    }

    function _recordVolume(address nftContract, address seller, address buyer, uint256 salePrice) internal {
        totalVolumeTraded += salePrice;
        volumeByCollection[nftContract] += salePrice;
        volumeBySeller[seller] += salePrice;
        volumeByBuyer[buyer] += salePrice;
    }

    // receive fallback
    receive() external payable {}
}
ABI · 23 entries
json
[
  {
    "type": "constructor",
    "inputs": [
      {
        "name": "name",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "version",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "_platformFeeBps",
        "type": "uint16",
        "internalType": "uint16"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "OrderCancelled",
    "type": "event",
    "inputs": [
      {
        "name": "orderHash",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "seller",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OrderExecuted",
    "type": "event",
    "inputs": [
      {
        "name": "orderHash",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "seller",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "buyer",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "price",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OwnershipTransferred",
    "type": "event",
    "inputs": [
      {
        "name": "previousOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "newOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "PlatformFeeUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "newBps",
        "type": "uint16",
        "indexed": false,
        "internalType": "uint16"
      }
    ],
    "anonymous": false
  },
  {
    "name": "WithdrawnFees",
    "type": "event",
    "inputs": [
      {
        "name": "to",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "amount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "DOMAIN_SEPARATOR",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "ORDER_TYPEHASH",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "accruedPlatformFees",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "cancelOrder",
    "type": "function",
    "inputs": [
      {
        "name": "o",
        "type": "tuple",
        "components": [
          {
            "name": "seller",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "nftContract",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "tokenId",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "amount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "price",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "std",
            "type": "uint8",
            "internalType": "enum KeyFarmMarketplaceV3.TokenStandard"
          },
          {
            "name": "skipRoyalties",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "expiry",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "nonce",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct KeyFarmMarketplaceV3.Order"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "executeOrder",
    "type": "function",
    "inputs": [
      {
        "name": "o",
        "type": "tuple",
        "components": [
          {
            "name": "seller",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "nftContract",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "tokenId",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "amount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "price",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "std",
            "type": "uint8",
            "internalType": "enum KeyFarmMarketplaceV3.TokenStandard"
          },
          {
            "name": "skipRoyalties",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "expiry",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "nonce",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct KeyFarmMarketplaceV3.Order"
      },
      {
        "name": "signature",
        "type": "bytes",
        "internalType": "bytes"
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "name": "orderHash",
    "type": "function",
    "inputs": [
      {
        "name": "o",
        "type": "tuple",
        "components": [
          {
            "name": "seller",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "nftContract",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "tokenId",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "amount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "price",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "std",
            "type": "uint8",
            "internalType": "enum KeyFarmMarketplaceV3.TokenStandard"
          },
          {
            "name": "skipRoyalties",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "expiry",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "nonce",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct KeyFarmMarketplaceV3.Order"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "owner",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "platformFeeBps",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint16",
        "internalType": "uint16"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "setPlatformFeeBps",
    "type": "function",
    "inputs": [
      {
        "name": "bps",
        "type": "uint16",
        "internalType": "uint16"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "totalVolumeTraded",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "transferOwnership",
    "type": "function",
    "inputs": [
      {
        "name": "newOwner",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "usedOrders",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "volumeByBuyer",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "volumeByCollection",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "volumeBySeller",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "withdrawFees",
    "type": "function",
    "inputs": [
      {
        "name": "to",
        "type": "address",
        "internalType": "address payable"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "receive",
    "stateMutability": "payable"
  }
]