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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|