Marketplace Implementation - candylabs-gg/CandyLabsWiki GitHub Wiki

The Candy NFT Marketplace supports trading of full NFTs and trait-based assets using Solana’s Core Non-Fungible Tokens (core NFTs) via the Metaplex Core Program. Instead of traditional escrow models, we utilize Token Delegates to allow users to list items without transferring ownership, improving UX and wallet visibility.

This system enables:

  • Users to delegate selling authority to Candy's smart contract.
  • Buyers to purchase listed items atomically.
  • Sellers to revoke listing permissions independently of the Candy program.
  • Off-chain services to detect revoked listings and clean up state.
  • It also ensures compatibility with future Compressed NFTs , Metaplex standards , and on-chain verifiability .
Action Description Notes
List Item User delegates sale rights via Sale delegate to Candy marketplace PDA or vault. No transfer of ownership needed.
Buy Item Buyer initiates transaction that transfers item via delegate mechanism. Requires delegate still active.
Delist Item Seller removes delegate permission; no direct interaction with Candy required. Off-chain service must detect and update DB.
Place Offer Optional future feature. Allows buyers to bid on unlisted items. Not MVP-critical.
Accept Offer Seller accepts an offer by granting delegate and triggering sale. TBD if on-chain or off-chain.
Auction Optional advanced feature allowing timed bidding. May be added in Season 2.

Marketplace Listings

create table "public"."listings" (
    "listing_id" uuid not null default gen_random_uuid(),
    "item_id" uuid not null,
    "seller_id" uuid not null,
    "price" numeric(20,8) not null,
    "currency" text not null default 'SOL'::text,
    "status" text not null default 'active'::text,
    "buyer_id" uuid,
    "created_at" timestamp with time zone not null default now(),
    "updated_at" timestamp with time zone not null default now()

Trait Sales

create table "public"."trait_sales" (
    "id" uuid not null default gen_random_uuid(),
    "buyer_wallet" character varying(255) not null,
    "user_id" uuid,
    "trait_id" integer,
    "user_traits_inventory_id" uuid,
    "quantity" integer not null default 1,
    "sale_price" numeric(10,4) not null,
    "timestamp" timestamp without time zone default now(),
    "tx_hash" character varying(255) not null
);
# Basic functions
Listing
Buying (+ sweeping, which is a bunch of buying instructions, assumming we can fit more than 1/2 instructions in a tx)
Delisting
Place offer
Reject offer
Accept offer
(unclear if these will be cross compatible with all protocols or need special instructions, ex: T22)
================= Unclear if needed
Auction (similar to listing but not fixed price)
Bidding
Finalise
Cancel auction? (need to decide on how the auction flow should look like)


it'd be a great help if you could helpp with the O(n) O(n^2) math for CU units for the stuff we're writting
like a clear scenario: say we implement a long string of idk, max 1000 chars which implements the ruleset for the pack openings
and for each nft we have to traverse this ruleset and the nft array
for marketplace, as refference, I'm using their (tensor) IDL in a pretty formated JSON version

cuz, as it is, a user can "Delegate" (grant us the permission) to transfer the pnft/cnft to the buyer
but the user still retains ownership of the actual pnft/cnft
and on a simple transfer instruction from the user, he can reset this delegate permission while our listing is still active

https://developers.metaplex.com/token-metadata/delegates#token-delegates

However, the owner can revoke the Sale Delegate at any time, which will remove the Listed Token State and make the PNFT transferable and burnable again.
emphasis on owner doing this WITHOUT interacting with the program
replicate the way tensor does it

Metaplex
the whole premise of "do not transfer, delegate" is that you can still see your pNFT/cNFT in your wallet while it's up for sale
1. user A delegates sale to our escrow -> listing active -> user A removes sale delegate -> listing still active
2. user B clicks buy on listing -> tx simulation fails -> check ownership -> not same owner -> ping server to clean up the listing

on the other hand -> escrow method -> we remove most of the cpi calls to metaplex -> we have to do most of the account validation on our end
⚠️ **GitHub.com Fallback** ⚠️