/// https://docs.dedust.io/reference/tlb-schemes#message-deposit_liquidity-1
message(0x40e108d6) JettonDepositLiquidity {
// Pool type: 0 for volatile, 1 for stable
// Volatile pool is based on the "Constant Product" formula
// Stable-swap pool is optimized for assets of near-equal value,
// e.g. USDT/USDC, TON/stTON, etc.
// Minimal amount of LP tokens to be received
// If there's less liquidity provided, the provisioning will be rejected
// Defaults to 0, makes this value ignored
minimalLpAmount: Int as coins = 0;
// Target amount of the first asset
targetBalances0: Int as coins;
// Target amount of the second asset
targetBalances1: Int as coins;
// Custom payload attached to the transaction if the provisioning is successful
// Defaults to `null`, which means no payload
fulfillPayload: Cell? = null;
// Custom payload attached to the transaction if the provisioning is rejected
// Defaults to `null`, which means no payload
rejectPayload: Cell? = null;
/// https://docs.dedust.io/reference/tlb-schemes#message-deposit_liquidity
message(0xd55e4686) NativeDepositLiquidity {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means we don't mark messages to trace their chains
queryId: Int as uint64 = 0;
// Toncoin amount for the deposit
// Inlined fields of JettonDepositLiquidity Message without the opcode prefix
minimalLpAmount: Int as coins = 0;
targetBalances0: Int as coins;
targetBalances1: Int as coins;
fulfillPayload: Cell? = null;
rejectPayload: Cell? = null;
/// https://docs.dedust.io/reference/tlb-schemes#asset
// Specify 0 for native (TON) and omit all following fields
// Specify 1 for Jetton and then you must set non-null values for the following fields
workchain: Int as uint8 = 0; // Both this zeroes will be removed during .build() function. Only type will remain.
address: Int as uint256 = 0;
const PoolTypeVolatile: Int = 0;
const PoolTypeStable: Int = 1;
const AssetTypeNative: Int = 0b0000;
const AssetTypeJetton: Int = 0b0001;
const JettonProvideLpGas: Int = ton("0.5");
const JettonProvideLpGasFwd: Int = ton("0.4");
const TonProvideLpGas: Int = ton("0.15");
// This example directly uses the provided `myJettonWalletAddress`
// In real-world scenarios, it's more reliable to calculate this address on-chain or save it during initialization to prevent any issues
fun provideLiquidity(myJettonWalletAddress: Address) {
let jettonMasterRaw = parseStdAddress(
address("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs")
let jettonAmount = ton("1");
let tonAmount = ton("1");
workchain: jettonMasterRaw.workchain,
address: jettonMasterRaw.address,
// Step 2. Deposit Jetton to Vault
let jettonDepositBody = JettonDepositLiquidity{
poolType: PoolTypeVolatile,
targetBalances0: tonAmount,
targetBalances1: jettonAmount,
}.build(); // notice the .build() and not .toCell(),
// since we want some custom serialization logic!
to: myJettonWalletAddress,
value: JettonProvideLpGas,
destination: address("EQAYqo4u7VF0fa4DPAebk4g9lBytj2VFny7pzXR0trjtXQaO"),
responseDestination: myAddress(),
forwardTonAmount: JettonProvideLpGasFwd,
forwardPayload: jettonDepositBody,
// Step 3. Deposit TON to Vault
let nativeDepositBody = NativeDepositLiquidity{
poolType: PoolTypeVolatile,
targetBalances0: tonAmount,
targetBalances1: jettonAmount,
}.build(); // notice the .build() and not .toCell(),
// since we want some custom serialization logic!
to: address("EQDa4VOnTYlLvDJ0gZjNYm5PXfSmmtL6Vs6A_CZEtXCNICq_"),
value: tonAmount + TonProvideLpGas,
// Helper extension functions to build respective Structs and Messages
extends fun build(self: Asset): Cell {
let assetBuilder = beginCell()
.storeUint(self.type, 4);
if (self.type == AssetTypeNative) {
return assetBuilder.endCell();
if (self.type == AssetTypeJetton) {
.storeUint(self.workchain, 8)
.storeUint(self.address, 256)
return beginCell().endCell();
extends fun build(self: JettonDepositLiquidity): Cell {
.storeUint(0x40e108d6, 32)
.storeUint(self.poolType, 1)
.storeSlice(self.asset0.build().asSlice())
.storeSlice(self.asset1.build().asSlice())
.storeCoins(self.minimalLpAmount)
.storeCoins(self.targetBalances0)
.storeCoins(self.targetBalances1)
.storeMaybeRef(self.fulfillPayload)
.storeMaybeRef(self.rejectPayload)
extends fun build(self: NativeDepositLiquidity): Cell {
.storeUint(0xd55e4686, 32)
.storeUint(self.queryId, 64)
.storeUint(self.poolType, 1)
.storeSlice(self.asset0.build().asSlice())
.storeSlice(self.asset1.build().asSlice())
.storeCoins(self.minimalLpAmount)
.storeCoins(self.targetBalances0)
.storeCoins(self.targetBalances1)
.storeMaybeRef(self.fulfillPayload)
.storeMaybeRef(self.rejectPayload)
// Messages from the Jetton standard
message(0xf8a7ea5) JettonTransfer {
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted