Skip to content

Commit

Permalink
Merge pull request #101 from hifi-finance/feat/uniswap-v3-price-feed
Browse files Browse the repository at this point in the history
Add Uniswap V3 Price Feed
  • Loading branch information
scorpion9979 authored Oct 25, 2023
2 parents 70f7c92 + 6a01de9 commit 706984f
Show file tree
Hide file tree
Showing 68 changed files with 5,140 additions and 14 deletions.
1 change: 1 addition & 0 deletions packages/constants/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./addresses";
export * from "./chains";
export * from "./gas";
export * from "./oracles";
export * from "./prices";
export * from "./protocol";
export * from "./tokens";
9 changes: 9 additions & 0 deletions packages/constants/src/oracles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BigNumber } from "@ethersproject/bignumber";

export const DEFAULT_CARDINALITY: number = 144;
export const DEFAULT_TWAP_INTERVAL: number = 1800;
export const Q192: BigNumber = BigNumber.from("6277101735386680763835789423207666416102355444464034512896");
export const TICKS = {
lowerBound: -798544800,
upperBound: 798544800,
};
3 changes: 3 additions & 0 deletions packages/errors/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export { OwnableErrors } from "./external";
// flashSwap.ts
export { FlashUniswapV2Errors, FlashUniswapV3Errors } from "./flashSwap";

// oracles.ts
export { UniswapV3PriceFeedErrors } from "./oracles";

// protocol.ts
export {
BalanceSheetErrors,
Expand Down
5 changes: 5 additions & 0 deletions packages/errors/src/oracles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum UniswapV3PriceFeedErrors {
QUOTE_ASSET_NOT_IN_POOL = "IUniswapV3PriceFeed__QuoteAssetNotInPool",
TWAP_CRITERIA_NOT_SATISFIED = "IUniswapV3PriceFeed__TwapCriteriaNotSatisfied",
MAX_PRICE_LESS_THAN_OR_EQUAL_TO_ZERO = "IUniswapV3PriceFeed__MaxPriceLessThanOrEqualToZero",
}
3 changes: 1 addition & 2 deletions packages/flash-swap/contracts/uniswap-v3/NoDelegateCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// solhint-disable
pragma solidity =0.7.6;

/// @title Prevents delegatecall to a contract
/// @notice Base contract that provides a modifier for preventing delegatecall to methods in a child contract
/// @dev https://raw.githubusercontent.com/Uniswap/v3-core/v1.0.0/contracts/NoDelegateCall.sol
abstract contract NoDelegateCall {
/// @dev The original address of this contract
address private immutable original;
Expand Down
1 change: 1 addition & 0 deletions packages/flash-swap/contracts/uniswap-v3/UniswapV3Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3MintCallback.so
import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol";
import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol";

/// @dev https://raw.githubusercontent.com/Uniswap/v3-core/v1.0.0/contracts/UniswapV3Pool.sol
contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall {
using LowGasSafeMath for uint256;
using LowGasSafeMath for int256;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity >=0.8.4;
/// @title IAggregatorV3
/// @author Hifi
/// @dev Forked from Chainlink
/// github.com/smartcontractkit/chainlink/blob/v1.2.0/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol
/// https://github.com/smartcontractkit/chainlink/blob/v1.2.0/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol
interface IAggregatorV3 {
function decimals() external view returns (uint8);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.4;

/// @title IUniswapV3Pool
/// @author Hifi
/// @dev Forked from Uniswap
/// https://github.com/Uniswap/v3-core/blob/v1.0.0/contracts/interfaces/IUniswapV3Factory.sol
interface IUniswapV3Pool {
function factory() external view returns (address);

function fee() external view returns (uint24);

function initialize(uint160 sqrtPriceX96) external;

function maxLiquidityPerTick() external view returns (uint128);

function observe(uint32[] calldata secondsAgos)
external
view
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);

function observations(uint256 index)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);

function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);

function tickSpacing() external view returns (int24);

function token0() external view returns (address);

function token1() external view returns (address);
}
131 changes: 131 additions & 0 deletions packages/protocol/contracts/external/uniswap/libraries/FullMath.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// SPDX-License-Identifier: MIT
// solhint-disable max-line-length, no-inline-assembly, reason-string
pragma solidity ^0.8.4;

/// @title FullMath
/// @author Hifi
/// @dev Forked from Euler
/// https://github.com/euler-xyz/euler-contracts/blob/dfaa7788b17ac7c2a826a3ed242d7181998a778f/contracts/vendor/FullMath.sol
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 = denominator & (~denominator + 1);

// 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++;
}
}
}
}
Loading

0 comments on commit 706984f

Please sign in to comment.