跳转到内容

STON.fi

STON.fi是一个建立在TON 区块链上的去中心化自动做市商(AMM),提供几乎零费用、低滑点、极其简单的界面以及与 TON 钱包的直接集成。

在进一步介绍之前,请自己熟悉以下内容:

Swaps

STON.fi 文档中阅读更多关于 Swaps 的信息。

Swaps使用 StonfiSwap MessageSwapAdditionalData Struct

/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#swap-0x6664de2a
message(0x6664de2a) StonfiSwap {
// Address of the other Router token wallet
otherTokenWallet: Address;
// Where to send refunds upon a failed swap
refundAddress: Address;
// Where to send excesses upon a successful swap
excessesAddress: Address;
// UNIX timestamp of execution deadline for the swap
deadline: Int as uint64;
// Reference to another Cell with additional data,
// using the Tact's greedy auto-layout mechanism
additionalData: SwapAdditionalData;
}
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#additional_data-body
struct SwapAdditionalData {
// Minimum required amount of tokens to receive
// Defaults to 1, which causes the swap to fail
// only if no tokens are received
minOut: Int as coins = 1;
// Where to send tokens upon a successful swap
receiverAddress: Address;
// Forward fees for the `customPayload` if it's not `null`
// Defaults to 0
fwdGas: Int as coins = 0;
// Custom payload that will be sent upon a successful swap
// Defaults to `null`, which means no payload
customPayload: Cell? = null;
// Forward fees for `refundPayload` if it's not `null`
// Defaults to 0
refundFwdGas: Int as coins = 0;
// Custom payload that will be sent upon a failed swap
// Defaults to `null`, which means no payload
refundPayload: Cell? = null;
// Referral fee, between 0 (no fee) and 100 (1%)
// Defaults to 10, which means 0.1% fee
refFee: Int as uint16 = 10;
// Address of the referral
// Defaults to `null`
referralAddress: Address? = null;
}

STON.fi SDK 定义了一些常量用于处理费用。 请注意这些是硬编码值,但最佳做法是用当前配置参数动态计算费用

/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToJetton: Int = ton("0.3");
/// Hardcoded fee value to pay forward fees from the Jetton wallet
const FeeSwapJettonToJettonFwd: Int = ton("0.24");
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToToncoin: Int = ton("0.3");
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToToncoinFwd: Int = ton("0.24");
/// Hardcoded fee value to pay for sending a message and subsequent forwarding
const FeeSwapToncoinToJetton: Int = ton("0.01") + ton("0.3");

Jetton to Jetton

// CPI Router v2.1.0
const RouterAddress: Address =
address("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v");
// Router Jetton Wallet address
const RouterJettonWallet: Address =
address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
/// NOTE: To calculate and provide Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonToJetton(myJettonWalletAddress: Address) {
// Amount of Jettons to swap
let offerAmount: Int = 100_000;
// Prepare the payload
let forwardPayload = StonfiSwap{
otherTokenWallet: RouterJettonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 10,000 seconds from now
deadline: now() + 10_000,
additionalData: SwapAdditionalData{ receiverAddress: myAddress() },
};
// Start a swap with the message to the Jetton wallet
send(SendParameters{
to: myJettonWalletAddress,
value: FeeSwapJettonToJetton,
body: JettonTransfer{
queryId: 42,
amount: offerAmount,
destination: RouterAddress,
responseDestination: myAddress(),
forwardTonAmount: FeeSwapJettonToJettonFwd,
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper Messages, Structs and constants described earlier on this page
//
message(0x6664de2a) StonfiSwap {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: SwapAdditionalData;
}
struct SwapAdditionalData {
minOut: Int as coins = 1;
receiverAddress: Address;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
refundFwdGas: Int as coins = 0;
refundPayload: Cell? = null;
refFee: Int as uint16 = 10;
referralAddress: Address? = null;
}
const FeeSwapJettonToJetton: Int = ton("0.3");
const FeeSwapJettonToJettonFwd: Int = ton("0.24");
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}

Jetton to Toncoin

Jetton to Toncoin swap与Jetton to Jetton swap 非常相似,唯一不同的是,RouterJettonWallet地址被替换为 RouterProxyTonWallet

// CPI Router v2.1.0
const RouterAddress: Address =
address("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v");
// Router's pTON address
const RouterProxyTonWallet: Address =
address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
/// NOTE: To calculate and provide Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonToToncoin(myJettonWalletAddress: Address) {
// Amount of Jettons to swap
let offerAmount: Int = 100_000;
// Prepare the payload
let forwardPayload = StonfiSwap{
otherTokenWallet: RouterProxyTonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 10,000 seconds from now
deadline: now() + 10_000,
additionalData: SwapAdditionalData{ receiverAddress: myAddress() },
};
// Start a swap with the message to the Jetton wallet
send(SendParameters{
to: myJettonWalletAddress,
value: FeeSwapJettonToToncoin,
body: JettonTransfer{
queryId: 42,
amount: offerAmount,
destination: RouterAddress,
responseDestination: myAddress(),
forwardTonAmount: FeeSwapJettonToToncoinFwd,
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper Messages, Structs and constants described earlier on this page
//
message(0x6664de2a) StonfiSwap {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: SwapAdditionalData;
}
struct SwapAdditionalData {
minOut: Int as coins = 1;
receiverAddress: Address;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
refundFwdGas: Int as coins = 0;
refundPayload: Cell? = null;
refFee: Int as uint16 = 10;
referralAddress: Address? = null;
}
const FeeSwapJettonToToncoin: Int = ton("0.3");
const FeeSwapJettonToToncoinFwd: Int = ton("0.24");
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}

Toncoin 交换至 Jetton

要将 Toncoin 兑换为 Jetton,STON.fi 需要使用一种被称为代理 Toncoin 钱包(简称 pTON)的工具。 要与它进行适当的互动,我们需要引入一个 ProxyToncoinTransfer Message

/// https://github.com/ston-fi/sdk/blob/786ece758794bd5c575db8b38f5e5de19f43f0d1/packages/sdk/src/contracts/pTON/v2_1/PtonV2_1.ts
message(0x01f3835d) ProxyToncoinTransfer {
// 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 swap
tonAmount: Int as coins;
// Where to send refunds upon a failed swap
refundAddress: Address;
// Optional custom payload to attach to the swap
// Defaults to `null`
forwardPayload: Cell?;
}

请注意,ProxyToncoinTransferJettonTransfer相似, 但不要求除退款地址以外的任何地址,也不要求指定任何预付金额。

// Router's pTON wallet address
const RouterProxyTonWallet: Address
= address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
// Router's Jetton wallet address
const RouterJettonWallet: Address =
address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
fun toncoinToJetton() {
// Amount of Toncoin to swap
let offerAmount: Int = 1_000;
// Prepare the payload
let forwardPayload = StonfiSwap{
otherTokenWallet: RouterJettonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 10,000 seconds from now
deadline: now() + 10_000,
additionalData: SwapAdditionalData{ receiverAddress: myAddress() },
};
// Start a swap with the message to the proxy Toncoin wallet
send(SendParameters{
to: RouterProxyTonWallet,
value: FeeSwapToncoinToJetton + offerAmount,
body: ProxyToncoinTransfer{
tonAmount: offerAmount,
refundAddress: myAddress(),
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper Messages, Structs and constants described earlier on this page
//
message(0x01f3835d) ProxyToncoinTransfer {
queryId: Int as uint64 = 0;
tonAmount: Int as coins;
refundAddress: Address;
forwardPayload: Cell?;
}
message(0x6664de2a) StonfiSwap {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: SwapAdditionalData;
}
struct SwapAdditionalData {
minOut: Int as coins = 1;
receiverAddress: Address;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
refundFwdGas: Int as coins = 0;
refundPayload: Cell? = null;
refFee: Int as uint16 = 10;
referralAddress: Address? = null;
}
const FeeSwapToncoinToJetton: Int = ton("0.3");

流动资金

阅读更多关于STON.fi documentation中流动资金条款的信息。

STON.fi 允许您只指定一种代币来存入流动性—池将自动执行交换并铸造流动性提供者(LP)代币。 要做到这一点,您需要将 ProvideLiquidity MessagebothPositive 字段设置为 false

流动性存款使用 ProvideLiquidity MessageProvideLiquidityAdditionalData Struct

/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#provide_lp-0x37c096df
message(0x37c096df) ProvideLiquidity {
// Address of the other Router token wallet
otherTokenWallet: Address;
// Where to send refunds if provisioning fails
refundAddress: Address;
// Where to send excesses if provisioning succeeds
excessesAddress: Address;
// UNIX timestamp of execution deadline for the provisioning
deadline: Int as uint64;
// Reference to another Cell with additional data,
// using the Tact's greedy auto-layout mechanism
additionalData: ProvideLiquidityAdditionalData;
}
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#additional_data-body-1
struct ProvideLiquidityAdditionalData {
// Minimum required amount of LP tokens to receive
// Defaults to 1, which causes the provisioning to fail
// only if no tokens are received
minLpOut: Int as coins = 1;
// Where to send LP tokens if provisioning succeeds
receiverAddress: Address;
// Should both tokens in a pair have a positive quantity?
// If not, then the pool would perform an additional swap for the lacking token
// Defaults to `true`, which means that deposit would only go through
// when both token amounts are non-zero
bothPositive: Bool = true;
// Forward fees for the `customPayload` if it's not `null`
// Defaults to 0
fwdGas: Int as coins = 0;
// Custom payload that will be sent if provisioning succeeds
// Defaults to `null`, which means no payload
customPayload: Cell? = null;
}

STON.fi SDK 定义了一些常量用于处理费用。 请注意这些是硬编码值,但最佳做法是用当前配置参数动态计算费用

/// Hardcoded fee value to pay for sending a liquidity provisioning message
/// when depositing a certain amount of Jettons
const FeeSingleSideProvideLpJetton: Int = ton("1");
/// Hardcoded fee value to pay forward fees of subsequent messages for liquidity provisioning
const FeeSingleSideProvideLpJettonFwd: Int = ton("0.8");
/// Hardcoded fee value to pay for sending a liquidity provisioning message
/// when depositing a certain amount of Toncoins
const FeeSingleSideProvideLpToncoin: Int = ton("0.01") + ton("0.8");

存入 Jetton

// CPI Router v2.1.0
const RouterAddress: Address =
address("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v");
// Router's pTON wallet address
const RouterProxyTonWallet: Address =
address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
// Router's Jetton wallet address
const RouterJettonWallet: Address =
address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
/// NOTE: To calculate and provide Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonDeposit(myJettonWalletAddress: Address) {
// Amount of Jettons for liquidity provisioning
let offerAmount = 100_000;
// Prepare the payload
let forwardPayload = ProvideLiquidity{
otherTokenWallet: RouterProxyTonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 1,000 seconds from now
deadline: now() + 1_000,
additionalData: ProvideLiquidityAdditionalData{
receiverAddress: myAddress(),
bothPositive: false, // i.e. single side
},
};
send(SendParameters{
to: myJettonWalletAddress,
value: FeeSingleSideProvideLpJetton,
body: JettonTransfer{
queryId: 42,
amount: offerAmount,
destination: RouterAddress,
responseDestination: myAddress(),
forwardTonAmount: FeeSingleSideProvideLpJettonFwd,
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper Messages, Structs and constants described earlier on this page
//
message(0x37c096df) ProvideLiquidity {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: ProvideLiquidityAdditionalData;
}
struct ProvideLiquidityAdditionalData {
minLpOut: Int as coins = 1;
receiverAddress: Address;
bothPositive: Bool = true;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
}
const FeeSingleSideProvideLpJetton: Int = ton("1");
const FeeSingleSideProvideLpJettonFwd: Int = ton("0.8");
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}

存入 Toncoin

// Router's pTON wallet address
const RouterProxyTonWallet: Address =
address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
// Router's Jetton wallet address
const RouterJettonWallet: Address =
address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
fun toncoinDeposit() {
// Amount of Jettons for liquidity provisioning
let offerAmount = 100_000;
// Prepare the payload
let forwardPayload = ProvideLiquidity{
otherTokenWallet: RouterJettonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
deadline: now() + 1000,
additionalData: ProvideLiquidityAdditionalData{
receiverAddress: myAddress(),
bothPositive: false, // i.e. single side
},
};
send(SendParameters{
to: RouterProxyTonWallet,
value: FeeSingleSideProvideLpToncoin + offerAmount,
body: ProxyToncoinTransfer{
queryId: 42,
tonAmount: offerAmount,
refundAddress: myAddress(),
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper Messages, Structs and constants described earlier on this page
//
message(0x01f3835d) ProxyToncoinTransfer {
queryId: Int as uint64 = 0;
tonAmount: Int as coins;
refundAddress: Address;
forwardPayload: Cell?;
}
message(0x37c096df) ProvideLiquidity {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: ProvideLiquidityAdditionalData;
}
struct ProvideLiquidityAdditionalData {
minLpOut: Int as coins = 1;
receiverAddress: Address;
bothPositive: Bool = true;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
}
const FeeSingleSideProvideLpToncoin: Int = ton("0.01") + ton("0.8");

提取流动资金

要提取流动性,需要燃烧的 LP 代币。 您可以参考 Jettons Cookbook 页面中有关 Jetton 销毁的相关部分 的示例。 然而,应该添加比正常销毁更多的 Toncoin,因为如果添加的 Toncoin 太少,可能会导致 LP 代币被销毁,但不会从池中发送任何(或仅部分)流动性。 因此,请考虑至少附上 0.50.5 Toncoin - 超额部分将予以退还。