编译器
0.8.17+commit.8df45f5f
文件 1 的 11:Babylonian.sol
pragma solidity 0.8.17;
library Babylonian {
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
文件 2 的 11:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 11:FixedPoint.sol
pragma solidity 0.8.17;
import './Babylonian.sol';
library FixedPoint {
struct uq112x112 {
uint224 _x;
}
struct uq144x112 {
uint256 _x;
}
uint8 private constant RESOLUTION = 112;
uint256 private constant Q112 = uint256(1) << RESOLUTION;
uint256 private constant Q224 = Q112 << RESOLUTION;
function encode(uint112 x) internal pure returns (uq112x112 memory) {
return uq112x112(uint224(x) << RESOLUTION);
}
function encode144(uint144 x) internal pure returns (uq144x112 memory) {
return uq144x112(uint256(x) << RESOLUTION);
}
function div(
uq112x112 memory self,
uint112 x
) internal pure returns (uq112x112 memory) {
require(x != 0, 'FixedPoint: DIV_BY_ZERO');
return uq112x112(self._x / uint224(x));
}
function mul(
uq112x112 memory self,
uint256 y
) internal pure returns (uq144x112 memory) {
uint256 z;
require(
y == 0 || (z = uint256(self._x) * y) / y == uint256(self._x),
'FixedPoint: MULTIPLICATION_OVERFLOW'
);
return uq144x112(z);
}
function fraction(
uint112 numerator,
uint112 denominator
) internal pure returns (uq112x112 memory) {
require(denominator > 0, 'FixedPoint: DIV_BY_ZERO');
return uq112x112((uint224(numerator) << RESOLUTION) / denominator);
}
function decode(uq112x112 memory self) internal pure returns (uint112) {
return uint112(self._x >> RESOLUTION);
}
function decode144(uq144x112 memory self) internal pure returns (uint144) {
return uint144(self._x >> RESOLUTION);
}
function reciprocal(
uq112x112 memory self
) internal pure returns (uq112x112 memory) {
require(self._x != 0, 'FixedPoint: ZERO_RECIPROCAL');
return uq112x112(uint224(Q224 / self._x));
}
function sqrt(
uq112x112 memory self
) internal pure returns (uq112x112 memory) {
return uq112x112(uint224(Babylonian.sqrt(uint256(self._x)) << 56));
}
}
文件 4 的 11:IOracle.sol
pragma solidity 0.8.17;
interface IOracle {
function viewPriceInUSD() external view returns (uint256);
}
文件 5 的 11:IPriceOracleAggregator.sol
pragma solidity 0.8.17;
import {IOracle} from './IOracle.sol';
interface IPriceOracleAggregator {
event UpdateOracle(address token, IOracle oracle);
function updateOracleForAsset(address _asset, IOracle _oracle) external;
function viewPriceInUSD(address _token) external view returns (uint256);
}
文件 6 的 11:IUniswapV2Factory.sol
pragma solidity 0.8.17;
interface IUniswapV2Factory {
function getPair(
address tokenA,
address tokenB
) external view returns (address pair);
}
文件 7 的 11:IUniswapV2Pair.sol
pragma solidity 0.8.17;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(
address owner,
address spender
) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(
address from,
address to,
uint value
) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(
address owner,
address spender,
uint value,
uint deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(
address indexed sender,
uint amount0,
uint amount1,
address indexed to
);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(
uint amount0Out,
uint amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
文件 8 的 11:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 9 的 11:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 10 的 11:UniswapV2Oracle.sol
pragma solidity 0.8.17;
import '@openzeppelin/contracts/utils/math/SafeMath.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '../libraries/FixedPoint.sol';
import '../interfaces/IPriceOracleAggregator.sol';
import '../interfaces/IUniswapV2Pair.sol';
import '../interfaces/IUniswapV2Factory.sol';
interface IERC20Metadata {
function decimals() external view returns (uint8);
}
library UniswapV2Library {
using SafeMath for uint256;
function sortTokens(
address tokenA,
address tokenB
) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
function pairFor(
address factory,
address tokenA,
address tokenB
) internal view returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = IUniswapV2Factory(factory).getPair(token0, token1);
}
function pairForCreate2(
address factory,
address tokenA,
address tokenB
) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
bytes20(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
)
)
)
)
);
}
function getReserves(
address factory,
address tokenA,
address tokenB
) internal view returns (uint256 reserveA, uint256 reserveB) {
(address token0, ) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(
pairFor(factory, tokenA, tokenB)
).getReserves();
(reserveA, reserveB) = tokenA == token0
? (reserve0, reserve1)
: (reserve1, reserve0);
}
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) internal pure returns (uint256 amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(
reserveA > 0 && reserveB > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
amountB = amountA.mul(reserveB) / reserveA;
}
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(
reserveIn > 0 && reserveOut > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(
reserveIn > 0 && reserveOut > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
uint256 numerator = reserveIn.mul(amountOut).mul(1000);
uint256 denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountsOut(
address factory,
uint256 amountIn,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint256 i = 0; i < path.length - 1; i++) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(
factory,
path[i],
path[i + 1]
);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function getAmountsIn(
address factory,
uint256 amountOut,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint256 i = path.length - 1; i > 0; i--) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(
factory,
path[i - 1],
path[i]
);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
library UniswapV2OracleLibrary {
using FixedPoint for *;
function currentBlockTimestamp() internal view returns (uint32) {
return uint32(block.timestamp % 2 ** 32);
}
function currentCumulativePrices(
address pair
)
internal
view
returns (
uint256 price0Cumulative,
uint256 price1Cumulative,
uint32 blockTimestamp
)
{
blockTimestamp = currentBlockTimestamp();
price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();
price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();
(
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
) = IUniswapV2Pair(pair).getReserves();
if (blockTimestampLast != blockTimestamp) {
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
price0Cumulative +=
uint256(FixedPoint.fraction(reserve1, reserve0)._x) *
timeElapsed;
price1Cumulative +=
uint256(FixedPoint.fraction(reserve0, reserve1)._x) *
timeElapsed;
}
}
}
contract UniswapV2Oracle is IOracle, Ownable {
using FixedPoint for *;
IPriceOracleAggregator public immutable aggregator;
uint256 public PERIOD = 1;
uint256 public CONSULT_LENIENCY = 120;
bool public ALLOW_STALE_CONSULTS = false;
IUniswapV2Pair public immutable pair;
bool public isFirstToken;
address public immutable token0;
address public immutable token1;
uint256 public price0CumulativeLast;
uint256 public price1CumulativeLast;
uint32 public blockTimestampLast;
FixedPoint.uq112x112 public price0Average;
FixedPoint.uq112x112 public price1Average;
constructor(
address _factory,
address _tokenA,
address _tokenB,
address _priceOracleAggregator
) {
require(
_priceOracleAggregator != address(0),
'UNIV2: Invalid Aggregator'
);
require(_factory != address(0), 'UNIV2: Invalid factory');
require(_tokenA != address(0), 'UNIV2: Invalid tokenA');
require(_tokenB != address(0), 'UNIV2: Invalid tokenB');
aggregator = IPriceOracleAggregator(_priceOracleAggregator);
IUniswapV2Pair _pair = IUniswapV2Pair(
UniswapV2Library.pairFor(_factory, _tokenA, _tokenB)
);
require(address(_pair) != address(0), 'UNIV2: Invalid Pair');
pair = _pair;
token0 = _pair.token0();
token1 = _pair.token1();
price0CumulativeLast = _pair.price0CumulativeLast();
price1CumulativeLast = _pair.price1CumulativeLast();
uint112 reserve0;
uint112 reserve1;
(reserve0, reserve1, blockTimestampLast) = _pair.getReserves();
require(reserve0 != 0 && reserve1 != 0, 'UNIV2: NO_RESERVES');
if (_tokenA == _pair.token0()) {
isFirstToken = true;
} else {
isFirstToken = false;
}
}
function setPeriod(uint256 _period) external onlyOwner {
PERIOD = _period;
}
function setConsultLeniency(uint256 _consult_leniency) external onlyOwner {
CONSULT_LENIENCY = _consult_leniency;
}
function setAllowStaleConsults(
bool _allow_stale_consults
) external onlyOwner {
ALLOW_STALE_CONSULTS = _allow_stale_consults;
}
function canUpdate() public view returns (bool) {
uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
return (timeElapsed >= PERIOD);
}
function update() external {
(
uint256 price0Cumulative,
uint256 price1Cumulative,
uint32 blockTimestamp
) = UniswapV2OracleLibrary.currentCumulativePrices(address(pair));
uint256 timeElapsed = blockTimestamp > blockTimestampLast
? blockTimestamp - blockTimestampLast
: uint256(blockTimestamp) + 2 ** 32 - uint256(blockTimestampLast);
require(timeElapsed >= PERIOD, 'UniswapPairOracle: PERIOD_NOT_ELAPSED');
price0Average = FixedPoint.uq112x112(
uint224((price0Cumulative - price0CumulativeLast) / timeElapsed)
);
price1Average = FixedPoint.uq112x112(
uint224((price1Cumulative - price1CumulativeLast) / timeElapsed)
);
price0CumulativeLast = price0Cumulative;
price1CumulativeLast = price1Cumulative;
blockTimestampLast = blockTimestamp;
}
function viewPriceInUSD() external view override returns (uint256 price) {
uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
require(
(timeElapsed < (PERIOD + CONSULT_LENIENCY)) || ALLOW_STALE_CONSULTS,
'UniswapPairOracle: PRICE_IS_STALE_NEED_TO_CALL_UPDATE'
);
if (isFirstToken) {
price =
(aggregator.viewPriceInUSD(token1) *
(10 ** IERC20Metadata(token0).decimals())) /
(
price1Average
.mul(10 ** IERC20Metadata(token1).decimals())
.decode144()
);
} else {
price =
(aggregator.viewPriceInUSD(token0) *
(10 ** IERC20Metadata(token1).decimals())) /
(
price0Average
.mul(10 ** IERC20Metadata(token0).decimals())
.decode144()
);
}
}
}
文件 11 的 11:UniswapV2OracleV2.sol
pragma solidity 0.8.17;
import '@openzeppelin/contracts/utils/math/SafeMath.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '../libraries/FixedPoint.sol';
import '../interfaces/IPriceOracleAggregator.sol';
import '../interfaces/IUniswapV2Pair.sol';
import '../interfaces/IUniswapV2Factory.sol';
import {UniswapV2Oracle} from './UniswapV2Oracle.sol';
interface IERC20Metadata {
function decimals() external view returns (uint8);
}
library UniswapV2Library {
using SafeMath for uint256;
function sortTokens(
address tokenA,
address tokenB
) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
function pairFor(
address factory,
address tokenA,
address tokenB
) internal view returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = IUniswapV2Factory(factory).getPair(token0, token1);
}
function pairForCreate2(
address factory,
address tokenA,
address tokenB
) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
bytes20(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
)
)
)
)
);
}
function getReserves(
address factory,
address tokenA,
address tokenB
) internal view returns (uint256 reserveA, uint256 reserveB) {
(address token0, ) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(
pairFor(factory, tokenA, tokenB)
).getReserves();
(reserveA, reserveB) = tokenA == token0
? (reserve0, reserve1)
: (reserve1, reserve0);
}
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) internal pure returns (uint256 amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(
reserveA > 0 && reserveB > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
amountB = amountA.mul(reserveB) / reserveA;
}
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(
reserveIn > 0 && reserveOut > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(
reserveIn > 0 && reserveOut > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
uint256 numerator = reserveIn.mul(amountOut).mul(1000);
uint256 denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountsOut(
address factory,
uint256 amountIn,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint256 i = 0; i < path.length - 1; i++) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(
factory,
path[i],
path[i + 1]
);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function getAmountsIn(
address factory,
uint256 amountOut,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint256 i = path.length - 1; i > 0; i--) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(
factory,
path[i - 1],
path[i]
);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
library UniswapV2OracleLibrary {
using FixedPoint for *;
function currentBlockTimestamp() internal view returns (uint32) {
return uint32(block.timestamp % 2 ** 32);
}
function currentCumulativePrices(
address pair
)
internal
view
returns (
uint256 price0Cumulative,
uint256 price1Cumulative,
uint32 blockTimestamp
)
{
blockTimestamp = currentBlockTimestamp();
price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();
price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();
(
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
) = IUniswapV2Pair(pair).getReserves();
if (blockTimestampLast != blockTimestamp) {
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
price0Cumulative +=
uint256(FixedPoint.fraction(reserve1, reserve0)._x) *
timeElapsed;
price1Cumulative +=
uint256(FixedPoint.fraction(reserve0, reserve1)._x) *
timeElapsed;
}
}
}
contract UniswapV2OracleV2 is IOracle, Ownable {
using FixedPoint for *;
IPriceOracleAggregator public immutable aggregator;
uint256 public PERIOD = 1;
uint256 public CONSULT_LENIENCY = 120;
bool public ALLOW_STALE_CONSULTS = false;
IUniswapV2Pair public immutable pair;
bool public isFirstToken;
address public immutable token0;
address public immutable token1;
uint256 public price0CumulativeLast;
uint256 public price1CumulativeLast;
uint32 public blockTimestampLast;
FixedPoint.uq112x112 public price0Average;
FixedPoint.uq112x112 public price1Average;
constructor(address _prevAggregator) {
aggregator = UniswapV2Oracle(_prevAggregator).aggregator();
PERIOD = UniswapV2Oracle(_prevAggregator).PERIOD();
CONSULT_LENIENCY = UniswapV2Oracle(_prevAggregator).CONSULT_LENIENCY();
ALLOW_STALE_CONSULTS = UniswapV2Oracle(_prevAggregator)
.ALLOW_STALE_CONSULTS();
pair = UniswapV2Oracle(_prevAggregator).pair();
isFirstToken = UniswapV2Oracle(_prevAggregator).isFirstToken();
token0 = UniswapV2Oracle(_prevAggregator).token0();
token1 = UniswapV2Oracle(_prevAggregator).token1();
price0CumulativeLast = UniswapV2Oracle(_prevAggregator)
.price0CumulativeLast();
price1CumulativeLast = UniswapV2Oracle(_prevAggregator)
.price1CumulativeLast();
blockTimestampLast = UniswapV2Oracle(_prevAggregator)
.blockTimestampLast();
price0Average = FixedPoint.uq112x112(
UniswapV2Oracle(_prevAggregator).price0Average()
);
price1Average = FixedPoint.uq112x112(
UniswapV2Oracle(_prevAggregator).price1Average()
);
}
function setPeriod(uint256 _period) external onlyOwner {
PERIOD = _period;
}
function setConsultLeniency(uint256 _consult_leniency) external onlyOwner {
CONSULT_LENIENCY = _consult_leniency;
}
function setAllowStaleConsults(
bool _allow_stale_consults
) external onlyOwner {
ALLOW_STALE_CONSULTS = _allow_stale_consults;
}
function canUpdate() public view returns (bool) {
uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
return (timeElapsed >= PERIOD);
}
function update() external {
(
uint256 price0Cumulative,
uint256 price1Cumulative,
uint32 blockTimestamp
) = UniswapV2OracleLibrary.currentCumulativePrices(address(pair));
uint256 timeElapsed = blockTimestamp > blockTimestampLast
? blockTimestamp - blockTimestampLast
: uint256(blockTimestamp) + 2 ** 32 - uint256(blockTimestampLast);
require(
timeElapsed >= PERIOD && timeElapsed < 2 ** 32,
'UniswapPairOracle: PERIOD_NOT_ELAPSED'
);
price0Average = FixedPoint.uq112x112(
uint224((price0Cumulative - price0CumulativeLast) / timeElapsed)
);
price1Average = FixedPoint.uq112x112(
uint224((price1Cumulative - price1CumulativeLast) / timeElapsed)
);
price0CumulativeLast = price0Cumulative;
price1CumulativeLast = price1Cumulative;
blockTimestampLast = blockTimestamp;
}
function viewPriceInUSD() external view override returns (uint256 price) {
uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
require(
(timeElapsed < (PERIOD + CONSULT_LENIENCY)) || ALLOW_STALE_CONSULTS,
'UniswapPairOracle: PRICE_IS_STALE_NEED_TO_CALL_UPDATE'
);
if (isFirstToken) {
price =
(aggregator.viewPriceInUSD(token1) *
(10 ** IERC20Metadata(token0).decimals())) /
(
price1Average
.mul(10 ** IERC20Metadata(token1).decimals())
.decode144()
);
} else {
price =
(aggregator.viewPriceInUSD(token0) *
(10 ** IERC20Metadata(token1).decimals())) /
(
price0Average
.mul(10 ** IERC20Metadata(token0).decimals())
.decode144()
);
}
}
}
{
"compilationTarget": {
"contracts/oracle/UniswapV2OracleV2.sol": "UniswapV2OracleV2"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_prevAggregator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"ALLOW_STALE_CONSULTS","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONSULT_LENIENCY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggregator","outputs":[{"internalType":"contract IPriceOracleAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampLast","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFirstToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price0Average","outputs":[{"internalType":"uint224","name":"_x","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price1Average","outputs":[{"internalType":"uint224","name":"_x","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_allow_stale_consults","type":"bool"}],"name":"setAllowStaleConsults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_consult_leniency","type":"uint256"}],"name":"setConsultLeniency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"setPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"viewPriceInUSD","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"}]