50 求助pancake smart router V3合约计算存储量和价格影响

大佬们好,现在在做的一个项目,通过在pancake smart router V3地址上(0x13f4EA83D0bd40E75C8222255bc855a974568Dd4)发生的交易,使用合约计算发生交易的流动池的存储量和价格影响,已经网上扒了一些代码,但是在计算存储量和实际的不一致,而且价格影响的计算貌似只支持v2的池子,请大佬们帮忙看看

image.png

合约代码我也贴一部分出来,大佬们麻烦帮忙看看

using SafeMath for uint;

struct TradeOrdered {
    address[] _targetPath;
    address _targetRouter;
    uint _targetAmountIn;
    address tokenA;
    address tokenB;
    uint tradeType;
    uint24 fee;
}

function decimals(address _token) public view returns (uint8 decimal) {
  return IERC20(_token).decimals();
}

function getAmountsOut(address _router, uint amountIn, address[] memory path) public view returns (uint[] memory amounts) {
    return IUniswapV2Router02(_router).getAmountsOut(amountIn, path);
}

function getAmountOut(address _router, uint amountIn, uint reserveIn, uint reserveOut) public pure returns (uint amountOut) {
    return IUniswapV2Router02(_router).getAmountOut(amountIn, reserveIn, reserveOut);
}

function getAmountsIn(address _router, uint amountOut, address[] memory path) public view returns (uint[] memory amounts) {
    return IUniswapV2Router02(_router).getAmountsIn(amountOut, path);
}

function getAmountIn(address _router, uint amountOut, uint reserveIn, uint reserveOut) public pure returns (uint amountIn) {
    return IUniswapV2Router02(_router).getAmountIn(amountOut, reserveIn, reserveOut);
}

// 获取V3地址对储备量信息
function getReservesV3(address _router, address tokenA, address tokenB, uint24 fee) public view returns (uint _reserveInput, uint _reserveOutput) {
    address poolAddress = getPoolAddress(_router, tokenA, tokenB, fee);
    require(poolAddress != address(0), "Pool not found");

    IUniswapV3Pool pool = IUniswapV3Pool(poolAddress);
    (uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
    (uint reserve0, uint reserve1) = calculateReserves(sqrtPriceX96);
    (uint reserveIn, uint reserveOut) = tokenA == poolAddress ? (reserve0, reserve1) : (reserve1, reserve0);
    return (reserveIn,reserveOut);
}

function calculateReserves(uint160 sqrtPriceX96) internal pure returns (uint _reserveInput, uint _reserveOutput) {
    _reserveInput = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, 2**96);
    _reserveOutput = FullMath.mulDiv(1, 2**96, sqrtPriceX96);
}

function getPoolAddress(address _router, address tokenA, address tokenB, uint24 fee) public view returns (address) {
    IUniswapV3Factory factory = IUniswapV3Factory(_router);
    return factory.getPool(tokenA, tokenB, fee);
}

//获取v3交易买入卖出后的涨幅或者跌幅(百分比)(tokenA:bnb || usdt || busd    tokenB:token)
function getTradePriceImpactV3(address[] memory _targetPath, address _targetRouter, uint _targetAmountIn, address tokenA, address tokenB, uint tradeType, uint24 fee) public view returns (uint _priceImpact){
    uint beforePrice = getTokenPrice(_targetRouter, tokenA, tokenB);
    //使用结构体,解决stack too deep错误
    TradeOrdered memory tradeOrdered;
    tradeOrdered._targetPath = _targetPath;
    tradeOrdered._targetRouter = _targetRouter;
    tradeOrdered._targetAmountIn = _targetAmountIn;
    tradeOrdered.tokenA = tokenA;
    tradeOrdered.tokenB = tokenB;
    tradeOrdered.tradeType = tradeType;
    tradeOrdered.fee = fee;

    (uint reserveIn, uint reserveOut) = getReservesV3(tradeOrdered._targetRouter, tradeOrdered.tokenA, tradeOrdered.tokenB, tradeOrdered.fee);
    uint input = 1000000000000000;//bnb || busd || usdt
    uint tokenDecimals = uint(IERC20(tradeOrdered.tokenB).decimals());
    uint amountOut2;
    uint buyOrSell = 0;//买还是卖 0:买 1:卖
    uint afterPrice = 0;
    if(tradeOrdered._targetPath[0] == tradeOrdered.tokenB){
        //卖单
        buyOrSell = 1;
        //tradeType 0:  输入卖出代币数 来获取bnb  1:输入能获得的bnb数  来卖出代币
        if(tradeOrdered.tradeType == 0){
            uint amountOut = getAmountOut(tradeOrdered._targetRouter, tradeOrdered._targetAmountIn, reserveOut, reserveIn);
            amountOut2 = getAmountOut(tradeOrdered._targetRouter, input, reserveIn.sub(amountOut), reserveOut.add(tradeOrdered._targetAmountIn));
        }else{
            //这里传参的_amountIn 实际上是amountOut 注:这个amountOut是路径最终获取的代币的数量
            uint amountOut = tradeOrdered._targetAmountIn;
            uint[] memory amounts = getAmountsIn(tradeOrdered._targetRouter, amountOut, tradeOrdered._targetPath);//0: 是传入token数量 1:token 换取[1]代币 的数量
            amountOut2 = getAmountOut(tradeOrdered._targetRouter, input, reserveIn.sub(amounts[1]), reserveOut.add(amounts[0]));
        }
    }else if(tradeOrdered._targetPath[tradeOrdered._targetPath.length - 1] == tradeOrdered.tokenB){
        //买单
        //tradeType 0:  输入购买(bnb || usdt || busd) 数量 来获取代币  1:输入能获得的代币数  来买入代币
        if(tradeOrdered.tradeType == 0){
            uint[] memory amounts = getAmountsOut(tradeOrdered._targetRouter, tradeOrdered._targetAmountIn, tradeOrdered._targetPath);
            amountOut2 = getAmountOut(tradeOrdered._targetRouter, input, reserveIn.add(amounts[tradeOrdered._targetPath.length - 2]), reserveOut.sub(amounts[tradeOrdered._targetPath.length - 1]));
        }else{
            //这里传参的_amountIn 实际上是amountOut 注:这个amountOut是路径最终获取的代币的数量
            uint amountOut = tradeOrdered._targetAmountIn;
            uint[] memory amounts = getAmountsIn(tradeOrdered._targetRouter, amountOut, tradeOrdered._targetPath);
            amountOut2 = getAmountOut(tradeOrdered._targetRouter, input, reserveIn.add(amounts[tradeOrdered._targetPath.length - 2]), reserveOut.sub(amountOut));
        }
    } 
    if(tokenDecimals < 18){
        afterPrice = input.mul(10 ** 18).div(amountOut2.mul(10 ** (18 - tokenDecimals)));
    }else{
        afterPrice = input.mul(10 ** 18).div(amountOut2);
    }
    return buyOrSell == 0 ? afterPrice.sub(beforePrice).mul(10000).div(beforePrice) : (beforePrice.sub(afterPrice).mul(10000).div(beforePrice));
}

//获取当前代币的价格 (tokenA:bnb || usdt || busd  tokenB:token)
function getTokenPrice(address _router, address tokenA, address tokenB) public view returns (uint _price){
    uint reserveInput = 1000000000000000;
    address[] memory _path = new address[](2);
    _path[0] = tokenA;
    _path[1] = tokenB;
    uint[] memory amounts = getAmountsOut(_router, reserveInput, _path);
    uint tokenDecimals = uint(IERC20(tokenB).decimals());
    uint price = 0;
    if(tokenDecimals < 18){
         price = reserveInput.mul(10 ** 18).div(amounts[1].mul(10 ** (18 - tokenDecimals)));
    }else{
         price = reserveInput.mul(10 ** 18).div(amounts[1]);
    }
    return price;
}
请先 登录 后评论

1 个回答

Tiny熊
  擅长:智能合约,以太坊
请先 登录 后评论
  • 3 关注
  • 0 收藏,2544 浏览
  • 路远 提出于 2023-06-05 10:18