Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.0 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0072f | gamedev — crypto on-chain (NFT assets, payments, leaderboards firmadas) | pendiente | feature |
|
multi-app | media |
|
2026-05-10 | 2026-05-17 |
|
Objetivo
Construir las primitivas para juegos crypto-aware: cargar assets desde NFTs del wallet del jugador, gating de contenido por tenencia de tokens, pagos in-game on-chain, y leaderboards verificables (firmados, anti-cheat basico).
Toda la logica viaja por el bridge JS de 0072e + funciones backend nuevas.
Casos de uso
| Caso | Descripcion |
|---|---|
| NFT skin | Player conecta wallet, juego carga PFP/skin desde NFT que posee. |
| Token gating | Modos/niveles desbloqueados solo si wallet tiene cierto token o NFT. |
| In-game shop | Pagos en stablecoin (USDC) por items. |
| Earn-to-play | Pagos del juego al jugador (tx outgoing del game treasury). |
| Leaderboard firmada | Score tagged con firma del jugador, servidor verifica autenticidad. |
| Cross-game inventory | Inventario portable entre varios juegos del mismo studio (NFT estandar). |
Funciones a crear
Lectura on-chain (en JS bridge, expuesto a WASM)
window.fnGameBridge.crypto = {
async getNFTs(address, contractAddr) // ERC721/1155 listing
async getTokenBalance(address, token) // ERC20 balance
async getENS(address) // ENS reverse lookup
async ownsNFT(address, contract, tokenId) // bool, gating
};
Implementacion: usar viem (~50KB gz) o llamadas RPC directas (fetch a Alchemy/Infura/Public RPC).
En C++ (registry)
cpp/functions/crypto/nft_loader.{cpp,h,md} (impure, WASM):
struct NFTAsset {
std::string contract;
std::string token_id;
std::string name;
std::string image_url; // ipfs:// o https://
std::string metadata_json; // raw
};
void crypto_list_nfts(const std::string& address,
void (*cb)(std::vector<NFTAsset>, void*), void* user);
void crypto_load_nft_image(const NFTAsset& nft,
void (*cb)(std::vector<uint8_t>, void*), void* user);
cpp/functions/crypto/token_gating.{cpp,h,md} (impure, WASM):
struct GateRule {
std::string contract;
std::string token_id; // "" = any token of contract
uint64_t min_balance;
};
void crypto_check_gate(const std::string& address, const GateRule& rule,
void (*cb)(bool ok), void* user);
cpp/functions/crypto/sign_score.{cpp,h,md} (impure, WASM):
// Player firma su score → servidor verifica
struct ScoreEntry {
std::string game_id;
std::string level;
uint64_t score;
uint64_t timestamp;
std::string nonce;
};
void crypto_sign_score(const ScoreEntry& s,
void (*cb)(std::string sig, void*), void* user);
Backend (verificacion de firmas)
Funciones Go nuevas en functions/crypto/:
eth_verify_signature_go_crypto(pure) — recover signer address de firma + mensaje. Vendoring:go-ethereum/crypto.eip712_hash_go_crypto(pure) — hash de typed data segun EIP-712.solana_verify_signature_go_crypto(pure) — ed25519 verify.
Service nuevo en apps/: crypto_leaderboard_api (tag service):
- POST
/scoreconScoreEntry+ firma → verifica → guarda en BD si valido. - GET
/leaderboard?game=X&level=Y→ top scores firmados. - BD: SQLite con tabla
scores(game_id, level, address, score, signature, timestamp).
Frontend dashboard
apps/crypto_leaderboard_api/web/ — pagina React/Mantine que consume la API y muestra leaderboards. Usa @fn_library.
NFT image loading
Las imagenes de NFTs vienen via:
ipfs://Qm...— resolver con gateway publico (https://ipfs.io/ipfs/,https://nftstorage.link,https://cloudflare-ipfs.com).https://...— directo.data:image/png;base64,...— embebido.
Funcion: crypto_resolve_ipfs_url_cpp_crypto (pure):
std::string resolve_ipfs(const std::string& uri,
const std::vector<std::string>& gateways = {});
Failover entre gateways si uno falla.
Cache local
NFTs raramente cambian. Cache en localStorage / IndexedDB:
window.fnGameBridge.cache = {
async getNFT(contract, tokenId) { /* IndexedDB lookup */ },
async putNFT(nft) { /* IndexedDB store */ },
};
C++ no toca cache directamente; el JS bridge gestiona cache con TTL 24h.
Pagos in-game
Patron canonico:
// Comprar power-up por 1 USDC
struct Payment {
std::string token_contract; // USDC mainnet
std::string to_address; // Game treasury
std::string amount_wei; // 1000000 = 1 USDC (6 decimales)
std::string memo; // "buy:powerup_001:player_123"
};
void crypto_pay(const Payment& p, void (*cb)(std::string tx_hash, void*), void* user);
Backend verifica via webhook / polling:
- Watch transactions on
to_address. - Match
memo→ entregar item al usuario. - Servicio nuevo:
crypto_payment_watcher(tagservice).
EIP-712 typed data
Para firmas estructuradas (mejor UX que personal_sign plano):
// JS bridge expone:
async signTypedData(domain, types, message) {
return await signer.signTypedData(domain, types, message);
}
Beneficio: MetaMask muestra el contenido legible al usuario, no un blob hex. Reduce phishing.
Anti-cheat layers
Score firmado NO es anti-cheat completo (un cheater puede firmar scores falsos). Layers complementarios:
- Sanity bounds — backend rechaza scores imposibles (ej. > max teorico).
- Replay attestation — guardar inputs del juego junto al score, replay deterministic en backend para validar.
- Server-authoritative para modos competitivos — el juego envia inputs, el server simula. No es para todos los juegos.
- Rate limit por wallet — max N scores/hora.
Documentar en cpp/GAMEDEV.md que la firma es autenticacion, no integridad del score.
Integracion con apps existentes
Si una app C++ quiere features crypto:
- Declara
uses_functions: [bridge_web3_cpp_crypto, nft_loader_cpp_crypto, ...]. - Compila con
-sASYNCIFYy losASYNCIFY_IMPORTSdel bridge. - Embebe
web/bridge.js+web/crypto.jsen sushell.html.
Tamaño
- C++ extra: ~10 KB total (bridge + nft loader + token gating + sign score).
- JS host extra: ~50 KB gz (viem) + ~20 KB gz (helpers). Lazy loaded, no afecta TTI inicial salvo que el juego conecte wallet en startup (no recomendado).
- Backend Go: parte de un service separado, no afecta runtime del juego.
Standards a soportar
| Standard | Para qué |
|---|---|
| ERC-721 | NFT unicos (skins, characters) |
| ERC-1155 | NFT semi-fungibles (items, currency) |
| ERC-20 | Tokens fungibles (in-game currency) |
| EIP-712 | Typed data signing |
| EIP-1193 | Wallet provider interface |
| Metaplex (Solana) | NFTs Solana |
Criterio de exito
engine_democarga PFP NFT del wallet conectado.- Token gating: solo wallets con NFT X pueden entrar al modo Y.
- Pago de 1 USDC testnet entrega un item in-game tras confirmacion.
- Leaderboard API valida firmas correctamente y rechaza falsificaciones.
- Tests: mock provider para validar flujos sin red real.
- Documentacion completa en
cpp/GAMEDEV.mdseccion crypto on-chain.
Riesgos
- Gas fees — pagos pequeños on-chain en mainnet ETH son inviables (gas > tx). Estrategia: L2 (Base, Arbitrum, Polygon) o Solana de default.
- IPFS gateway flaky — failover entre gateways, cache local.
- Wallet UX en mobile — WalletConnect deep links requieren testing real en devices.
- Regulacion — payments crypto pueden caer bajo MiCA (EU) o equivalentes. Documentar disclaimers, no consejo legal aqui.
- Phishing — siempre EIP-712 con domain explicito. Documentar para devs que usen el stack.
No-objetivos
- Wallet integrado en el juego (custodial). Demasiado complejo + responsabilidad legal.
- Smart contracts propios — issue separado por juego, no aplica al stack genérico.
- Tokenomics / gobernanza — no es problema del runtime.