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