// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;
/// @title IOracle
/// @notice Read price of various token
interface IOracle {
function getPrice(address token) external view returns (uint256);
function postPrices(address[] calldata tokens, uint256[] calldata prices) external;
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;
import {IPool} from "./IPool.sol";
struct Order {
IPool pool;
address owner;
address indexToken;
address collateralToken;
address payToken;
uint256 expiresAt;
uint256 submissionBlock;
uint256 price;
uint256 executionFee;
bool triggerAboveThreshold;
}
struct SwapOrder {
IPool pool;
address owner;
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 minAmountOut;
uint256 price;
uint256 executionFee;
}
interface IOrderManager {
function orders(uint256 id) external view returns (Order memory);
function swapOrders(uint256 id) external view returns (SwapOrder memory);
function executeOrder(uint256 _key, address payable _feeTo) external;
function executeSwapOrder(uint256 _orderId, address payable _feeTo) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {SignedInt} from "../lib/SignedInt.sol";
enum Side {
LONG,
SHORT
}
struct TokenWeight {
address token;
uint256 weight;
}
interface IPool {
function increasePosition(
address _account,
address _indexToken,
address _collateralToken,
uint256 _sizeChanged,
Side _side
) external;
function decreasePosition(
address _account,
address _indexToken,
address _collateralToken,
uint256 _desiredCollateralReduce,
uint256 _sizeChanged,
Side _side,
address _receiver
) external;
function liquidatePosition(address _account, address _indexToken, address _collateralToken, Side _side) external;
function validateToken(address indexToken, address collateralToken, Side side, bool isIncrease)
external
view
returns (bool);
function swap(address _tokenIn, address _tokenOut, uint256 _minOut, address _to, bytes calldata extradata)
external;
function addLiquidity(address _tranche, address _token, uint256 _amountIn, uint256 _minLpAmount, address _to)
external;
function removeLiquidity(address _tranche, address _tokenOut, uint256 _lpAmount, uint256 _minOut, address _to)
external;
// =========== EVENTS ===========
event SetOrderManager(address indexed orderManager);
event IncreasePosition(
bytes32 indexed key,
address account,
address collateralToken,
address indexToken,
uint256 collateralValue,
uint256 sizeChanged,
Side side,
uint256 indexPrice,
uint256 feeValue
);
event UpdatePosition(
bytes32 indexed key,
uint256 size,
uint256 collateralValue,
uint256 entryPrice,
uint256 entryInterestRate,
uint256 reserveAmount,
uint256 indexPrice
);
event DecreasePosition(
bytes32 indexed key,
address account,
address collateralToken,
address indexToken,
uint256 collateralChanged,
uint256 sizeChanged,
Side side,
uint256 indexPrice,
SignedInt pnl,
uint256 feeValue
);
event ClosePosition(
bytes32 indexed key,
uint256 size,
uint256 collateralValue,
uint256 entryPrice,
uint256 entryInterestRate,
uint256 reserveAmount
);
event LiquidatePosition(
bytes32 indexed key,
address account,
address collateralToken,
address indexToken,
Side side,
uint256 size,
uint256 collateralValue,
uint256 reserveAmount,
uint256 indexPrice,
SignedInt pnl,
uint256 feeValue
);
event DaoFeeWithdrawn(address indexed token, address recipient, uint256 amount);
event DaoFeeReduced(address indexed token, uint256 amount);
event FeeDistributorSet(address indexed feeDistributor);
event LiquidityAdded(
address indexed tranche, address indexed sender, address token, uint256 amount, uint256 lpAmount, uint256 fee
);
event LiquidityRemoved(
address indexed tranche, address indexed sender, address token, uint256 lpAmount, uint256 amountOut, uint256 fee
);
event TokenWeightSet(TokenWeight[]);
event Swap(
address indexed sender, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 fee
);
event PositionFeeSet(uint256 positionFee, uint256 liquidationFee);
event DaoFeeSet(uint256 value);
event SwapFeeSet(
uint256 baseSwapFee, uint256 taxBasisPoint, uint256 stableCoinBaseSwapFee, uint256 stableCoinTaxBasisPoint
);
event InterestAccrued(address indexed token, uint256 borrowIndex);
event MaxLeverageChanged(uint256 maxLeverage);
event TokenWhitelisted(address indexed token);
event TokenDelisted(address indexed token);
event OracleChanged(address indexed oldOracle, address indexed newOracle);
event InterestRateSet(uint256 interestRate, uint256 interval);
event PoolHookChanged(address indexed hook);
event TrancheAdded(address indexed lpToken);
event TokenRiskFactorUpdated(address indexed token);
event PnLDistributed(address indexed asset, address indexed tranche, uint256 amount, bool hasProfit);
event MaintenanceMarginChanged(uint256 ratio);
event AddRemoveLiquidityFeeSet(uint256 value);
event MaxGlobalPositionSizeSet(address indexed token, uint256 maxLongRatios, uint256 maxShortSize);
event PoolControllerChanged(address controller);
event AssetRebalanced();
event MaxLiquiditySet(address token, uint256 maxLiquidity);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IOrderManager} from "../interfaces/IOrderManager.sol";
import {IOracle} from "../interfaces/IOracle.sol";
/**
* @title PriceReporter
* @notice Utility contract to call post prices and execute orders on a single transaction. Used on
* testnet only
*/
contract PriceReporter is Ownable {
IOracle public oracle;
IOrderManager public orderManager;
mapping(address => bool) public isReporter;
address[] public reporters;
event ExecuteOrderError(uint256 indexed orderId, string msg);
event ExecuteOrderBytesError(uint256 indexed orderId, bytes msg);
constructor(address _oracle, address _orderManager) {
require(_oracle != address(0), "PriceReporter:invalidOracle");
require(_orderManager != address(0), "PriceReporter:invalidPositionManager");
oracle = IOracle(_oracle);
orderManager = IOrderManager(_orderManager);
}
function postPriceAndExecuteOrders(address[] calldata tokens, uint256[] calldata prices, uint256[] calldata orders)
external
{
require(isReporter[msg.sender], "PriceReporter:unauthorized");
oracle.postPrices(tokens, prices);
for (uint256 i = 0; i < orders.length;) {
try orderManager.executeOrder(orders[i], payable(msg.sender)) {}
catch Error(string memory reason) {
emit ExecuteOrderError(orders[i], reason);
}
// catch (bytes memory reason) {
// emit ExecuteOrderBytesError(orders[i], reason);
// }
unchecked {
++i;
}
}
}
function executeSwapOrders(uint256[] calldata orders) external {
require(isReporter[msg.sender], "PriceReporter:unauthorized");
if (orders.length > 0) {
for (uint256 i = 0; i < orders.length; i++) {
try orderManager.executeSwapOrder(orders[i], payable(msg.sender)) {} catch {}
}
}
}
function addReporter(address reporter) external onlyOwner {
require(reporter != address(0), "PriceReporter:invalidAddress");
require(!isReporter[reporter], "PriceReporter:reporterAlreadyAdded");
isReporter[reporter] = true;
reporters.push(reporter);
}
function setOracle(address _oracle) external onlyOwner {
// require(_oracle != address(0), "PriceReporter:invalidAddress");
oracle = IOracle(_oracle);
}
function setOrderManager(address _orderManager) external onlyOwner {
require(_orderManager != address(0), "PriceReporter:invalidAddress");
orderManager = IOrderManager(_orderManager);
}
function removeReporter(address reporter) external onlyOwner {
require(isReporter[reporter], "PriceReporter:reporterNotExists");
isReporter[reporter] = false;
for (uint256 i = 0; i < reporters.length; i++) {
if (reporters[i] == reporter) {
reporters[i] = reporters[reporters.length - 1];
break;
}
}
reporters.pop();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/ma/SafeCast.solth)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Extract from OpenZeppelin SafeCast to shorten revert message
*/
library SafeCast {
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value < 0");
return uint256(value);
}
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value > int256.max");
return int256(value);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
import {SafeCast} from "../lib/SafeCast.sol";
uint256 constant POS = 1;
uint256 constant NEG = 0;
/// SignedInt is integer number with sign. It value range is -(2 ^ 256 - 1) to (2 ^ 256 - 1)
struct SignedInt {
/// @dev sig = 1 -> positive, sig = 0 is negative
/// using uint256 which take up full word to optimize gas and contract size
uint256 sig;
uint256 abs;
}
library SignedIntOps {
using SafeCast for uint256;
function frac(int256 a, uint256 num, uint256 denom) internal pure returns (int256) {
return a * num.toInt256() / denom.toInt256();
}
function abs(int256 x) internal pure returns (uint256) {
return x < 0 ? uint256(-x) : uint256(x);
}
function asTuple(int256 x) internal pure returns (SignedInt memory) {
return SignedInt({abs: abs(x), sig: x < 0 ? NEG : POS});
}
function lowerCap(int256 x, uint256 maxAbs) internal pure returns (int256) {
int256 min = -maxAbs.toInt256();
return x > min ? x : min;
}
}
{
"compilationTarget": {
"contracts/oracle/PriceReporter.sol": "PriceReporter"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_orderManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"msg","type":"bytes"}],"name":"ExecuteOrderBytesError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"string","name":"msg","type":"string"}],"name":"ExecuteOrderError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"reporter","type":"address"}],"name":"addReporter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orders","type":"uint256[]"}],"name":"executeSwapOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isReporter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"orderManager","outputs":[{"internalType":"contract IOrderManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"},{"internalType":"uint256[]","name":"orders","type":"uint256[]"}],"name":"postPriceAndExecuteOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reporter","type":"address"}],"name":"removeReporter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reporters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_orderManager","type":"address"}],"name":"setOrderManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]