Docs
Giftfolio lets you gift real assets, a graded card (Pokémon, basketball, baseball or football) or a tokenized stock, as a shareable link. Real ownership is held in an on-chain escrow and released to whoever opens the link.
Overview
Every gift follows the same shape: a real asset is locked in a single-purpose escrow contract, and a link is created carrying a one-time secret. Whoever opens the link and reveals that secret can release the asset to their own wallet. The sender can refund an unclaimed gift at any time. Prices, card images, and pack odds are pulled live from the market, nothing is faked.
There are two ways to gift:
- Mystery packs — pay and get a random real Courtyard card, sealed into a link the recipient tears open.
- Direct gifts — gift a specific card or stock you already hold on-chain.
Mystery packs
A pack is a sealed gift that reveals one real graded card when opened. It works buy-on-demand: you don't need any inventory or to own a card first.
- You pick a pack tier and pay its price in USDC on Polygon.
- A backend service verifies the payment, then buys a real Courtyard graded card from the open market (OpenSea) inside that tier's value band.
- The card is locked in escrow and sealed into your claim link.
- The recipient opens the link, tears the pack, and claims the real card NFT, gasless.
You always receive exactly one real card. If no card can be sourced in the band, or a purchase fails, the order is automatically refunded. The card is priced in USDC.e (the bridged USDC that Courtyard listings use); if you pay in native USDC the backend swaps it for you, so you just hold ordinary USDC. See pack odds for each tier's real value band, pool size, and per-card chances.
Direct gifts
Gift a specific asset you already hold on-chain:
- Graded cards — Pokémon, basketball, baseball and football. If you own a Courtyard vaulted card (a real graded card on Polygon, redeemable for the physical), connect your wallet on the cards tab and gift the real NFT.
- Tokenized stocks — 50+ names (NVDA, TSLA, AAPL, MSFT, GOOGL, META, COIN, HOOD and more) with live prices. Stocks with a real Robinhood Chain token move the actual tokens from your wallet into escrow. Buy-on-demand for stocks (pay and the recipient gets a real tokenized stock, no holding required) is in development.
Claiming (gasless)
The recipient opens the link and presses Claim. They connect a wallet to receive the asset, and the real asset is released from escrow straight to it, with an explorer link as the receipt.
For pack cards, claiming is gasless: the treasury submits the claim on the recipient's behalf, so they need no gas at all, just a wallet address to receive the card. A "claim it yourself on-chain" option is always available as well.
Chains & contracts
All contracts are minimal, single-purpose, and verified on the explorer.
| Contract | Chain | Address |
|---|---|---|
PackVendor | Polygon (137) | 0xee57E1B9B87Ca4318E046FAE2C45923f61d8D199 |
CardDropEscrow | Polygon (137) | 0xb77116D990FA13B19A1E826c664983439dF51e8a |
StockDropEscrow | Robinhood Chain (4663) | 0xb77116D990FA13B19A1E826c664983439dF51e8a |
Cards are ERC-721s from the Courtyard collection
(0x251BE3A17Af4892035C37ebf5890F4a4D889dcAD) on Polygon. Stocks
are ERC-20s on Robinhood Chain mainnet. Each escrow moves an asset only two
ways: claimed by the holder of the link secret, or refunded to
the sender.
Pack API
The buy-on-demand backend is a small service (base URL
giftfolio-packs-production.up.railway.app). Payments are
idempotent by transaction hash, one payment can never be fulfilled twice.
GET /api/pack/config
-> { packs: { grab: { price }, ... }, treasury, usdc, chainId, gasless }
POST /api/pack/fulfill
{ packId, txHash, buyer, to?, note? }
-> { ok, claimUrl, tokenId, card } # after the buy succeeds
GET /api/pack/status/:txHash
-> { status, claimUrl, card }
POST /api/claim # gasless claim relayer
{ kind: "card"|"pack", id, secret, recipient }
-> { ok, tx, recipient }
GET /health
Odds & fairness
Within a pack, every card in the pool has an equal chance, a pool of N cards means each card is a 1-in-N draw. The pools, value ranges, and odds shown on the pack odds page are computed live from the same catalog the packs draw from. No hidden numbers, no pay-to-lose: if a pack can't be filled you are refunded.
What's live
- Mystery card packs — buy-on-demand, live on Polygon. Pay USDC, get a real Courtyard card sealed into a link.
- Direct card gifts — live on Polygon; gift a Courtyard card you own.
- Direct stock gifts — live on Robinhood Chain mainnet (25 real stock tokens); gift a tokenized stock you hold.
- Gasless claims — live for pack cards (recipient needs no gas).
- Stock buy-on-demand — in development (pay and the recipient gets a real stock, no holding required).
Security
- Assets are held by a minimal escrow contract, not by us.
- Each gift is guarded by a secret carried in the link; only its holder can claim.
- Unclaimed gifts are always refundable to the original sender.
- The gasless relayer validates the secret off-chain before spending any gas, and write endpoints are rate-limited.
SECURITY.md in the repo for the self-review.For developers
Brand, chains, and assets live in config.js (single source of truth):
window.APP_CONFIG = {
brand: "Giftfolio", ticker: "GIFT",
onchain: { escrow, chain: {chainId: 4663}, tokens }, // stocks (RH Chain)
onchainCards: { escrow, chain: {chainId: 137}, collection }, // Courtyard (Polygon)
paidPacks: { backend, prices, chain, usdc }, // buy-on-demand packs
packs: [ /* tiers: { id, name, tag, hue, min, max } */ ],
stocks: [ /* { t: "NVDA", name: "NVIDIA" } */ ],
};
Contracts (Foundry, all tested):
contracts/StockDropEscrow.sol,
CardDropEscrow.sol,
PackVendor.sol,
PackVendorCR.sol (commit-reveal variant). The pack backend is
under server/. Card data via /api/cards, stock
prices via /api/prices.
FAQ
Do I need to own the card to gift a pack?
No. Packs are buy-on-demand, you pay and the card is bought for you and sealed into the link.
Do recipients need a wallet or gas?
They need a wallet address to receive the asset. For pack cards, claiming is gasless, no gas needed.
What if a link is never claimed?
Nothing is lost, the sender can refund it at any time. Packs that can't be filled auto-refund.
Can a link be claimed twice?
No. Each gift is single-use and marked claimed on-chain.
← Back home