Contracts routinely process jettons for DEX, escrow, and lending protocols by handlingDocumentation Index
Fetch the complete documentation index at: https://docs.ton.org/llms.txt
Use this file to discover all available pages before exploring further.
JettonNotify messages from jetton wallets. However, since anyone can send these messages, receiving contracts must verify the message sender has the correct jetton wallet address.
The problem is, that the jetton minter deploys the jetton wallet on the first jetton transfer to the contract, so the wallet address is unknown at the moment of contract deployment. This means, the contract needs logic to learn about the wallet address after deployment to be able to verify JettonNotify messages.
Comparison of approaches
There are three approaches to verifyJettonNotify messages, depending on the level of trust in the contract deployer and whether the approach requires TEP-89.
| Requirement | Manual management | Automatic discovery | Get-method emulation |
|---|---|---|---|
| Jetton type known | Yes | No | No |
| Trust in deployer | Yes | No | No |
| Jetton is TEP-89 compatible | No | Yes | No |
| Implementation complexity | Low | Medium | High |
Manual wallet management
If the jetton type is known in advance, calculate the corresponding jetton wallet address off-chain and set it via a message after deployment. It is impossible to hardcode the jetton wallet address in the contract’sStateInit because the wallet address depends on the contract address and creates a circular dependency. This is the most efficient approach, because it only requires one address comparison.
The following example of a receiving contract handles JettonNotify messages for a trusted jetton wallet address that can be set by the owner of the contract.
Tolk
SetTrustedJettonWallet messages to set the trusted jetton wallet address whose owner is the receiving contract address.
Include the jetton minter address in the contract Storage to ensure each instance of the contract is unique to a specific jetton, and thus has a unique address. This allows deploying multiple instances of the contract for different jettons, even if they share the same owner. Each instance can then set its own trustedJettonWallet address corresponding to its jettonMinter.
Modify trustedJettonWallet to store several addresses, to handle several jetton types with a single contract.
Automatic wallet discovery
In the first approach, the deploying party chooses addresses of the jetton minter and wallet contracts off-chain. The contract’s dependents have to trust that the wallet belongs to the corresponding minter, which is not a problem for an exchange. However, if the deployer is not trustworthy, the first approach is not suitable, and the contract must compute thetrustedJettonWallet address on-chain.
Most modern jetton contracts implement TEP-89, which defines a provide_wallet_address message that requests a jetton wallet address for an arbitrary owner, and a take_wallet_address message with a response.
The receiving contract works similarly to the first approach, except it is initialized with an InitContract message that asks the jetton minter which jetton wallet address it should use.
The following example of a receiving contract handles JettonNotify messages for a jetton wallet address that is unknown at the moment of deployment, and is set by the JettonMinter in response to the ProvideWalletAddress message sent during initialization.
Tolk
On-chain get-method emulation
If a jetton contract doesn’t implement TEP-89, it is possible to compute the jetton wallet address on-chain by executing theget_wallet_address method of the jetton minter. This approach doesn’t require any trust in the jetton deployer and works for jettons that don’t implement TEP-89.
With the state of a jetton minter, the RUNVM instruction can emulate the execution of the get_wallet_address get-method to derive the wallet address for any owner.
Use the following helper function. It relies on Fift because it’s impossible to assign a type to c7. It executes the get_wallet_address method of a jetton minter on-chain, and calculates the corresponding wallet address for a given owner.
Tolk/Fift
Minters without vanity addresses
Minter address andStateInit will match if the jetton minter was not deployed with a vanity contract. The logic for the contract that handles JettonNotify messages is thus:
- Get the
StateInitof the jetton minter off-chain. - Deploy the receiver contract with the address of the jetton minter in its data.
- Send a message to the contract with the
StateInitof the jetton minter. - Validate that
StateInitmatches the address of the jetton minter. - Run
calculateJettonWalletwith the following arguments:owner: address of the contract (e.g.,contract.getAddress()).jettonDataandjettonCode:StateInitof the jetton minter.jettonMinter: address of the jetton minter.
Minters with vanity addresses or invalid get-methods
If the jetton minter was deployed with a vanity contract, or otherwise lacksget_wallet_address method, or get_wallet_address returns incorrect addresses, use the current state of the contract instead.
A full state proof is required to prove that the state is currently at the jetton minter address.