Skip to content

Commit

Permalink
Merge pull request #2 from VasuGupta153/main
Browse files Browse the repository at this point in the history
Oracle Integration
  • Loading branch information
guzus authored Nov 16, 2024
2 parents 1392948 + 7138098 commit b53c424
Show file tree
Hide file tree
Showing 4 changed files with 3,425 additions and 3,071 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@
"packageManager": "[email protected]",
"engines": {
"node": ">=18.18.0"
},
"dependencies": {
"@chainlink/contracts": "^1.3.0"
}
}
3 changes: 2 additions & 1 deletion packages/foundry/remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ forge-std/=lib/v4-core/lib/forge-std/src/
permit2/=lib/v4-periphery/lib/permit2/
solmate/=lib/v4-core/lib/solmate/
v4-core/=lib/v4-core/
v4-periphery/=lib/v4-periphery/
@v4-periphery/=lib/v4-periphery/
@chainlink/=lib/chainlink/
@pythnetwork/entropy-sdk-solidity/=node_modules/@pythnetwork/entropy-sdk-solidity
129 changes: 84 additions & 45 deletions packages/foundry/src/EtfHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,42 @@ import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "v4-core/src/types/BeforeS
import {IEntropyConsumer} from "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
import {IEntropy} from "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
import {ETFManager} from "./EtfToken.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

contract ETFHook is BaseHook ,ETFManager, IEntropyConsumer {

// Copied from [chronicle-std](https://github.com/chronicleprotocol/chronicle-std/blob/main/src/IChronicle.sol).
interface IChronicle {
/*
* @notice Returns the oracle's current value.
* @dev Reverts if no value set.
* @return value The oracle's current value.
*/
function read() external view returns (uint256 value);
}


interface ISelfKisser {
/// @notice Kisses caller on oracle `oracle`.
function selfKiss(address oracle) external;
}
contract ETFHook is ETFManager, BaseHook,IEntropyConsumer {
IEntropy public entropy;
bytes32 private latestRandomNumber;
bool private isRandomNumberReady;

address[2] public tokens;
address[2] public tokens; // the underlying tokens will be stored in this hook contract
uint256[2] public weights;
uint256 public rebalanceThreshold;

// chronicle oracle addresses
address public Chronicle_BTC_USD_3 =0xdc3ef3E31AdAe791d9D5054B575f7396851Fa432;
address public Chronicle_ETH_USD_3 =0xdd6D76262Fd7BdDe428dcfCd94386EbAe0151603;

// Chainlink oracle addresses
address public Chainlink_ETH_USD = 0x694AA1769357215DE4FAC081bf1f309aDC325306;
address public Chainlink_BTC_USD = 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43;

// token balances
uint256[2] public tokenBalances;

// Oracle addresses
Expand Down Expand Up @@ -52,6 +79,10 @@ contract ETFHook is BaseHook ,ETFManager, IEntropyConsumer {
for (uint256 i = 0; i < 2; i++) {
tokenBalances[i] = 0;
}

// This allows the contract to read from the chronicle oracle.
ISelfKisser(Chronicle_BTC_USD_3).selfKiss(address(this));
ISelfKisser(Chronicle_ETH_USD_3).selfKiss(address(this));
}

// Entropy Implementation
Expand Down Expand Up @@ -82,18 +113,15 @@ contract ETFHook is BaseHook ,ETFManager, IEntropyConsumer {
return address(entropy);
}

function selectOracle() internal returns (address) {
function selectOracle() internal returns (bool) {
if (!isRandomNumberReady) {
requestRandomNumber();
return chainlinkOracle; // Default to Chainlink if random number not ready
}

uint256 randomValue = uint256(latestRandomNumber) % 3;
uint256 randomValue = uint256(latestRandomNumber) % 2;
emit OracleSelected(randomValue);

if (randomValue == 0) return chainlinkOracle;
if (randomValue == 1) return pythOracle;
return api3Oracle;
return randomValue;
}

// Hook permissions
Expand All @@ -120,29 +148,25 @@ contract ETFHook is BaseHook ,ETFManager, IEntropyConsumer {
function getPrices() internal returns (uint256[2] memory prices) {
address selectedOracle = selectOracle();

if (selectedOracle == chainlinkOracle) {
if (!selectedOracle) {
return getChainlinkPrices();
} else if (selectedOracle == pythOracle) {
return getPythPrices();
} else {
return getAPI3Prices();
return getChroniclePrices();
}
}

function getChainlinkPrices() internal view returns (uint256[2] memory prices) {
// TODO: Implement Chainlink price fetching
return prices;
(, int256 answerETH, , ,) = AggregatorV3Interface(Chainlink_ETH_USD).latestRoundData();
(, int256 answerBTC, , ,) = AggregatorV3Interface(Chainlink_BTC_USD).latestRoundData();
return [uint256(answerETH), uint256(answerBTC)];
}

function getPythPrices() internal view returns (uint256[2] memory prices) {
function getChroniclePrices() internal view returns (uint256[2] memory prices) {
// TODO: Implement Pyth price fetching
return prices;
return [IChronicle(Chronicle_ETH_USD_3).read(), IChronicle(Chronicle_BTC_USD_3).read()];
}

function getAPI3Prices() internal view returns (uint256[2] memory prices) {
// TODO: Implement API3 price fetching
return prices;
}

// Hook callbacks
function beforeSwap(address sender, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata)
Expand Down Expand Up @@ -182,64 +206,79 @@ contract ETFHook is BaseHook ,ETFManager, IEntropyConsumer {
return BaseHook.beforeRemoveLiquidity.selector;
}

// Your existing functions
function checkIfRebalanceNeeded() private returns (bool) {
uint256[2] memory prices = getPrices();

uint256[2] memory tokenValues;
for (uint256 i = 0; i < 2; i++) {
tokenValues[i] = prices[i] * tokenBalances[i];
}

uint256 totalValue = tokenValues[0] + tokenValues[1];
if (totalValue == 0) return false;

uint256[2] memory currentWeights;
for (uint256 i = 0; i < 2; i++) {
currentWeights[i] = (tokenValues[i] * 10000) / totalValue;
}

for (uint256 i = 0; i < 2; i++) {
if (currentWeights[i] > weights[i]) {
if (currentWeights[i] - weights[i] > rebalanceThreshold) return true;
} else {
if (weights[i] - currentWeights[i] > rebalanceThreshold) return true;
}
uint256[2] memory prices = getPrices();

// Calculate current value of each token
uint256[2] memory tokenValues;
for (uint256 i = 0; i < 2; i++) {
tokenValues[i] = prices[i] * tokenBalances[i];
}

// Calculate total portfolio value
uint256 totalValue = tokenValues[0] + tokenValues[1];
if (totalValue == 0) return false;

// Calculate current weights (in basis points - 10000 = 100%)
uint256[2] memory currentWeights;
for (uint256 i = 0; i < 2; i++) {
currentWeights[i] = (tokenValues[i] * 10000) / totalValue;
}

// Check if any weight deviates more than the threshold
for (uint256 i = 0; i < 2; i++) {
if (currentWeights[i] > weights[i]) {
if (currentWeights[i] - weights[i] > rebalanceThreshold) return true;
} else {
if (weights[i] - currentWeights[i] > rebalanceThreshold) return true;
}
}

return false;
}

function rebalance() private {
uint256[2] memory prices = getPrices();

// Calculate current value of each token
uint256[2] memory tokenValues;
for (uint256 i = 0; i < 2; i++) {
tokenValues[i] = prices[i] * tokenBalances[i];
}

// Calculate total portfolio value
uint256 totalValue = tokenValues[0] + tokenValues[1];
if (totalValue == 0) return;

// Calculate target values for each token
uint256[2] memory targetValues;
for (uint256 i = 0; i < 2; i++) {
targetValues[i] = (totalValue * weights[i]) / 10000;
}

// Determine which token to sell and which to buy
if (tokenValues[0] > targetValues[0]) {
// Token 0 is overweight, sell token 0 for token 1
uint256 token0ToSell = (tokenValues[0] - targetValues[0]) / prices[0];
// TODO: Implement swap logic
// Execute swap through Uniswap pool
// TODO: Implement swap logic using poolManager
} else {
// Token 1 is overweight, sell token 1 for token 0
uint256 token1ToSell = (tokenValues[1] - targetValues[1]) / prices[1];
// TODO: Implement swap logic
// Execute swap through Uniswap pool
// TODO: Implement swap logic using poolManager
}
}

function mintETFToken(uint256 etfAmount) private {
// TODO: Implement minting logic
// transfer tokens to ETF pool contract
// update token balances
// mint ETF token to msg.sender
}

function burnETFToken() private {
// TODO: Implement burning logic
// transfer tokens to msg.sender
// update token balances
// burn ETF token from msg.sender
}
}
Loading

0 comments on commit b53c424

Please sign in to comment.