Arbitrage Optimal amountIn calculation problem #7
-
I write a function to calculate optimal amountIn but it doesnt calculate correctly. Functions: /// @dev calculate the maximum base asset amount to borrow in order to get maximum profit during arbitrage
function calcBorrowAmount(OrderedReserves memory reserves) internal pure returns (uint256 amount) {
// we can't use a1,b1,a2,b2 directly, because it will result overflow/underflow on the intermediate result
// so we:
// 1. divide all the numbers by d to prevent from overflow/underflow
// 2. calculate the result by using above numbers
// 3. multiply d with the result to get the final result
// Note: this workaround is only suitable for ERC20 token with 18 decimals, which I believe most tokens do
/*
r = optimal amount in
x_a = reserve out of AMM A ( b1)
y_a = reserve in of AMM A a1
x_b = reserve in of AMM B
y_b = reserve out of AMM B
f = fee (0.03%) */
uint256 x_a_256 = reserves.b1;
uint256 y_a_256 = reserves.a1;
uint256 x_b_256 = reserves.a2;
uint256 y_b_256 = reserves.b2;
// choose appropriate number to divide based on the minimum number
uint256 d;
{
uint256 min1 = y_a_256 < x_a_256 ? y_a_256 : x_a_256;
uint256 min2 = x_b_256 < y_b_256 ? x_b_256 : y_b_256;
uint256 min = min1 < min2 ? min1 : min2;
if (min > 1e24) {
d = 1e20;
} else if (min > 1e23) {
d = 1e19;
} else if (min > 1e22) {
d = 1e18;
} else if (min > 1e21) {
d = 1e17;
} else if (min > 1e20) {
d = 1e16;
} else if (min > 1e19) {
d = 1e15;
} else if (min > 1e18) {
d = 1e14;
} else if (min > 1e17) {
d = 1e13;
} else if (min > 1e16) {
d = 1e12;
} else if (min > 1e15) {
d = 1e11;
} else {
d = 1e10;
}
}
(int256 y_a, int256 x_b, int256 x_a, int256 y_b) =
(int256(y_a_256 / d), int256(x_b_256 / d), int256(x_a_256 / d), int256(y_b_256 / d));
/* k = (1-f)*x_b + (1-f)**2*x_a
a = k**2
b = 2*k*y_a*x_b
c = (y_a*x_b)**2 - (1-f)**2*x_a*y_b*y_a*x_b
r = (-b + sqrt(b**2 - 4*a*c)) / (2*a) */
int256 k = (x_b * 997) / 1000 + (x_a * 997 * 977) / 1000 / 1000;
int256 a = k * k;
int256 b = 2 * k * y_a * x_b;
int256 c = (y_a * x_b) * (y_a * x_b) - (x_a * y_b * y_a * x_b * 997 * 997) / 1000 / 1000;
(int256 x1, int256 x2) = calcSolutionForQuadratic(a, b, c);
// 0 < x < b1 and 0 < x < b2
require((x1 > 0 && x1 < x_a && x1 < y_b) || (x2 > 0 && x2 < x_a && x2 < y_b), "Wrong input order");
amount = (x1 > 0 && x1 < x_a && x1 < y_b) ? uint256(x1) * d : uint256(x2) * d;
}
function calcSolutionForQuadratic(int256 a, int256 b, int256 c) internal pure returns (int256 x1, int256 x2) {
int256 m = b ** 2 - 4 * a * c;
// m < 0 leads to complex number
require(m > 0, "Complex number");
int256 sqrtM = int256(sqrt(uint256(m)));
x1 = (-b + sqrtM) / (2 * a);
x2 = (-b - sqrtM) / (2 * a);
}
/// @dev Newton’s method for caculating square root of n
function sqrt(uint256 n) internal pure returns (uint256 res) {
assert(n > 1);
// The scale factor is a crude way to turn everything into integer calcs.
// Actually do (n * 10 ^ 4) ^ (1/2)
uint256 _n = n * 10 ** 6;
uint256 c = _n;
res = _n;
uint256 xi;
while (true) {
xi = (res + c / res) / 2;
// don't need be too precise to save gas
if (res - xi < 1000) {
break;
}
res = xi;
}
res = res / 10 ** 3;
}
/// @notice Calculate how much profit we can by arbitraging between two pools
function getProfit(address pool0, address pool1) external view returns (uint256 profit, address baseToken) {
(bool baseTokenSmaller,,) = isbaseTokenSmaller(pool0, pool1);
baseToken = baseTokenSmaller ? IUniswapV2Pair(pool0).token0() : IUniswapV2Pair(pool0).token1();
(,, OrderedReserves memory orderedReserves) = getOrderedReserves(pool0, pool1, baseTokenSmaller);
uint256 borrowAmount = calcBorrowAmount(orderedReserves);
// borrow quote token on lower price pool,
uint256 debtAmount = getAmountIn(borrowAmount, orderedReserves.a1, orderedReserves.b1);
// sell borrowed quote token on higher price pool
uint256 baseTokenOutAmount = getAmountOut(borrowAmount, orderedReserves.b2, orderedReserves.a2);
if (baseTokenOutAmount < debtAmount) {
profit = 0;
} else {
profit = baseTokenOutAmount - debtAmount;
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 5 replies
-
This is what I would try instead
function normalize(uint256 a, uint256 d) pure returns (uint256) {
return a * (10**(18 - d));
}
function mul(uint256 x, uint256 y) pure returns (uint256) {
return x * y / 1e18;
}
function div(uint256 x, uint256 y) pure returns (uint256) {
return x * 1e18 / y;
} |
Beta Was this translation helpful? Give feedback.
-
Also i have another question. I created an opportunity to arbitrage between sushi and uni. I sell on uni 90 eth. Then i take the reserves. When put reserve number to desmos graph xr = 3.0797718755*1e21 ( i also write an node js script it match )
https://www.desmos.com/calculator/gjujz3ayta?lang=tr Then i write this function the validate this number: /// @notice Calculate how much profit we can by arbitraging between two pools
function getProfitByAmount(address pool0, address pool1, uint256 amount)
external
view
returns (uint256 profit, address baseToken)
{
(bool baseTokenSmaller,,) = isbaseTokenSmaller(pool0, pool1);
baseToken = baseTokenSmaller ? IUniswapV2Pair(pool0).token0() : IUniswapV2Pair(pool0).token1();
(,, OrderedReserves memory orderedReserves) = getOrderedReserves(pool0, pool1, baseTokenSmaller);
uint256 borrowAmount = amount;
// borrow quote token on lower price pool,
uint256 debtAmount = getAmountIn(borrowAmount, orderedReserves.a1, orderedReserves.b1);
// sell borrowed quote token on higher price pool
uint256 baseTokenOutAmount = getAmountOut(borrowAmount, orderedReserves.b2, orderedReserves.a2);
if (baseTokenOutAmount < debtAmount) {
profit = 0;
} else {
profit = baseTokenOutAmount - debtAmount;
}
} then this test: function test_flashArbitrage() public {
vm.prank(arbitrager);
uint256 profit;
(profit,) = arb.getProfitByAmount(UNISWAP_V2_PAIR_DAI_WETH, SUSHISWAP_V2_PAIR_DAI_WETH, 3.0797718755 * 1e21);
console2.log("profit", profit);
(profit,) = arb.getProfitByAmount(UNISWAP_V2_PAIR_DAI_WETH, SUSHISWAP_V2_PAIR_DAI_WETH, 30000 * 1e18);
console2.log("profit", profit);
(profit,) = arb.getProfitByAmount(UNISWAP_V2_PAIR_DAI_WETH, SUSHISWAP_V2_PAIR_DAI_WETH, 90000 * 1e18);
console2.log("profit", profit);
(profit,) = arb.getProfitByAmount(UNISWAP_V2_PAIR_DAI_WETH, SUSHISWAP_V2_PAIR_DAI_WETH, 92000 * 1e18);
console2.log("profit", profit);
} Here is the console log:
as you can see the optimum amount in should be between 90000-92000 not 3079 why this math doesnt add up? |
Beta Was this translation helpful? Give feedback.
3.0797718755 * 1e21
is optimal amount in but it's being used as amount outhttps://github.com/Uniswap/v2-periphery/blob/0335e8f7e1bd1e8d8329fd300aea2ef2f36dd19f/contracts/libraries/UniswapV2Library.sol#L52-L53