大佬们好,现在在做的一个项目,通过在pancake smart router V3地址上(0x13f4EA83D0bd40E75C8222255bc855a974568Dd4)发生的交易,使用合约计算发生交易的流动池的存储量和价格影响,已经网上扒了一些代码,但是在计算存储量和实际的不一致,而且价格影响的计算貌似只支持v2的池子,请大佬们帮忙看看
合约代码我也贴一部分出来,大佬们麻烦帮忙看看
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;
}