Payments Processing
This page explains how to process (send and accept) digital assets on the TON blockchain.
It mostly describes how to work with TON coins, but theoretical part is important even if you want to process only jettons.
It's recommended to get acquainted with Asset Processing Overview before reading this tutorial.
Wallet smart contract
Wallet smart contracts on the TON Network allow external actors to interact with blockchain entities.
- Authenticates the owner: Rejects requests that attempt to process or pay fees on behalf of non-owners.
- Provides replay protection: Prevents the repeated execution of the same request, such as sending assets to another smart contract.
- Initiates arbitrary interactions with other smart contracts.
Standard solution for the first challenge is public-key cryptography: wallet stores the public key and checks that an incoming message with a request is signed by the corresponding private key which is known only by the owner.
The solution to the third challenge is also common; generally, a request contains a fully formed inner message that the wallet sends to the network. However, for replay protection, there are a few different approaches.
Seqno-based wallets
Seqno-based wallets use the simplest approach to sequencing messages. Each message has a special seqno integer that must coincide with the counter stored in the wallet smart contract. wallet updates its counter on each request, thus ensuring that one request will not be processed twice. There are a few wallet versions that differ in publicly available methods: the ability to limit requests by expiration time, and the ability to have multiple wallets with the same public key. However, an inherent requirement of that approach is to send requests one by one, since any gap in seqno sequence will result in the inability to process all subsequent requests.
High-load wallets
This wallet type follows an approach based on storing the identifier of the non-expired processed requests in smart-contract storage. In this approach, any request is checked for being a duplicate of an already processed request and, if a replay is detected, dropped. Due to expiration, the contract may not store all requests forever, but it will remove those that cannot be processed due to the expiration limit. Requests to this wallet can be sent in parallel without interference, but this approach requires more sophisticated monitoring of request processing.
Wallet deployment
To deploy a wallet via TonLib, one needs to:
- Generate a private/public key pair via createNewKey or its wrapper functions (example in tonlib-go). Note that the private key is generated locally and does not leave the host machine.
- Form InitialAccountWallet structure corresponding to one of the enabled
wallets. Currentlywallet.v3,wallet.v4,wallet.highload.v1,wallet.highload.v2are available. - Calculate the address of a new
walletsmart contract via the getAccountAddress method. We recommend using a default revision0and also deploying wallets in the basechainworkchain=0for lower processing and storage fees. - Send some Toncoin to the calculated address. Note that you need to send them in
non-bouncemode, as this address has no code yet and cannot process incoming messages.non-bounceflag indicates that even if processing fails, money should not be returned with a bounce message. We do not recommend using thenon-bounceflag for other transactions, especially when carrying large sums, since the bounce mechanism provides some degree of protection against mistakes. - Form the desired action, for instance
actionNoopfor deploy only. Then use createQuery and sendQuery to initiate interactions with the blockchain. - Check the contract in a few seconds with getAccountState method.
Read more in the Wallet Tutorial
Check the validity of wallet address
Most SDKs force you to verify address (most verify it during wallet creation or transaction preparation process), so, usually, it's not require any additional complex steps from you.
- JS (Tonweb)
- tonutils-go
- Ton4j
- ton-kotlin
const TonWeb = require("tonweb")
TonWeb.utils.Address.isValid('...')
package main
import (
"fmt"
"github.com/xssnick/tonutils-go/address"
)
if _, err := address.ParseAddr("EQCD39VS5j...HUn4bpAOg8xqB2N"); err != nil {
return errors.New("invalid address")
}