Выставишь NFT на продажу через sale: деплой sale, transfer item, разбор куда уходят цена, fee маркетплейса и royalty.
Зачем нужен sale-контракт
На TON нет approve + transferFrom как в ERC-721. Продажа — отдельный sale-контракт: продавец переводит NFT на sale (new_owner = sale), покупатель шлёт Gram на sale. Sale атомарно (в рамках своей логики) распределяет оплату и делает transfer item покупателю.
Пока NFT на sale, owner айтема — адрес sale, не кошелёк продавца.
Выставляем fixed-price sale и разбираем платеж
typescript
// @ton/core ^0.59.0, @ton/ton ^15.1.0// Паттерн: Getgems NFT Fixed Price Sale (упрощённая схема сообщений)// Конкретные opcode/поля — сверь с nft-contracts Getgems или своим saleimport { Address, beginCell, toNano, Cell } from "@ton/core";const OP_NFT_TRANSFER = 0x5fcc3d14;/** * После деплоя sale продавец переводит NFT на адрес sale. * forward_amount > 0 — sale получает ownership_assigned и «активируется». */export function buildTransferNftToSale(opts: { saleAddress: Address; sellerAddress: Address; forwardTon: bigint;}) { return beginCell() .storeUint(OP_NFT_TRANSFER, 32) .storeUint(0n, 64) .storeAddress(opts.saleAddress) // new_owner = sale .storeAddress(opts.sellerAddress) // excesses продавцу .storeBit(false) .storeCoins(opts.forwardTon) .storeBit(false) .endCell();}/** * Покупка: покупатель шлёт Gram ≥ price на sale. * Многие fixed-price sale принимают пустое тело или op::buy — смотри контракт. */export function buildBuyMessage(saleAddress: Address, price: bigint) { return { to: saleAddress, value: price + toNano("0.1"), // цена + газ на transfer NFT и рассылки body: beginCell().endCell(), // или opcode buy — по исходнику sale };}/** * Куда уходит цена при успешной покупке (типичный fixed-price + TEP-66): * * payment = msg_value (фактически price) * marketplace_fee = price * marketplaceFeeNumerator / marketplaceFeeDenominator * royalty = price * royaltyNumerator / royaltyDenominator // из collection * seller_gets = price - marketplace_fee - royalty * * Sale шлёт: * marketplace_fee → marketplaceAddress (комиссия площадки) * royalty → royaltyDestination (из royalty_params коллекции) * seller_gets → fullPrice / seller address * NFT transfer → buyer (new_owner) */export function splitSalePayment(opts: { price: bigint; marketplaceFeeNumerator: number; marketplaceFeeDenominator: number; royaltyNumerator: number; royaltyDenominator: number;}) { const marketplaceFee = (opts.price * BigInt(opts.marketplaceFeeNumerator)) / BigInt(opts.marketplaceFeeDenominator); const royalty = opts.royaltyDenominator === 0 ? 0n : (opts.price * BigInt(opts.royaltyNumerator)) / BigInt(opts.royaltyDenominator); const sellerGets = opts.price - marketplaceFee - royalty; return { marketplaceFee, royalty, sellerGets };}// Пример: price 10 GRAM, marketplace 5%, royalty 5%const split = splitSalePayment({ price: toNano("10"), marketplaceFeeNumerator: 5, marketplaceFeeDenominator: 100, royaltyNumerator: 50, royaltyDenominator: 1000,});// marketplaceFee = 0.5, royalty = 0.5, sellerGets = 9.0 GRAM
Материалы gramdocs.tech носят образовательный характер и не являются финансовой, юридической или инвестиционной рекомендацией. Работа с блокчейном TON и токеном Gram связана с рисками потери средств. Правовая информация