diff --git a/brownie-config.yaml b/brownie-config.yaml index 17e0433..edfc35b 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -6,13 +6,15 @@ autofetch_sources: true # require OpenZepplin Contracts dependencies: - OpenZeppelin/openzeppelin-contracts@4.1.0 + - 16slim/v3-core@1.0.2-solc-0.8-simulate # path remapping to support imports from GitHub/NPM compiler: solc: - version: 0.8.11 + version: 0.8.12 remappings: - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.1.0" + - "@uniswap=16slim/v3-core@1.0.2-solc-0.8-simulate" optimizer: details: diff --git a/contracts/Helpers/TupleHelper.sol b/contracts/Helpers/TupleHelper.sol index 2db0eab..62f2c66 100644 --- a/contracts/Helpers/TupleHelper.sol +++ b/contracts/Helpers/TupleHelper.sol @@ -36,5 +36,18 @@ contract TupleHelper { } } } + + function getElement(bytes calldata tuple, uint256 index) + public + pure + returns (bytes memory) + { + uint256 byteIndex; + unchecked { + byteIndex = index * 32; + require(tuple.length >= 32 && byteIndex <= tuple.length - 32); + return tuple[byteIndex:byteIndex+32]; + } + } } diff --git a/contracts/Helpers/UniswapV3Helper.sol b/contracts/Helpers/UniswapV3Helper.sol new file mode 100644 index 0000000..c9d6349 --- /dev/null +++ b/contracts/Helpers/UniswapV3Helper.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import '../Libraries/UniswapV3/LiquidityAmounts.sol'; +import '../Libraries/UniswapV3/TickMath.sol'; +import {IUniswapV3Pool} from "@uniswap/contracts/interfaces/IUniswapV3Pool.sol"; +import {VM} from "../VM.sol"; + + +contract UniswapV3Helper is VM { + + function getLPAmount( + address pool, + int24 minTick, + int24 maxTick, + uint256 maxToken0Amount, + uint256 maxToken1Amount + ) public view returns (uint256, uint256) { + + (uint160 sqrtRatioX96,,,,,,) = IUniswapV3Pool(pool).slot0(); + + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(minTick); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(maxTick); + + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + if (sqrtRatioX96 <= sqrtRatioAX96) { + return (maxToken0Amount, 0); + } else if (sqrtRatioX96 < sqrtRatioBX96) { + uint128 liquidity0 = LiquidityAmounts.getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, maxToken0Amount); + uint128 liquidity1 = LiquidityAmounts.getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, maxToken1Amount); + + if (liquidity0 < liquidity1) { + return (maxToken0Amount, LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity0)); + } else { + return (LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity1), maxToken1Amount); + } + } else { + return (0, maxToken1Amount); + } + } + + function getLPAmount0( + address pool, + int24 minTick, + int24 maxTick, + uint256 maxToken0Amount, + uint256 maxToken1Amount + ) external view returns (uint256 amount0) { + (amount0,) = getLPAmount(pool, minTick, maxTick, maxToken0Amount, maxToken1Amount); + } + + function getLPAmount1( + address pool, + int24 minTick, + int24 maxTick, + uint256 maxToken0Amount, + uint256 maxToken1Amount + ) external view returns (uint256 amount1) { + (, amount1) = getLPAmount(pool, minTick, maxTick, maxToken0Amount, maxToken1Amount); + } + + function execute(bytes32[] calldata commands, bytes[] memory state) + public payable returns (bytes[] memory) { + return _execute(commands, state); + } +} + diff --git a/contracts/Libraries/UniswapV3/FixedPoint96.sol b/contracts/Libraries/UniswapV3/FixedPoint96.sol new file mode 100644 index 0000000..63b42c2 --- /dev/null +++ b/contracts/Libraries/UniswapV3/FixedPoint96.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.4.0; + +/// @title FixedPoint96 +/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) +/// @dev Used in SqrtPriceMath.sol +library FixedPoint96 { + uint8 internal constant RESOLUTION = 96; + uint256 internal constant Q96 = 0x1000000000000000000000000; +} diff --git a/contracts/Libraries/UniswapV3/FullMath.sol b/contracts/Libraries/UniswapV3/FullMath.sol new file mode 100644 index 0000000..e357426 --- /dev/null +++ b/contracts/Libraries/UniswapV3/FullMath.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title Contains 512-bit math functions +/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision +/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits +library FullMath { + /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + /// @param a The multiplicand + /// @param b The multiplier + /// @param denominator The divisor + /// @return result The 256-bit result + /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv + function mulDiv( + uint256 a, + uint256 b, + uint256 denominator + ) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = a * b + // Compute the product mod 2**256 and mod 2**256 - 1 + // then use the Chinese Remainder Theorem to reconstruct + // the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2**256 + prod0 + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(a, b, not(0)) + prod0 := mul(a, b) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division + if (prod1 == 0) { + require(denominator > 0); + assembly { + result := div(prod0, denominator) + } + return result; + } + + // Make sure the result is less than 2**256. + // Also prevents denominator == 0 + require(denominator > prod1); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0] + // Compute remainder using mulmod + uint256 remainder; + assembly { + remainder := mulmod(a, b, denominator) + } + // Subtract 256 bit number from 512 bit number + assembly { + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator + // Compute largest power of two divisor of denominator. + // Always >= 1. + uint256 twos = (0 - denominator) & denominator; + // Divide denominator by power of two + assembly { + denominator := div(denominator, twos) + } + + // Divide [prod1 prod0] by the factors of two + assembly { + prod0 := div(prod0, twos) + } + // Shift in bits from prod1 into prod0. For this we need + // to flip `twos` such that it is 2**256 / twos. + // If twos is zero, then it becomes one + assembly { + twos := add(div(sub(0, twos), twos), 1) + } + prod0 |= prod1 * twos; + + // Invert denominator mod 2**256 + // Now that denominator is an odd number, it has an inverse + // modulo 2**256 such that denominator * inv = 1 mod 2**256. + // Compute the inverse by starting with a seed that is correct + // correct for four bits. That is, denominator * inv = 1 mod 2**4 + uint256 inv = (3 * denominator) ^ 2; + // Now use Newton-Raphson iteration to improve the precision. + // Thanks to Hensel's lifting lemma, this also works in modular + // arithmetic, doubling the correct bits in each step. + inv *= 2 - denominator * inv; // inverse mod 2**8 + inv *= 2 - denominator * inv; // inverse mod 2**16 + inv *= 2 - denominator * inv; // inverse mod 2**32 + inv *= 2 - denominator * inv; // inverse mod 2**64 + inv *= 2 - denominator * inv; // inverse mod 2**128 + inv *= 2 - denominator * inv; // inverse mod 2**256 + + // Because the division is now exact we can divide by multiplying + // with the modular inverse of denominator. This will give us the + // correct result modulo 2**256. Since the precoditions guarantee + // that the outcome is less than 2**256, this is the final result. + // We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inv; + return result; + } + } + + /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + /// @param a The multiplicand + /// @param b The multiplier + /// @param denominator The divisor + /// @return result The 256-bit result + function mulDivRoundingUp( + uint256 a, + uint256 b, + uint256 denominator + ) internal pure returns (uint256 result) { + unchecked { + result = mulDiv(a, b, denominator); + if (mulmod(a, b, denominator) > 0) { + require(result < type(uint256).max); + result++; + } + } + } +} diff --git a/contracts/Libraries/UniswapV3/LiquidityAmounts.sol b/contracts/Libraries/UniswapV3/LiquidityAmounts.sol new file mode 100644 index 0000000..082e8aa --- /dev/null +++ b/contracts/Libraries/UniswapV3/LiquidityAmounts.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +import "./FullMath.sol"; +import "./FixedPoint96.sol"; + +/// @title Liquidity amount functions +/// @notice Provides functions for computing liquidity amounts from token amounts and prices +library LiquidityAmounts { + /// @notice Downcasts uint256 to uint128 + /// @param x The uint258 to be downcasted + /// @return y The passed value, downcasted to uint128 + function toUint128(uint256 x) private pure returns (uint128 y) { + require((y = uint128(x)) == x); + } + + /// @notice Computes the amount of liquidity received for a given amount of token0 and price range + /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param amount0 The amount0 being sent in + /// @return liquidity The amount of returned liquidity + function getLiquidityForAmount0( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint256 amount0 + ) internal pure returns (uint128 liquidity) { + if (sqrtRatioAX96 > sqrtRatioBX96) + (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + uint256 intermediate = FullMath.mulDiv( + sqrtRatioAX96, + sqrtRatioBX96, + FixedPoint96.Q96 + ); + return + toUint128( + FullMath.mulDiv( + amount0, + intermediate, + sqrtRatioBX96 - sqrtRatioAX96 + ) + ); + } + + /// @notice Computes the amount of liquidity received for a given amount of token1 and price range + /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param amount1 The amount1 being sent in + /// @return liquidity The amount of returned liquidity + function getLiquidityForAmount1( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint256 amount1 + ) internal pure returns (uint128 liquidity) { + if (sqrtRatioAX96 > sqrtRatioBX96) + (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + return + toUint128( + FullMath.mulDiv( + amount1, + FixedPoint96.Q96, + sqrtRatioBX96 - sqrtRatioAX96 + ) + ); + } + + /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current + /// pool prices and the prices at the tick boundaries + /// @param sqrtRatioX96 A sqrt price representing the current pool prices + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param amount0 The amount of token0 being sent in + /// @param amount1 The amount of token1 being sent in + /// @return liquidity The maximum amount of liquidity received + function getLiquidityForAmounts( + uint160 sqrtRatioX96, + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint256 amount0, + uint256 amount1 + ) internal pure returns (uint128 liquidity) { + if (sqrtRatioAX96 > sqrtRatioBX96) + (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + if (sqrtRatioX96 <= sqrtRatioAX96) { + liquidity = getLiquidityForAmount0( + sqrtRatioAX96, + sqrtRatioBX96, + amount0 + ); + } else if (sqrtRatioX96 < sqrtRatioBX96) { + uint128 liquidity0 = getLiquidityForAmount0( + sqrtRatioX96, + sqrtRatioBX96, + amount0 + ); + uint128 liquidity1 = getLiquidityForAmount1( + sqrtRatioAX96, + sqrtRatioX96, + amount1 + ); + + liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; + } else { + liquidity = getLiquidityForAmount1( + sqrtRatioAX96, + sqrtRatioBX96, + amount1 + ); + } + } + + /// @notice Computes the amount of token0 for a given amount of liquidity and a price range + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param liquidity The liquidity being valued + /// @return amount0 The amount of token0 + function getAmount0ForLiquidity( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint128 liquidity + ) internal pure returns (uint256 amount0) { + if (sqrtRatioAX96 > sqrtRatioBX96) + (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + return + FullMath.mulDiv( + uint256(liquidity) << FixedPoint96.RESOLUTION, + sqrtRatioBX96 - sqrtRatioAX96, + sqrtRatioBX96 + ) / sqrtRatioAX96; + } + + /// @notice Computes the amount of token1 for a given amount of liquidity and a price range + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param liquidity The liquidity being valued + /// @return amount1 The amount of token1 + function getAmount1ForLiquidity( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint128 liquidity + ) internal pure returns (uint256 amount1) { + if (sqrtRatioAX96 > sqrtRatioBX96) + (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + return + FullMath.mulDiv( + liquidity, + sqrtRatioBX96 - sqrtRatioAX96, + FixedPoint96.Q96 + ); + } + + /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current + /// pool prices and the prices at the tick boundaries + /// @param sqrtRatioX96 A sqrt price representing the current pool prices + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param liquidity The liquidity being valued + /// @return amount0 The amount of token0 + /// @return amount1 The amount of token1 + function getAmountsForLiquidity( + uint160 sqrtRatioX96, + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint128 liquidity + ) internal pure returns (uint256 amount0, uint256 amount1) { + if (sqrtRatioAX96 > sqrtRatioBX96) + (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + if (sqrtRatioX96 <= sqrtRatioAX96) { + amount0 = getAmount0ForLiquidity( + sqrtRatioAX96, + sqrtRatioBX96, + liquidity + ); + } else if (sqrtRatioX96 < sqrtRatioBX96) { + amount0 = getAmount0ForLiquidity( + sqrtRatioX96, + sqrtRatioBX96, + liquidity + ); + amount1 = getAmount1ForLiquidity( + sqrtRatioAX96, + sqrtRatioX96, + liquidity + ); + } else { + amount1 = getAmount1ForLiquidity( + sqrtRatioAX96, + sqrtRatioBX96, + liquidity + ); + } + } +} diff --git a/contracts/Libraries/UniswapV3/TickMath.sol b/contracts/Libraries/UniswapV3/TickMath.sol new file mode 100644 index 0000000..33fbfee --- /dev/null +++ b/contracts/Libraries/UniswapV3/TickMath.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.12; + +/// @title Math library for computing sqrt prices from ticks and vice versa +/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports +/// prices between 2**-128 and 2**128 +library TickMath { + error T(); + error R(); + + /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 + int24 internal constant MIN_TICK = -887272; + /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 + int24 internal constant MAX_TICK = -MIN_TICK; + + /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) + uint160 internal constant MIN_SQRT_RATIO = 4295128739; + /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) + uint160 internal constant MAX_SQRT_RATIO = + 1461446703485210103287273052203988822378723970342; + + /// @notice Calculates sqrt(1.0001^tick) * 2^96 + /// @dev Throws if |tick| > max tick + /// @param tick The input tick for the above formula + /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) + /// at the given tick + function getSqrtRatioAtTick(int24 tick) + internal + pure + returns (uint160 sqrtPriceX96) + { + unchecked { + uint256 absTick = tick < 0 + ? uint256(-int256(tick)) + : uint256(int256(tick)); + if (absTick > uint256(int256(MAX_TICK))) revert T(); + + uint256 ratio = absTick & 0x1 != 0 + ? 0xfffcb933bd6fad37aa2d162d1a594001 + : 0x100000000000000000000000000000000; + if (absTick & 0x2 != 0) + ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; + if (absTick & 0x4 != 0) + ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; + if (absTick & 0x8 != 0) + ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; + if (absTick & 0x10 != 0) + ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; + if (absTick & 0x20 != 0) + ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; + if (absTick & 0x40 != 0) + ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; + if (absTick & 0x80 != 0) + ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; + if (absTick & 0x100 != 0) + ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; + if (absTick & 0x200 != 0) + ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; + if (absTick & 0x400 != 0) + ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; + if (absTick & 0x800 != 0) + ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; + if (absTick & 0x1000 != 0) + ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; + if (absTick & 0x2000 != 0) + ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; + if (absTick & 0x4000 != 0) + ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; + if (absTick & 0x8000 != 0) + ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; + if (absTick & 0x10000 != 0) + ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; + if (absTick & 0x20000 != 0) + ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; + if (absTick & 0x40000 != 0) + ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; + if (absTick & 0x80000 != 0) + ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; + + if (tick > 0) ratio = type(uint256).max / ratio; + + // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. + // we then downcast because we know the result always fits within 160 bits due to our tick input constraint + // we round up in the division so getTickAtSqrtRatio of the output price is always consistent + sqrtPriceX96 = uint160( + (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) + ); + } + } + + /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio + /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may + /// ever return. + /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 + /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio + function getTickAtSqrtRatio(uint160 sqrtPriceX96) + internal + pure + returns (int24 tick) + { + unchecked { + // second inequality must be < because the price can never reach the price at the max tick + if ( + !(sqrtPriceX96 >= MIN_SQRT_RATIO && + sqrtPriceX96 < MAX_SQRT_RATIO) + ) revert R(); + uint256 ratio = uint256(sqrtPriceX96) << 32; + + uint256 r = ratio; + uint256 msb = 0; + + assembly { + let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(5, gt(r, 0xFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(4, gt(r, 0xFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(3, gt(r, 0xFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(2, gt(r, 0xF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(1, gt(r, 0x3)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := gt(r, 0x1) + msb := or(msb, f) + } + + if (msb >= 128) r = ratio >> (msb - 127); + else r = ratio << (127 - msb); + + int256 log_2 = (int256(msb) - 128) << 64; + + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(63, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(62, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(61, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(60, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(59, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(58, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(57, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(56, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(55, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(54, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(53, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(52, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(51, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(50, f)) + } + + int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number + + int24 tickLow = int24( + (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 + ); + int24 tickHi = int24( + (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 + ); + + tick = tickLow == tickHi + ? tickLow + : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 + ? tickHi + : tickLow; + } + } +} diff --git a/poetry.lock b/poetry.lock index 2377e9f..6174e6f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,37 +1,46 @@ [[package]] name = "aiohttp" -version = "3.8.1" +version = "3.7.4.post0" description = "Async http client/server framework (asyncio)" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -aiosignal = ">=1.1.2" -async-timeout = ">=4.0.0a3,<5.0" +async-timeout = ">=3.0,<4.0" attrs = ">=17.3.0" -charset-normalizer = ">=2.0,<3.0" -frozenlist = ">=1.1.1" +chardet = ">=2.0,<5.0" multidict = ">=4.5,<7.0" +typing-extensions = ">=3.6.5" yarl = ">=1.0,<2.0" [package.extras] -speedups = ["aiodns", "brotli", "cchardet"] +speedups = ["aiodns", "brotlipy", "cchardet"] [[package]] -name = "aiosignal" -version = "1.2.0" -description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" +name = "ape-safe" +version = "0.5.1" +description = "Build complex Gnosis Safe transactions and safely preview them in a forked environment." +category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8,<4.0" [package.dependencies] -frozenlist = ">=1.1.0" +eth-brownie = ">=1.17.0,<2.0.0" +gnosis-py = ">=3.7.5,<4.0.0" +trezor = ">=0.13.0,<0.14.0" + +[[package]] +name = "asn1crypto" +version = "1.5.1" +description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "asttokens" -version = "2.0.5" +version = "2.0.4" description = "Annotate AST trees with source code positions" category = "main" optional = false @@ -45,11 +54,11 @@ test = ["astroid", "pytest"] [[package]] name = "async-timeout" -version = "4.0.2" +version = "3.0.1" description = "Timeout context manager for asyncio programs" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.5.3" [[package]] name = "atomicwrites" @@ -61,28 +70,28 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.4.0" +version = "21.2.0" description = "Classes Without Boilerplate" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] name = "base58" -version = "2.1.1" +version = "2.1.0" description = "Base58 and Base58Check implementation." category = "main" optional = false python-versions = ">=3.5" [package.extras] -tests = ["mypy", "PyHamcrest (>=2.0.2)", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] +tests = ["pytest-benchmark", "coveralls", "PyHamcrest (>=2.0.2)", "pytest-cov", "pytest-flake8", "pytest (>=4.6)"] [[package]] name = "bitarray" @@ -94,37 +103,66 @@ python-versions = "*" [[package]] name = "black" -version = "22.3.0" +version = "21.9b0" description = "The uncompromising code formatter." category = "main" optional = false python-versions = ">=3.6.2" [package.dependencies] -click = ">=8.0.0" +click = ">=7.1.2" mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" +pathspec = ">=0.9.0,<1" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +regex = ">=2020.1.8" +tomli = ">=0.2.6,<2.0.0" +typing-extensions = ">=3.10.0.0" [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cached-property" +version = "1.5.2" +description = "A decorator for caching properties in classes." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "certifi" -version = "2022.5.18.1" +version = "2021.10.8" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = ">=3.6" +python-versions = "*" + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "chardet" +version = "4.0.0" +description = "Universal encoding detector for Python 2 and 3" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.0.7" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -135,15 +173,27 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.1.3" +version = "8.0.3" description = "Composable command line interface toolkit" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "coincurve" +version = "17.0.0" +description = "Cross-platform Python CFFI bindings for libsecp256k1" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +asn1crypto = "*" +cffi = ">=1.3.0" + [[package]] name = "colorama" version = "0.4.5" @@ -152,13 +202,24 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "construct" +version = "2.10.68" +description = "A powerful declarative symmetric parser/builder for binary data" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +extras = ["arrow", "cloudpickle", "enum34", "lz4", "numpy", "ruamel.yaml"] + [[package]] name = "cytoolz" -version = "0.11.2" +version = "0.11.0" description = "Cython implementation of Toolz: High performance functional utilities" category = "main" optional = false -python-versions = ">=3.5" +python-versions = "*" [package.dependencies] toolz = ">=0.8.0" @@ -168,12 +229,27 @@ cython = ["cython"] [[package]] name = "dataclassy" -version = "0.11.1" +version = "0.11.0" description = "A fast and flexible reimplementation of data classes" category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "ecdsa" +version = "0.18.0" +description = "ECDSA cryptographic signature library (pure python)" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[package.dependencies] +six = ">=1.9.0" + +[package.extras] +gmpy = ["gmpy"] +gmpy2 = ["gmpy2"] + [[package]] name = "eip712" version = "0.1.0" @@ -197,6 +273,18 @@ lint = ["black (>=20.8b1,<21.0)", "mypy (>=0.800,<1.0)", "flake8 (>=3.8.3,<4.0)" release = ["setuptools", "setuptools-scm", "wheel", "twine"] test = ["pytest (>=6.0,<7.0)", "pytest-xdist", "pytest-cov", "hypothesis (>=6.2.0,<7.0)"] +[[package]] +name = "eip712-structs" +version = "1.1.0" +description = "A python library for EIP712 objects" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +eth-utils = ">=1.4.0" +pysha3 = ">=1.0.2" + [[package]] name = "eth-abi" version = "2.1.1" @@ -219,7 +307,7 @@ tools = ["hypothesis (>=3.6.1,<4)"] [[package]] name = "eth-account" -version = "0.5.7" +version = "0.5.6" description = "eth-account: Sign Ethereum transactions and messages with local private keys" category = "main" optional = false @@ -229,108 +317,109 @@ python-versions = ">=3.6, <4" bitarray = ">=1.2.1,<1.3.0" eth-abi = ">=2.0.0b7,<3" eth-keyfile = ">=0.5.0,<0.6.0" -eth-keys = ">=0.3.4,<0.4.0" +eth-keys = ">=0.2.1,<0.3.2 || >0.3.2,<0.4.0" eth-rlp = ">=0.1.2,<2" eth-utils = ">=1.3.0,<2" hexbytes = ">=0.1.0,<1" rlp = ">=1.0.0,<3" [package.extras] -dev = ["bumpversion (>=0.5.3,<1)", "pytest-watch (>=4.1.0,<5)", "wheel", "twine", "ipython", "hypothesis (>=4.18.0,<5)", "pytest (>=6.2.5,<7)", "pytest-xdist", "tox (==3.14.6)", "flake8 (==3.7.9)", "isort (>=4.2.15,<5)", "mypy (==0.770)", "pydocstyle (>=5.0.0,<6)", "Sphinx (>=1.6.5,<2)", "sphinx-rtd-theme (>=0.1.9,<1)", "towncrier (>=19.2.0,<20)"] +dev = ["bumpversion (>=0.5.3,<1)", "pytest-watch (>=4.1.0,<5)", "wheel", "twine", "ipython", "hypothesis (>=4.18.0,<5)", "pytest (==5.4.1)", "pytest-xdist", "tox (==3.14.6)", "flake8 (==3.7.9)", "isort (>=4.2.15,<5)", "mypy (==0.770)", "pydocstyle (>=5.0.0,<6)", "Sphinx (>=1.6.5,<2)", "sphinx-rtd-theme (>=0.1.9,<1)", "towncrier (>=19.2.0,<20)"] doc = ["Sphinx (>=1.6.5,<2)", "sphinx-rtd-theme (>=0.1.9,<1)", "towncrier (>=19.2.0,<20)"] lint = ["flake8 (==3.7.9)", "isort (>=4.2.15,<5)", "mypy (==0.770)", "pydocstyle (>=5.0.0,<6)"] -test = ["hypothesis (>=4.18.0,<5)", "pytest (>=6.2.5,<7)", "pytest-xdist", "tox (==3.14.6)"] +test = ["hypothesis (>=4.18.0,<5)", "pytest (==5.4.1)", "pytest-xdist", "tox (==3.14.6)"] [[package]] name = "eth-brownie" -version = "1.19.0" +version = "1.17.0" description = "A Python framework for Ethereum smart contract deployment, testing and interaction." category = "main" optional = false python-versions = ">=3.7,<4" [package.dependencies] -aiohttp = "3.8.1" -aiosignal = "1.2.0" -asttokens = "2.0.5" -async-timeout = "4.0.2" -attrs = "21.4.0" -base58 = "2.1.1" +aiohttp = "3.7.4.post0" +asttokens = "2.0.4" +async-timeout = "3.0.1" +attrs = "21.2.0" +base58 = "2.1.0" bitarray = "1.2.2" -black = "22.3.0" -certifi = "2022.5.18.1" -charset-normalizer = "2.0.12" -click = "8.1.3" -cytoolz = "0.11.2" -dataclassy = "0.11.1" +black = "21.9b0" +certifi = "2021.10.8" +chardet = "4.0.0" +charset-normalizer = "2.0.7" +click = "8.0.3" +cytoolz = "0.11.0" +dataclassy = "0.11.0" eip712 = "0.1.0" eth-abi = "2.1.1" -eth-account = "0.5.7" +eth-account = "0.5.6" eth-event = "1.2.3" eth-hash = {version = "0.3.2", extras = ["pycryptodome"]} eth-keyfile = "0.5.1" -eth-keys = "0.3.4" +eth-keys = "0.3.3" eth-rlp = "0.2.1" -eth-typing = "2.3.0" +eth-typing = "2.2.2" eth-utils = "1.10.0" execnet = "1.9.0" -frozenlist = "1.3.0" hexbytes = "0.2.2" -hypothesis = "6.27.3" -idna = "3.3" +hypothesis = "6.23.2" +idna = "3.2" inflection = "0.5.0" iniconfig = "1.1.1" ipfshttpclient = "0.8.0a2" jsonschema = "3.2.0" -lazy-object-proxy = "1.7.1" +lazy-object-proxy = "1.6.0" lru-dict = "1.1.7" multiaddr = "0.0.9" -multidict = "6.0.2" +multidict = "5.2.0" mypy-extensions = "0.4.3" mythx-models = "1.9.1" netaddr = "0.8.0" -packaging = "21.3" +packaging = "21.0" parsimonious = "0.8.1" pathspec = "0.9.0" -platformdirs = "2.5.2" +platformdirs = "2.4.0" pluggy = "1.0.0" -prompt-toolkit = "3.0.29" -protobuf = "3.20.1" -psutil = "5.9.1" -py = "1.11.0" +prompt-toolkit = "3.0.20" +protobuf = "3.18.1" +psutil = "5.8.0" +py = "1.10.0" py-solc-ast = "1.2.9" py-solc-x = "1.1.1" -pycryptodome = "3.14.1" -pygments = "2.12.0" +pycryptodome = "3.11.0" +pygments = "2.10.0" pygments-lexer-solidity = "0.7.0" pyjwt = "1.7.1" -pyparsing = "3.0.9" -pyrsistent = "0.18.1" +pyparsing = "2.4.7" +pyrsistent = "0.18.0" pytest = "6.2.5" -pytest-forked = "1.4.0" +pytest-forked = "1.3.0" pytest-xdist = "1.34.0" python-dateutil = "2.8.1" python-dotenv = "0.16.0" pythx = "1.6.1" pyyaml = "5.4.1" -requests = "2.27.1" -rlp = "2.0.1" +regex = "2021.10.8" +requests = "2.26.0" +rlp = "1.2.0" semantic-version = "2.8.5" six = "1.16.0" sortedcontainers = "2.4.0" toml = "0.10.2" -tomli = "2.0.1" -toolz = "0.11.2" -tqdm = "4.64.0" -urllib3 = "1.26.9" +tomli = "1.2.1" +toolz = "0.11.1" +tqdm = "4.62.3" +typing-extensions = "3.10.0.2" +urllib3 = "1.26.7" varint = "1.0.2" vvm = "0.1.0" -vyper = "0.3.3" +vyper = "0.3.0" wcwidth = "0.2.5" -web3 = "5.29.1" +web3 = "5.24.0" websockets = "9.1" -wrapt = "1.14.1" -yarl = "1.7.2" +wrapt = "1.13.1" +yarl = "1.7.0" [[package]] name = "eth-event" @@ -381,7 +470,7 @@ pycryptodome = ">=3.4.7,<4.0.0" [[package]] name = "eth-keys" -version = "0.3.4" +version = "0.3.3" description = "Common API for Ethereum key operations." category = "main" optional = false @@ -389,14 +478,14 @@ python-versions = "*" [package.dependencies] eth-typing = ">=2.2.1,<3.0.0" -eth-utils = ">=1.8.2,<2.0.0" +eth-utils = ">=1.3.0,<2.0.0" [package.extras] +test = ["eth-hash", "eth-hash", "hypothesis (>=4.56.1,<5.0.0)", "pytest (==3.2.2)", "pyasn1 (>=0.4.5,<0.5)", "asn1tools (>=0.146.2,<0.147)"] +lint = ["mypy (==0.701)", "flake8 (==3.0.4)"] +eth-keys = ["eth-typing (>=2.2.1,<3.0.0)", "eth-utils (>=1.3.0,<2.0.0)"] +dev = ["eth-hash", "eth-hash", "hypothesis (>=4.56.1,<5.0.0)", "pytest (==3.2.2)", "pyasn1 (>=0.4.5,<0.5)", "asn1tools (>=0.146.2,<0.147)", "mypy (==0.701)", "flake8 (==3.0.4)", "eth-typing (>=2.2.1,<3.0.0)", "eth-utils (>=1.3.0,<2.0.0)", "twine", "bumpversion (==0.5.3)", "tox (==2.7.0)"] coincurve = ["coincurve (>=7.0.0,<13.0.0)"] -dev = ["tox (==3.20.0)", "bumpversion (==0.5.3)", "twine", "eth-utils (>=1.8.2,<2.0.0)", "eth-typing (>=2.2.1,<3.0.0)", "flake8 (==3.0.4)", "mypy (==0.782)", "asn1tools (>=0.146.2,<0.147)", "factory-boy (>=3.0.1,<3.1)", "pyasn1 (>=0.4.5,<0.5)", "pytest (==5.4.1)", "hypothesis (>=5.10.3,<6.0.0)", "eth-hash", "eth-hash"] -eth-keys = ["eth-utils (>=1.8.2,<2.0.0)", "eth-typing (>=2.2.1,<3.0.0)"] -lint = ["flake8 (==3.0.4)", "mypy (==0.782)"] -test = ["asn1tools (>=0.146.2,<0.147)", "factory-boy (>=3.0.1,<3.1)", "pyasn1 (>=0.4.5,<0.5)", "pytest (==5.4.1)", "hypothesis (>=5.10.3,<6.0.0)", "eth-hash", "eth-hash"] [[package]] name = "eth-rlp" @@ -419,7 +508,7 @@ test = ["eth-hash", "pytest-xdist", "pytest (==5.4.1)", "tox (==3.14.6)"] [[package]] name = "eth-typing" -version = "2.3.0" +version = "2.2.2" description = "eth-typing: Common type annotations for ethereum python packages" category = "main" optional = false @@ -451,6 +540,27 @@ doc = ["Sphinx (>=1.6.5,<2)", "sphinx-rtd-theme (>=0.1.9,<2)", "towncrier (>=19. lint = ["black (>=18.6b4,<19)", "flake8 (==3.7.9)", "isort (>=4.2.15,<5)", "mypy (==0.720)", "pydocstyle (>=5.0.0,<6)", "pytest (>=3.4.1,<4.0.0)"] test = ["hypothesis (>=4.43.0,<5.0.0)", "pytest (==5.4.1)", "pytest-xdist", "tox (==3.14.6)"] +[[package]] +name = "ethereum" +version = "2.3.2" +description = "Next generation cryptocurrency network" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +coincurve = ">=7.0.0" +future = "*" +pbkdf2 = "*" +py_ecc = "*" +pycryptodome = ">=3.4.7" +pyethash = ">=0.1.27,<1.0.0" +pysha3 = ">=1.0.1" +PyYAML = "*" +"repoze.lru" = "*" +rlp = ">=1.0.1,<2.0.0" +scrypt = "*" + [[package]] name = "execnet" version = "1.9.0" @@ -463,13 +573,31 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" testing = ["pre-commit"] [[package]] -name = "frozenlist" -version = "1.3.0" -description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" +name = "future" +version = "0.18.2" +description = "Clean single-source support for Python 3 and 2" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "gnosis-py" +version = "3.7.8" +description = "Gnosis libraries for Python Projects" +category = "dev" optional = false python-versions = ">=3.7" +[package.dependencies] +eip712-structs = "*" +ethereum = ">=2.3.2" +packaging = "*" +requests = ">=2" +web3 = ">=5.23.0" + +[package.extras] +django = ["django (>=2)", "django-filter (>=2)", "djangorestframework (>=2)"] + [[package]] name = "hexbytes" version = "0.2.2" @@ -486,7 +614,7 @@ test = ["eth-utils (>=1.0.1,<2)", "hypothesis (>=3.44.24,<4)", "pytest-xdist", " [[package]] name = "hypothesis" -version = "6.27.3" +version = "6.23.2" description = "A library for property-based testing" category = "main" optional = false @@ -514,7 +642,7 @@ zoneinfo = ["importlib-resources (>=3.3.0)", "backports.zoneinfo (>=0.2.1)", "tz [[package]] name = "idna" -version = "3.3" +version = "3.2" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -567,11 +695,19 @@ format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator [[package]] name = "lazy-object-proxy" -version = "1.7.1" +version = "1.6.0" description = "A fast and thorough lazy object proxy." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "libusb1" +version = "3.0.0" +description = "Pure-python wrapper for libusb-1.0" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "lru-dict" @@ -581,6 +717,14 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "mnemonic" +version = "0.20" +description = "Implementation of Bitcoin BIP-0039" +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "multiaddr" version = "0.0.9" @@ -597,11 +741,11 @@ varint = "*" [[package]] name = "multidict" -version = "6.0.2" +version = "5.2.0" description = "multidict implementation" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [[package]] name = "mypy-extensions" @@ -634,14 +778,14 @@ python-versions = "*" [[package]] name = "packaging" -version = "21.3" +version = "21.0" description = "Core utilities for Python packages" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +pyparsing = ">=2.0.2" [[package]] name = "parsimonious" @@ -662,17 +806,25 @@ category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +[[package]] +name = "pbkdf2" +version = "1.3" +description = "PKCS#5 v2.0 PBKDF2 Module" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "platformdirs" -version = "2.5.2" +version = "2.4.0" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] -test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] +test = ["pytest-mock (>=3.6)", "pytest-cov (>=2.7)", "pytest (>=6)", "appdirs (==1.4.4)"] +docs = ["sphinx-autodoc-typehints (>=1.12)", "proselint (>=0.10.2)", "furo (>=2021.7.5b38)", "Sphinx (>=4)"] [[package]] name = "pluggy" @@ -688,7 +840,7 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.29" +version = "3.0.20" description = "Library for building powerful interactive command lines in Python" category = "main" optional = false @@ -699,30 +851,49 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "3.20.1" +version = "3.18.1" description = "Protocol Buffers" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.5" [[package]] name = "psutil" -version = "5.9.1" +version = "5.8.0" description = "Cross-platform lib for process and system monitoring in Python." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.extras] -test = ["ipaddress", "mock", "enum34", "pywin32", "wmi"] +test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] [[package]] name = "py" -version = "1.11.0" +version = "1.10.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "py-ecc" +version = "5.2.0" +description = "Elliptic curve crypto in python including secp256k1 and alt_bn128" +category = "dev" +optional = false +python-versions = ">=3.5, <4" + +[package.dependencies] +cached-property = ">=1.5.1,<2" +eth-typing = ">=2.1.0,<3.0.0" +eth-utils = ">=1.3.0,<2" +mypy-extensions = ">=0.4.1" + +[package.extras] +dev = ["bumpversion (>=0.5.3,<1)", "twine", "pytest (==3.10.1)", "pytest-xdist (==1.26.0)", "flake8 (==3.5.0)", "mypy (==0.641)", "mypy-extensions (>=0.4.1)"] +lint = ["flake8 (==3.5.0)", "mypy (==0.641)", "mypy-extensions (>=0.4.1)"] +test = ["pytest (==3.10.1)", "pytest-xdist (==1.26.0)"] [[package]] name = "py-solc-ast" @@ -744,21 +915,37 @@ python-versions = ">=3.6, <4" requests = ">=2.19.0,<3" semantic-version = ">=2.8.1,<3" +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "pycryptodome" -version = "3.14.1" +version = "3.11.0" description = "Cryptographic library for Python" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "pyethash" +version = "0.1.27" +description = "Python wrappers for ethash, the ethereum proof of workhashing function" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "pygments" -version = "2.12.0" +version = "2.10.0" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.5" [[package]] name = "pygments-lexer-solidity" @@ -786,22 +973,27 @@ test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner [[package]] name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" +version = "2.4.7" +description = "Python parsing module" category = "main" optional = false -python-versions = ">=3.6.8" - -[package.extras] -diagrams = ["railroad-diagrams", "jinja2"] +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "pyrsistent" -version = "0.18.1" +version = "0.18.0" description = "Persistent/Functional/Immutable data structures" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" + +[[package]] +name = "pysha3" +version = "1.0.2" +description = "SHA-3 (Keccak) for Python 2.7 - 3.5" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "pytest" @@ -826,11 +1018,11 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest-forked" -version = "1.4.0" +version = "1.3.0" description = "run tests in isolated forked subprocesses" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] py = "*" @@ -906,9 +1098,29 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +[[package]] +name = "regex" +version = "2021.10.8" +description = "Alternative regular expression module, to replace re." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "repoze.lru" +version = "0.7" +description = "A tiny LRU cache implementation and decorator" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +docs = ["sphinx"] +testing = ["coverage", "nose"] + [[package]] name = "requests" -version = "2.27.1" +version = "2.26.0" description = "Python HTTP for Humans." category = "main" optional = false @@ -926,7 +1138,7 @@ use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rlp" -version = "2.0.1" +version = "1.2.0" description = "A package for Recursive Length Prefix encoding and decoding" category = "main" optional = false @@ -936,11 +1148,18 @@ python-versions = "*" eth-utils = ">=1.0.2,<2" [package.extras] -dev = ["Sphinx (>=1.6.5,<2)", "bumpversion (>=0.5.3,<1)", "flake8 (==3.4.1)", "hypothesis (==5.19.0)", "ipython", "pytest-watch (>=4.1.0,<5)", "pytest-xdist", "pytest (==5.4.3)", "setuptools (>=36.2.0)", "sphinx-rtd-theme (>=0.1.9)", "tox (>=2.9.1,<3)", "twine", "wheel"] -doc = ["Sphinx (>=1.6.5,<2)", "sphinx-rtd-theme (>=0.1.9)"] +test = ["hypothesis (==3.56.5)", "tox (>=2.9.1,<3)", "pytest (==3.3.2)"] lint = ["flake8 (==3.4.1)"] -rust-backend = ["rusty-rlp (>=0.1.15,<0.2)"] -test = ["hypothesis (==5.19.0)", "pytest (==5.4.3)", "tox (>=2.9.1,<3)"] +doc = ["sphinx-rtd-theme (>=0.1.9)", "Sphinx (>=1.6.5,<2)"] +dev = ["sphinx-rtd-theme (>=0.1.9)", "Sphinx (>=1.6.5,<2)", "flake8 (==3.4.1)", "hypothesis (==3.56.5)", "tox (>=2.9.1,<3)", "pytest (==3.3.2)", "twine", "ipython", "wheel", "pytest-watch (>=4.1.0,<5)", "pytest-xdist", "setuptools (>=36.2.0)", "bumpversion (>=0.5.3,<1)"] + +[[package]] +name = "scrypt" +version = "0.8.20" +description = "Bindings for the scrypt key derivation function library" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "semantic-version" @@ -950,6 +1169,14 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "simple-rlp" +version = "0.1.2" +description = "RLP (Recursive Length Prefix) - Encode and decode data structures" +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "six" version = "1.16.0" @@ -976,15 +1203,15 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" -version = "2.0.1" +version = "1.2.1" description = "A lil' TOML parser" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [[package]] name = "toolz" -version = "0.11.2" +version = "0.11.1" description = "List processing tools and functional utilities" category = "main" optional = false @@ -992,7 +1219,7 @@ python-versions = ">=3.5" [[package]] name = "tqdm" -version = "4.64.0" +version = "4.62.3" description = "Fast, Extensible Progress Meter" category = "main" optional = false @@ -1004,27 +1231,52 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] dev = ["py-make (>=0.1.0)", "twine", "wheel"] notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "trezor" +version = "0.13.3" +description = "Python library for communicating with Trezor Hardware Wallet" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +click = ">=7,<8.2" +construct = ">=2.9,<2.10.55 || >2.10.55" +ecdsa = ">=0.9" +libusb1 = ">=1.6.4" +mnemonic = ">=0.20" +requests = ">=2.4.0" +simple-rlp = {version = ">=0.1.2", markers = "python_version >= \"3.7\""} +typing-extensions = ">=3.10" + +[package.extras] +ethereum = ["web3 (>=4.8)", "rlp (>=1.1.0)"] +extra = ["pillow"] +full = ["hidapi (>=0.7.99.post20)", "web3 (>=4.8)", "pyqt5", "pillow", "stellar-sdk (>=4.0.0,<6.0.0)", "rlp (>=1.1.0)"] +hidapi = ["hidapi (>=0.7.99.post20)"] +qt-widgets = ["pyqt5"] +stellar = ["stellar-sdk (>=4.0.0,<6.0.0)"] + [[package]] name = "typing-extensions" -version = "4.3.0" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false -python-versions = ">=3.7" +python-versions = "*" [[package]] name = "urllib3" -version = "1.26.9" +version = "1.26.7" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] -brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] @@ -1050,22 +1302,22 @@ semantic-version = ">=2.8.1,<3" [[package]] name = "vyper" -version = "0.3.3" +version = "0.3.0" description = "Vyper: the Pythonic Programming Language for the EVM" category = "main" optional = false -python-versions = ">=3.7,<3.11" +python-versions = ">=3.7,<3.10" [package.dependencies] -asttokens = "2.0.5" +asttokens = "2.0.4" pycryptodome = ">=3.5.1,<4" semantic-version = "2.8.5" [package.extras] -dev = ["pytest (>=6.2.5,<7.0)", "pytest-cov (>=2.10,<3.0)", "pytest-instafail (>=0.4,<1.0)", "pytest-xdist (>=2.5,<3.0)", "pytest-split (>=0.7.0,<1.0)", "pytest-rerunfailures (>=10.2,<11)", "eth-tester[py-evm] (>=0.6.0b6,<0.7)", "py-evm (>=0.5.0a3,<0.6)", "web3 (==5.27.0)", "tox (>=3.15,<4.0)", "lark-parser (==0.10.0)", "hypothesis[lark] (>=5.37.1,<6.0)", "black (==21.9b0)", "click (<8.1.0)", "flake8 (==3.9.2)", "flake8-bugbear (==20.1.4)", "flake8-use-fstring (==1.1)", "isort (==5.9.3)", "mypy (==0.910)", "recommonmark", "sphinx (>=3.0,<4.0)", "sphinx-rtd-theme (>=0.5,<0.6)", "ipython", "pre-commit", "pyinstaller", "twine"] +dev = ["mypy (==0.910)", "pytest (>=5.4,<6.0)", "pytest-cov (>=2.10,<3.0)", "pytest-instafail (>=0.4,<1.0)", "pytest-xdist (>=1.32,<2.0)", "eth-tester[py-evm] (>=0.5.0b1,<0.6)", "py-evm (==0.4.0a4)", "web3 (==5.12.3)", "tox (>=3.15,<4.0)", "lark-parser (==0.10.0)", "hypothesis[lark] (>=5.37.1,<6.0)", "black (==21.9b0)", "flake8 (==3.9.2)", "flake8-bugbear (==20.1.4)", "flake8-use-fstring (==1.1)", "isort (==5.9.3)", "recommonmark", "sphinx (>=3.0,<4.0)", "sphinx-rtd-theme (>=0.5,<0.6)", "ipython", "pre-commit", "pyinstaller", "twine"] docs = ["recommonmark", "sphinx (>=3.0,<4.0)", "sphinx-rtd-theme (>=0.5,<0.6)"] -lint = ["black (==21.9b0)", "click (<8.1.0)", "flake8 (==3.9.2)", "flake8-bugbear (==20.1.4)", "flake8-use-fstring (==1.1)", "isort (==5.9.3)", "mypy (==0.910)"] -test = ["pytest (>=6.2.5,<7.0)", "pytest-cov (>=2.10,<3.0)", "pytest-instafail (>=0.4,<1.0)", "pytest-xdist (>=2.5,<3.0)", "pytest-split (>=0.7.0,<1.0)", "pytest-rerunfailures (>=10.2,<11)", "eth-tester[py-evm] (>=0.6.0b6,<0.7)", "py-evm (>=0.5.0a3,<0.6)", "web3 (==5.27.0)", "tox (>=3.15,<4.0)", "lark-parser (==0.10.0)", "hypothesis[lark] (>=5.37.1,<6.0)"] +lint = ["black (==21.9b0)", "flake8 (==3.9.2)", "flake8-bugbear (==20.1.4)", "flake8-use-fstring (==1.1)", "isort (==5.9.3)", "mypy (==0.910)"] +test = ["pytest (>=5.4,<6.0)", "pytest-cov (>=2.10,<3.0)", "pytest-instafail (>=0.4,<1.0)", "pytest-xdist (>=1.32,<2.0)", "eth-tester[py-evm] (>=0.5.0b1,<0.6)", "py-evm (==0.4.0a4)", "web3 (==5.12.3)", "tox (>=3.15,<4.0)", "lark-parser (==0.10.0)", "hypothesis[lark] (>=5.37.1,<6.0)"] [[package]] name = "wcwidth" @@ -1077,7 +1329,7 @@ python-versions = "*" [[package]] name = "web3" -version = "5.29.1" +version = "5.24.0" description = "Web3.py" category = "main" optional = false @@ -1086,13 +1338,13 @@ python-versions = ">=3.6,<4" [package.dependencies] aiohttp = ">=3.7.4.post0,<4" eth-abi = ">=2.0.0b6,<3.0.0" -eth-account = ">=0.5.7,<0.6.0" +eth-account = ">=0.5.6,<0.6.0" eth-hash = {version = ">=0.2.0,<1.0.0", extras = ["pycryptodome"]} eth-typing = ">=2.0.0,<3.0.0" eth-utils = ">=1.9.5,<2.0.0" hexbytes = ">=0.1.0,<1.0.0" ipfshttpclient = "0.8.0a2" -jsonschema = ">=3.2.0,<5" +jsonschema = ">=3.2.0,<4.0.0" lru-dict = ">=1.1.6,<2.0.0" protobuf = ">=3.10.0,<4" pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} @@ -1100,10 +1352,10 @@ requests = ">=2.16.0,<3.0.0" websockets = ">=9.1,<10" [package.extras] -dev = ["eth-tester[py-evm] (==v0.6.0-beta.6)", "py-geth (>=3.8.0,<4)", "flake8 (==3.8.3)", "isort (>=4.2.15,<4.3.5)", "mypy (==0.910)", "types-setuptools (>=57.4.4,<58)", "types-requests (>=2.26.1,<3)", "types-protobuf (==3.19.13)", "mock", "sphinx-better-theme (>=0.1.4)", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "sphinx (>=3.0,<4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "urllib3", "wheel", "Jinja2 (<=3.0.3)", "bumpversion", "flaky (>=3.7.0,<4)", "hypothesis (>=3.31.2,<6)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-mock (>=1.10,<2)", "pytest-pythonpath (>=0.3)", "pytest-watch (>=4.2,<5)", "pytest-xdist (>=1.29,<2)", "setuptools (>=38.6.0)", "tox (>=1.8.0)", "tqdm (>4.32,<5)", "twine (>=1.13,<2)", "pluggy (==0.13.1)", "when-changed (>=0.3.0,<0.4)"] -docs = ["mock", "sphinx-better-theme (>=0.1.4)", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "py-geth (>=3.8.0,<4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "sphinx (>=3.0,<4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "urllib3", "wheel", "Jinja2 (<=3.0.3)"] -linter = ["flake8 (==3.8.3)", "isort (>=4.2.15,<4.3.5)", "mypy (==0.910)", "types-setuptools (>=57.4.4,<58)", "types-requests (>=2.26.1,<3)", "types-protobuf (==3.19.13)"] -tester = ["eth-tester[py-evm] (==v0.6.0-beta.6)", "py-geth (>=3.8.0,<4)"] +dev = ["eth-tester[py-evm] (==v0.5.0-beta.4)", "py-geth (>=3.5.0,<4)", "flake8 (==3.8.3)", "isort (>=4.2.15,<4.3.5)", "mypy (==0.812)", "mock", "sphinx-better-theme (>=0.1.4)", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "sphinx (>=3.0,<4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "urllib3", "wheel", "bumpversion", "flaky (>=3.7.0,<4)", "hypothesis (>=3.31.2,<6)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-mock (>=1.10,<2)", "pytest-pythonpath (>=0.3)", "pytest-watch (>=4.2,<5)", "pytest-xdist (>=1.29,<2)", "setuptools (>=38.6.0)", "tox (>=1.8.0)", "tqdm (>4.32,<5)", "twine (>=1.13,<2)", "pluggy (==0.13.1)", "when-changed (>=0.3.0,<0.4)"] +docs = ["mock", "sphinx-better-theme (>=0.1.4)", "click (>=5.1)", "configparser (==3.5.0)", "contextlib2 (>=0.5.4)", "py-geth (>=3.5.0,<4)", "py-solc (>=0.4.0)", "pytest (>=4.4.0,<5.0.0)", "sphinx (>=3.0,<4)", "sphinx-rtd-theme (>=0.1.9)", "toposort (>=1.4)", "towncrier (==18.5.0)", "urllib3", "wheel"] +linter = ["flake8 (==3.8.3)", "isort (>=4.2.15,<4.3.5)", "mypy (==0.812)"] +tester = ["eth-tester[py-evm] (==v0.5.0-beta.4)", "py-geth (>=3.5.0,<4)"] [[package]] name = "websockets" @@ -1115,7 +1367,7 @@ python-versions = ">=3.6.1" [[package]] name = "wrapt" -version = "1.14.1" +version = "1.13.1" description = "Module for decorators, wrappers and monkey patching." category = "main" optional = false @@ -1123,7 +1375,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "yarl" -version = "1.7.2" +version = "1.7.0" description = "Yet another URL library" category = "main" optional = false @@ -1136,11 +1388,12 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "42e1adabc5276c1805723c2e3e7651d66f20a425cd1ee11594295eaea53d4938" +content-hash = "eca26f74f8c54b7c573445089a094fda021ccd712dc2fb1a7dbceb50e896eb35" [metadata.files] aiohttp = [] -aiosignal = [] +ape-safe = [] +asn1crypto = [] asttokens = [] async-timeout = [] atomicwrites = [] @@ -1148,13 +1401,20 @@ attrs = [] base58 = [] bitarray = [] black = [] +cached-property = [] certifi = [] +cffi = [] +chardet = [] charset-normalizer = [] click = [] +coincurve = [] colorama = [] +construct = [] cytoolz = [] dataclassy = [] +ecdsa = [] eip712 = [] +eip712-structs = [] eth-abi = [] eth-account = [] eth-brownie = [] @@ -1165,8 +1425,10 @@ eth-keys = [] eth-rlp = [] eth-typing = [] eth-utils = [] +ethereum = [] execnet = [] -frozenlist = [] +future = [] +gnosis-py = [] hexbytes = [] hypothesis = [] idna = [] @@ -1175,7 +1437,9 @@ iniconfig = [] ipfshttpclient = [] jsonschema = [] lazy-object-proxy = [] +libusb1 = [] lru-dict = [] +mnemonic = [] multiaddr = [] multidict = [] mypy-extensions = [] @@ -1184,20 +1448,25 @@ netaddr = [] packaging = [] parsimonious = [] pathspec = [] +pbkdf2 = [] platformdirs = [] pluggy = [] prompt-toolkit = [] protobuf = [] psutil = [] py = [] +py-ecc = [] py-solc-ast = [] py-solc-x = [] +pycparser = [] pycryptodome = [] +pyethash = [] pygments = [] pygments-lexer-solidity = [] pyjwt = [] pyparsing = [] pyrsistent = [] +pysha3 = [] pytest = [] pytest-forked = [] pytest-xdist = [] @@ -1206,15 +1475,20 @@ python-dotenv = [] pythx = [] pywin32 = [] pyyaml = [] +regex = [] +"repoze.lru" = [] requests = [] rlp = [] +scrypt = [] semantic-version = [] +simple-rlp = [] six = [] sortedcontainers = [] toml = [] tomli = [] toolz = [] tqdm = [] +trezor = [] typing-extensions = [] urllib3 = [] varint = [] diff --git a/pyproject.toml b/pyproject.toml index 15d8e99..93bb136 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,9 +10,10 @@ packages = [ [tool.poetry.dependencies] python = ">=3.9,<3.10" -eth-brownie = "^v1.17" +eth-brownie = "1.17" [tool.poetry.dev-dependencies] +ape-safe = "0.5.1" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 36966f4..c815f5b 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -72,3 +72,19 @@ def test_replace(tuple_helper): ) inserted = HexBytes(rands[: i * 32] + HexBytes(b4) + rands[(i + 1) * 32 :]) assert r == inserted + + +def test_get(tuple_helper): + + with reverts(): + tuple_helper.replaceElement.transact(b2 + b1, 2, b4, False) + + rands = HexBytes( + b"".join([to_bytes(random.randint(0, 2 ** 256 - 1)) for _ in range(100)]) + ) + + for i in range(100): + r = HexBytes( + tuple_helper.getElement.transact(rands, i).return_value + ) + assert r == rands[i*32:(i+1)*32] diff --git a/tests/test_lp.py b/tests/test_lp.py new file mode 100644 index 0000000..3a375e2 --- /dev/null +++ b/tests/test_lp.py @@ -0,0 +1,94 @@ +import weiroll +from weiroll import WeirollContract +from ape_safe import ApeSafe +from gnosis.safe import SafeOperation +from brownie import Contract +from math import isclose + + +def test_univ3_lp(alice, UniswapV3Helper): + + helper = WeirollContract.createContract(alice.deploy(UniswapV3Helper)) + + safe = ApeSafe("0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7") + + planner = weiroll.WeirollPlanner(safe) + + # Read providers + provider_usdc = WeirollContract.createContract( + Contract("0xD94f90E8df35c649573b6d2F909EDd8C8a791422") + ) + provider_usdt = WeirollContract.createContract( + Contract("0xdb67Dd2f3074bA25da2A487B1C61D3b3aF9aafA8") + ) + + joint = safe.contract(provider_usdc.brownieContract.joint()) + + # Read vaults + vault_usdc = WeirollContract.createContract( + Contract(provider_usdc.brownieContract.vault()) + ) + vault_usdt = WeirollContract.createContract( + Contract(provider_usdt.brownieContract.vault()) + ) + + # Total between both amounts ahould be ~1m + target_usdc = int(1_000_000 * 10 ** 6) + dr_usdc = int(target_usdc / vault_usdc.brownieContract.totalAssets() * 1e4) + + # Total between both amounts ahould be ~1m + target_usdt = int(1_000_000 * 10 ** 6) + dr_usdt = int(target_usdt / vault_usdt.brownieContract.totalAssets() * 1e4) + + # Need to allocate some extra DR due to real debt ratios != desired debt ratios + planner.add( + vault_usdc.updateStrategyDebtRatio(provider_usdc.address, int(dr_usdc + 1500)) + ) + planner.add( + vault_usdt.updateStrategyDebtRatio(provider_usdt.address, int(dr_usdt + 1000)) + ) + + w_amount_usdc = planner.add( + helper.getLPAmount0(joint.pool(), -4, -1, target_usdc, target_usdt) + ) + w_amount_usdt = planner.add( + helper.getLPAmount1(joint.pool(), -4, -1, target_usdc, target_usdt) + ) + + # Need to allocate some extra DR due to real debt ratios != desired debt ratios + planner.add( + vault_usdc.updateStrategyMaxDebtPerHarvest(provider_usdc.address, w_amount_usdc) + ) + planner.add( + vault_usdt.updateStrategyMaxDebtPerHarvest(provider_usdt.address, w_amount_usdt) + ) + + # Harvest providers to launch it + planner.add(provider_usdc.harvest()) + planner.add(provider_usdt.harvest()) + + # Give back dr usdc and usdt + planner.add(vault_usdc.updateStrategyDebtRatio(provider_usdc.address, 0)) + planner.add(vault_usdt.updateStrategyDebtRatio(provider_usdt.address, 0)) + # Avoid getting new debt in harvest trigger + planner.add(vault_usdc.updateStrategyMaxDebtPerHarvest(provider_usdc.address, 0)) + planner.add(vault_usdt.updateStrategyMaxDebtPerHarvest(provider_usdt.address, 0)) + + cmds, state = planner.plan() + tx_input = helper.brownieContract.execute.encode_input(cmds, state) + + safe_tx = safe.build_multisig_tx( + helper.address, + 0, + tx_input, + SafeOperation.DELEGATE_CALL.value, + safe.pending_nonce(), + ) + safe.preview(safe_tx, reset=False, call_trace=True) + + assert isclose(joint.balanceOfTokensInLP()[0] / 1e6, target_usdc / 1e6) or isclose( + joint.balanceOfTokensInLP()[1] / 1e6, target_usdt / 1e6 + ) + assert isclose( + provider_usdc.brownieContract.balanceOfWant() / 1e6, 0, abs_tol=1e-3 + ) and isclose(provider_usdt.brownieContract.balanceOfWant() / 1e6, 0, abs_tol=1e-3) diff --git a/tests/test_swaps.py b/tests/test_swaps.py index 5c3fc94..b297c32 100644 --- a/tests/test_swaps.py +++ b/tests/test_swaps.py @@ -13,7 +13,6 @@ def test_swaps(accounts, weiroll_vm): crvseth = Contract("0xc5424B857f758E906013F3555Dad202e4bdB4567") susd = Contract("0x57Ab1ec28D129707052df4dF418D58a2D46d5f51") - weiroll_vm = accounts[0].deploy(TestableVM) planner = WeirollPlanner(whale) yvweth = WeirollContract.createContract( Contract("0xa258C4606Ca8206D8aA700cE2143D7db854D168c") @@ -161,7 +160,7 @@ def test_balancer_swap(accounts, weiroll_vm, tuple_helper): ) cmds, state = planner.plan() - + assert bal.balanceOf(weiroll_vm) > 0 assert weth.balanceOf(weiroll_vm) == 0