Skip to content

Commit a8d9996

Browse files
committed
clone QuantAMM contracts
1 parent 976b6d6 commit a8d9996

File tree

77 files changed

+22592
-417
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+22592
-417
lines changed

contracts/ChainlinkOracle.sol

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.20;
3+
4+
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
5+
import "./OracleWrapper.sol";
6+
7+
/// @title ChainlinkOracle contract based on the underlying QuantAMM oracle wrapper
8+
/// @notice Contains the logic for retrieving data from a Chainlink oracle and converting it to the QuantAMM format using the oracle wrapper contract
9+
contract ChainlinkOracle is OracleWrapper {
10+
AggregatorV3Interface internal immutable priceFeed;
11+
12+
///@notice Difference of feed result to 18 decimals. We store the difference instead of the oracle decimals for optimization reasons (saves a subtraction in _getData)
13+
uint internal immutable normalizationFactor;
14+
15+
/// @param _chainlinkFeed the address of the Chainlink oracle to wrap
16+
constructor(address _chainlinkFeed) {
17+
require(_chainlinkFeed != address(0), "INVADDR"); //Invalid address provided
18+
priceFeed = AggregatorV3Interface(_chainlinkFeed);
19+
// Chainlink oracles have <= 18 decimals, cannot underflow
20+
normalizationFactor = 18 - priceFeed.decimals();
21+
}
22+
23+
/// @notice Returns the latest data from the oracle in the QuantAMM format
24+
/// @return data the latest data from the oracle in the QuantAMM format
25+
/// @return timestamp the timestamp of the data retrieval
26+
function _getData() internal view override returns (int216, uint40) {
27+
(, /*uint80 roundID*/ int data, , /*uint startedAt*/ uint timestamp /*uint80 answeredInRound*/, ) = priceFeed
28+
.latestRoundData();
29+
require(data > 0, "INVLDDATA");
30+
data = data * int(10 ** normalizationFactor);
31+
return (int216(data), uint40(timestamp)); // Overflow of data is extremely improbable and uint40 is large enough for timestamps for a very long time
32+
}
33+
}

contracts/CustomPool.sol

Lines changed: 0 additions & 75 deletions
This file was deleted.

contracts/CustomPoolFactory.sol

Lines changed: 0 additions & 79 deletions
This file was deleted.

contracts/MultiHopOracle.sol

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.24;
3+
4+
import "./OracleWrapper.sol";
5+
6+
/// @notice For tokens where no direct oracle / price feeds exists, multiple oracle wrappers can be combined to one.
7+
contract MultiHopOracle is OracleWrapper {
8+
/// @notice Configuration for one hop
9+
/// @dev Fits in one storage slot
10+
struct HopConfig {
11+
OracleWrapper oracle;
12+
/// @notice Set to true if the result should be inverted, e.g. if we have TOK1/TOK2 but want to multiply by TOK2/TOK1 (i.e., divide by TOK1/TOK2)
13+
bool invert;
14+
}
15+
16+
/// @notice configuration for the oracles
17+
HopConfig[] public oracles;
18+
19+
constructor(HopConfig[] memory _oracles) {
20+
//CODEHAWKS INFO /s/716
21+
require(_oracles.length > 0, "NOORACLES");
22+
for (uint i = 0; i < _oracles.length; i++) {
23+
//CODEHAWKS INFO /s/716
24+
require(address(_oracles[i].oracle) != address(0), "INVORACLE");
25+
oracles.push(_oracles[i]);
26+
}
27+
}
28+
29+
/// @notice Returns the latest data from one oracle hopping across n oracles
30+
/// @return data the latest data from the oracle in the QuantAMM format
31+
/// @return timestamp the timestamp of the data retrieval
32+
function _getData() internal view override returns (int216 data, uint40 timestamp) {
33+
HopConfig memory firstOracle = oracles[0];
34+
(data, timestamp) = firstOracle.oracle.getData();
35+
if (firstOracle.invert) {
36+
data = 10 ** 36 / data; // 10^36 (i.e., 1 with 18 decimals * 10^18) to get the inverse with 18 decimals.
37+
// 10**36 is automatically precomputed by the compiler, no explicit caching needed
38+
}
39+
uint256 oracleLength = oracles.length;
40+
41+
for (uint i = 1; i < oracleLength; ) {
42+
HopConfig memory oracleConfig = oracles[i];
43+
(int216 oracleRes, uint40 oracleTimestamp) = oracleConfig.oracle.getData();
44+
if (oracleTimestamp < timestamp) {
45+
timestamp = oracleTimestamp; // Return minimum timestamp
46+
}
47+
48+
// depends which way the oracle conversion is happening
49+
if (oracleConfig.invert) {
50+
data = (data * 10 ** 18) / oracleRes;
51+
} else {
52+
data = (data * oracleRes) / 10 ** 18;
53+
}
54+
unchecked {
55+
++i;
56+
}
57+
}
58+
}
59+
}

contracts/OracleWrapper.sol

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.24;
3+
4+
/// @notice Generic wrapper around an arbitrary oracle that returns normalized values.
5+
abstract contract OracleWrapper {
6+
//CODEHAWKS INFO /s/294 remove unused enum
7+
8+
/// @notice Get the data of the underlying oracle, interpretation of data depends on oracle type
9+
/// @param data The underlying data (can be negative), normalized to 18 decimals
10+
/// @return data Retrieved oracle data
11+
/// @return timestamp Last update timestamp
12+
function getData() public view returns (int216 data, uint40 timestamp) {
13+
(data, timestamp) = _getData();
14+
require(timestamp > 0, "INVORCLVAL"); // Sanity check in case oracle returns invalid values
15+
}
16+
17+
/// @notice Get data from oracle, to be implemented by child contracts. Needs to return data with 18 decimals
18+
function _getData() internal view virtual returns (int216 data, uint40 timestamp) {}
19+
}

0 commit comments

Comments
 (0)