price constraints working

This commit is contained in:
Tim Olson
2023-11-05 16:50:06 -04:00
parent aa007a4fcd
commit add4f72611
5 changed files with 52 additions and 17 deletions

View File

@@ -2,7 +2,7 @@
# this script requires the jq command $(sudo apt install jq)
# first-pass build
forge build "$@" || exit 1
forge build --force "$@" || exit 1
# calculate the Vault init code hash using the bytecode generated for Vault
# shellcheck disable=SC2046

View File

@@ -220,11 +220,14 @@ library OrderLib {
// c.valueSqrtX96 = uint160(price * c.valueSqrtX96 / 2**96);
int256 limit256 = int256(uint256(lc.valueSqrtX96));
if( lc.slopeSqrtX96 != 0 ) {
// todo cannot add square roots.
limit256 += int256(block.timestamp - lc.time) * lc.slopeSqrtX96 / 2**96;
if( limit256 < 0 )
limit256 = 0;
}
console2.log(limit256);
console2.log(price);
console2.log(lc.isAbove);
uint160 limit = uint160(uint256(limit256));
// use <= and >= here because trading AT the limit results in 0 volume. price must exceed the limit.
if( lc.isAbove && price <= limit || !lc.isAbove && price >= limit )
@@ -254,6 +257,10 @@ library OrderLib {
- (status.order.amountIsInput ? status.trancheFilledIn[trancheIndex] : status.trancheFilledOut[trancheIndex]); // minus tranche fills
console2.log('amount');
console2.log(amount);
console2.log('limit');
console2.log(sqrtPriceLimitX96);
console2.log('price');
console2.log(sqrtPriceX96);
// order amount remaining
require( (status.order.amountIsInput ? status.filledIn : status.filledOut) <= status.order.amount, 'OVERFILL' );
uint256 remaining = status.order.amount - (status.order.amountIsInput ? status.filledIn : status.filledOut);

View File

@@ -1,5 +1,4 @@
// SPDX-License-Identifier: UNLICENSED
//pragma solidity =0.7.6;
pragma solidity >=0.8.0;
pragma abicoder v2;
@@ -9,6 +8,8 @@ import "./OrderLib.sol";
import "./Vault.sol";
import "./VaultDeployer.sol";
import "./Factory.sol";
import "forge-std/console2.sol";
contract QueryHelper {
uint8 constant public version = 1;
@@ -47,28 +48,40 @@ contract QueryHelper {
function getRoutes( address tokenA, address tokenB ) public view
returns(RoutesResult[] memory routes) {
// todo discover all supported pools
console2.log('getRoutes');
console2.log(tokenA);
console2.log(tokenB);
// here we find the highest liquidity pool for v2 and for v3
uint24[4] memory fees = [uint24(100),500,3000,10000];
uint24 uniswapV2Fee = 0;
// uint128 uniswapV2Liquidity = 0;
// address uniswapV2Pool = address(0);
uint24 uniswapV3Fee = 0;
uint128 uniswapV3Liquidity = 0;
uint256 uniswapV3Liquidity = 0;
address uniswapV3Pool = address(0);
IERC20 ercA = IERC20(tokenA);
for( uint8 f=0; f<4; f++ ) {
IUniswapV3Pool pool = IUniswapV3Pool(Constants.uniswapV3Factory.getPool(tokenA, tokenB, fees[f]));
try pool.liquidity() returns (uint128 liquidity) {
// todo v2
if( liquidity > uniswapV3Liquidity ) {
uniswapV3Fee = fees[f];
uniswapV3Liquidity = liquidity;
uniswapV3Pool = address(pool);
}
console2.log('getPool..');
uint24 fee = fees[f];
IUniswapV3Pool pool = IUniswapV3Pool(Constants.uniswapV3Factory.getPool(tokenA, tokenB, fee));
if( address(pool) == address(0) ) {
console2.log('no pool');
continue;
}
catch {
console2.log('gotPool.');
console2.log(address(pool));
// NOTE: pool.liquidity() is only the current tick's liquidity, so we look at the pool's balance
// of one of the tokens as a measure of liquidity
uint256 liquidity = ercA.balanceOf(address(pool));
if( liquidity > uniswapV3Liquidity ) {
uniswapV3Fee = fee;
uniswapV3Liquidity = liquidity;
uniswapV3Pool = address(pool);
}
}
uint8 routesCount = uniswapV3Fee > 0 ? 1 : 0 + uniswapV2Fee > 0 ? 1 : 0;
console2.log(uniswapV3Pool);
console2.log(uint(routesCount));
routes = new QueryHelper.RoutesResult[](routesCount);
uint8 i = 0;
// todo v2

View File

@@ -1,5 +1,4 @@
// SPDX-License-Identifier: UNLICENSED
//pragma solidity =0.7.6;
pragma solidity >=0.8.0;
pragma abicoder v2;
@@ -15,7 +14,7 @@ library UniswapSwapper {
address pool;
address tokenIn;
address tokenOut;
address recipient;
address recipient; // todo refactor back into bool outputToOwner to save space and constrain the money path
uint24 fee;
uint256 amount;
uint160 sqrtPriceLimitX96;
@@ -135,4 +134,19 @@ library UniswapSwapper {
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), 0);
}
// from https://github.com/ethereum/dapp-bin/pull/50/files
// the same logic as UniswapV2's version of sqrt
function sqrt(uint x) internal pure returns (uint y) {
// todo overflow is not possible in this algorithm, correct? we map wrap it in unchecked {}
if (x == 0) return 0;
else if (x <= 3) return 1;
uint z = (x + 1) / 2;
y = x;
while (z < y)
{
y = z;
z = (x / z + z) / 2;
}
}
}

View File

@@ -41,7 +41,8 @@ contract MockEnv {
inverted = address(COIN) > address(USD);
token0 = inverted ? address(USD) : address(COIN);
token1 = inverted ? address(COIN) : address(USD);
uint160 initialPrice = uint160(79228162514264337593543); // price 1e-12 = sqrt price 1e-6 = 2**96 / 10**6
// uint160 initialPrice = uint160(79228162514264337593543); // price 1e-12 = sqrt price 1e-6 = 2**96 / 10**6
uint160 initialPrice = uint160(79228162514264337593543950336000000); // $1.00
console2.log('if this is the last line before a revert then make sure to run forge with --rpc-url');
// if this reverts here make sure Anvil is started and you are running forge with --rpc-url
pool = IUniswapV3Pool(nfpm.createAndInitializePoolIfNecessary(token0, token1, fee, initialPrice));
@@ -138,8 +139,8 @@ contract MockEnv {
return swapper.exactInputSingle(params);
}
function price() public view returns (uint160 sqrtPrice) {
(sqrtPrice,,,,,,) = pool.slot0();
function price() public view returns (uint160 sqrtPriceX96) {
(sqrtPriceX96,,,,,,) = pool.slot0();
}
function swapToPrice(uint160 sqrtPriceLimitX96) public {