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"
}
]