NFT Marketplace Standard
Canonical NFT marketplace infrastructure for Lux Network using Seaport and Sudoswap protocols.
See also: LP-4155, LP-6022
Abstract
This LP defines the canonical NFT marketplace infrastructure for the Lux Network, providing trading primitives for ERC-721 and ERC-1155 assets. The standard adopts two complementary protocols: Seaport (MIT license) as the primary order-book marketplace from OpenSea, and Sudoswap v2 (AGPL-3.0) as an automated market maker (AMM) for NFTs. Together these protocols enable auctions, fixed-price listings, collection offers, royalty enforcement, and liquidity pools for NFT trading on Lux C-Chain and compatible EVMs.
Activation
| Parameter | Value |
|---|---|
| Flag string | lp2502-nft-marketplace-standard |
| Default in code | N/A |
| Deployment branch | N/A |
| Roll-out criteria | N/A |
| Back-off plan | N/A |
Motivation
NFT marketplaces require battle-tested, audited infrastructure to ensure secure trading. Rather than building custom marketplace contracts, Lux adopts industry-standard protocols with proven security records:
- Security: Seaport and Sudoswap have undergone extensive audits (OpenZeppelin, Trail of Bits, Spearbit, Cyfrin)
- Interoperability: Standard order formats enable cross-marketplace liquidity aggregation
- Feature Completeness: Auctions, offers, bundles, royalties, and AMM pools in unified infrastructure
- Ecosystem Alignment: Zoo ecosystem NFT marketplace uses these same primitives
- Developer Experience: Well-documented APIs with existing SDK and tooling support
Specification
Protocol Selection
Seaport (Primary Marketplace)
License: MIT
Location: lib/seaport/
Version: 1.6
Seaport is the order-book marketplace protocol from OpenSea supporting:
- Basic Orders: Fixed-price listings and purchases
- Dutch Auctions: Descending price auctions
- English Auctions: Ascending price auctions with bid increments
- Collection Offers: Offers on any item in a collection
- Trait Offers: Offers on items with specific attributes
- Bundle Orders: Multiple NFTs in single transaction
- Partial Fills: Partial fulfillment of orders
- Conduits: Approval management for efficient transfers
Core Contracts:
lib/seaport/contracts/
├── Seaport.sol # Main marketplace contract
├── conduit/
│ ├── Conduit.sol # Token transfer conduit
│ └── ConduitController.sol # Conduit management
├── helpers/
│ ├── SeaportRouter.sol # Multi-call router
│ ├── TransferHelper.sol # Batch transfers
│ └── navigator/ # Order building helpers
│ └── SeaportNavigator.sol
├── zones/
│ ├── PausableZone.sol # Pausable order zone
│ └── PausableZoneController.sol
└── helpers/order-validator/
└── SeaportValidator.sol # Order validation
Canonical Addresses (cross-chain):
| Contract | Address |
|---|---|
| Seaport 1.6 | 0x0000000000000068F116a894984e2DB1123eB395 |
| ConduitController | 0x00000000F9490004C11Cef243f5400493c00Ad63 |
| SeaportValidator | 0x00e5F120f500006757E984F1DED400fc00370000 |
| SeaportNavigator | 0x0000f00000627D293Ab4Dfb40082001724dB006F |
Sudoswap v2 (NFT AMM)
License: AGPL-3.0
Location: src/sudo2/
Version: 1.1
Sudoswap provides automated market making for NFTs with bonding curves:
- Liquidity Pools: Deposit NFTs + tokens to provide liquidity
- Bonding Curves: Linear, exponential, XYK, GDA pricing
- Property Checking: Filter by traits or token IDs
- Royalty Support: ERC-2981 and Manifold registry
- Settings: Project-controlled pool configurations
- ERC-1155 Support: Multi-token AMM pools
Core Contracts:
src/sudo2/src/
├── LSSVMPair.sol # Base pair contract
├── LSSVMPairFactory.sol # Pair deployment factory
├── LSSVMRouter.sol # Swap routing
├── VeryFastRouter.sol # Optimized multi-swap router
├── RoyaltyEngine.sol # On-chain royalty lookup
├── bonding-curves/
│ ├── LinearCurve.sol # Linear price curve
│ ├── ExponentialCurve.sol # Exponential price curve
│ ├── XykCurve.sol # Constant product curve
│ └── GDACurve.sol # Gradual Dutch Auction
├── erc721/
│ ├── LSSVMPairERC721.sol # ERC-721 pairs
│ ├── LSSVMPairERC721ETH.sol # 721<>ETH pairs
│ └── LSSVMPairERC721ERC20.sol # 721<>ERC20 pairs
├── erc1155/
│ ├── LSSVMPairERC1155.sol # ERC-1155 pairs
│ ├── LSSVMPairERC1155ETH.sol # 1155<>ETH pairs
│ └── LSSVMPairERC1155ERC20.sol # 1155<>ERC20 pairs
├── property-checking/
│ ├── MerklePropertyChecker.sol # Merkle-based ID filtering
│ └── RangePropertyChecker.sol # ID range filtering
└── settings/
├── StandardSettings.sol # Configurable pool settings
└── StandardSettingsFactory.sol
Dependencies
Sudoswap v2 requires additional dependencies (configured in src/sudo2/foundry.toml):
| Dependency | Import Path | Purpose |
|---|---|---|
| Manifold Royalty Registry | manifoldxyz/ | ERC-2981 royalty lookup |
| PRB Math | @prb/math/ | Fixed-point arithmetic |
| Solmate | solmate/ | Gas-optimized ERC20 |
| Clones With Immutable Args | clones-with-immutable-args/ | Minimal proxy deployment |
Standards Compliance
ERC-721 (Non-Fungible Tokens)
Both protocols fully support ERC-721:
safeTransferFromfor secure transfersapprove/setApprovalForAllfor marketplace approvalsownerOffor ownership verification
ERC-1155 (Multi-Token Standard)
Both protocols support ERC-1155:
safeTransferFrom/safeBatchTransferFrombalanceOf/balanceOfBatchsetApprovalForAll- Sudoswap ERC-1155 pools trade specific token IDs
ERC-2981 (Royalty Standard)
Royalty enforcement via:
- Native ERC-2981
royaltyInfo()queries - Manifold Royalty Registry fallback
- Support for legacy royalty interfaces (Rarible, Foundation, SuperRare, ArtBlocks)
interface IERC2981 {
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external view returns (address receiver, uint256 royaltyAmount);
}
Seaport Integration
Order Structure
struct OrderParameters {
address offerer;
address zone;
OfferItem[] offer;
ConsiderationItem[] consideration;
OrderType orderType;
uint256 startTime;
uint256 endTime;
bytes32 zoneHash;
uint256 salt;
bytes32 conduitKey;
uint256 totalOriginalConsiderationItems;
}
struct OfferItem {
ItemType itemType; // NATIVE, ERC20, ERC721, ERC1155
address token;
uint256 identifierOrCriteria;
uint256 startAmount;
uint256 endAmount;
}
struct ConsiderationItem {
ItemType itemType;
address token;
uint256 identifierOrCriteria;
uint256 startAmount;
uint256 endAmount;
address payable recipient;
}
Order Types
| Type | Description |
|---|---|
FULL_OPEN | Anyone can fulfill |
PARTIAL_OPEN | Partial fills allowed |
FULL_RESTRICTED | Zone approval required |
PARTIAL_RESTRICTED | Partial + zone restricted |
CONTRACT | Contract-generated order |
Conduit System
Conduits enable single-approval token transfers:
// User approves conduit once
IERC721(nft).setApprovalForAll(conduitAddress, true);
// All Seaport orders use same approval
// No per-order approvals needed
Sudoswap Adaptations
Pool Types
| Type | Buy NFT | Sell NFT | Trading Fee |
|---|---|---|---|
TOKEN | Yes | No | No |
NFT | No | Yes | No |
TRADE | Yes | Yes | Yes |
Bonding Curves
Linear Curve:
newPrice = currentPrice + delta (buy)
newPrice = currentPrice - delta (sell)
Exponential Curve:
newPrice = currentPrice * (1 + delta/1e18) (buy)
newPrice = currentPrice / (1 + delta/1e18) (sell)
XYK Curve (Constant Product):
x * y = k
newPrice derived from reserves
GDA Curve (Gradual Dutch Auction):
Price decays over time until purchase
Resets on each sale
Property Checking
Pools can restrict tradeable NFTs:
interface IPropertyChecker {
function hasProperties(
uint256[] calldata ids,
bytes calldata propertyData
) external view returns (bool);
}
Implementations:
MerklePropertyChecker: Merkle proof of ID inclusionRangePropertyChecker: ID range verification
Gas Costs
| Operation | Gas Cost |
|---|---|
| Create pool | ~250,000 |
| Swap (single NFT) | ~150,000 |
| Swap (5 NFTs) | ~400,000 |
| Add liquidity | ~180,000 |
| Remove liquidity | ~120,000 |
Cross-Chain NFTs
Warp Messaging Integration
NFTs can be transferred cross-chain using LP-6022 Warp Messaging:
interface ICrossChainNFT {
// Lock NFT on source chain
function lockAndBridge(
uint256 tokenId,
bytes32 destinationChainId,
address recipient
) external returns (bytes32 messageId);
// Mint wrapped NFT on destination
function receiveAndMint(
bytes32 sourceChainId,
address originalCollection,
uint256 tokenId,
address recipient,
bytes calldata warpProof
) external;
}
Supported Chains
| Chain | Chain ID | Status |
|---|---|---|
| C-Chain | 96369 | Primary |
| Hanzo EVM | 36963 | Supported |
| Zoo EVM | 200200 | Supported |
| chains | Various | Via Warp |
Zoo Ecosystem Integration
The Zoo NFT marketplace uses these same primitives:
~/work/zoo/contracts/
├── marketplace/
│ ├── ZooSeaport.sol # Seaport wrapper with Zoo fees
│ ├── ZooSudoPool.sol # Sudoswap pool factory
│ └── ZooRoyaltyEngine.sol # Zoo-specific royalty handling
Zoo-Specific Features:
- ZOO token fee discounts
- Creator royalty enforcement (minimum 2.5%)
- Curated collection verification
- Community governance for marketplace parameters
Rationale
Why Seaport
- Battle-tested: Processes billions in NFT volume on OpenSea
- Flexible: Supports any order type (auctions, offers, bundles)
- Gas-efficient: Single-approval conduit system
- MIT License: Permissive for commercial use
- Standards: EIP-712 signatures, ERC-2981 royalties
Why Sudoswap
- Instant Liquidity: No waiting for buyers/sellers
- Price Discovery: Automated pricing via bonding curves
- LP Incentives: Earn trading fees by providing liquidity
- Property Filtering: Trade only specific traits/IDs
- AGPL-3.0: Ensures derivatives remain open source
Protocol Complementarity
| Feature | Seaport | Sudoswap |
|---|---|---|
| Fixed-price listings | Yes | No |
| Auctions | Yes | No |
| Collection offers | Yes | No |
| Instant liquidity | No | Yes |
| Bonding curves | No | Yes |
| LP rewards | No | Yes |
| Bundle trades | Yes | Limited |
Backwards Compatibility
This LP introduces new marketplace infrastructure without modifying existing token standards. Collections using ERC-721 or ERC-1155 work without modification.
Migration Path:
- Existing listings on other marketplaces remain valid
- Users approve Seaport conduit for new listings
- Sudoswap pools can be created for any collection
- Royalty settings from ERC-2981 are respected
Test Cases
Seaport Tests
describe("Seaport NFT Marketplace", () => {
it("should execute basic order", async () => {
const order = await createOrder({
offerer: seller,
offer: [{ itemType: 2, token: nft, identifier: 1 }],
consideration: [{ itemType: 0, amount: parseEther("1") }]
});
await seaport.connect(buyer).fulfillOrder(order, { value: parseEther("1") });
expect(await nft.ownerOf(1)).to.equal(buyer.address);
});
it("should execute dutch auction", async () => {
const startPrice = parseEther("10");
const endPrice = parseEther("1");
const order = await createOrder({
offer: [{ token: nft, identifier: 1, startAmount: 1, endAmount: 1 }],
consideration: [{ amount: startPrice, endAmount: endPrice }],
startTime: now,
endTime: now + 86400
});
// Price decreases over time
await time.increase(43200); // 50% through auction
const midPrice = parseEther("5.5");
await seaport.connect(buyer).fulfillOrder(order, { value: midPrice });
});
it("should enforce royalties", async () => {
const royaltyRecipient = await nft.royaltyInfo(1, parseEther("1"));
await seaport.connect(buyer).fulfillOrder(order, { value: parseEther("1") });
expect(await ethers.provider.getBalance(royaltyRecipient)).to.be.gt(0);
});
});
Sudoswap Tests
describe("Sudoswap NFT AMM", () => {
it("should create liquidity pool", async () => {
const pool = await factory.createPairERC721ETH(
nft.address,
linearCurve.address,
parseEther("1"), // spotPrice
parseEther("0.1"), // delta
0, // fee
[1, 2, 3], // initialNFTIds
{ value: parseEther("10") }
);
expect(await nft.balanceOf(pool.address)).to.equal(3);
});
it("should swap NFT for ETH", async () => {
const [quote, newSpotPrice, newDelta, fee] = await pool.getSellNFTQuote(1, 1);
await nft.approve(pool.address, 4);
await pool.swapNFTsForToken([4], quote, seller.address);
expect(await nft.ownerOf(4)).to.equal(pool.address);
});
it("should swap ETH for NFT", async () => {
const [quote, newSpotPrice, newDelta, fee] = await pool.getBuyNFTQuote(1, 1);
await pool.swapTokenForAnyNFTs(
1,
quote,
buyer.address,
false,
address(0),
{ value: quote }
);
});
it("should enforce property checking", async () => {
const merkleProof = generateProof([1, 2, 3]);
await pool.setPropertyChecker(merkleChecker.address, merkleProof);
// Only IDs 1, 2, 3 can be traded
await expect(
pool.swapNFTsForToken([5], quote, seller.address)
).to.be.revertedWith("PropertyCheckFailed");
});
});
Reference Implementation
Lux Standard Library
Seaport: lib/seaport/
- Full OpenSea Seaport 1.6 deployment
- Includes conduits, zones, validators, helpers
Sudoswap: src/sudo2/
- Complete Sudoswap v2 with bonding curves
- ERC-721 and ERC-1155 pool support
- Royalty engine with Manifold integration
Deployment Commands
# Build contracts
cd ~/work/lux/standard
forge build
# Run Sudoswap tests (requires dependencies)
cd src/sudo2
forge test
# Deploy Seaport (uses canonical addresses)
forge script script/DeploySeaport.s.sol --broadcast
Integration Example
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ConsiderationInterface} from "seaport/contracts/interfaces/ConsiderationInterface.sol";
import {LSSVMPairFactory} from "./sudo2/src/LSSVMPairFactory.sol";
contract NFTMarketplace {
ConsiderationInterface public immutable seaport;
LSSVMPairFactory public immutable sudoFactory;
constructor(address _seaport, address _sudoFactory) {
seaport = ConsiderationInterface(_seaport);
sudoFactory = LSSVMPairFactory(_sudoFactory);
}
// List NFT via Seaport
function listNFT(
address nft,
uint256 tokenId,
uint256 price
) external returns (bytes32 orderHash) {
// Create and sign Seaport order
// ...
}
// Create Sudoswap pool
function createPool(
address nft,
uint256[] calldata tokenIds,
uint256 spotPrice
) external payable returns (address pool) {
pool = sudoFactory.createPairERC721ETH(
IERC721(nft),
linearCurve,
spotPrice,
0.05e18, // 5% delta
0, // no fee
tokenIds
);
}
}
Security Considerations
Seaport Security
- Signature Validation: EIP-712 typed data signatures prevent replay attacks
- Zone Restrictions: Pausable zones enable emergency stops
- Conduit Isolation: Separate conduits isolate approval risks
- Order Cancellation: Users can cancel orders on-chain
- Audits: OpenZeppelin, Trail of Bits (multiple rounds)
Sudoswap Security
- Reentrancy Protection: All swap functions use reentrancy guards
- Overflow Protection: Solidity 0.8.x + PRB Math for safe arithmetic
- Royalty Caps: Maximum royalty percentage enforced
- Owner Controls: Pool owners can pause or migrate
- Audits: Spearbit, Cyfrin, Narya (see
v2-auditsrepo)
Cross-Chain Risks
- Warp Message Verification: Always verify BLS aggregate signatures
- Wrapped NFT Trust: Wrapped NFTs rely on bridge security
- Finality: Wait for quantum finality on Q-Chain for high-value transfers
- Metadata Sync: Off-chain metadata may lag cross-chain transfers
Economic Attacks
- Wash Trading: Monitor for suspicious LP activity
- Price Manipulation: Use time-weighted prices for oracles
- Front-Running: Consider private mempools for high-value trades
- Royalty Evasion: Off-chain royalty enforcement may be bypassed
Economic Impact
Fee Structure
| Component | Seaport | Sudoswap |
|---|---|---|
| Protocol Fee | Configurable | 0.5% default |
| Creator Royalty | ERC-2981 | ERC-2981 |
| LP Fee | N/A | Pool-configurable |
| Gas | ~150k per trade | ~150k per swap |
Liquidity Benefits
- Sudoswap pools provide instant exit liquidity
- No listing fees for pool deposits
- LP providers earn trading fees
- Price discovery improves market efficiency
Open Questions
- Royalty Enforcement: Should protocol enforce minimum royalties?
- Cross-Chain Listings: Can Seaport orders span multiple chains?
- Curve Governance: Who approves new bonding curve implementations?
- Zoo Integration: Standardize Zoo marketplace fee handling?
References
- Seaport Documentation
- Seaport GitHub
- Sudoswap Documentation
- Sudoswap v2 Audits
- ERC-721: Non-Fungible Token Standard
- ERC-1155: Multi Token Standard
- ERC-2981: NFT Royalty Standard
- Manifold Royalty Registry
- LP-6022
- LP-4155
Copyright
Copyright and related rights waived via CC0.