docs/custom-fragment.md
Rama main · réplica de lectura del repositorio original.
# CustomFragment gift withdrawal
CustomFragment replaces the old local-only completion page behind
`payments.getStarGiftWithdrawalUrl` with a self-hosted TON mainnet mint flow.
The RPC's existing SRP/2FA check remains the gate: its returned withdrawal URL
is a short-lived bearer capability. Username minting is not implemented.
## Contracts
The upstream TON reference implementation requested for new collections is
vendored at [`contracts/nft-v1.1`](../contracts/nft-v1.1). It is the
`ton-blockchain/acton-contracts` `nft-v1.1` package (including its wrappers,
scripts, and tests), with only a local Acton manifest pinned to `1.1.0` so it
can be built reproducibly alongside gramsrv.
```sh
cd contracts/nft-v1.1
acton build NftCollection
acton test tests
```
That reference collection deliberately accepts deployment messages only from
its admin address. The already deployed **InvGram Gifts** collection remains
the signed-mint compatibility collection for existing withdrawal URLs; it is
not replaced in place (TON contract addresses and storage layouts are
immutable). A new upstream collection can be deployed for a future relayer
flow after its admin wallet and collection address are configured.
The contracts in `contracts/customfragment` are an idiomatic typed Tolk rewrite
of the minting subset of Telegram's GPL-3.0 TeleMint contracts. They use a new
storage layout and deterministic item address scheme, so they are not address-
compatible with the original FunC contracts.
```sh
cd contracts/customfragment
acton build
acton test --coverage --coverage-format text
acton wrapper CustomFragmentCollection
acton wrapper CustomFragmentItem
```
Deploy `CustomFragmentItem`, then deploy `CustomFragmentCollection` with:
- `subwalletId`: the configured uint32 (default `1196573005`, ASCII `GRAM`);
- `publicKey`: the Ed25519 public key printed by telesrv on startup;
- `itemCode`: the compiled CustomFragment item code;
- collection metadata and royalty cells for the deployment.
Deployment is intentionally an operator action: telesrv will never deploy a
mainnet contract or generate/replace the mint authority key automatically.
The included `deploy-mainnet` Acton script deploys the collection from the
global `customfragment-deployer` wallet and takes the authority seed only from
`CUSTOM_FRAGMENT_SIGNING_SEED`.
## Server configuration
Set the `TELESRV_CUSTOM_FRAGMENT_*` variables documented in `.env.example` and
enable the public Web listener. The collection address must be a TON basechain
mainnet address. Keep the signing key outside the repository with restrictive
filesystem permissions.
Set `TELESRV_CUSTOM_FRAGMENT_PUBLIC_BASE_URL` to a dedicated HTTPS host served
by the same Web listener. It must differ from the native client's internal link
host; otherwise Android may parse `/gift-withdrawal/{token}` as a username link
instead of opening the browser.
The browser sends a wallet-bound, five-minute authorization to TON Connect. The
server does not accept the wallet callback as proof. It derives the expected NFT
address with `get_nft_address_by_index`, reads `get_nft_data` through proof-
checking mainnet lite servers, and atomically marks the gift exported only when
the index, collection and owner all match.
The claim path uses the same fail-closed compare-and-swap rule: the database
owner observed when a TON Proof challenge is issued must still be the owner
when the single-use challenge is committed. A concurrent ownership sync or
second claim therefore returns a conflict instead of overwriting a newer
projection.
Public routes:
- `/custom-fragment` — service and collection information;
- `/gift-withdrawal/{token}` — private mint page returned by the TL method;
- `/custom-fragment/tonconnect-manifest.json` — TON Connect manifest;
- `/custom-fragment/collection.json` — TEP-64 metadata for **InvGram Gifts**;
- `/custom-fragment/metadata/gift/{slug}.json` — TEP-64 metadata;
- `/custom-fragment/media/gift/{slug}.png` — rendered gift poster with its
backdrop, tiled pattern, and model rest frame;
- `/custom-fragment/media/gift/{slug}.lottie.json` — the selected model's raw
Lottie JSON, cached in memory and suitable for client-side animation.
The public Web listener also exposes `/botfather` and `/stickers` as local
Telegram-style mini apps. They use only relative `/api/miniapps/*` requests;
creation is delegated to the existing bot/files services and requires signed
Telegram `initData`. A newly generated bot token is returned once over the
server response and is not retained by the page.
The media routes and all metadata URLs use
`TELESRV_CUSTOM_FRAGMENT_PUBLIC_BASE_URL`, so CustomFragment can live on a
dedicated HTTPS host while the main server keeps its normal public URL.