232 lines
7.9 KiB
Markdown
232 lines
7.9 KiB
Markdown
ytLp用户前端交互文档
|
||
1.用户添加流动性
|
||
Solidity
|
||
function addLiquidity(
|
||
address _token, //YT代币或WUSD地址
|
||
uint256 _amount, //代币数量
|
||
uint256 _minUsdy, //最小USDY数量
|
||
uint256 _minYtLP //最小ytLP数量
|
||
)
|
||
_minUsdy和_minYtLP计算方式(滑点可以让用户在界面选择)
|
||
TypeScript
|
||
/**
|
||
* 计算添加流动性的 _minUsdy 和 _minYtLP 参数
|
||
* @param {string} token - 代币地址
|
||
* @param {BigNumber} amount - 代币数量
|
||
* @param {number} slippageTolerance - 滑点容忍度 (0.005 = 0.5%)
|
||
* @returns {Promise<{minUsdy, minYtLP, expectedYtLP, feeInfo}>}
|
||
*/
|
||
async function calculateAddLiquidityParams(token, amount, slippageTolerance = 0.005) {
|
||
const PRICE_PRECISION = ethers.BigNumber.from("1000000000000000000000000000000");
|
||
const BASIS_POINTS = 10000;
|
||
|
||
try {
|
||
// 1. 获取价格(使用MinPrice)
|
||
const tokenPrice = await ytVault.getMinPrice(token);
|
||
|
||
// 2. 计算理论USDY(扣费前)
|
||
const theoreticalUsdy = amount.mul(tokenPrice).div(PRICE_PRECISION);
|
||
|
||
// 3. 获取手续费率
|
||
const feeBasisPoints = await ytVault.getSwapFeeBasisPoints(
|
||
token,
|
||
USDY_ADDRESS,
|
||
theoreticalUsdy
|
||
);
|
||
|
||
// 4. 计算扣费后的代币和USDY
|
||
const amountAfterFees = amount
|
||
.mul(BASIS_POINTS - feeBasisPoints)
|
||
.div(BASIS_POINTS);
|
||
|
||
const usdyAmount = amountAfterFees.mul(tokenPrice).div(PRICE_PRECISION);
|
||
|
||
// 5. 获取AUM和供应量
|
||
const [aum, ytLPSupply] = await Promise.all([
|
||
ytPoolManager.getAumInUsdy(true), // 使用MaxPrice
|
||
ytLP.totalSupply()
|
||
]);
|
||
|
||
// 6. 计算预期ytLP
|
||
let expectedYtLP;
|
||
if (ytLPSupply.eq(0)) {
|
||
expectedYtLP = usdyAmount;
|
||
} else {
|
||
expectedYtLP = usdyAmount.mul(ytLPSupply).div(aum);
|
||
}
|
||
|
||
// 7. 应用滑点
|
||
const minUsdy = usdyAmount.mul(
|
||
ethers.BigNumber.from(Math.floor((1 - slippageTolerance) * 10000))
|
||
).div(10000);
|
||
|
||
const minYtLP = expectedYtLP.mul(
|
||
ethers.BigNumber.from(Math.floor((1 - slippageTolerance) * 10000))
|
||
).div(10000);
|
||
|
||
return {
|
||
minUsdy,
|
||
minYtLP,
|
||
expectedYtLP,
|
||
usdyAmount,
|
||
feeInfo: {
|
||
feeBasisPoints: feeBasisPoints.toNumber(),
|
||
feeAmount: amount.sub(amountAfterFees),
|
||
amountAfterFees
|
||
},
|
||
priceInfo: {
|
||
tokenPrice: ethers.utils.formatUnits(tokenPrice, 30),
|
||
aum: ethers.utils.formatEther(aum),
|
||
ytLPSupply: ethers.utils.formatEther(ytLPSupply)
|
||
}
|
||
};
|
||
} catch (error) {
|
||
console.error("计算添加流动性参数失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
2.用户移除流动性
|
||
Solidity
|
||
function removeLiquidity(
|
||
address _tokenOut, //出代币地址
|
||
uint256 _ytLPAmount, //ytLP数量
|
||
uint256 _minOut, //最小输出数量
|
||
address _receiver //接收地址
|
||
)
|
||
_minOut计算方式(滑点可以让用户在界面选择)
|
||
TypeScript
|
||
/**
|
||
* 计算移除流动性的 _minOut 参数
|
||
* @param {string} tokenOut - 目标代币地址
|
||
* @param {BigNumber} ytLPAmount - ytLP数量
|
||
* @param {number} slippageTolerance - 滑点容忍度 (0.01 = 1%)
|
||
* @returns {Promise<{minOut, expectedOut, feeBps, priceInfo}>}
|
||
*/
|
||
async function calculateMinOut(tokenOut, ytLPAmount, slippageTolerance = 0.01) {
|
||
const PRICE_PRECISION = ethers.BigNumber.from("1000000000000000000000000000000");
|
||
const BASIS_POINTS = 10000;
|
||
|
||
try {
|
||
// 1. 获取AUM和供应量
|
||
const [aum, ytLPSupply] = await Promise.all([
|
||
ytPoolManager.getAumInUsdy(false),
|
||
ytLP.totalSupply()
|
||
]);
|
||
|
||
// 2. 计算USDY价值
|
||
const usdyAmount = ytLPAmount.mul(aum).div(ytLPSupply);
|
||
|
||
// 3. 获取代币价格和手续费(并行查询)
|
||
const [tokenPrice, feeBasisPoints] = await Promise.all([
|
||
ytVault.getMaxPrice(tokenOut),
|
||
ytVault.getRedemptionFeeBasisPoints(tokenOut, usdyAmount)
|
||
]);
|
||
|
||
// 4. 计算理论输出
|
||
const theoreticalOut = usdyAmount.mul(PRICE_PRECISION).div(tokenPrice);
|
||
|
||
// 5. 扣除手续费
|
||
const expectedOut = theoreticalOut
|
||
.mul(BASIS_POINTS - feeBasisPoints)
|
||
.div(BASIS_POINTS);
|
||
|
||
// 6. 应用滑点
|
||
const minOut = expectedOut.mul(
|
||
ethers.BigNumber.from(Math.floor((1 - slippageTolerance) * 10000))
|
||
).div(10000);
|
||
|
||
return {
|
||
minOut,
|
||
expectedOut,
|
||
theoreticalOut,
|
||
usdyAmount,
|
||
feeBasisPoints: feeBasisPoints.toNumber(),
|
||
priceInfo: {
|
||
tokenPrice: ethers.utils.formatUnits(tokenPrice, 30),
|
||
aum: ethers.utils.formatEther(aum),
|
||
ytLPSupply: ethers.utils.formatEther(ytLPSupply)
|
||
}
|
||
};
|
||
} catch (error) {
|
||
console.error("计算_minOut失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
3.用户交换代币
|
||
TypeScript
|
||
function swapYT(
|
||
address _tokenIn, //输入代币地址
|
||
address _tokenOut, //输出代币地址
|
||
uint256 _amountIn, //输入数量
|
||
uint256 _minOut, //最小输出数量
|
||
address _receiver //接收地址
|
||
)
|
||
_minOut计算方式(滑点可以让用户在界面选择)
|
||
TypeScript
|
||
/**
|
||
* 计算 swapYT 的 _minOut 参数
|
||
* @param {string} tokenIn - 输入代币地址
|
||
* @param {string} tokenOut - 输出代币地址
|
||
* @param {BigNumber} amountIn - 输入数量
|
||
* @param {number} slippageTolerance - 滑点容忍度 (0.005 = 0.5%)
|
||
* @returns {Promise<{minOut, expectedOut, feeInfo, priceInfo}>}
|
||
*/
|
||
async function calculateSwapMinOut(tokenIn, tokenOut, amountIn, slippageTolerance = 0.005) {
|
||
const PRICE_PRECISION = ethers.BigNumber.from("1000000000000000000000000000000");
|
||
const BASIS_POINTS = 10000;
|
||
|
||
try {
|
||
// 1. 获取价格(并行查询)
|
||
const [priceIn, priceOut] = await Promise.all([
|
||
ytVault.getMinPrice(tokenIn), // 输入用MinPrice
|
||
ytVault.getMaxPrice(tokenOut) // 输出用MaxPrice
|
||
]);
|
||
|
||
// 2. 计算USDY价值
|
||
const usdyAmount = amountIn.mul(priceIn).div(PRICE_PRECISION);
|
||
|
||
// 3. 获取手续费率
|
||
const feeBasisPoints = await ytVault.getSwapFeeBasisPoints(
|
||
tokenIn,
|
||
tokenOut,
|
||
usdyAmount
|
||
);
|
||
|
||
// 4. 计算理论输出
|
||
const theoreticalOut = usdyAmount.mul(PRICE_PRECISION).div(priceOut);
|
||
|
||
// 5. 扣除手续费
|
||
const expectedOut = theoreticalOut
|
||
.mul(BASIS_POINTS - feeBasisPoints)
|
||
.div(BASIS_POINTS);
|
||
|
||
// 6. 应用滑点
|
||
const minOut = expectedOut.mul(
|
||
ethers.BigNumber.from(Math.floor((1 - slippageTolerance) * 10000))
|
||
).div(10000);
|
||
|
||
return {
|
||
minOut,
|
||
expectedOut,
|
||
theoreticalOut,
|
||
usdyAmount,
|
||
feeBasisPoints: feeBasisPoints.toNumber(),
|
||
priceInfo: {
|
||
priceIn: ethers.utils.formatUnits(priceIn, 30),
|
||
priceOut: ethers.utils.formatUnits(priceOut, 30),
|
||
effectiveRate: theoreticalOut.mul(10000).div(amountIn).toNumber() / 100
|
||
},
|
||
feeInfo: {
|
||
feeBps: feeBasisPoints.toNumber(),
|
||
feeAmount: theoreticalOut.sub(expectedOut)
|
||
}
|
||
};
|
||
} catch (error) {
|
||
console.error("计算 _minOut 失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
|