Przejdź do głównej zawartości

Przetwarzanie płatności

Ta strona wyjaśnia, jak przetwarzać (wysyłać i akceptować) "aktywa cyfrowe" na blockchainie TON. Opisuje głównie jak pracować z monetami TON, ale część teoretyczna jest ważna, nawet jeśli chcą Państwo przetwarzać tylko jettony.

Inteligentny kontrakt portfela

Inteligentne kontrakty Wallet to kontrakty w sieci TON, których zadaniem jest umożliwienie podmiotom spoza łańcucha bloków interakcji z podmiotami łańcucha bloków. Ogólnie rzecz biorąc, rozwiązują one trzy wyzwania:

  • uwierzytelnia właściciela: Odmawia przetwarzania i uiszczania opłat za wnioski osób niebędących właścicielami.
  • Ochrona przed powtórzeniami: Zabrania powtarzalnego wykonywania jednego żądania, na przykład wysyłania aktywów do innego inteligentnego kontraktu.
  • inicjuje dowolną interakcję z innymi inteligentnymi kontraktami.

Standardowym rozwiązaniem dla pierwszego wyzwania jest kryptografia klucza publicznego: wallet przechowuje klucz publiczny i sprawdza, czy przychodząca wiadomość z żądaniem jest podpisana odpowiednim kluczem prywatnym, który jest znany tylko właścicielowi.

Rozwiązanie trzeciego wyzwania jest również powszechne; ogólnie rzecz biorąc, żądanie zawiera w pełni uformowaną wewnętrzną wiadomość, którą wallet wysyła do sieci. Jednak w przypadku ochrony przed powtórkami istnieje kilka różnych podejść.

Portfele oparte na sekwencji

Portfele oparte na Seqno stosują najprostsze podejście do sekwencjonowania wiadomości. Każda wiadomość ma specjalną liczbę całkowitą seqno, która musi pokrywać się z licznikiem przechowywanym w inteligentnym kontrakcie wallet. wallet aktualizuje swój licznik przy każdym żądaniu, zapewniając w ten sposób, że jedno żądanie nie zostanie przetworzone dwukrotnie. Istnieje kilka wersji wallet, które różnią się publicznie dostępnymi metodami: możliwość ograniczenia żądań według czasu wygaśnięcia oraz możliwość posiadania wielu portfeli z tym samym kluczem publicznym. Jednak nieodłącznym wymogiem tego podejścia jest wysyłanie żądań jedno po drugim, ponieważ każda luka w sekwencji seqno spowoduje niemożność przetworzenia wszystkich kolejnych żądań.

Portfele o dużym obciążeniu

Ten typ wallet stosuje podejście oparte na przechowywaniu identyfikatora niewygasłych przetworzonych żądań w pamięci smart-contract. W tym podejściu każde żądanie jest sprawdzane pod kątem bycia duplikatem już przetworzonego żądania i, jeśli zostanie wykryta powtórka, jest odrzucane. Ze względu na wygaśnięcie, kontrakt może nie przechowywać wszystkich żądań na zawsze, ale usunie te, które nie mogą zostać przetworzone ze względu na limit wygaśnięcia. Żądania do tego "portfela" mogą być wysyłane równolegle bez zakłócania siebie nawzajem; jednak takie podejście wymaga bardziej zaawansowanego monitorowania przetwarzania żądań.

Wdrożenie portfela

Aby wdrożyć portfel za pośrednictwem TonLib, należy:

  1. Proszę wygenerować parę kluczy prywatny/publiczny za pomocą funkcji createNewKey lub jej funkcji opakowujących (przykład w tonlib-go). Proszę zauważyć, że klucz prywatny jest generowany lokalnie i nie opuszcza komputera hosta.
  2. Formularz InitialAccountWallet struktury odpowiadającej jednemu z włączonych wallets. Obecnie dostępne są wallet.v3, wallet.v4, wallet.highload.v1, wallet.highload.v2.
  3. Proszę obliczyć adres nowego inteligentnego kontraktu wallet za pomocą metody getAccountAddress. Zalecamy użycie domyślnej wersji 0, a także wdrożenie portfeli w łańcuchu bazowym workchain=0 w celu obniżenia opłat za przetwarzanie i przechowywanie.
  4. Proszę wysłać Toncoin na obliczony adres. Proszę zauważyć, że należy wysłać je w trybie non-bounce, ponieważ ten adres nie ma jeszcze kodu, a zatem nie może przetwarzać przychodzących wiadomości. Flaga non-bounce wskazuje, że nawet jeśli przetwarzanie nie powiedzie się, pieniądze nie powinny zostać zwrócone z wiadomością bounce. Nie zalecamy używania flagi non-bounce w innych transakcjach, szczególnie w przypadku dużych kwot, ponieważ mechanizm bounce zapewnia pewien stopień ochrony przed błędami.
  5. Proszę utworzyć żądaną akcję, na przykład actionNoop tylko do wdrożenia. Następnie proszę użyć createQuery i sendQuery, aby zainicjować interakcję z blockchainem.
  6. Proszę sprawdzić umowę w ciągu kilku sekund za pomocą metody getAccountState.
wskazówka

Proszę przeczytać więcej w [Wallet Tutorial] (/develop/smart-contracts/tutorials/wallet#-deploying-a-wallet).

Proszę sprawdzić ważność adresu portfela

Większość zestawów SDK wymusza weryfikację adresu (większość weryfikuje go podczas tworzenia portfela lub procesu przygotowywania transakcji), więc zazwyczaj nie wymaga to od użytkownika żadnych dodatkowych skomplikowanych kroków.

  const TonWeb = require("tonweb")
TonWeb.utils.Address.isValid('...')
wskazówka

Pełny opis adresu na stronie Smart Contract Addresses.

Praca z transferami

Proszę sprawdzić transakcje kontraktu

Transakcje kontraktu można uzyskać za pomocą getTransactions. Metoda ta pozwala uzyskać 10 transakcji od pewnego last_transaction_id i wcześniejszych. Aby przetworzyć wszystkie przychodzące transakcje, należy wykonać następujące kroki:

  1. Najnowszy last_transaction_id można uzyskać za pomocą getAddressInformation.
  2. Lista 10 transakcji powinna zostać załadowana za pomocą metody getTransactions.
  3. Przetwarzanie transakcji z niepustym źródłem w wiadomości przychodzącej i miejscem docelowym równym adresowi konta.
  4. Należy wczytać kolejne 10 transakcji i powtarzać kroki 2,3,4,5 aż do przetworzenia wszystkich przychodzących transakcji.

Proszę pobrać transakcje przychodzące/wychodzące

Możliwe jest śledzenie przepływu wiadomości podczas przetwarzania transakcji. Ponieważ przepływ wiadomości jest DAG, wystarczy pobrać bieżącą transakcję za pomocą metody getTransactions i znaleźć transakcję przychodzącą przez out_msg za pomocą tryLocateResultTx lub transakcje wychodzące przez in_msg za pomocą tryLocateSourceTx.

import { TonClient, Transaction } from '@ton/ton';
import { getHttpEndpoint } from '@orbs-network/ton-access';
import { CommonMessageInfoInternal } from '@ton/core';

async function findIncomingTransaction(client: TonClient, transaction: Transaction): Promise<Transaction | null> {
const inMessage = transaction.inMessage?.info;
if (inMessage?.type !== 'internal') return null;
return client.tryLocateSourceTx(inMessage.src, inMessage.dest, inMessage.createdLt.toString());
}

async function findOutgoingTransactions(client: TonClient, transaction: Transaction): Promise<Transaction[]> {
const outMessagesInfos = transaction.outMessages.values()
.map(message => message.info)
.filter((info): info is CommonMessageInfoInternal => info.type === 'internal');

return Promise.all(
outMessagesInfos.map((info) => client.tryLocateResultTx(info.src, info.dest, info.createdLt.toString())),
);
}

async function traverseIncomingTransactions(client: TonClient, transaction: Transaction): Promise<void> {
const inTx = await findIncomingTransaction(client, transaction);
// now you can traverse this transaction graph backwards
if (!inTx) return;
await traverseIncomingTransactions(client, inTx);
}

async function traverseOutgoingTransactions(client: TonClient, transaction: Transaction): Promise<void> {
const outTxs = await findOutgoingTransactions(client, transaction);
// do smth with out txs
for (const out of outTxs) {
await traverseOutgoingTransactions(client, out);
}
}

async function main() {
const endpoint = await getHttpEndpoint({ network: 'testnet' });
const client = new TonClient({
endpoint,
apiKey: '[API-KEY]',
});

const transaction: Transaction = ...; // Obtain first transaction to start traversing
await traverseIncomingTransactions(client, transaction);
await traverseOutgoingTransactions(client, transaction);
}

main();

Proszę wysyłać płatności

  1. Usługa powinna wdrożyć "portfel" i utrzymywać go w stanie finansowania, aby zapobiec zniszczeniu kontraktu z powodu opłat za przechowywanie. Proszę zauważyć, że opłaty za przechowywanie są zazwyczaj niższe niż 1 Toncoin rocznie.
  2. Usługa powinna otrzymać od użytkownika destination_address i opcjonalnie comment. Proszę zauważyć, że w międzyczasie zalecamy zakazanie niedokończonych płatności wychodzących z tym samym zestawem (destination_address, value, comment) lub odpowiednie zaplanowanie tych płatności; w ten sposób następna płatność zostanie zainicjowana dopiero po potwierdzeniu poprzedniej.
  3. Formularz msg.dataText z komentarzem jako tekstem.
  4. Formularz msg.message, który zawiera destination_address, pusty public_key, amount i msg.dataText.
  5. Formularz Action zawierający zestaw wiadomości wychodzących.
  6. Do wysyłania płatności wychodzących proszę używać zapytań createQuery i sendQuery.
  7. Usługa powinna regularnie sprawdzać metodę getTransactions dla kontraktu wallet. Dopasowanie potwierdzonych transakcji do wychodzących płatności według (destination_address, value, comment) pozwala oznaczyć płatności jako zakończone; wykryć i pokazać użytkownikowi odpowiedni hash transakcji i lt (czas logiczny).
  8. Żądania do v3 portfeli high-load mają domyślnie czas wygaśnięcia równy 60 sekund. Po tym czasie nieprzetworzone żądania mogą być bezpiecznie ponownie wysłane do sieci (proszę zobaczyć kroki 3-6).

Proszę pobrać identyfikator transakcji

Może być niejasne, że aby uzyskać więcej informacji na temat transakcji, użytkownik musi przeskanować blockchain za pomocą funkcji getTransactions. Niemożliwe jest pobranie identyfikatora transakcji natychmiast po wysłaniu wiadomości, ponieważ transakcja musi najpierw zostać potwierdzona przez sieć blockchain. Aby zrozumieć wymagany potok, proszę uważnie przeczytać [Wyślij płatności] (https://docs.ton.org/develop/dapps/asset-processing/#send-payments), zwłaszcza punkt 7.

Podejście oparte na fakturach

Aby akceptować płatności na podstawie załączonych komentarzy, usługa powinna

  1. Proszę wdrożyć kontrakt wallet.
  2. Proszę wygenerować unikalną fakturę dla każdego użytkownika. Wystarczy ciąg znaków reprezentujący uuid32.
  3. Użytkownicy powinni zostać poinstruowani, aby wysłać Toncoin do umowy "portfela" usługi z załączoną "fakturą" jako komentarzem.
  4. Usługa powinna regularnie sprawdzać metodę getTransactions dla kontraktu wallet.
  5. W przypadku nowych transakcji, przychodząca wiadomość powinna zostać wyodrębniona, komentarz dopasowany do bazy danych, a wartość przychodzącej wiadomości zdeponowana na koncie użytkownika.

Aby obliczyć wartość przychodzącej wiadomości, którą wiadomość wnosi do umowy, należy przeanalizować transakcję. Dzieje się tak, gdy wiadomość trafia do kontraktu. Transakcję można uzyskać za pomocą getTransactions. W przypadku przychodzącej transakcji portfela prawidłowe dane składają się z jednej wiadomości przychodzącej i zero wiadomości wychodzących. W przeciwnym razie albo wiadomość zewnętrzna zostanie wysłana do portfela, w którym to przypadku właściciel wyda Toncoin, albo portfel nie zostanie wdrożony, a transakcja przychodząca zostanie odrzucona.

W każdym razie, ogólnie rzecz biorąc, kwota, którą wiadomość wnosi do kontraktu może być obliczona jako wartość wiadomości przychodzącej minus suma wartości wiadomości wychodzących minus opłata: value_{in_msg} - SUM(value_{out_msg}) - fee. Technicznie, reprezentacja transakcji zawiera trzy różne pola z fee w nazwie: fee, storage_fee i other_fee, czyli całkowitą opłatę, część opłaty związaną z kosztami przechowywania i część opłaty związaną z przetwarzaniem transakcji. Tylko pierwsza z nich powinna być używana.

Faktury z TON Connect

Najlepiej nadaje się do aplikacji dApps, które muszą podpisywać wiele płatności/transakcji w ramach sesji lub muszą utrzymywać połączenie z portfelem przez pewien czas.

  • ✅ Istnieje stały kanał komunikacji z portfelem, informacje o adresie użytkownika

  • Użytkownicy muszą zeskanować kod QR tylko raz.

  • ✅ Możliwe jest sprawdzenie, czy użytkownik potwierdził transakcję w portfelu, śledzenie transakcji przez zwrócony BOC

  • Gotowe zestawy SDK i UI są dostępne dla różnych platform.

  • Jeśli wystarczy wysłać tylko jedną płatność, użytkownik musi wykonać dwie czynności: połączyć portfel i potwierdzić transakcję.

  • Integracja jest bardziej złożona niż link ton://

Proszę dowiedzieć się więcej

Faktury z linkiem ton://

ważne

Ton link jest przestarzały, proszę go nie używać

Jeśli potrzebują Państwo łatwej integracji dla prostego przepływu użytkowników, odpowiednie jest użycie łącza ton://. Najlepiej nadaje się do jednorazowych płatności i faktur.

ton://transfer/<destination-address>?
[nft=<nft-address>&]
[fee-amount=<nanocoins>&]
[forward-amount=<nanocoins>]
  • Łatwa integracja

  • Nie ma potrzeby podłączania portfela

  • Użytkownicy muszą zeskanować nowy kod QR dla każdej płatności.

  • Nie jest możliwe śledzenie, czy użytkownik podpisał transakcję, czy nie.

  • Brak informacji o adresie użytkownika

  • Obejścia są potrzebne na platformach, na których takie linki nie są klikalne (np. wiadomości od botów dla klientów Telegram na komputery stacjonarne).

Więcej informacji na temat ton linków tutaj

Odkrywcy

Eksplorator blockchain to https://tonscan.org.

Aby wygenerować link do transakcji w eksploratorze, usługa musi uzyskać lt (czas logiczny), hash transakcji i adres konta (adres konta, dla którego lt i txhash zostały pobrane za pomocą metody getTransactions). https://tonscan.org i https://explorer.toncoin.org/ mogą następnie wyświetlać stronę dla tego tx w następującym formacie:

https://tonviewer.com/transaction/{txhash as base64url}

https://tonscan.org/tx/{lt as int}:{txhash as base64url}:{account address}

https://explorer.toncoin.org/transaction?account={account address}&lt={lt as int}&hash={txhash as base64url}

Najlepsze praktyki

Tworzenie portfela

Depozyty toncoinów (Zdobądź toncoiny)

Wypłaty toncoinów (proszę wysłać toncoiny)

Proszę pobrać transakcje kontraktu

SDK

Listę zestawów SDK dla różnych języków (JS, Python, Golang, C#, Rust itp.) można znaleźć [tutaj] (/develop/dapps/apis/sdk).