Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ShuaJJ committed Nov 24, 2023
2 parents 9cdd1ce + 9b92ef0 commit ee1ed2b
Show file tree
Hide file tree
Showing 13 changed files with 347 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ out
# files
*.env
*.log

.DS_Store
.pnp.*
lcov.info
Expand All @@ -15,4 +16,4 @@ yarn.lock
# broadcasts
!broadcast
broadcast/*
broadcast/*/31337/
broadcast/*/31337/
6 changes: 5 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Full reference https://github.com/foundry-rs/foundry/tree/master/config

[profile.default]
auto_detect_solc = false
auto_detect_solc = true
block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT
bytecode_hash = "none"
cbor_metadata = false
Expand All @@ -16,7 +16,11 @@
solc = "/opt/homebrew/bin/solc"
src = "src"
test = "test"
<<<<<<< HEAD

=======
fs_permissions = [{ access = "read", path = "./"}]
>>>>>>> 2cc67f69b5f96b719233ac2e7764d3d3829d523c

[profile.ci]
fuzz = { runs = 10_000 }
Expand Down
2 changes: 1 addition & 1 deletion lib/prb-test
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@prb/test/=lib/prb-test/src/
forge-std/=lib/forge-std/src/
@openzeppelin/=lib/openzeppelin-contracts/
@uniswap/=lib/
21 changes: 21 additions & 0 deletions src/interfaces/IFastPriceFeed.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.21;


interface IFastPriceFeed {
function lastUpdatedAt() external view returns (uint256);
function lastUpdatedBlock() external view returns (uint256);
// function setSigner(address _account, bool _isActive) external;
// function setUpdater(address _account, bool _isActive) external;
// function setPriceDuration(uint256 _priceDuration) external;
// function setMaxPriceUpdateDelay(uint256 _maxPriceUpdateDelay) external;
// function setSpreadBasisPointsIfInactive(uint256 _spreadBasisPointsIfInactive) external;
// function setSpreadBasisPointsIfChainError(uint256 _spreadBasisPointsIfChainError) external;
// function setMinBlockInterval(uint256 _minBlockInterval) external;
// function setIsSpreadEnabled(bool _isSpreadEnabled) external;
// function setMaxDeviationBasisPoints(uint256 _maxDeviationBasisPoints) external;
// function setMaxCumulativeDeltaDiffs(address[] memory _tokens, uint256[] memory _maxCumulativeDeltaDiffs) external;
// function setPriceDataInterval(uint256 _priceDataInterval) external;
// function setVaultPriceFeed(address _vaultPriceFeed) external;
}
3 changes: 2 additions & 1 deletion src/libraries/SafeMath.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pragma solidity >= 0.8.21;
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)

Expand Down
11 changes: 7 additions & 4 deletions src/libraries/UniswapV2Library.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity >= 0.8.21;

import "./IUniswapV2Pair.sol";
import "./SafeMath.sol";
import "forge-std/console.sol"; // test

library UniswapV2Library {
using SafeMath for uint;
Expand All @@ -17,17 +18,19 @@ library UniswapV2Library {
// calculates the CREATE2 address for a pair without making any external calls
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
pair = address(uint160(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
))));
hex'7bde1f13037ef911e48141560d287f633c69de3963649fa4bfbfaf8e7c27dd97' // init code hash
)))));
}

// fetches and sorts the reserves for a pair
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
// address p = pairFor(factory, tokenA, tokenB);
// console.log(factory, tokenA, tokenB, p);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
Expand Down
166 changes: 166 additions & 0 deletions src/oracle/FastPriceFeed.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.21;

import "../interfaces/IFastPriceFeed.sol";
import "../interfaces/IVaultPriceFeed.sol";

contract FastPriceFeed is IFastPriceFeed {
// fit data in a uint256 slot to save gas costs
struct PriceDataItem {
uint160 refPrice; // Chainlink price
uint32 refTime; // last updated at time
uint32 cumulativeRefDelta; // cumulative Chainlink price delta
uint32 cumulativeFastDelta; // cumulative fast price delta
}

address public fastPriceEvents;
address public vaultPriceFeed;
uint256 constant public BITMASK_32 = ~uint256(0) >> (256 - 32);
uint256 public constant MAX_REF_PRICE = type(uint160).max;
uint256 public constant MAX_CUMULATIVE_REF_DELTA = type(uint32).max;
uint256 public constant MAX_CUMULATIVE_FAST_DELTA = type(uint32).max;
uint256 public constant PRICE_PRECISION = 10 ** 30;
uint256 public constant CUMULATIVE_DELTA_PRECISION = 10 * 1000 * 1000;

// array of tokens used in setCompactedPrices, saves L1 calldata gas costs
address[] public tokens;
// array of tokenPrecisions used in setCompactedPrices, saves L1 calldata gas costs
// if the token price will be sent with 3 decimals, then tokenPrecision for that token
// should be 10 ** 3
uint256[] public tokenPrecisions;


uint256 public priceDuration;
uint256 public maxPriceUpdateDelay;
uint256 public spreadBasisPointsIfInactive;
uint256 public spreadBasisPointsIfChainError;
uint256 public minBlockInterval;
uint256 public maxTimeDeviation;

uint256 public override lastUpdatedAt;
uint256 public override lastUpdatedBlock;

uint256 public priceDataInterval;

mapping (address => uint256) public prices;

mapping (address => bool) public isUpdater;

mapping (address => PriceDataItem) public priceData;
mapping (address => uint256) public maxCumulativeDeltaDiffs;

event DisableFastPrice(address signer);
event EnableFastPrice(address signer);
event PriceData(address token, uint256 refPrice, uint256 fastPrice, uint256 cumulativeRefDelta, uint256 cumulativeFastDelta);
event MaxCumulativeDeltaDiffExceeded(address token, uint256 refPrice, uint256 fastPrice, uint256 cumulativeRefDelta, uint256 cumulativeFastDelta);

modifier onlyUpdater() {
require(isUpdater[msg.sender], "FastPriceFeed: forbidden");
_;
}

function setPricesWithBits(uint256 _priceBits, uint256 _timestamp) external onlyUpdater {
_setPricesWithBits(_priceBits, _timestamp);
}

function _setPricesWithBits(uint256 _priceBits, uint256 _timestamp) private {
bool shouldUpdate = _setLastUpdatedValues(_timestamp);

if (shouldUpdate) {
address _fastPriceEvents = fastPriceEvents;
address _vaultPriceFeed = vaultPriceFeed;

for (uint256 j = 0; j < 8; j++) {
uint256 index = j;
if (index >= tokens.length) { return; }
uint256 startBit = 32 * j;
uint256 price = (_priceBits >> startBit) & BITMASK_32;

address token = tokens[j];
uint256 tokenPrecision = tokenPrecisions[j];
// uint256 adjustedPrice = price.mul(PRICE_PRECISION).div(tokenPrecision);
uint256 adjustedPrice = price * PRICE_PRECISION / tokenPrecision;
_setPrice(token, adjustedPrice, _vaultPriceFeed, _fastPriceEvents);
}
}
}

function _setLastUpdatedValues(uint256 _timestamp) private returns (bool) {
if (minBlockInterval > 0) {
// require(block.number.sub(lastUpdatedBlock) >= minBlockInterval, "FastPriceFeed: minBlockInterval not yet passed");
require(block.number - lastUpdatedBlock >= minBlockInterval, "FastPriceFeed: minBlockInterval not yet passed");
}

uint256 _maxTimeDeviation = maxTimeDeviation;
require(_timestamp > block.timestamp - _maxTimeDeviation, "FastPriceFeed: _timestamp below allowed range");
require(_timestamp < block.timestamp + _maxTimeDeviation, "FastPriceFeed: _timestamp exceeds allowed range");

// do not update prices if _timestamp is before the current lastUpdatedAt value
if (_timestamp < lastUpdatedAt) {
return false;
}

lastUpdatedAt = _timestamp;
lastUpdatedBlock = block.number;

return true;
}

function _setPrice(address _token, uint256 _price, address _vaultPriceFeed, address _fastPriceEvents) private {
// if (_vaultPriceFeed != address(0)) {
// uint256 refPrice = IVaultPriceFeed(_vaultPriceFeed).getLatestPrimaryPrice(_token);
// uint256 fastPrice = prices[_token];

// (uint256 prevRefPrice, uint256 refTime, uint256 cumulativeRefDelta, uint256 cumulativeFastDelta) = getPriceData(_token);

// if (prevRefPrice > 0) {
// uint256 refDeltaAmount = refPrice > prevRefPrice ? refPrice.sub(prevRefPrice) : prevRefPrice.sub(refPrice);
// uint256 fastDeltaAmount = fastPrice > _price ? fastPrice.sub(_price) : _price.sub(fastPrice);

// if (refTime.div(priceDataInterval) != block.timestamp.div(priceDataInterval)) {
// cumulativeRefDelta = 0;
// cumulativeFastDelta = 0;
// }

// cumulativeRefDelta = cumulativeRefDelta.add(refDeltaAmount.mul(CUMULATIVE_DELTA_PRECISION).div(prevRefPrice));
// cumulativeFastDelta = cumulativeFastDelta.add(fastDeltaAmount.mul(CUMULATIVE_DELTA_PRECISION).div(fastPrice));
// }

// if (cumulativeFastDelta > cumulativeRefDelta && cumulativeFastDelta.sub(cumulativeRefDelta) > maxCumulativeDeltaDiffs[_token]) {
// emit MaxCumulativeDeltaDiffExceeded(_token, refPrice, fastPrice, cumulativeRefDelta, cumulativeFastDelta);
// }

// _setPriceData(_token, refPrice, cumulativeRefDelta, cumulativeFastDelta);
// emit PriceData(_token, refPrice, fastPrice, cumulativeRefDelta, cumulativeFastDelta);
// }

// prices[_token] = _price;
// _emitPriceEvent(_fastPriceEvents, _token, _price);
}
function _setPriceData(address _token, uint256 _refPrice, uint256 _cumulativeRefDelta, uint256 _cumulativeFastDelta) private {
require(_refPrice < MAX_REF_PRICE, "FastPriceFeed: invalid refPrice");
// skip validation of block.timestamp, it should only be out of range after the year 2100
require(_cumulativeRefDelta < MAX_CUMULATIVE_REF_DELTA, "FastPriceFeed: invalid cumulativeRefDelta");
require(_cumulativeFastDelta < MAX_CUMULATIVE_FAST_DELTA, "FastPriceFeed: invalid cumulativeFastDelta");

priceData[_token] = PriceDataItem(
uint160(_refPrice),
uint32(block.timestamp),
uint32(_cumulativeRefDelta),
uint32(_cumulativeFastDelta)
);
}

function getPriceData(address _token) public view returns (uint256, uint256, uint256, uint256) {
PriceDataItem memory data = priceData[_token];
return (uint256(data.refPrice), uint256(data.refTime), uint256(data.cumulativeRefDelta), uint256(data.cumulativeFastDelta));
}

function _emitPriceEvent(address _fastPriceEvents, address _token, uint256 _price) private {
if (_fastPriceEvents == address(0)) {
return;
}
// IFastPriceEvents(_fastPriceEvents).emitPriceEvent(_token, _price);
}
}
1 change: 0 additions & 1 deletion src/oracle/UnitPriceFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pragma solidity ^0.8.21;
import { IPriceFeed } from "../interfaces/IPriceFeed.sol";

// import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract UnitPriceFeed is IPriceFeed {
int256 public answer;
uint80 public roundId;
Expand Down
39 changes: 23 additions & 16 deletions src/peripherals/FarmRouer2.sol → src/peripherals/FarmRouter2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract FarmRouter2 is Ownable {

address public uniswapRouter;

address public constant UNISWAP_FACTORY;
address public UNISWAP_FACTORY;

address public WETH;

Expand All @@ -41,27 +41,33 @@ contract FarmRouter2 is Ownable {
address _WETH ,
address _uniswapRouter,
address _farm,
address _pair0,
address _pair1,
address _VAULT
) {
address _VAULT,
address _UNISWAP_FACTORY
) Ownable(initialOnwer) {
TINU = _tinu;
UN = _un;
WETH = _WETH;
uniswapRouter = _uniswapRouter;
farm = _farm;
pair0 = _pair0;
pair1 = _pair1;
VAULT = _VAULT;
UNISWAP_FACTORY = _UNISWAP_FACTORY;
}

function deposit() public payable {
function depositETH() public payable {
require(msg.value > 0, "FarmRouter: value cannot be 0");
IWETH(WETH).deposit{value: msg.value}();
// (uint amountA, uint amountB) = _addLiquidity(WETH, TINU, );
}

// bytes memory _data = abi.encodeWithSignature("addLiquidity(address)", amountA);

function deposit() public payable {

(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(UNISWAP_FACTORY, WETH, TINU);
console.log(reserveA, reserveB);
// uint amountBOptimal = UniswapV2Library.quote(wethBalance, reserveA, reserveB);
// console.log(amountBOptimal);

// console.log(amountBOptimal);
// bytes memory _data = abi.encodeWithSignature("addLiquidity(address)", amountA);
// IVault(VAULT).flashLoan(pair0, amountB, address(this), _data);
}

Expand All @@ -74,24 +80,25 @@ contract FarmRouter2 is Ownable {
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IUniswapV2Factory(UNISWAP_FACTORY).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(UNISWAP_FACTORY).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = PancakeLibrary.getReserves(UNISWAP_FACTORY, tokenA, tokenB);
// if (IUniswapV2Factory(UNISWAP_FACTORY).getPair(tokenA, tokenB) == address(0)) {
// IUniswapV2Factory(UNISWAP_FACTORY).createPair(tokenA, tokenB);
// }
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(UNISWAP_FACTORY, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = PancakeLibrary.quote(amountADesired, reserveA, reserveB);
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'PancakeRouter: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = PancakeLibrary.quote(amountBDesired, reserveB, reserveA);
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}

}

// function addLiquidity(address user, uint256 wethAmount, uint256 tinuAmount) public {
Expand Down
2 changes: 1 addition & 1 deletion test/BaseSetup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ contract BaseSetup is PRBTest, StdCheats {
vault.setPriceFeed(address(vaultPriceFeed));
tinu.setMinter(address(vault));
vaultPriceFeed.setTokenConfig(address(WETH), address(priceFeed), 18);
liquidationRatio = vault.liquidationRatio();
liquidationRatio = vault.liquidationRatio(address(WETH));
vm.stopPrank();
}
}
Loading

0 comments on commit ee1ed2b

Please sign in to comment.