编译器
0.8.18+commit.87f61d96
文件 1 的 108:AccountUtils.sol
pragma solidity ^0.8.0;
import "../error/Errors.sol";
library AccountUtils {
function validateAccount(address account) internal pure {
if (account == address(0)) {
revert Errors.EmptyAccount();
}
}
function validateReceiver(address receiver) internal pure {
if (receiver == address(0)) {
revert Errors.EmptyReceiver();
}
}
}
文件 2 的 108:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 3 的 108:AggregatorInterface.sol
pragma solidity ^0.8.0;
interface AggregatorInterface {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}
文件 4 的 108:AggregatorV2V3Interface.sol
pragma solidity ^0.8.0;
import {AggregatorInterface} from "./AggregatorInterface.sol";
import {AggregatorV3Interface} from "./AggregatorV3Interface.sol";
interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}
文件 5 的 108:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
文件 6 的 108:ArbSys.sol
pragma solidity ^0.8.0;
interface ArbSys {
function arbBlockNumber() external view returns (uint256);
function arbBlockHash(uint256 blockNumber) external view returns (bytes32);
}
文件 7 的 108:Array.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "../error/Errors.sol";
library Array {
using SafeCast for int256;
function get(bytes32[] memory arr, uint256 index) internal pure returns (bytes32) {
if (index < arr.length) {
return arr[index];
}
return bytes32(0);
}
function areEqualTo(uint256[] memory arr, uint256 value) internal pure returns (bool) {
for (uint256 i; i < arr.length; i++) {
if (arr[i] != value) {
return false;
}
}
return true;
}
function areGreaterThan(uint256[] memory arr, uint256 value) internal pure returns (bool) {
for (uint256 i; i < arr.length; i++) {
if (arr[i] <= value) {
return false;
}
}
return true;
}
function areGreaterThanOrEqualTo(uint256[] memory arr, uint256 value) internal pure returns (bool) {
for (uint256 i; i < arr.length; i++) {
if (arr[i] < value) {
return false;
}
}
return true;
}
function areLessThan(uint256[] memory arr, uint256 value) internal pure returns (bool) {
for (uint256 i; i < arr.length; i++) {
if (arr[i] >= value) {
return false;
}
}
return true;
}
function areLessThanOrEqualTo(uint256[] memory arr, uint256 value) internal pure returns (bool) {
for (uint256 i; i < arr.length; i++) {
if (arr[i] > value) {
return false;
}
}
return true;
}
function getMedian(uint256[] memory arr) internal pure returns (uint256) {
if (arr.length % 2 == 1) {
return arr[arr.length / 2];
}
return (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2;
}
function getUncompactedValue(
uint256[] memory compactedValues,
uint256 index,
uint256 compactedValueBitLength,
uint256 bitmask,
string memory label
) internal pure returns (uint256) {
uint256 compactedValuesPerSlot = 256 / compactedValueBitLength;
uint256 slotIndex = index / compactedValuesPerSlot;
if (slotIndex >= compactedValues.length) {
revert Errors.CompactedArrayOutOfBounds(compactedValues, index, slotIndex, label);
}
uint256 slotBits = compactedValues[slotIndex];
uint256 offset = (index - slotIndex * compactedValuesPerSlot) * compactedValueBitLength;
uint256 value = (slotBits >> offset) & bitmask;
return value;
}
}
文件 8 的 108:Bank.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../token/TokenUtils.sol";
import "../role/RoleModule.sol";
contract Bank is RoleModule {
using SafeERC20 for IERC20;
DataStore public immutable dataStore;
constructor(RoleStore _roleStore, DataStore _dataStore) RoleModule(_roleStore) {
dataStore = _dataStore;
}
receive() external payable {
address wnt = TokenUtils.wnt(dataStore);
if (msg.sender != wnt) {
revert Errors.InvalidNativeTokenSender(msg.sender);
}
}
function transferOut(
address token,
address receiver,
uint256 amount
) external onlyController {
_transferOut(token, receiver, amount);
}
function transferOut(
address token,
address receiver,
uint256 amount,
bool shouldUnwrapNativeToken
) external onlyController {
address wnt = TokenUtils.wnt(dataStore);
if (token == wnt && shouldUnwrapNativeToken) {
_transferOutNativeToken(token, receiver, amount);
} else {
_transferOut(token, receiver, amount);
}
}
function transferOutNativeToken(
address receiver,
uint256 amount
) external onlyController {
address wnt = TokenUtils.wnt(dataStore);
_transferOutNativeToken(wnt, receiver, amount);
}
function _transferOut(
address token,
address receiver,
uint256 amount
) internal {
if (receiver == address(this)) {
revert Errors.SelfTransferNotSupported(receiver);
}
TokenUtils.transfer(dataStore, token, receiver, amount);
_afterTransferOut(token);
}
function _transferOutNativeToken(
address token,
address receiver,
uint256 amount
) internal {
if (receiver == address(this)) {
revert Errors.SelfTransferNotSupported(receiver);
}
TokenUtils.withdrawAndSendNativeToken(
dataStore,
token,
receiver,
amount
);
_afterTransferOut(token);
}
function _afterTransferOut(address ) internal virtual {}
}
文件 9 的 108:BaseOrderUtils.sol
pragma solidity ^0.8.0;
import "./Order.sol";
import "../market/Market.sol";
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "../referral/IReferralStorage.sol";
import "../order/OrderVault.sol";
import "../oracle/Oracle.sol";
import "../swap/SwapHandler.sol";
library BaseOrderUtils {
using SafeCast for int256;
using SafeCast for uint256;
using Order for Order.Props;
using Price for Price.Props;
struct ExecuteOrderParams {
ExecuteOrderParamsContracts contracts;
bytes32 key;
Order.Props order;
Market.Props[] swapPathMarkets;
uint256 minOracleTimestamp;
uint256 maxOracleTimestamp;
Market.Props market;
address keeper;
uint256 startingGas;
Order.SecondaryOrderType secondaryOrderType;
}
struct ExecuteOrderParamsContracts {
DataStore dataStore;
EventEmitter eventEmitter;
OrderVault orderVault;
Oracle oracle;
SwapHandler swapHandler;
IReferralStorage referralStorage;
}
struct GetExecutionPriceCache {
uint256 price;
uint256 executionPrice;
int256 adjustedPriceImpactUsd;
}
function isSupportedOrder(Order.OrderType orderType) internal pure returns (bool) {
return orderType == Order.OrderType.MarketSwap ||
orderType == Order.OrderType.LimitSwap ||
orderType == Order.OrderType.MarketIncrease ||
orderType == Order.OrderType.MarketDecrease ||
orderType == Order.OrderType.LimitIncrease ||
orderType == Order.OrderType.LimitDecrease ||
orderType == Order.OrderType.StopIncrease ||
orderType == Order.OrderType.StopLossDecrease ||
orderType == Order.OrderType.Liquidation;
}
function isMarketOrder(Order.OrderType orderType) internal pure returns (bool) {
return orderType == Order.OrderType.MarketSwap ||
orderType == Order.OrderType.MarketIncrease ||
orderType == Order.OrderType.MarketDecrease;
}
function isSwapOrder(Order.OrderType orderType) internal pure returns (bool) {
return orderType == Order.OrderType.MarketSwap ||
orderType == Order.OrderType.LimitSwap;
}
function isPositionOrder(Order.OrderType orderType) internal pure returns (bool) {
return isIncreaseOrder(orderType) || isDecreaseOrder(orderType);
}
function isIncreaseOrder(Order.OrderType orderType) internal pure returns (bool) {
return orderType == Order.OrderType.MarketIncrease ||
orderType == Order.OrderType.LimitIncrease ||
orderType == Order.OrderType.StopIncrease;
}
function isDecreaseOrder(Order.OrderType orderType) internal pure returns (bool) {
return orderType == Order.OrderType.MarketDecrease ||
orderType == Order.OrderType.LimitDecrease ||
orderType == Order.OrderType.StopLossDecrease ||
orderType == Order.OrderType.Liquidation;
}
function isLiquidationOrder(Order.OrderType orderType) internal pure returns (bool) {
return orderType == Order.OrderType.Liquidation;
}
function validateOrderTriggerPrice(
Oracle oracle,
address indexToken,
Order.OrderType orderType,
uint256 triggerPrice,
bool isLong
) internal view {
if (
isSwapOrder(orderType) ||
isMarketOrder(orderType) ||
isLiquidationOrder(orderType)
) {
return;
}
Price.Props memory primaryPrice = oracle.getPrimaryPrice(indexToken);
if (orderType == Order.OrderType.LimitIncrease) {
bool ok = isLong ? primaryPrice.max <= triggerPrice : primaryPrice.min >= triggerPrice;
if (!ok) {
revert Errors.InvalidOrderPrices(primaryPrice.min, primaryPrice.max, triggerPrice, uint256(orderType));
}
return;
}
if (orderType == Order.OrderType.StopIncrease) {
bool ok = isLong ? primaryPrice.max >= triggerPrice : primaryPrice.min <= triggerPrice;
if (!ok) {
revert Errors.InvalidOrderPrices(primaryPrice.min, primaryPrice.max, triggerPrice, uint256(orderType));
}
return;
}
if (orderType == Order.OrderType.LimitDecrease) {
bool ok = isLong ? primaryPrice.min >= triggerPrice : primaryPrice.max <= triggerPrice;
if (!ok) {
revert Errors.InvalidOrderPrices(primaryPrice.min, primaryPrice.max, triggerPrice, uint256(orderType));
}
return;
}
if (orderType == Order.OrderType.StopLossDecrease) {
bool ok = isLong ? primaryPrice.min <= triggerPrice : primaryPrice.max >= triggerPrice;
if (!ok) {
revert Errors.InvalidOrderPrices(primaryPrice.min, primaryPrice.max, triggerPrice, uint256(orderType));
}
return;
}
revert Errors.UnsupportedOrderType(uint256(orderType));
}
function validateOrderValidFromTime(
Order.OrderType orderType,
uint256 validFromTime
) internal view {
if (isMarketOrder(orderType)) {
return;
}
uint256 currentTimestamp = Chain.currentTimestamp();
if (validFromTime > currentTimestamp) {
revert Errors.OrderValidFromTimeNotReached(validFromTime, currentTimestamp);
}
}
function getExecutionPriceForIncrease(
uint256 sizeDeltaUsd,
uint256 sizeDeltaInTokens,
uint256 acceptablePrice,
bool isLong
) internal pure returns (uint256) {
if (sizeDeltaInTokens == 0) {
revert Errors.EmptySizeDeltaInTokens();
}
uint256 executionPrice = sizeDeltaUsd / sizeDeltaInTokens;
if (
(isLong && executionPrice <= acceptablePrice) ||
(!isLong && executionPrice >= acceptablePrice)
) {
return executionPrice;
}
revert Errors.OrderNotFulfillableAtAcceptablePrice(executionPrice, acceptablePrice);
}
function getExecutionPriceForDecrease(
Price.Props memory indexTokenPrice,
uint256 positionSizeInUsd,
uint256 positionSizeInTokens,
uint256 sizeDeltaUsd,
int256 priceImpactUsd,
uint256 acceptablePrice,
bool isLong
) internal pure returns (uint256) {
GetExecutionPriceCache memory cache;
cache.price = indexTokenPrice.pickPrice(!isLong);
cache.executionPrice = cache.price;
if (sizeDeltaUsd > 0 && positionSizeInTokens > 0) {
cache.adjustedPriceImpactUsd = isLong ? priceImpactUsd : -priceImpactUsd;
if (cache.adjustedPriceImpactUsd < 0 && (-cache.adjustedPriceImpactUsd).toUint256() > sizeDeltaUsd) {
revert Errors.PriceImpactLargerThanOrderSize(cache.adjustedPriceImpactUsd, sizeDeltaUsd);
}
int256 adjustment = Precision.mulDiv(positionSizeInUsd, cache.adjustedPriceImpactUsd, positionSizeInTokens) / sizeDeltaUsd.toInt256();
int256 _executionPrice = cache.price.toInt256() + adjustment;
if (_executionPrice < 0) {
revert Errors.NegativeExecutionPrice(_executionPrice, cache.price, positionSizeInUsd, cache.adjustedPriceImpactUsd, sizeDeltaUsd);
}
cache.executionPrice = _executionPrice.toUint256();
}
if (
(isLong && cache.executionPrice >= acceptablePrice) ||
(!isLong && cache.executionPrice <= acceptablePrice)
) {
return cache.executionPrice;
}
revert Errors.OrderNotFulfillableAtAcceptablePrice(cache.executionPrice, acceptablePrice);
}
function validateNonEmptyOrder(Order.Props memory order) internal pure {
if (order.account() == address(0)) {
revert Errors.EmptyOrder();
}
if (order.sizeDeltaUsd() == 0 && order.initialCollateralDeltaAmount() == 0) {
revert Errors.EmptyOrder();
}
}
function getPositionKey(Order.Props memory order) internal pure returns (bytes32) {
if (isDecreaseOrder(order.orderType())) {
return Position.getPositionKey(
order.account(),
order.market(),
order.initialCollateralToken(),
order.isLong()
);
}
revert Errors.UnsupportedOrderType(uint256(order.orderType()));
}
}
文件 10 的 108:BaseRouter.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../utils/PayableMulticall.sol";
import "../utils/AccountUtils.sol";
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "../token/TokenUtils.sol";
import "./Router.sol";
contract BaseRouter is ReentrancyGuard, PayableMulticall, RoleModule {
using SafeERC20 for IERC20;
Router public immutable router;
DataStore public immutable dataStore;
EventEmitter public immutable eventEmitter;
constructor(
Router _router,
RoleStore _roleStore,
DataStore _dataStore,
EventEmitter _eventEmitter
) RoleModule(_roleStore) {
router = _router;
dataStore = _dataStore;
eventEmitter = _eventEmitter;
}
function sendWnt(address receiver, uint256 amount) external payable nonReentrant {
AccountUtils.validateReceiver(receiver);
TokenUtils.depositAndSendWrappedNativeToken(dataStore, receiver, amount);
}
function sendTokens(address token, address receiver, uint256 amount) external payable nonReentrant {
AccountUtils.validateReceiver(receiver);
address account = msg.sender;
router.pluginTransfer(token, account, receiver, amount);
}
function sendNativeToken(address receiver, uint256 amount) external payable nonReentrant {
AccountUtils.validateReceiver(receiver);
TokenUtils.sendNativeToken(dataStore, receiver, amount);
}
}
文件 11 的 108:Calc.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
library Calc {
using SignedMath for int256;
using SafeCast for uint256;
function boundMagnitude(int256 value, uint256 min, uint256 max) internal pure returns (int256) {
uint256 magnitude = value.abs();
if (magnitude < min) {
magnitude = min;
}
if (magnitude > max) {
magnitude = max;
}
int256 sign = value == 0 ? int256(1) : value / value.abs().toInt256();
return magnitude.toInt256() * sign;
}
function roundUpDivision(uint256 a, uint256 b) internal pure returns (uint256) {
return (a + b - 1) / b;
}
function roundUpMagnitudeDivision(int256 a, uint256 b) internal pure returns (int256) {
if (a < 0) {
return (a - b.toInt256() + 1) / b.toInt256();
}
return (a + b.toInt256() - 1) / b.toInt256();
}
function sumReturnUint256(uint256 a, int256 b) internal pure returns (uint256) {
if (b > 0) {
return a + b.abs();
}
return a - b.abs();
}
function sumReturnInt256(uint256 a, int256 b) internal pure returns (int256) {
return a.toInt256() + b;
}
function diff(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}
function boundedAdd(int256 a, int256 b) internal pure returns (int256) {
if (a == 0 || b == 0 || (a < 0 && b > 0) || (a > 0 && b < 0)) {
return a + b;
}
if (a < 0 && b <= type(int256).min - a) {
return type(int256).min;
}
if (a > 0 && b >= type(int256).max - a) {
return type(int256).max;
}
return a + b;
}
function boundedSub(int256 a, int256 b) internal pure returns (int256) {
if (a == 0 || b == 0 || (a > 0 && b > 0) || (a < 0 && b < 0)) {
return a - b;
}
if (a > 0 && -b >= type(int256).max - a) {
return type(int256).max;
}
if (a < 0 && -b <= type(int256).min - a) {
return type(int256).min;
}
return a - b;
}
function toSigned(uint256 a, bool isPositive) internal pure returns (int256) {
if (isPositive) {
return a.toInt256();
} else {
return -a.toInt256();
}
}
}
文件 12 的 108:CallbackUtils.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Address.sol";
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "./IOrderCallbackReceiver.sol";
import "./IDepositCallbackReceiver.sol";
import "./IWithdrawalCallbackReceiver.sol";
import "./IShiftCallbackReceiver.sol";
import "./IGasFeeCallbackReceiver.sol";
import "./IGlvDepositCallbackReceiver.sol";
import "./IGlvWithdrawalCallbackReceiver.sol";
library CallbackUtils {
using Address for address;
using Deposit for Deposit.Props;
using Withdrawal for Withdrawal.Props;
using Shift for Shift.Props;
using Order for Order.Props;
using GlvDeposit for GlvDeposit.Props;
using GlvWithdrawal for GlvWithdrawal.Props;
event AfterDepositExecutionError(bytes32 key, Deposit.Props deposit);
event AfterDepositCancellationError(bytes32 key, Deposit.Props deposit);
event AfterWithdrawalExecutionError(bytes32 key, Withdrawal.Props withdrawal);
event AfterWithdrawalCancellationError(bytes32 key, Withdrawal.Props withdrawal);
event AfterShiftExecutionError(bytes32 key, Shift.Props shift);
event AfterShiftCancellationError(bytes32 key, Shift.Props shift);
event AfterOrderExecutionError(bytes32 key, Order.Props order);
event AfterOrderCancellationError(bytes32 key, Order.Props order);
event AfterOrderFrozenError(bytes32 key, Order.Props order);
event AfterGlvDepositExecutionError(bytes32 key, GlvDeposit.Props glvDeposit);
event AfterGlvDepositCancellationError(bytes32 key, GlvDeposit.Props glvDeposit);
event AfterGlvWithdrawalExecutionError(bytes32 key, GlvWithdrawal.Props glvWithdrawal);
event AfterGlvWithdrawalCancellationError(bytes32 key, GlvWithdrawal.Props glvWithdrawal);
function validateCallbackGasLimit(DataStore dataStore, uint256 callbackGasLimit) internal view {
uint256 maxCallbackGasLimit = dataStore.getUint(Keys.MAX_CALLBACK_GAS_LIMIT);
if (callbackGasLimit > maxCallbackGasLimit) {
revert Errors.MaxCallbackGasLimitExceeded(callbackGasLimit, maxCallbackGasLimit);
}
}
function validateGasLeftForCallback(uint256 callbackGasLimit) internal view {
uint256 gasToBeForwarded = gasleft() / 64 * 63;
if (gasToBeForwarded < callbackGasLimit) {
revert Errors.InsufficientGasLeftForCallback(gasToBeForwarded, callbackGasLimit);
}
}
function setSavedCallbackContract(DataStore dataStore, address account, address market, address callbackContract) external {
dataStore.setAddress(Keys.savedCallbackContract(account, market), callbackContract);
}
function getSavedCallbackContract(DataStore dataStore, address account, address market) internal view returns (address) {
return dataStore.getAddress(Keys.savedCallbackContract(account, market));
}
function refundExecutionFee(
DataStore dataStore,
bytes32 key,
address callbackContract,
uint256 refundFeeAmount,
EventUtils.EventLogData memory eventData
) internal returns (bool) {
if (!isValidCallbackContract(callbackContract)) { return false; }
uint256 gasLimit = dataStore.getUint(Keys.REFUND_EXECUTION_FEE_GAS_LIMIT);
validateGasLeftForCallback(gasLimit);
try IGasFeeCallbackReceiver(callbackContract).refundExecutionFee{ gas: gasLimit, value: refundFeeAmount }(
key,
eventData
) {
return true;
} catch {
return false;
}
}
function afterDepositExecution(
bytes32 key,
Deposit.Props memory deposit,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(deposit.callbackContract())) { return; }
validateGasLeftForCallback(deposit.callbackGasLimit());
try IDepositCallbackReceiver(deposit.callbackContract()).afterDepositExecution{ gas: deposit.callbackGasLimit() }(
key,
deposit,
eventData
) {
} catch {
emit AfterDepositExecutionError(key, deposit);
}
}
function afterDepositCancellation(
bytes32 key,
Deposit.Props memory deposit,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(deposit.callbackContract())) { return; }
validateGasLeftForCallback(deposit.callbackGasLimit());
try IDepositCallbackReceiver(deposit.callbackContract()).afterDepositCancellation{ gas: deposit.callbackGasLimit() }(
key,
deposit,
eventData
) {
} catch {
emit AfterDepositCancellationError(key, deposit);
}
}
function afterWithdrawalExecution(
bytes32 key,
Withdrawal.Props memory withdrawal,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(withdrawal.callbackContract())) { return; }
validateGasLeftForCallback(withdrawal.callbackGasLimit());
try IWithdrawalCallbackReceiver(withdrawal.callbackContract()).afterWithdrawalExecution{ gas: withdrawal.callbackGasLimit() }(
key,
withdrawal,
eventData
) {
} catch {
emit AfterWithdrawalExecutionError(key, withdrawal);
}
}
function afterWithdrawalCancellation(
bytes32 key,
Withdrawal.Props memory withdrawal,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(withdrawal.callbackContract())) { return; }
validateGasLeftForCallback(withdrawal.callbackGasLimit());
try IWithdrawalCallbackReceiver(withdrawal.callbackContract()).afterWithdrawalCancellation{ gas: withdrawal.callbackGasLimit() }(
key,
withdrawal,
eventData
) {
} catch {
emit AfterWithdrawalCancellationError(key, withdrawal);
}
}
function afterShiftExecution(
bytes32 key,
Shift.Props memory shift,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(shift.callbackContract())) { return; }
validateGasLeftForCallback(shift.callbackGasLimit());
try IShiftCallbackReceiver(shift.callbackContract()).afterShiftExecution{ gas: shift.callbackGasLimit() }(
key,
shift,
eventData
) {
} catch {
emit AfterShiftExecutionError(key, shift);
}
}
function afterShiftCancellation(
bytes32 key,
Shift.Props memory shift,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(shift.callbackContract())) { return; }
validateGasLeftForCallback(shift.callbackGasLimit());
try IShiftCallbackReceiver(shift.callbackContract()).afterShiftCancellation{ gas: shift.callbackGasLimit() }(
key,
shift,
eventData
) {
} catch {
emit AfterShiftCancellationError(key, shift);
}
}
function afterOrderExecution(
bytes32 key,
Order.Props memory order,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(order.callbackContract())) { return; }
validateGasLeftForCallback(order.callbackGasLimit());
try IOrderCallbackReceiver(order.callbackContract()).afterOrderExecution{ gas: order.callbackGasLimit() }(
key,
order,
eventData
) {
} catch {
emit AfterOrderExecutionError(key, order);
}
}
function afterOrderCancellation(
bytes32 key,
Order.Props memory order,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(order.callbackContract())) { return; }
validateGasLeftForCallback(order.callbackGasLimit());
try IOrderCallbackReceiver(order.callbackContract()).afterOrderCancellation{ gas: order.callbackGasLimit() }(
key,
order,
eventData
) {
} catch {
emit AfterOrderCancellationError(key, order);
}
}
function afterOrderFrozen(
bytes32 key,
Order.Props memory order,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(order.callbackContract())) { return; }
validateGasLeftForCallback(order.callbackGasLimit());
try IOrderCallbackReceiver(order.callbackContract()).afterOrderFrozen{ gas: order.callbackGasLimit() }(
key,
order,
eventData
) {
} catch {
emit AfterOrderFrozenError(key, order);
}
}
function afterGlvDepositExecution(
bytes32 key,
GlvDeposit.Props memory glvDeposit,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(glvDeposit.callbackContract())) {
return;
}
validateGasLeftForCallback(glvDeposit.callbackGasLimit());
try IGlvDepositCallbackReceiver(glvDeposit.callbackContract()).afterGlvDepositExecution{ gas: glvDeposit.callbackGasLimit() }(
key,
glvDeposit,
eventData
) {
} catch {
emit AfterGlvDepositExecutionError(key, glvDeposit);
}
}
function afterGlvDepositCancellation(
bytes32 key,
GlvDeposit.Props memory glvDeposit,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(glvDeposit.callbackContract())) { return; }
validateGasLeftForCallback(glvDeposit.callbackGasLimit());
try IGlvDepositCallbackReceiver(glvDeposit.callbackContract()).afterGlvDepositCancellation{ gas: glvDeposit.callbackGasLimit() }(
key,
glvDeposit,
eventData
) {
} catch {
emit AfterGlvDepositCancellationError(key, glvDeposit);
}
}
function afterGlvWithdrawalExecution(
bytes32 key,
GlvWithdrawal.Props memory glvWithdrawal,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(glvWithdrawal.callbackContract())) { return; }
validateGasLeftForCallback(glvWithdrawal.callbackGasLimit());
try IGlvWithdrawalCallbackReceiver(glvWithdrawal.callbackContract()).afterGlvWithdrawalExecution{ gas: glvWithdrawal.callbackGasLimit() }(
key,
glvWithdrawal,
eventData
) {
} catch {
emit AfterGlvWithdrawalExecutionError(key, glvWithdrawal);
}
}
function afterGlvWithdrawalCancellation(
bytes32 key,
GlvWithdrawal.Props memory glvWithdrawal,
EventUtils.EventLogData memory eventData
) internal {
if (!isValidCallbackContract(glvWithdrawal.callbackContract())) { return; }
validateGasLeftForCallback(glvWithdrawal.callbackGasLimit());
try IGlvWithdrawalCallbackReceiver(glvWithdrawal.callbackContract()).afterGlvWithdrawalCancellation{ gas: glvWithdrawal.callbackGasLimit() }(
key,
glvWithdrawal,
eventData
) {
} catch {
emit AfterGlvWithdrawalCancellationError(key, glvWithdrawal);
}
}
function isValidCallbackContract(address callbackContract) internal view returns (bool) {
if (callbackContract == address(0)) { return false; }
if (!callbackContract.isContract()) { return false; }
return true;
}
}
文件 13 的 108:Cast.sol
pragma solidity ^0.8.0;
import "../error/Errors.sol";
library Cast {
function toBytes32(address value) internal pure returns (bytes32) {
return bytes32(uint256(uint160(value)));
}
function bytesToUint256(bytes memory uint256AsBytes) internal pure returns (uint256) {
uint256 length = uint256AsBytes.length;
if(length > 32) {
revert Errors.Uint256AsBytesLengthExceeds32Bytes(length);
}
if (length == 0) {
return 0;
}
uint256 value;
assembly {
value := mload(add(uint256AsBytes, 32))
}
return value = value >> (8 * (32 - length));
}
}
文件 14 的 108:Chain.sol
pragma solidity ^0.8.0;
import "./ArbSys.sol";
library Chain {
uint256 public constant ARBITRUM_CHAIN_ID = 42161;
uint256 public constant ARBITRUM_SEPOLIA_CHAIN_ID = 421614;
ArbSys public constant arbSys = ArbSys(address(100));
function currentTimestamp() internal view returns (uint256) {
return block.timestamp;
}
function currentBlockNumber() internal view returns (uint256) {
if (shouldUseArbSysValues()) {
return arbSys.arbBlockNumber();
}
return block.number;
}
function getBlockHash(uint256 blockNumber) internal view returns (bytes32) {
if (shouldUseArbSysValues()) {
return arbSys.arbBlockHash(blockNumber);
}
return blockhash(blockNumber);
}
function shouldUseArbSysValues() internal view returns (bool) {
return block.chainid == ARBITRUM_CHAIN_ID || block.chainid == ARBITRUM_SEPOLIA_CHAIN_ID;
}
}
文件 15 的 108:ChainlinkPriceFeedUtils.sol
pragma solidity ^0.8.0;
import "../chain/Chain.sol";
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../utils/Precision.sol";
import "./IPriceFeed.sol";
library ChainlinkPriceFeedUtils {
function getPriceFeedPrice(DataStore dataStore, address token) internal view returns (bool, uint256) {
address priceFeedAddress = dataStore.getAddress(Keys.priceFeedKey(token));
if (priceFeedAddress == address(0)) {
return (false, 0);
}
IPriceFeed priceFeed = IPriceFeed(priceFeedAddress);
(
,
int256 _price,
,
uint256 timestamp,
) = priceFeed.latestRoundData();
if (_price <= 0) {
revert Errors.InvalidFeedPrice(token, _price);
}
uint256 heartbeatDuration = dataStore.getUint(Keys.priceFeedHeartbeatDurationKey(token));
if (Chain.currentTimestamp() > timestamp && Chain.currentTimestamp() - timestamp > heartbeatDuration) {
revert Errors.ChainlinkPriceFeedNotUpdated(token, timestamp, heartbeatDuration);
}
uint256 price = SafeCast.toUint256(_price);
uint256 precision = getPriceFeedMultiplier(dataStore, token);
uint256 adjustedPrice = Precision.mulDiv(price, precision, Precision.FLOAT_PRECISION);
return (true, adjustedPrice);
}
function getPriceFeedMultiplier(DataStore dataStore, address token) internal view returns (uint256) {
uint256 multiplier = dataStore.getUint(Keys.priceFeedMultiplierKey(token));
if (multiplier == 0) {
revert Errors.EmptyChainlinkPriceFeedMultiplier(token);
}
return multiplier;
}
}
文件 16 的 108: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;
}
}
文件 17 的 108:DataStore.sol
pragma solidity ^0.8.0;
import "../role/RoleModule.sol";
import "../utils/Calc.sol";
contract DataStore is RoleModule {
using SafeCast for int256;
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableValues for EnumerableSet.Bytes32Set;
using EnumerableValues for EnumerableSet.AddressSet;
using EnumerableValues for EnumerableSet.UintSet;
mapping(bytes32 => uint256) public uintValues;
mapping(bytes32 => int256) public intValues;
mapping(bytes32 => address) public addressValues;
mapping(bytes32 => bool) public boolValues;
mapping(bytes32 => string) public stringValues;
mapping(bytes32 => bytes32) public bytes32Values;
mapping(bytes32 => uint256[]) public uintArrayValues;
mapping(bytes32 => int256[]) public intArrayValues;
mapping(bytes32 => address[]) public addressArrayValues;
mapping(bytes32 => bool[]) public boolArrayValues;
mapping(bytes32 => string[]) public stringArrayValues;
mapping(bytes32 => bytes32[]) public bytes32ArrayValues;
mapping(bytes32 => EnumerableSet.Bytes32Set) internal bytes32Sets;
mapping(bytes32 => EnumerableSet.AddressSet) internal addressSets;
mapping(bytes32 => EnumerableSet.UintSet) internal uintSets;
constructor(RoleStore _roleStore) RoleModule(_roleStore) {}
function getUint(bytes32 key) external view returns (uint256) {
return uintValues[key];
}
function setUint(bytes32 key, uint256 value) external onlyController returns (uint256) {
uintValues[key] = value;
return value;
}
function removeUint(bytes32 key) external onlyController {
delete uintValues[key];
}
function applyDeltaToUint(bytes32 key, int256 value, string memory errorMessage) external onlyController returns (uint256) {
uint256 currValue = uintValues[key];
if (value < 0 && (-value).toUint256() > currValue) {
revert(errorMessage);
}
uint256 nextUint = Calc.sumReturnUint256(currValue, value);
uintValues[key] = nextUint;
return nextUint;
}
function applyDeltaToUint(bytes32 key, uint256 value) external onlyController returns (uint256) {
uint256 currValue = uintValues[key];
uint256 nextUint = currValue + value;
uintValues[key] = nextUint;
return nextUint;
}
function applyBoundedDeltaToUint(bytes32 key, int256 value) external onlyController returns (uint256) {
uint256 uintValue = uintValues[key];
if (value < 0 && (-value).toUint256() > uintValue) {
uintValues[key] = 0;
return 0;
}
uint256 nextUint = Calc.sumReturnUint256(uintValue, value);
uintValues[key] = nextUint;
return nextUint;
}
function incrementUint(bytes32 key, uint256 value) external onlyController returns (uint256) {
uint256 nextUint = uintValues[key] + value;
uintValues[key] = nextUint;
return nextUint;
}
function decrementUint(bytes32 key, uint256 value) external onlyController returns (uint256) {
uint256 nextUint = uintValues[key] - value;
uintValues[key] = nextUint;
return nextUint;
}
function getInt(bytes32 key) external view returns (int256) {
return intValues[key];
}
function setInt(bytes32 key, int256 value) external onlyController returns (int256) {
intValues[key] = value;
return value;
}
function removeInt(bytes32 key) external onlyController {
delete intValues[key];
}
function applyDeltaToInt(bytes32 key, int256 value) external onlyController returns (int256) {
int256 nextInt = intValues[key] + value;
intValues[key] = nextInt;
return nextInt;
}
function incrementInt(bytes32 key, int256 value) external onlyController returns (int256) {
int256 nextInt = intValues[key] + value;
intValues[key] = nextInt;
return nextInt;
}
function decrementInt(bytes32 key, int256 value) external onlyController returns (int256) {
int256 nextInt = intValues[key] - value;
intValues[key] = nextInt;
return nextInt;
}
function getAddress(bytes32 key) external view returns (address) {
return addressValues[key];
}
function setAddress(bytes32 key, address value) external onlyController returns (address) {
addressValues[key] = value;
return value;
}
function removeAddress(bytes32 key) external onlyController {
delete addressValues[key];
}
function getBool(bytes32 key) external view returns (bool) {
return boolValues[key];
}
function setBool(bytes32 key, bool value) external onlyController returns (bool) {
boolValues[key] = value;
return value;
}
function removeBool(bytes32 key) external onlyController {
delete boolValues[key];
}
function getString(bytes32 key) external view returns (string memory) {
return stringValues[key];
}
function setString(bytes32 key, string memory value) external onlyController returns (string memory) {
stringValues[key] = value;
return value;
}
function removeString(bytes32 key) external onlyController {
delete stringValues[key];
}
function getBytes32(bytes32 key) external view returns (bytes32) {
return bytes32Values[key];
}
function setBytes32(bytes32 key, bytes32 value) external onlyController returns (bytes32) {
bytes32Values[key] = value;
return value;
}
function removeBytes32(bytes32 key) external onlyController {
delete bytes32Values[key];
}
function getUintArray(bytes32 key) external view returns (uint256[] memory) {
return uintArrayValues[key];
}
function setUintArray(bytes32 key, uint256[] memory value) external onlyController {
uintArrayValues[key] = value;
}
function removeUintArray(bytes32 key) external onlyController {
delete uintArrayValues[key];
}
function getIntArray(bytes32 key) external view returns (int256[] memory) {
return intArrayValues[key];
}
function setIntArray(bytes32 key, int256[] memory value) external onlyController {
intArrayValues[key] = value;
}
function removeIntArray(bytes32 key) external onlyController {
delete intArrayValues[key];
}
function getAddressArray(bytes32 key) external view returns (address[] memory) {
return addressArrayValues[key];
}
function setAddressArray(bytes32 key, address[] memory value) external onlyController {
addressArrayValues[key] = value;
}
function removeAddressArray(bytes32 key) external onlyController {
delete addressArrayValues[key];
}
function getBoolArray(bytes32 key) external view returns (bool[] memory) {
return boolArrayValues[key];
}
function setBoolArray(bytes32 key, bool[] memory value) external onlyController {
boolArrayValues[key] = value;
}
function removeBoolArray(bytes32 key) external onlyController {
delete boolArrayValues[key];
}
function getStringArray(bytes32 key) external view returns (string[] memory) {
return stringArrayValues[key];
}
function setStringArray(bytes32 key, string[] memory value) external onlyController {
stringArrayValues[key] = value;
}
function removeStringArray(bytes32 key) external onlyController {
delete stringArrayValues[key];
}
function getBytes32Array(bytes32 key) external view returns (bytes32[] memory) {
return bytes32ArrayValues[key];
}
function setBytes32Array(bytes32 key, bytes32[] memory value) external onlyController {
bytes32ArrayValues[key] = value;
}
function removeBytes32Array(bytes32 key) external onlyController {
delete bytes32ArrayValues[key];
}
function containsBytes32(bytes32 setKey, bytes32 value) external view returns (bool) {
return bytes32Sets[setKey].contains(value);
}
function getBytes32Count(bytes32 setKey) external view returns (uint256) {
return bytes32Sets[setKey].length();
}
function getBytes32ValuesAt(bytes32 setKey, uint256 start, uint256 end) external view returns (bytes32[] memory) {
return bytes32Sets[setKey].valuesAt(start, end);
}
function addBytes32(bytes32 setKey, bytes32 value) external onlyController {
bytes32Sets[setKey].add(value);
}
function removeBytes32(bytes32 setKey, bytes32 value) external onlyController {
bytes32Sets[setKey].remove(value);
}
function containsAddress(bytes32 setKey, address value) external view returns (bool) {
return addressSets[setKey].contains(value);
}
function getAddressCount(bytes32 setKey) external view returns (uint256) {
return addressSets[setKey].length();
}
function getAddressValuesAt(bytes32 setKey, uint256 start, uint256 end) external view returns (address[] memory) {
return addressSets[setKey].valuesAt(start, end);
}
function addAddress(bytes32 setKey, address value) external onlyController {
addressSets[setKey].add(value);
}
function removeAddress(bytes32 setKey, address value) external onlyController {
addressSets[setKey].remove(value);
}
function containsUint(bytes32 setKey, uint256 value) external view returns (bool) {
return uintSets[setKey].contains(value);
}
function getUintCount(bytes32 setKey) external view returns (uint256) {
return uintSets[setKey].length();
}
function getUintValuesAt(bytes32 setKey, uint256 start, uint256 end) external view returns (uint256[] memory) {
return uintSets[setKey].valuesAt(start, end);
}
function addUint(bytes32 setKey, uint256 value) external onlyController {
uintSets[setKey].add(value);
}
function removeUint(bytes32 setKey, uint256 value) external onlyController {
uintSets[setKey].remove(value);
}
}
文件 18 的 108:Deposit.sol
pragma solidity ^0.8.0;
library Deposit {
enum DepositType {
Normal,
Shift,
Glv
}
struct Props {
Addresses addresses;
Numbers numbers;
Flags flags;
}
struct Addresses {
address account;
address receiver;
address callbackContract;
address uiFeeReceiver;
address market;
address initialLongToken;
address initialShortToken;
address[] longTokenSwapPath;
address[] shortTokenSwapPath;
}
struct Numbers {
uint256 initialLongTokenAmount;
uint256 initialShortTokenAmount;
uint256 minMarketTokens;
uint256 updatedAtTime;
uint256 executionFee;
uint256 callbackGasLimit;
}
struct Flags {
bool shouldUnwrapNativeToken;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function receiver(Props memory props) internal pure returns (address) {
return props.addresses.receiver;
}
function setReceiver(Props memory props, address value) internal pure {
props.addresses.receiver = value;
}
function callbackContract(Props memory props) internal pure returns (address) {
return props.addresses.callbackContract;
}
function setCallbackContract(Props memory props, address value) internal pure {
props.addresses.callbackContract = value;
}
function uiFeeReceiver(Props memory props) internal pure returns (address) {
return props.addresses.uiFeeReceiver;
}
function setUiFeeReceiver(Props memory props, address value) internal pure {
props.addresses.uiFeeReceiver = value;
}
function market(Props memory props) internal pure returns (address) {
return props.addresses.market;
}
function setMarket(Props memory props, address value) internal pure {
props.addresses.market = value;
}
function initialLongToken(Props memory props) internal pure returns (address) {
return props.addresses.initialLongToken;
}
function setInitialLongToken(Props memory props, address value) internal pure {
props.addresses.initialLongToken = value;
}
function initialShortToken(Props memory props) internal pure returns (address) {
return props.addresses.initialShortToken;
}
function setInitialShortToken(Props memory props, address value) internal pure {
props.addresses.initialShortToken = value;
}
function longTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.longTokenSwapPath;
}
function setLongTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.longTokenSwapPath = value;
}
function shortTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.shortTokenSwapPath;
}
function setShortTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.shortTokenSwapPath = value;
}
function initialLongTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.initialLongTokenAmount;
}
function setInitialLongTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.initialLongTokenAmount = value;
}
function initialShortTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.initialShortTokenAmount;
}
function setInitialShortTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.initialShortTokenAmount = value;
}
function minMarketTokens(Props memory props) internal pure returns (uint256) {
return props.numbers.minMarketTokens;
}
function setMinMarketTokens(Props memory props, uint256 value) internal pure {
props.numbers.minMarketTokens = value;
}
function updatedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.updatedAtTime;
}
function setUpdatedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.updatedAtTime = value;
}
function executionFee(Props memory props) internal pure returns (uint256) {
return props.numbers.executionFee;
}
function setExecutionFee(Props memory props, uint256 value) internal pure {
props.numbers.executionFee = value;
}
function callbackGasLimit(Props memory props) internal pure returns (uint256) {
return props.numbers.callbackGasLimit;
}
function setCallbackGasLimit(Props memory props, uint256 value) internal pure {
props.numbers.callbackGasLimit = value;
}
function shouldUnwrapNativeToken(Props memory props) internal pure returns (bool) {
return props.flags.shouldUnwrapNativeToken;
}
function setShouldUnwrapNativeToken(Props memory props, bool value) internal pure {
props.flags.shouldUnwrapNativeToken = value;
}
}
文件 19 的 108:DepositEventUtils.sol
pragma solidity ^0.8.0;
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Cast.sol";
import "./Deposit.sol";
import "../pricing/ISwapPricingUtils.sol";
library DepositEventUtils {
using Deposit for Deposit.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
function emitDepositCreated(
EventEmitter eventEmitter,
bytes32 key,
Deposit.Props memory deposit,
Deposit.DepositType depositType
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(6);
eventData.addressItems.setItem(0, "account", deposit.account());
eventData.addressItems.setItem(1, "receiver", deposit.receiver());
eventData.addressItems.setItem(2, "callbackContract", deposit.callbackContract());
eventData.addressItems.setItem(3, "market", deposit.market());
eventData.addressItems.setItem(4, "initialLongToken", deposit.initialLongToken());
eventData.addressItems.setItem(5, "initialShortToken", deposit.initialShortToken());
eventData.addressItems.initArrayItems(2);
eventData.addressItems.setItem(0, "longTokenSwapPath", deposit.longTokenSwapPath());
eventData.addressItems.setItem(1, "shortTokenSwapPath", deposit.shortTokenSwapPath());
eventData.uintItems.initItems(7);
eventData.uintItems.setItem(0, "initialLongTokenAmount", deposit.initialLongTokenAmount());
eventData.uintItems.setItem(1, "initialShortTokenAmount", deposit.initialShortTokenAmount());
eventData.uintItems.setItem(2, "minMarketTokens", deposit.minMarketTokens());
eventData.uintItems.setItem(3, "updatedAtTime", deposit.updatedAtTime());
eventData.uintItems.setItem(4, "executionFee", deposit.executionFee());
eventData.uintItems.setItem(5, "callbackGasLimit", deposit.callbackGasLimit());
eventData.uintItems.setItem(6, "depositType", uint256(depositType));
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "shouldUnwrapNativeToken", deposit.shouldUnwrapNativeToken());
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventEmitter.emitEventLog2(
"DepositCreated",
key,
Cast.toBytes32(deposit.account()),
eventData
);
}
function emitDepositExecuted(
EventEmitter eventEmitter,
bytes32 key,
address account,
uint256 longTokenAmount,
uint256 shortTokenAmount,
uint256 receivedMarketTokens,
ISwapPricingUtils.SwapPricingType swapPricingType
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.uintItems.initItems(4);
eventData.uintItems.setItem(0, "longTokenAmount", longTokenAmount);
eventData.uintItems.setItem(1, "shortTokenAmount", shortTokenAmount);
eventData.uintItems.setItem(2, "receivedMarketTokens", receivedMarketTokens);
eventData.uintItems.setItem(3, "swapPricingType", uint256(swapPricingType));
eventEmitter.emitEventLog2(
"DepositExecuted",
key,
Cast.toBytes32(account),
eventData
);
}
function emitDepositCancelled(
EventEmitter eventEmitter,
bytes32 key,
address account,
string memory reason,
bytes memory reasonBytes
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.stringItems.initItems(1);
eventData.stringItems.setItem(0, "reason", reason);
eventData.bytesItems.initItems(1);
eventData.bytesItems.setItem(0, "reasonBytes", reasonBytes);
eventEmitter.emitEventLog2(
"DepositCancelled",
key,
Cast.toBytes32(account),
eventData
);
}
}
文件 20 的 108:DepositStoreUtils.sol
pragma solidity ^0.8.0;
import "../data/Keys.sol";
import "../data/DataStore.sol";
import "./Deposit.sol";
library DepositStoreUtils {
using Deposit for Deposit.Props;
bytes32 public constant ACCOUNT = keccak256(abi.encode("ACCOUNT"));
bytes32 public constant RECEIVER = keccak256(abi.encode("RECEIVER"));
bytes32 public constant CALLBACK_CONTRACT = keccak256(abi.encode("CALLBACK_CONTRACT"));
bytes32 public constant UI_FEE_RECEIVER = keccak256(abi.encode("UI_FEE_RECEIVER"));
bytes32 public constant MARKET = keccak256(abi.encode("MARKET"));
bytes32 public constant INITIAL_LONG_TOKEN = keccak256(abi.encode("INITIAL_LONG_TOKEN"));
bytes32 public constant INITIAL_SHORT_TOKEN = keccak256(abi.encode("INITIAL_SHORT_TOKEN"));
bytes32 public constant LONG_TOKEN_SWAP_PATH = keccak256(abi.encode("LONG_TOKEN_SWAP_PATH"));
bytes32 public constant SHORT_TOKEN_SWAP_PATH = keccak256(abi.encode("SHORT_TOKEN_SWAP_PATH"));
bytes32 public constant INITIAL_LONG_TOKEN_AMOUNT = keccak256(abi.encode("INITIAL_LONG_TOKEN_AMOUNT"));
bytes32 public constant INITIAL_SHORT_TOKEN_AMOUNT = keccak256(abi.encode("INITIAL_SHORT_TOKEN_AMOUNT"));
bytes32 public constant MIN_MARKET_TOKENS = keccak256(abi.encode("MIN_MARKET_TOKENS"));
bytes32 public constant UPDATED_AT_TIME = keccak256(abi.encode("UPDATED_AT_TIME"));
bytes32 public constant EXECUTION_FEE = keccak256(abi.encode("EXECUTION_FEE"));
bytes32 public constant CALLBACK_GAS_LIMIT = keccak256(abi.encode("CALLBACK_GAS_LIMIT"));
bytes32 public constant SHOULD_UNWRAP_NATIVE_TOKEN = keccak256(abi.encode("SHOULD_UNWRAP_NATIVE_TOKEN"));
function get(DataStore dataStore, bytes32 key) external view returns (Deposit.Props memory) {
Deposit.Props memory deposit;
if (!dataStore.containsBytes32(Keys.DEPOSIT_LIST, key)) {
return deposit;
}
deposit.setAccount(dataStore.getAddress(
keccak256(abi.encode(key, ACCOUNT))
));
deposit.setReceiver(dataStore.getAddress(
keccak256(abi.encode(key, RECEIVER))
));
deposit.setCallbackContract(dataStore.getAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
));
deposit.setUiFeeReceiver(dataStore.getAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
));
deposit.setMarket(dataStore.getAddress(
keccak256(abi.encode(key, MARKET))
));
deposit.setInitialLongToken(dataStore.getAddress(
keccak256(abi.encode(key, INITIAL_LONG_TOKEN))
));
deposit.setInitialShortToken(dataStore.getAddress(
keccak256(abi.encode(key, INITIAL_SHORT_TOKEN))
));
deposit.setLongTokenSwapPath(dataStore.getAddressArray(
keccak256(abi.encode(key, LONG_TOKEN_SWAP_PATH))
));
deposit.setShortTokenSwapPath(dataStore.getAddressArray(
keccak256(abi.encode(key, SHORT_TOKEN_SWAP_PATH))
));
deposit.setInitialLongTokenAmount(dataStore.getUint(
keccak256(abi.encode(key, INITIAL_LONG_TOKEN_AMOUNT))
));
deposit.setInitialShortTokenAmount(dataStore.getUint(
keccak256(abi.encode(key, INITIAL_SHORT_TOKEN_AMOUNT))
));
deposit.setMinMarketTokens(dataStore.getUint(
keccak256(abi.encode(key, MIN_MARKET_TOKENS))
));
deposit.setUpdatedAtTime(dataStore.getUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
));
deposit.setExecutionFee(dataStore.getUint(
keccak256(abi.encode(key, EXECUTION_FEE))
));
deposit.setCallbackGasLimit(dataStore.getUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
));
deposit.setShouldUnwrapNativeToken(dataStore.getBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN))
));
return deposit;
}
function set(DataStore dataStore, bytes32 key, Deposit.Props memory deposit) external {
dataStore.addBytes32(
Keys.DEPOSIT_LIST,
key
);
dataStore.addBytes32(
Keys.accountDepositListKey(deposit.account()),
key
);
dataStore.setAddress(
keccak256(abi.encode(key, ACCOUNT)),
deposit.account()
);
dataStore.setAddress(
keccak256(abi.encode(key, RECEIVER)),
deposit.receiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT)),
deposit.callbackContract()
);
dataStore.setAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER)),
deposit.uiFeeReceiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, MARKET)),
deposit.market()
);
dataStore.setAddress(
keccak256(abi.encode(key, INITIAL_LONG_TOKEN)),
deposit.initialLongToken()
);
dataStore.setAddress(
keccak256(abi.encode(key, INITIAL_SHORT_TOKEN)),
deposit.initialShortToken()
);
dataStore.setAddressArray(
keccak256(abi.encode(key, LONG_TOKEN_SWAP_PATH)),
deposit.longTokenSwapPath()
);
dataStore.setAddressArray(
keccak256(abi.encode(key, SHORT_TOKEN_SWAP_PATH)),
deposit.shortTokenSwapPath()
);
dataStore.setUint(
keccak256(abi.encode(key, INITIAL_LONG_TOKEN_AMOUNT)),
deposit.initialLongTokenAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, INITIAL_SHORT_TOKEN_AMOUNT)),
deposit.initialShortTokenAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, MIN_MARKET_TOKENS)),
deposit.minMarketTokens()
);
dataStore.setUint(
keccak256(abi.encode(key, UPDATED_AT_TIME)),
deposit.updatedAtTime()
);
dataStore.setUint(
keccak256(abi.encode(key, EXECUTION_FEE)),
deposit.executionFee()
);
dataStore.setUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT)),
deposit.callbackGasLimit()
);
dataStore.setBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN)),
deposit.shouldUnwrapNativeToken()
);
}
function remove(DataStore dataStore, bytes32 key, address account) external {
if (!dataStore.containsBytes32(Keys.DEPOSIT_LIST, key)) {
revert Errors.DepositNotFound(key);
}
dataStore.removeBytes32(
Keys.DEPOSIT_LIST,
key
);
dataStore.removeBytes32(
Keys.accountDepositListKey(account),
key
);
dataStore.removeAddress(
keccak256(abi.encode(key, ACCOUNT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, MARKET))
);
dataStore.removeAddress(
keccak256(abi.encode(key, INITIAL_LONG_TOKEN))
);
dataStore.removeAddress(
keccak256(abi.encode(key, INITIAL_SHORT_TOKEN))
);
dataStore.removeAddressArray(
keccak256(abi.encode(key, LONG_TOKEN_SWAP_PATH))
);
dataStore.removeAddressArray(
keccak256(abi.encode(key, SHORT_TOKEN_SWAP_PATH))
);
dataStore.removeUint(
keccak256(abi.encode(key, INITIAL_LONG_TOKEN_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, INITIAL_SHORT_TOKEN_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, MIN_MARKET_TOKENS))
);
dataStore.removeUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
);
dataStore.removeUint(
keccak256(abi.encode(key, EXECUTION_FEE))
);
dataStore.removeUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
);
dataStore.removeBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN))
);
}
function getDepositCount(DataStore dataStore) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.DEPOSIT_LIST);
}
function getDepositKeys(DataStore dataStore, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.DEPOSIT_LIST, start, end);
}
function getAccountDepositCount(DataStore dataStore, address account) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.accountDepositListKey(account));
}
function getAccountDepositKeys(DataStore dataStore, address account, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.accountDepositListKey(account), start, end);
}
}
文件 21 的 108:DepositUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "./DepositVault.sol";
import "./DepositStoreUtils.sol";
import "./DepositEventUtils.sol";
import "../nonce/NonceUtils.sol";
import "../gas/GasUtils.sol";
import "../callback/CallbackUtils.sol";
import "../utils/AccountUtils.sol";
library DepositUtils {
using SafeCast for uint256;
using SafeCast for int256;
using Price for Price.Props;
using Deposit for Deposit.Props;
struct CreateDepositParams {
address receiver;
address callbackContract;
address uiFeeReceiver;
address market;
address initialLongToken;
address initialShortToken;
address[] longTokenSwapPath;
address[] shortTokenSwapPath;
uint256 minMarketTokens;
bool shouldUnwrapNativeToken;
uint256 executionFee;
uint256 callbackGasLimit;
}
function createDeposit(
DataStore dataStore,
EventEmitter eventEmitter,
DepositVault depositVault,
address account,
CreateDepositParams memory params
) external returns (bytes32) {
AccountUtils.validateAccount(account);
Market.Props memory market = MarketUtils.getEnabledMarket(dataStore, params.market);
MarketUtils.validateSwapPath(dataStore, params.longTokenSwapPath);
MarketUtils.validateSwapPath(dataStore, params.shortTokenSwapPath);
uint256 initialLongTokenAmount = depositVault.recordTransferIn(params.initialLongToken);
uint256 initialShortTokenAmount = depositVault.recordTransferIn(params.initialShortToken);
address wnt = TokenUtils.wnt(dataStore);
if (params.initialLongToken == wnt) {
initialLongTokenAmount -= params.executionFee;
} else if (params.initialShortToken == wnt) {
initialShortTokenAmount -= params.executionFee;
} else {
uint256 wntAmount = depositVault.recordTransferIn(wnt);
if (wntAmount < params.executionFee) {
revert Errors.InsufficientWntAmountForExecutionFee(wntAmount, params.executionFee);
}
params.executionFee = wntAmount;
}
if (initialLongTokenAmount == 0 && initialShortTokenAmount == 0) {
revert Errors.EmptyDepositAmounts();
}
AccountUtils.validateReceiver(params.receiver);
Deposit.Props memory deposit = Deposit.Props(
Deposit.Addresses(
account,
params.receiver,
params.callbackContract,
params.uiFeeReceiver,
market.marketToken,
params.initialLongToken,
params.initialShortToken,
params.longTokenSwapPath,
params.shortTokenSwapPath
),
Deposit.Numbers(
initialLongTokenAmount,
initialShortTokenAmount,
params.minMarketTokens,
Chain.currentTimestamp(),
params.executionFee,
params.callbackGasLimit
),
Deposit.Flags(
params.shouldUnwrapNativeToken
)
);
CallbackUtils.validateCallbackGasLimit(dataStore, deposit.callbackGasLimit());
uint256 estimatedGasLimit = GasUtils.estimateExecuteDepositGasLimit(dataStore, deposit);
uint256 oraclePriceCount = GasUtils.estimateDepositOraclePriceCount(
deposit.longTokenSwapPath().length + deposit.shortTokenSwapPath().length
);
GasUtils.validateExecutionFee(dataStore, estimatedGasLimit, params.executionFee, oraclePriceCount);
bytes32 key = NonceUtils.getNextKey(dataStore);
DepositStoreUtils.set(dataStore, key, deposit);
DepositEventUtils.emitDepositCreated(eventEmitter, key, deposit, Deposit.DepositType.Normal);
return key;
}
function cancelDeposit(
DataStore dataStore,
EventEmitter eventEmitter,
DepositVault depositVault,
bytes32 key,
address keeper,
uint256 startingGas,
string memory reason,
bytes memory reasonBytes
) external {
startingGas -= gasleft() / 63;
Deposit.Props memory deposit = DepositStoreUtils.get(dataStore, key);
if (deposit.account() == address(0)) {
revert Errors.EmptyDeposit();
}
if (
deposit.initialLongTokenAmount() == 0 &&
deposit.initialShortTokenAmount() == 0
) {
revert Errors.EmptyDepositAmounts();
}
DepositStoreUtils.remove(dataStore, key, deposit.account());
if (deposit.initialLongTokenAmount() > 0) {
depositVault.transferOut(
deposit.initialLongToken(),
deposit.account(),
deposit.initialLongTokenAmount(),
deposit.shouldUnwrapNativeToken()
);
}
if (deposit.initialShortTokenAmount() > 0) {
depositVault.transferOut(
deposit.initialShortToken(),
deposit.account(),
deposit.initialShortTokenAmount(),
deposit.shouldUnwrapNativeToken()
);
}
DepositEventUtils.emitDepositCancelled(
eventEmitter,
key,
deposit.account(),
reason,
reasonBytes
);
EventUtils.EventLogData memory eventData;
CallbackUtils.afterDepositCancellation(key, deposit, eventData);
GasUtils.payExecutionFee(
dataStore,
eventEmitter,
depositVault,
key,
deposit.callbackContract(),
deposit.executionFee(),
startingGas,
GasUtils.estimateDepositOraclePriceCount(deposit.longTokenSwapPath().length + deposit.shortTokenSwapPath().length),
keeper,
deposit.receiver()
);
}
}
文件 22 的 108:DepositVault.sol
pragma solidity ^0.8.0;
import "../bank/StrictBank.sol";
contract DepositVault is StrictBank {
constructor(RoleStore _roleStore, DataStore _dataStore) StrictBank(_roleStore, _dataStore) {}
}
文件 23 的 108:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
文件 24 的 108:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[toDeleteIndex] = lastValue;
set._indexes[lastValue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 25 的 108:EnumerableValues.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
library EnumerableValues {
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.UintSet;
function valuesAt(EnumerableSet.Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
uint256 max = set.length();
if (end > max) { end = max; }
bytes32[] memory items = new bytes32[](end - start);
for (uint256 i = start; i < end; i++) {
items[i - start] = set.at(i);
}
return items;
}
function valuesAt(EnumerableSet.AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {
uint256 max = set.length();
if (end > max) { end = max; }
address[] memory items = new address[](end - start);
for (uint256 i = start; i < end; i++) {
items[i - start] = set.at(i);
}
return items;
}
function valuesAt(EnumerableSet.UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {
if (start >= set.length()) {
return new uint256[](0);
}
uint256 max = set.length();
if (end > max) { end = max; }
uint256[] memory items = new uint256[](end - start);
for (uint256 i = start; i < end; i++) {
items[i - start] = set.at(i);
}
return items;
}
}
文件 26 的 108:ErrorUtils.sol
pragma solidity ^0.8.0;
library ErrorUtils {
function getRevertMessage(bytes memory result) internal pure returns (string memory, bool) {
if (result.length < 68) {
return ("", false);
}
bytes4 errorSelector = getErrorSelectorFromData(result);
if (errorSelector == bytes4(0x08c379a0)) {
assembly {
result := add(result, 0x04)
}
return (abi.decode(result, (string)), true);
}
return ("", false);
}
function getErrorSelectorFromData(bytes memory data) internal pure returns (bytes4) {
bytes4 errorSelector;
assembly {
errorSelector := mload(add(data, 0x20))
}
return errorSelector;
}
function revertWithParsedMessage(bytes memory result) internal pure {
(string memory revertMessage, bool hasRevertMessage) = getRevertMessage(result);
if (hasRevertMessage) {
revert(revertMessage);
} else {
revertWithCustomError(result);
}
}
function revertWithCustomError(bytes memory result) internal pure {
uint256 length = result.length;
assembly {
revert(add(result, 0x20), length)
}
}
}
文件 27 的 108:Errors.sol
pragma solidity ^0.8.0;
library Errors {
error AdlNotRequired(int256 pnlToPoolFactor, uint256 maxPnlFactorForAdl);
error InvalidAdl(int256 nextPnlToPoolFactor, int256 pnlToPoolFactor);
error PnlOvercorrected(int256 nextPnlToPoolFactor, uint256 minPnlFactorForAdl);
error InvalidSizeDeltaForAdl(uint256 sizeDeltaUsd, uint256 positionSizeInUsd);
error AdlNotEnabled();
error MaxAutoCancelOrdersExceeded(uint256 count, uint256 maxAutoCancelOrders);
error SelfTransferNotSupported(address receiver);
error InvalidNativeTokenSender(address msgSender);
error RequestNotYetCancellable(uint256 requestAge, uint256 requestExpirationAge, string requestType);
error MaxCallbackGasLimitExceeded(uint256 callbackGasLimit, uint256 maxCallbackGasLimit);
error InsufficientGasLeftForCallback(uint256 gasToBeForwarded, uint256 callbackGasLimit);
error InvalidBaseKey(bytes32 baseKey);
error ConfigValueExceedsAllowedRange(bytes32 baseKey, uint256 value);
error InvalidClaimableFactor(uint256 value);
error OracleProviderAlreadyExistsForToken(address token);
error PriceFeedAlreadyExistsForToken(address token);
error DataStreamIdAlreadyExistsForToken(address token);
error MaxFundingFactorPerSecondLimitExceeded(uint256 maxFundingFactorPerSecond, uint256 limit);
error InvalidSetContributorPaymentInput(uint256 tokensLength, uint256 amountsLength);
error InvalidContributorToken(address token);
error MaxTotalContributorTokenAmountExceeded(address token, uint256 totalAmount, uint256 maxTotalAmount);
error MinContributorPaymentIntervalNotYetPassed(uint256 minPaymentInterval);
error MinContributorPaymentIntervalBelowAllowedRange(uint256 interval);
error InvalidSetMaxTotalContributorTokenAmountInput(uint256 tokensLength, uint256 amountsLength);
error ActionAlreadySignalled();
error ActionNotSignalled();
error SignalTimeNotYetPassed(uint256 signalTime);
error InvalidTimelockDelay(uint256 timelockDelay);
error MaxTimelockDelayExceeded(uint256 timelockDelay);
error InvalidFeeReceiver(address receiver);
error InvalidOracleSigner(address receiver);
error GlvDepositNotFound(bytes32 key);
error GlvShiftNotFound(bytes32 key);
error GlvWithdrawalNotFound(bytes32 key);
error EmptyGlvDepositAmounts();
error EmptyGlvMarketAmount();
error EmptyGlvDeposit();
error InvalidMinGlvTokensForFirstGlvDeposit(uint256 minGlvTokens, uint256 expectedMinGlvTokens);
error InvalidReceiverForFirstGlvDeposit(address receiver, address expectedReceiver);
error EmptyGlvWithdrawal();
error EmptyGlvWithdrawalAmount();
error EmptyGlv(address glv);
error EmptyGlvTokenSupply();
error GlvNegativeMarketPoolValue(address glv, address market);
error GlvUnsupportedMarket(address glv, address market);
error GlvDisabledMarket(address glv, address market);
error GlvEnabledMarket(address glv, address market);
error GlvNonZeroMarketBalance(address glv, address market);
error GlvMaxMarketCountExceeded(address glv, uint256 glvMaxMarketCount);
error GlvMaxMarketTokenBalanceUsdExceeded(address glv, address market, uint256 maxMarketTokenBalanceUsd, uint256 marketTokenBalanceUsd);
error GlvMaxMarketTokenBalanceAmountExceeded(address glv, address market, uint256 maxMarketTokenBalanceAmount, uint256 marketTokenBalanceAmount);
error GlvInsufficientMarketTokenBalance(address glv, address market, uint256 marketTokenBalance, uint256 marketTokenAmount);
error GlvMarketAlreadyExists(address glv, address market);
error GlvInvalidLongToken(address glv, address provided, address expected);
error GlvInvalidShortToken(address glv, address provided, address expected);
error GlvShiftMaxPriceImpactExceeded(uint256 effectivePriceImpactFactor, uint256 glvMaxShiftPriceImpactFactor);
error GlvShiftIntervalNotYetPassed(uint256 currentTimestamp, uint256 lastGlvShiftExecutedAt, uint256 glvShiftMinInterval);
error GlvAlreadyExists(bytes32 salt, address glv);
error GlvSymbolTooLong();
error GlvNameTooLong();
error GlvNotFound(address key);
error DepositNotFound(bytes32 key);
error EmptyDeposit();
error EmptyDepositAmounts();
error MinMarketTokens(uint256 received, uint256 expected);
error EmptyDepositAmountsAfterSwap();
error InvalidPoolValueForDeposit(int256 poolValue);
error InvalidSwapOutputToken(address outputToken, address expectedOutputToken);
error InvalidReceiverForFirstDeposit(address receiver, address expectedReceiver);
error InvalidMinMarketTokensForFirstDeposit(uint256 minMarketTokens, uint256 expectedMinMarketTokens);
error ExternalCallFailed(bytes data);
error InvalidExternalCallInput(uint256 targetsLength, uint256 dataListLength);
error InvalidExternalReceiversInput(uint256 refundTokensLength, uint256 refundReceiversLength);
error InvalidExternalCallTarget(address target);
error FeeBatchNotFound(bytes32 key);
error InvalidFeeBatchTokenIndex(uint256 tokenIndex, uint256 feeBatchTokensLength);
error InvalidAmountInForFeeBatch(uint256 amountIn, uint256 remainingAmount);
error InvalidSwapPathForV1(address[] path, address bridgingToken);
error InvalidGlpAmount(uint256 totalGlpAmountToRedeem, uint256 totalGlpAmount);
error InvalidExecutionFeeForMigration(uint256 totalExecutionFee, uint256 msgValue);
error InvalidGlvDepositInitialLongToken(address initialLongToken);
error InvalidGlvDepositInitialShortToken(address initialShortToken);
error InvalidGlvDepositSwapPath(uint256 longTokenSwapPathLength, uint256 shortTokenSwapPathLength);
error MinGlvTokens(uint256 received, uint256 expected);
error OrderNotUpdatable(uint256 orderType);
error InvalidKeeperForFrozenOrder(address keeper);
error DisabledFeature(bytes32 key);
error InvalidBuybackToken(address buybackToken);
error InvalidVersion(uint256 version);
error InsufficientBuybackOutputAmount(address feeToken, address buybackToken, uint256 outputAmount, uint256 minOutputAmount);
error BuybackAndFeeTokenAreEqual(address feeToken, address buybackToken);
error AvailableFeeAmountIsZero(address feeToken, address buybackToken, uint256 availableFeeAmount);
error MaxBuybackPriceAgeExceeded(uint256 priceTimestamp, uint256 buybackMaxPriceAge, uint256 currentTimestamp);
error EmptyClaimFeesMarket();
error InsufficientExecutionFee(uint256 minExecutionFee, uint256 executionFee);
error InsufficientWntAmountForExecutionFee(uint256 wntAmount, uint256 executionFee);
error InsufficientExecutionGasForErrorHandling(uint256 startingGas, uint256 minHandleErrorGas);
error InsufficientExecutionGas(uint256 startingGas, uint256 estimatedGasLimit, uint256 minAdditionalGasForExecution);
error InsufficientHandleExecutionErrorGas(uint256 gas, uint256 minHandleExecutionErrorGas);
error InsufficientGasForCancellation(uint256 gas, uint256 minHandleExecutionErrorGas);
error MarketAlreadyExists(bytes32 salt, address existingMarketAddress);
error MarketNotFound(address key);
error EmptyMarket();
error DisabledMarket(address market);
error MaxSwapPathLengthExceeded(uint256 swapPathLengh, uint256 maxSwapPathLength);
error InsufficientPoolAmount(uint256 poolAmount, uint256 amount);
error InsufficientReserve(uint256 reservedUsd, uint256 maxReservedUsd);
error InsufficientReserveForOpenInterest(uint256 reservedUsd, uint256 maxReservedUsd);
error UnableToGetOppositeToken(address inputToken, address market);
error UnexpectedTokenForVirtualInventory(address token, address market);
error EmptyMarketTokenSupply();
error InvalidSwapMarket(address market);
error UnableToGetCachedTokenPrice(address token, address market);
error CollateralAlreadyClaimed(uint256 adjustedClaimableAmount, uint256 claimedAmount);
error OpenInterestCannotBeUpdatedForSwapOnlyMarket(address market);
error MaxOpenInterestExceeded(uint256 openInterest, uint256 maxOpenInterest);
error MaxPoolAmountExceeded(uint256 poolAmount, uint256 maxPoolAmount);
error MaxPoolUsdForDepositExceeded(uint256 poolUsd, uint256 maxPoolUsdForDeposit);
error UnexpectedBorrowingFactor(uint256 positionBorrowingFactor, uint256 cumulativeBorrowingFactor);
error UnableToGetBorrowingFactorEmptyPoolUsd();
error UnableToGetFundingFactorEmptyOpenInterest();
error InvalidPositionMarket(address market);
error InvalidCollateralTokenForMarket(address market, address token);
error PnlFactorExceededForLongs(int256 pnlToPoolFactor, uint256 maxPnlFactor);
error PnlFactorExceededForShorts(int256 pnlToPoolFactor, uint256 maxPnlFactor);
error InvalidUiFeeFactor(uint256 uiFeeFactor, uint256 maxUiFeeFactor);
error EmptyAddressInMarketTokenBalanceValidation(address market, address token);
error InvalidMarketTokenBalance(address market, address token, uint256 balance, uint256 expectedMinBalance);
error InvalidMarketTokenBalanceForCollateralAmount(address market, address token, uint256 balance, uint256 collateralAmount);
error InvalidMarketTokenBalanceForClaimableFunding(address market, address token, uint256 balance, uint256 claimableFundingFeeAmount);
error UnexpectedPoolValue(int256 poolValue);
error SequencerDown();
error SequencerGraceDurationNotYetPassed(uint256 timeSinceUp, uint256 sequencerGraceDuration);
error EmptyValidatedPrices();
error InvalidOracleProvider(address provider);
error InvalidOracleProviderForToken(address provider, address expectedProvider);
error GmEmptySigner(uint256 signerIndex);
error InvalidOracleSetPricesProvidersParam(uint256 tokensLength, uint256 providersLength);
error InvalidOracleSetPricesDataParam(uint256 tokensLength, uint256 dataLength);
error GmInvalidBlockNumber(uint256 minOracleBlockNumber, uint256 currentBlockNumber);
error GmInvalidMinMaxBlockNumber(uint256 minOracleBlockNumber, uint256 maxOracleBlockNumber);
error EmptyDataStreamFeedId(address token);
error InvalidDataStreamFeedId(address token, bytes32 feedId, bytes32 expectedFeedId);
error InvalidDataStreamBidAsk(address token, int192 bid, int192 ask);
error InvalidDataStreamPrices(address token, int192 bid, int192 ask);
error MaxPriceAgeExceeded(uint256 oracleTimestamp, uint256 currentTimestamp);
error MaxOracleTimestampRangeExceeded(uint256 range, uint256 maxRange);
error GmMinOracleSigners(uint256 oracleSigners, uint256 minOracleSigners);
error GmMaxOracleSigners(uint256 oracleSigners, uint256 maxOracleSigners);
error BlockNumbersNotSorted(uint256 minOracleBlockNumber, uint256 prevMinOracleBlockNumber);
error GmMinPricesNotSorted(address token, uint256 price, uint256 prevPrice);
error GmMaxPricesNotSorted(address token, uint256 price, uint256 prevPrice);
error EmptyChainlinkPriceFeedMultiplier(address token);
error EmptyDataStreamMultiplier(address token);
error InvalidFeedPrice(address token, int256 price);
error ChainlinkPriceFeedNotUpdated(address token, uint256 timestamp, uint256 heartbeatDuration);
error GmMaxSignerIndex(uint256 signerIndex, uint256 maxSignerIndex);
error InvalidGmOraclePrice(address token);
error InvalidGmSignerMinMaxPrice(uint256 minPrice, uint256 maxPrice);
error InvalidGmMedianMinMaxPrice(uint256 minPrice, uint256 maxPrice);
error NonEmptyTokensWithPrices(uint256 tokensWithPricesLength);
error InvalidMinMaxForPrice(address token, uint256 min, uint256 max);
error EmptyChainlinkPriceFeed(address token);
error PriceAlreadySet(address token, uint256 minPrice, uint256 maxPrice);
error MaxRefPriceDeviationExceeded(
address token,
uint256 price,
uint256 refPrice,
uint256 maxRefPriceDeviationFactor
);
error InvalidBlockRangeSet(uint256 largestMinBlockNumber, uint256 smallestMaxBlockNumber);
error EmptyChainlinkPaymentToken();
error NonAtomicOracleProvider(address provider);
error InvalidPrimaryPricesForSimulation(uint256 primaryTokensLength, uint256 primaryPricesLength);
error EndOfOracleSimulation();
error InvalidGmSignature(address recoveredSigner, address expectedSigner);
error EmptyPrimaryPrice(address token);
error OracleTimestampsAreSmallerThanRequired(uint256 minOracleTimestamp, uint256 expectedTimestamp);
error OracleTimestampsAreLargerThanRequestExpirationTime(uint256 maxOracleTimestamp, uint256 requestTimestamp, uint256 requestExpirationTime);
error EmptyOrder();
error UnsupportedOrderType(uint256 orderType);
error InvalidOrderPrices(
uint256 primaryPriceMin,
uint256 primaryPriceMax,
uint256 triggerPrice,
uint256 orderType
);
error EmptySizeDeltaInTokens();
error PriceImpactLargerThanOrderSize(int256 priceImpactUsd, uint256 sizeDeltaUsd);
error NegativeExecutionPrice(int256 executionPrice, uint256 price, uint256 positionSizeInUsd, int256 priceImpactUsd, uint256 sizeDeltaUsd);
error OrderNotFulfillableAtAcceptablePrice(uint256 price, uint256 acceptablePrice);
error OrderValidFromTimeNotReached(uint256 validFromTime, uint256 currentTimestamp);
error UnexpectedPositionState();
error OrderTypeCannotBeCreated(uint256 orderType);
error OrderAlreadyFrozen();
error MaxTotalCallbackGasLimitForAutoCancelOrdersExceeded(uint256 totalCallbackGasLimit, uint256 maxTotalCallbackGasLimit);
error InvalidReceiver(address receiver);
error UnexpectedValidFromTime(uint256 orderType);
error OrderNotFound(bytes32 key);
error UnexpectedMarket();
error InsufficientFundsToPayForCosts(uint256 remainingCostUsd, string step);
error InvalidOutputToken(address tokenOut, address expectedTokenOut);
error InvalidDecreaseOrderSize(uint256 sizeDeltaUsd, uint256 positionSizeInUsd);
error UnableToWithdrawCollateral(int256 estimatedRemainingCollateralUsd);
error InvalidDecreasePositionSwapType(uint256 decreasePositionSwapType);
error PositionShouldNotBeLiquidated(
string reason,
int256 remainingCollateralUsd,
int256 minCollateralUsd,
int256 minCollateralUsdForLeverage
);
error InsufficientCollateralAmount(uint256 collateralAmount, int256 collateralDeltaAmount);
error InsufficientCollateralUsd(int256 remainingCollateralUsd);
error PositionNotFound(bytes32 key);
error LiquidatablePosition(
string reason,
int256 remainingCollateralUsd,
int256 minCollateralUsd,
int256 minCollateralUsdForLeverage
);
error EmptyPosition();
error InvalidPositionSizeValues(uint256 sizeInUsd, uint256 sizeInTokens);
error MinPositionSize(uint256 positionSizeInUsd, uint256 minPositionSizeUsd);
error UsdDeltaExceedsLongOpenInterest(int256 usdDelta, uint256 longOpenInterest);
error UsdDeltaExceedsShortOpenInterest(int256 usdDelta, uint256 shortOpenInterest);
error ShiftNotFound(bytes32 key);
error EmptyShift();
error EmptyShiftAmount();
error ShiftFromAndToMarketAreEqual(address market);
error LongTokensAreNotEqual(address fromMarketLongToken, address toMarketLongToken);
error ShortTokensAreNotEqual(address fromMarketLongToken, address toMarketLongToken);
error UsdDeltaExceedsPoolValue(int256 usdDelta, uint256 poolUsd);
error Unauthorized(address msgSender, string role);
error ThereMustBeAtLeastOneRoleAdmin();
error ThereMustBeAtLeastOneTimelockMultiSig();
error InvalidClaimFundingFeesInput(uint256 marketsLength, uint256 tokensLength);
error InvalidClaimCollateralInput(uint256 marketsLength, uint256 tokensLength, uint256 timeKeysLength);
error InvalidClaimAffiliateRewardsInput(uint256 marketsLength, uint256 tokensLength);
error InvalidClaimUiFeesInput(uint256 marketsLength, uint256 tokensLength);
error InvalidTokenIn(address tokenIn, address market);
error InsufficientOutputAmount(uint256 outputAmount, uint256 minOutputAmount);
error InsufficientSwapOutputAmount(uint256 outputAmount, uint256 minOutputAmount);
error DuplicatedMarketInSwapPath(address market);
error SwapPriceImpactExceedsAmountIn(uint256 amountAfterFees, int256 negativeImpactAmount);
error InvalidReceiverForSubaccountOrder(address receiver, address expectedReceiver);
error SubaccountNotAuthorized(address account, address subaccount);
error MaxSubaccountActionCountExceeded(address account, address subaccount, uint256 count, uint256 maxCount);
error TokenTransferError(address token, address receiver, uint256 amount);
error EmptyHoldingAddress();
error EmptyTokenTranferGasLimit(address token);
error EmptyAccount();
error EmptyReceiver();
error CompactedArrayOutOfBounds(
uint256[] compactedValues,
uint256 index,
uint256 slotIndex,
string label
);
error ArrayOutOfBoundsUint256(
uint256[] values,
uint256 index,
string label
);
error ArrayOutOfBoundsBytes(
bytes[] values,
uint256 index,
string label
);
error SwapsNotAllowedForAtomicWithdrawal(uint256 longTokenSwapPathLength, uint256 shortTokenSwapPathLength);
error WithdrawalNotFound(bytes32 key);
error EmptyWithdrawal();
error EmptyWithdrawalAmount();
error MinLongTokens(uint256 received, uint256 expected);
error MinShortTokens(uint256 received, uint256 expected);
error InsufficientMarketTokens(uint256 balance, uint256 expected);
error InsufficientWntAmount(uint256 wntAmount, uint256 executionFee);
error InvalidPoolValueForWithdrawal(int256 poolValue);
error MaskIndexOutOfBounds(uint256 index, string label);
error DuplicatedIndex(uint256 index, string label);
error Uint256AsBytesLengthExceeds32Bytes(uint256 length);
error SyncConfigInvalidInputLengths(uint256 marketsLength, uint256 parametersLength);
error SyncConfigUpdatesDisabledForMarket(address market);
error SyncConfigUpdatesDisabledForParameter(string parameter);
error SyncConfigUpdatesDisabledForMarketParameter(address market, string parameter);
error SyncConfigInvalidMarketFromData(address market, address marketFromData);
error EmptyMarketPrice(address market);
}
文件 28 的 108:EventEmitter.sol
pragma solidity ^0.8.0;
import "../role/RoleModule.sol";
import "./EventUtils.sol";
contract EventEmitter is RoleModule {
event EventLog(
address msgSender,
string eventName,
string indexed eventNameHash,
EventUtils.EventLogData eventData
);
event EventLog1(
address msgSender,
string eventName,
string indexed eventNameHash,
bytes32 indexed topic1,
EventUtils.EventLogData eventData
);
event EventLog2(
address msgSender,
string eventName,
string indexed eventNameHash,
bytes32 indexed topic1,
bytes32 indexed topic2,
EventUtils.EventLogData eventData
);
constructor(RoleStore _roleStore) RoleModule(_roleStore) {}
function emitEventLog(
string memory eventName,
EventUtils.EventLogData memory eventData
) external onlyController {
emit EventLog(
msg.sender,
eventName,
eventName,
eventData
);
}
function emitEventLog1(
string memory eventName,
bytes32 topic1,
EventUtils.EventLogData memory eventData
) external onlyController {
emit EventLog1(
msg.sender,
eventName,
eventName,
topic1,
eventData
);
}
function emitEventLog2(
string memory eventName,
bytes32 topic1,
bytes32 topic2,
EventUtils.EventLogData memory eventData
) external onlyController {
emit EventLog2(
msg.sender,
eventName,
eventName,
topic1,
topic2,
eventData
);
}
function emitDataLog1(bytes32 topic1, bytes memory data) external onlyController {
uint256 len = data.length;
assembly {
log1(add(data, 32), len, topic1)
}
}
function emitDataLog2(bytes32 topic1, bytes32 topic2, bytes memory data) external onlyController {
uint256 len = data.length;
assembly {
log2(add(data, 32), len, topic1, topic2)
}
}
function emitDataLog3(bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes memory data) external onlyController {
uint256 len = data.length;
assembly {
log3(add(data, 32), len, topic1, topic2, topic3)
}
}
function emitDataLog4(bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes32 topic4, bytes memory data) external onlyController {
uint256 len = data.length;
assembly {
log4(add(data, 32), len, topic1, topic2, topic3, topic4)
}
}
}
文件 29 的 108:EventUtils.sol
pragma solidity ^0.8.0;
library EventUtils {
struct EmitPositionDecreaseParams {
bytes32 key;
address account;
address market;
address collateralToken;
bool isLong;
}
struct EventLogData {
AddressItems addressItems;
UintItems uintItems;
IntItems intItems;
BoolItems boolItems;
Bytes32Items bytes32Items;
BytesItems bytesItems;
StringItems stringItems;
}
struct AddressItems {
AddressKeyValue[] items;
AddressArrayKeyValue[] arrayItems;
}
struct UintItems {
UintKeyValue[] items;
UintArrayKeyValue[] arrayItems;
}
struct IntItems {
IntKeyValue[] items;
IntArrayKeyValue[] arrayItems;
}
struct BoolItems {
BoolKeyValue[] items;
BoolArrayKeyValue[] arrayItems;
}
struct Bytes32Items {
Bytes32KeyValue[] items;
Bytes32ArrayKeyValue[] arrayItems;
}
struct BytesItems {
BytesKeyValue[] items;
BytesArrayKeyValue[] arrayItems;
}
struct StringItems {
StringKeyValue[] items;
StringArrayKeyValue[] arrayItems;
}
struct AddressKeyValue {
string key;
address value;
}
struct AddressArrayKeyValue {
string key;
address[] value;
}
struct UintKeyValue {
string key;
uint256 value;
}
struct UintArrayKeyValue {
string key;
uint256[] value;
}
struct IntKeyValue {
string key;
int256 value;
}
struct IntArrayKeyValue {
string key;
int256[] value;
}
struct BoolKeyValue {
string key;
bool value;
}
struct BoolArrayKeyValue {
string key;
bool[] value;
}
struct Bytes32KeyValue {
string key;
bytes32 value;
}
struct Bytes32ArrayKeyValue {
string key;
bytes32[] value;
}
struct BytesKeyValue {
string key;
bytes value;
}
struct BytesArrayKeyValue {
string key;
bytes[] value;
}
struct StringKeyValue {
string key;
string value;
}
struct StringArrayKeyValue {
string key;
string[] value;
}
function initItems(AddressItems memory items, uint256 size) internal pure {
items.items = new EventUtils.AddressKeyValue[](size);
}
function initArrayItems(AddressItems memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.AddressArrayKeyValue[](size);
}
function setItem(AddressItems memory items, uint256 index, string memory key, address value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(AddressItems memory items, uint256 index, string memory key, address[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
function initItems(UintItems memory items, uint256 size) internal pure {
items.items = new EventUtils.UintKeyValue[](size);
}
function initArrayItems(UintItems memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.UintArrayKeyValue[](size);
}
function setItem(UintItems memory items, uint256 index, string memory key, uint256 value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(UintItems memory items, uint256 index, string memory key, uint256[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
function initItems(IntItems memory items, uint256 size) internal pure {
items.items = new EventUtils.IntKeyValue[](size);
}
function initArrayItems(IntItems memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.IntArrayKeyValue[](size);
}
function setItem(IntItems memory items, uint256 index, string memory key, int256 value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(IntItems memory items, uint256 index, string memory key, int256[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
function initItems(BoolItems memory items, uint256 size) internal pure {
items.items = new EventUtils.BoolKeyValue[](size);
}
function initArrayItems(BoolItems memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.BoolArrayKeyValue[](size);
}
function setItem(BoolItems memory items, uint256 index, string memory key, bool value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(BoolItems memory items, uint256 index, string memory key, bool[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
function initItems(Bytes32Items memory items, uint256 size) internal pure {
items.items = new EventUtils.Bytes32KeyValue[](size);
}
function initArrayItems(Bytes32Items memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.Bytes32ArrayKeyValue[](size);
}
function setItem(Bytes32Items memory items, uint256 index, string memory key, bytes32 value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(Bytes32Items memory items, uint256 index, string memory key, bytes32[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
function initItems(BytesItems memory items, uint256 size) internal pure {
items.items = new EventUtils.BytesKeyValue[](size);
}
function initArrayItems(BytesItems memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.BytesArrayKeyValue[](size);
}
function setItem(BytesItems memory items, uint256 index, string memory key, bytes memory value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(BytesItems memory items, uint256 index, string memory key, bytes[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
function initItems(StringItems memory items, uint256 size) internal pure {
items.items = new EventUtils.StringKeyValue[](size);
}
function initArrayItems(StringItems memory items, uint256 size) internal pure {
items.arrayItems = new EventUtils.StringArrayKeyValue[](size);
}
function setItem(StringItems memory items, uint256 index, string memory key, string memory value) internal pure {
items.items[index].key = key;
items.items[index].value = value;
}
function setItem(StringItems memory items, uint256 index, string memory key, string[] memory value) internal pure {
items.arrayItems[index].key = key;
items.arrayItems[index].value = value;
}
}
文件 30 的 108:ExchangeRouter.sol
pragma solidity ^0.8.0;
import "../exchange/IDepositHandler.sol";
import "../exchange/IWithdrawalHandler.sol";
import "../exchange/IShiftHandler.sol";
import "../exchange/IOrderHandler.sol";
import "../external/IExternalHandler.sol";
import "../shift/ShiftUtils.sol";
import "../shift/ShiftStoreUtils.sol";
import "../referral/ReferralUtils.sol";
import "../order/OrderStoreUtils.sol";
import "../feature/FeatureUtils.sol";
import "./BaseRouter.sol";
import "./IExchangeRouter.sol";
contract ExchangeRouter is IExchangeRouter, BaseRouter {
using Deposit for Deposit.Props;
using Withdrawal for Withdrawal.Props;
using Order for Order.Props;
using Shift for Shift.Props;
IDepositHandler public immutable depositHandler;
IWithdrawalHandler public immutable withdrawalHandler;
IShiftHandler public immutable shiftHandler;
IOrderHandler public immutable orderHandler;
IExternalHandler public immutable externalHandler;
constructor(
Router _router,
RoleStore _roleStore,
DataStore _dataStore,
EventEmitter _eventEmitter,
IDepositHandler _depositHandler,
IWithdrawalHandler _withdrawalHandler,
IShiftHandler _shiftHandler,
IOrderHandler _orderHandler,
IExternalHandler _externalHandler
) BaseRouter(_router, _roleStore, _dataStore, _eventEmitter) {
depositHandler = _depositHandler;
withdrawalHandler = _withdrawalHandler;
shiftHandler = _shiftHandler;
orderHandler = _orderHandler;
externalHandler = _externalHandler;
}
function makeExternalCalls(
address[] memory externalCallTargets,
bytes[] memory externalCallDataList,
address[] memory refundTokens,
address[] memory refundReceivers
) external nonReentrant {
externalHandler.makeExternalCalls(
externalCallTargets,
externalCallDataList,
refundTokens,
refundReceivers
);
}
function createDeposit(
DepositUtils.CreateDepositParams calldata params
) external override payable nonReentrant returns (bytes32) {
address account = msg.sender;
return depositHandler.createDeposit(
account,
params
);
}
function cancelDeposit(bytes32 key) external override payable nonReentrant {
Deposit.Props memory deposit = DepositStoreUtils.get(dataStore, key);
if (deposit.account() == address(0)) {
revert Errors.EmptyDeposit();
}
if (deposit.account() != msg.sender) {
revert Errors.Unauthorized(msg.sender, "account for cancelDeposit");
}
depositHandler.cancelDeposit(key);
}
function simulateExecuteDeposit(
bytes32 key,
OracleUtils.SimulatePricesParams memory simulatedOracleParams
) external payable nonReentrant {
depositHandler.simulateExecuteDeposit(key, simulatedOracleParams);
}
function simulateExecuteLatestDeposit(
OracleUtils.SimulatePricesParams memory simulatedOracleParams
) external payable nonReentrant {
bytes32 key = NonceUtils.getCurrentKey(dataStore);
depositHandler.simulateExecuteDeposit(key, simulatedOracleParams);
}
function createWithdrawal(
WithdrawalUtils.CreateWithdrawalParams calldata params
) external override payable nonReentrant returns (bytes32) {
address account = msg.sender;
return withdrawalHandler.createWithdrawal(
account,
params
);
}
function cancelWithdrawal(bytes32 key) external override payable nonReentrant {
Withdrawal.Props memory withdrawal = WithdrawalStoreUtils.get(dataStore, key);
if (withdrawal.account() != msg.sender) {
revert Errors.Unauthorized(msg.sender, "account for cancelWithdrawal");
}
withdrawalHandler.cancelWithdrawal(key);
}
function executeAtomicWithdrawal(
WithdrawalUtils.CreateWithdrawalParams calldata params,
OracleUtils.SetPricesParams calldata oracleParams
) external override payable nonReentrant {
address account = msg.sender;
return withdrawalHandler.executeAtomicWithdrawal(
account,
params,
oracleParams
);
}
function simulateExecuteWithdrawal(
bytes32 key,
OracleUtils.SimulatePricesParams memory simulatedOracleParams,
ISwapPricingUtils.SwapPricingType swapPricingType
) external payable nonReentrant {
withdrawalHandler.simulateExecuteWithdrawal(key, simulatedOracleParams, swapPricingType);
}
function simulateExecuteLatestWithdrawal(
OracleUtils.SimulatePricesParams memory simulatedOracleParams,
ISwapPricingUtils.SwapPricingType swapPricingType
) external payable nonReentrant {
bytes32 key = NonceUtils.getCurrentKey(dataStore);
withdrawalHandler.simulateExecuteWithdrawal(key, simulatedOracleParams, swapPricingType);
}
function createShift(
ShiftUtils.CreateShiftParams calldata params
) external override payable nonReentrant returns (bytes32) {
address account = msg.sender;
return shiftHandler.createShift(
account,
params
);
}
function cancelShift(bytes32 key) external override payable nonReentrant {
Shift.Props memory shift = ShiftStoreUtils.get(dataStore, key);
if (shift.account() != msg.sender) {
revert Errors.Unauthorized(msg.sender, "account for cancelShift");
}
shiftHandler.cancelShift(key);
}
function simulateExecuteShift(
bytes32 key,
OracleUtils.SimulatePricesParams memory simulatedOracleParams
) external payable nonReentrant {
shiftHandler.simulateExecuteShift(key, simulatedOracleParams);
}
function simulateExecuteLatestShift(
OracleUtils.SimulatePricesParams memory simulatedOracleParams
) external payable nonReentrant {
bytes32 key = NonceUtils.getCurrentKey(dataStore);
shiftHandler.simulateExecuteShift(key, simulatedOracleParams);
}
function createOrder(
IBaseOrderUtils.CreateOrderParams calldata params
) external override payable nonReentrant returns (bytes32) {
address account = msg.sender;
return orderHandler.createOrder(
account,
params
);
}
function setSavedCallbackContract(
address market,
address callbackContract
) external payable nonReentrant {
CallbackUtils.setSavedCallbackContract(
dataStore,
msg.sender,
market,
callbackContract
);
}
function updateOrder(
bytes32 key,
uint256 sizeDeltaUsd,
uint256 acceptablePrice,
uint256 triggerPrice,
uint256 minOutputAmount,
uint256 validFromTime,
bool autoCancel
) external payable nonReentrant {
Order.Props memory order = OrderStoreUtils.get(dataStore, key);
if (order.account() != msg.sender) {
revert Errors.Unauthorized(msg.sender, "account for updateOrder");
}
orderHandler.updateOrder(
key,
sizeDeltaUsd,
acceptablePrice,
triggerPrice,
minOutputAmount,
validFromTime,
autoCancel,
order
);
}
function cancelOrder(bytes32 key) external payable nonReentrant {
Order.Props memory order = OrderStoreUtils.get(dataStore, key);
if (order.account() == address(0)) {
revert Errors.EmptyOrder();
}
if (order.account() != msg.sender) {
revert Errors.Unauthorized(msg.sender, "account for cancelOrder");
}
orderHandler.cancelOrder(key);
}
function simulateExecuteOrder(
bytes32 key,
OracleUtils.SimulatePricesParams memory simulatedOracleParams
) external payable nonReentrant {
orderHandler.simulateExecuteOrder(key, simulatedOracleParams);
}
function simulateExecuteLatestOrder(
OracleUtils.SimulatePricesParams memory simulatedOracleParams
) external payable nonReentrant {
bytes32 key = NonceUtils.getCurrentKey(dataStore);
orderHandler.simulateExecuteOrder(key, simulatedOracleParams);
}
function claimFundingFees(
address[] memory markets,
address[] memory tokens,
address receiver
) external payable nonReentrant returns (uint256[] memory) {
if (markets.length != tokens.length) {
revert Errors.InvalidClaimFundingFeesInput(markets.length, tokens.length);
}
FeatureUtils.validateFeature(dataStore, Keys.claimFundingFeesFeatureDisabledKey(address(this)));
AccountUtils.validateReceiver(receiver);
address account = msg.sender;
uint256[] memory claimedAmounts = new uint256[](markets.length);
for (uint256 i; i < markets.length; i++) {
claimedAmounts[i] = MarketUtils.claimFundingFees(
dataStore,
eventEmitter,
markets[i],
tokens[i],
account,
receiver
);
}
return claimedAmounts;
}
function claimCollateral(
address[] memory markets,
address[] memory tokens,
uint256[] memory timeKeys,
address receiver
) external payable nonReentrant returns (uint256[] memory) {
if (markets.length != tokens.length || tokens.length != timeKeys.length) {
revert Errors.InvalidClaimCollateralInput(markets.length, tokens.length, timeKeys.length);
}
FeatureUtils.validateFeature(dataStore, Keys.claimCollateralFeatureDisabledKey(address(this)));
AccountUtils.validateReceiver(receiver);
address account = msg.sender;
uint256[] memory claimedAmounts = new uint256[](markets.length);
for (uint256 i; i < markets.length; i++) {
claimedAmounts[i] = MarketUtils.claimCollateral(
dataStore,
eventEmitter,
markets[i],
tokens[i],
timeKeys[i],
account,
receiver
);
}
return claimedAmounts;
}
function claimAffiliateRewards(
address[] memory markets,
address[] memory tokens,
address receiver
) external payable nonReentrant returns (uint256[] memory) {
if (markets.length != tokens.length) {
revert Errors.InvalidClaimAffiliateRewardsInput(markets.length, tokens.length);
}
FeatureUtils.validateFeature(dataStore, Keys.claimAffiliateRewardsFeatureDisabledKey(address(this)));
address account = msg.sender;
uint256[] memory claimedAmounts = new uint256[](markets.length);
for (uint256 i; i < markets.length; i++) {
claimedAmounts[i] = ReferralUtils.claimAffiliateReward(
dataStore,
eventEmitter,
markets[i],
tokens[i],
account,
receiver
);
}
return claimedAmounts;
}
function setUiFeeFactor(uint256 uiFeeFactor) external payable nonReentrant {
address account = msg.sender;
MarketUtils.setUiFeeFactor(dataStore, eventEmitter, account, uiFeeFactor);
}
function claimUiFees(
address[] memory markets,
address[] memory tokens,
address receiver
) external payable nonReentrant returns (uint256[] memory) {
if (markets.length != tokens.length) {
revert Errors.InvalidClaimUiFeesInput(markets.length, tokens.length);
}
FeatureUtils.validateFeature(dataStore, Keys.claimUiFeesFeatureDisabledKey(address(this)));
address uiFeeReceiver = msg.sender;
uint256[] memory claimedAmounts = new uint256[](markets.length);
for (uint256 i; i < markets.length; i++) {
claimedAmounts[i] = FeeUtils.claimUiFees(
dataStore,
eventEmitter,
uiFeeReceiver,
markets[i],
tokens[i],
receiver
);
}
return claimedAmounts;
}
}
文件 31 的 108:ExecuteDepositUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "./DepositVault.sol";
import "./DepositStoreUtils.sol";
import "./DepositEventUtils.sol";
import "../pricing/SwapPricingUtils.sol";
import "../oracle/Oracle.sol";
import "../position/PositionUtils.sol";
import "../gas/GasUtils.sol";
import "../callback/CallbackUtils.sol";
import "../utils/Array.sol";
library ExecuteDepositUtils {
using SafeCast for uint256;
using SafeCast for int256;
using Array for uint256[];
using Price for Price.Props;
using Deposit for Deposit.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct ExecuteDepositParams {
DataStore dataStore;
EventEmitter eventEmitter;
DepositVault depositVault;
Oracle oracle;
bytes32 key;
address keeper;
uint256 startingGas;
ISwapPricingUtils.SwapPricingType swapPricingType;
bool includeVirtualInventoryImpact;
}
struct _ExecuteDepositParams {
Market.Props market;
address account;
address receiver;
address uiFeeReceiver;
address tokenIn;
address tokenOut;
Price.Props tokenInPrice;
Price.Props tokenOutPrice;
uint256 amount;
int256 priceImpactUsd;
}
struct ExecuteDepositCache {
uint256 requestExpirationTime;
uint256 maxOracleTimestamp;
Market.Props market;
MarketUtils.MarketPrices prices;
uint256 longTokenAmount;
uint256 shortTokenAmount;
uint256 longTokenUsd;
uint256 shortTokenUsd;
uint256 receivedMarketTokens;
int256 priceImpactUsd;
uint256 marketTokensSupply;
EventUtils.EventLogData callbackEventData;
}
address public constant RECEIVER_FOR_FIRST_DEPOSIT = address(1);
function executeDeposit(ExecuteDepositParams memory params, Deposit.Props memory deposit) external returns (uint256 receivedMarketTokens) {
params.startingGas -= gasleft() / 63;
DepositStoreUtils.remove(params.dataStore, params.key, deposit.account());
if (deposit.account() == address(0)) {
revert Errors.EmptyDeposit();
}
if (params.oracle.minTimestamp() < deposit.updatedAtTime()) {
revert Errors.OracleTimestampsAreSmallerThanRequired(
params.oracle.minTimestamp(),
deposit.updatedAtTime()
);
}
ExecuteDepositCache memory cache;
cache.requestExpirationTime = params.dataStore.getUint(Keys.REQUEST_EXPIRATION_TIME);
cache.maxOracleTimestamp = params.oracle.maxTimestamp();
if (cache.maxOracleTimestamp > deposit.updatedAtTime() + cache.requestExpirationTime) {
revert Errors.OracleTimestampsAreLargerThanRequestExpirationTime(
cache.maxOracleTimestamp,
deposit.updatedAtTime(),
cache.requestExpirationTime
);
}
cache.market = MarketUtils.getEnabledMarket(params.dataStore, deposit.market());
_validateFirstDeposit(params, deposit, cache.market);
cache.prices = MarketUtils.getMarketPrices(params.oracle, cache.market);
MarketUtils.distributePositionImpactPool(
params.dataStore,
params.eventEmitter,
cache.market.marketToken
);
PositionUtils.updateFundingAndBorrowingState(
params.dataStore,
params.eventEmitter,
cache.market,
cache.prices
);
MarketUtils.validateMaxPnl(
params.dataStore,
cache.market,
cache.prices,
Keys.MAX_PNL_FACTOR_FOR_DEPOSITS,
Keys.MAX_PNL_FACTOR_FOR_DEPOSITS
);
cache.longTokenAmount = swap(
params,
deposit.longTokenSwapPath(),
deposit.initialLongToken(),
deposit.initialLongTokenAmount(),
cache.market.marketToken,
cache.market.longToken,
deposit.uiFeeReceiver()
);
cache.shortTokenAmount = swap(
params,
deposit.shortTokenSwapPath(),
deposit.initialShortToken(),
deposit.initialShortTokenAmount(),
cache.market.marketToken,
cache.market.shortToken,
deposit.uiFeeReceiver()
);
if (cache.longTokenAmount == 0 && cache.shortTokenAmount == 0) {
revert Errors.EmptyDepositAmountsAfterSwap();
}
cache.longTokenUsd = cache.longTokenAmount * cache.prices.longTokenPrice.midPrice();
cache.shortTokenUsd = cache.shortTokenAmount * cache.prices.shortTokenPrice.midPrice();
cache.priceImpactUsd = SwapPricingUtils.getPriceImpactUsd(
SwapPricingUtils.GetPriceImpactUsdParams(
params.dataStore,
cache.market,
cache.market.longToken,
cache.market.shortToken,
cache.prices.longTokenPrice.midPrice(),
cache.prices.shortTokenPrice.midPrice(),
cache.longTokenUsd.toInt256(),
cache.shortTokenUsd.toInt256(),
params.includeVirtualInventoryImpact
)
);
if (cache.longTokenAmount > 0) {
_ExecuteDepositParams memory _params = _ExecuteDepositParams(
cache.market,
deposit.account(),
deposit.receiver(),
deposit.uiFeeReceiver(),
cache.market.longToken,
cache.market.shortToken,
cache.prices.longTokenPrice,
cache.prices.shortTokenPrice,
cache.longTokenAmount,
Precision.mulDiv(cache.priceImpactUsd, cache.longTokenUsd, cache.longTokenUsd + cache.shortTokenUsd)
);
cache.receivedMarketTokens += _executeDeposit(params, _params);
}
if (cache.shortTokenAmount > 0) {
_ExecuteDepositParams memory _params = _ExecuteDepositParams(
cache.market,
deposit.account(),
deposit.receiver(),
deposit.uiFeeReceiver(),
cache.market.shortToken,
cache.market.longToken,
cache.prices.shortTokenPrice,
cache.prices.longTokenPrice,
cache.shortTokenAmount,
Precision.mulDiv(cache.priceImpactUsd, cache.shortTokenUsd, cache.longTokenUsd + cache.shortTokenUsd)
);
cache.receivedMarketTokens += _executeDeposit(params, _params);
}
if (cache.receivedMarketTokens < deposit.minMarketTokens()) {
revert Errors.MinMarketTokens(cache.receivedMarketTokens, deposit.minMarketTokens());
}
MarketUtils.validateMarketTokenBalance(params.dataStore, cache.market);
DepositEventUtils.emitDepositExecuted(
params.eventEmitter,
params.key,
deposit.account(),
cache.longTokenAmount,
cache.shortTokenAmount,
cache.receivedMarketTokens,
params.swapPricingType
);
MarketPoolValueInfo.Props memory poolValueInfo = MarketUtils.getPoolValueInfo(
params.dataStore,
cache.market,
cache.prices.indexTokenPrice,
cache.prices.longTokenPrice,
cache.prices.shortTokenPrice,
Keys.MAX_PNL_FACTOR_FOR_DEPOSITS,
true
);
cache.marketTokensSupply = MarketUtils.getMarketTokenSupply(MarketToken(payable(cache.market.marketToken)));
MarketEventUtils.emitMarketPoolValueUpdated(
params.eventEmitter,
keccak256(abi.encode("DEPOSIT")),
params.key,
cache.market.marketToken,
poolValueInfo,
cache.marketTokensSupply
);
cache.callbackEventData.uintItems.initItems(1);
cache.callbackEventData.uintItems.setItem(0, "receivedMarketTokens", cache.receivedMarketTokens);
CallbackUtils.afterDepositExecution(params.key, deposit, cache.callbackEventData);
GasUtils.payExecutionFee(
params.dataStore,
params.eventEmitter,
params.depositVault,
params.key,
deposit.callbackContract(),
deposit.executionFee(),
params.startingGas,
GasUtils.estimateDepositOraclePriceCount(deposit.longTokenSwapPath().length + deposit.shortTokenSwapPath().length),
params.keeper,
deposit.receiver()
);
return cache.receivedMarketTokens;
}
function _executeDeposit(ExecuteDepositParams memory params, _ExecuteDepositParams memory _params) internal returns (uint256) {
SwapPricingUtils.SwapFees memory fees = SwapPricingUtils.getSwapFees(
params.dataStore,
_params.market.marketToken,
_params.amount,
_params.priceImpactUsd > 0,
_params.uiFeeReceiver,
params.swapPricingType
);
FeeUtils.incrementClaimableFeeAmount(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
_params.tokenIn,
fees.feeReceiverAmount,
Keys.DEPOSIT_FEE_TYPE
);
FeeUtils.incrementClaimableUiFeeAmount(
params.dataStore,
params.eventEmitter,
_params.uiFeeReceiver,
_params.market.marketToken,
_params.tokenIn,
fees.uiFeeAmount,
Keys.UI_DEPOSIT_FEE_TYPE
);
SwapPricingUtils.emitSwapFeesCollected(
params.eventEmitter,
params.key,
_params.market.marketToken,
_params.tokenIn,
_params.tokenInPrice.min,
Keys.DEPOSIT_FEE_TYPE,
fees
);
uint256 mintAmount;
MarketPoolValueInfo.Props memory poolValueInfo = MarketUtils.getPoolValueInfo(
params.dataStore,
_params.market,
params.oracle.getPrimaryPrice(_params.market.indexToken),
_params.tokenIn == _params.market.longToken ? _params.tokenInPrice : _params.tokenOutPrice,
_params.tokenIn == _params.market.shortToken ? _params.tokenInPrice : _params.tokenOutPrice,
Keys.MAX_PNL_FACTOR_FOR_DEPOSITS,
true
);
if (poolValueInfo.poolValue < 0) {
revert Errors.InvalidPoolValueForDeposit(poolValueInfo.poolValue);
}
uint256 poolValue = poolValueInfo.poolValue.toUint256();
uint256 marketTokensSupply = MarketUtils.getMarketTokenSupply(MarketToken(payable(_params.market.marketToken)));
if (poolValueInfo.poolValue == 0 && marketTokensSupply > 0) {
revert Errors.InvalidPoolValueForDeposit(poolValueInfo.poolValue);
}
MarketEventUtils.emitMarketPoolValueInfo(
params.eventEmitter,
params.key,
_params.market.marketToken,
poolValueInfo,
marketTokensSupply
);
if (_params.priceImpactUsd > 0 && marketTokensSupply == 0) {
_params.priceImpactUsd = 0;
}
if (_params.priceImpactUsd > 0) {
(int256 positiveImpactAmount, ) = MarketUtils.applySwapImpactWithCap(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
_params.tokenOut,
_params.tokenOutPrice,
_params.priceImpactUsd
);
mintAmount += MarketUtils.usdToMarketTokenAmount(
positiveImpactAmount.toUint256() * _params.tokenOutPrice.max,
poolValue,
marketTokensSupply
);
MarketUtils.applyDeltaToPoolAmount(
params.dataStore,
params.eventEmitter,
_params.market,
_params.tokenOut,
positiveImpactAmount
);
MarketUtils.validatePoolAmount(
params.dataStore,
_params.market,
_params.tokenOut
);
}
if (_params.priceImpactUsd < 0) {
(int256 negativeImpactAmount, ) = MarketUtils.applySwapImpactWithCap(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
_params.tokenIn,
_params.tokenInPrice,
_params.priceImpactUsd
);
fees.amountAfterFees -= (-negativeImpactAmount).toUint256();
}
mintAmount += MarketUtils.usdToMarketTokenAmount(
fees.amountAfterFees * _params.tokenInPrice.min,
poolValue,
marketTokensSupply
);
MarketUtils.applyDeltaToPoolAmount(
params.dataStore,
params.eventEmitter,
_params.market,
_params.tokenIn,
(fees.amountAfterFees + fees.feeAmountForPool).toInt256()
);
MarketUtils.validatePoolUsdForDeposit(
params.dataStore,
_params.market,
_params.tokenIn,
_params.tokenInPrice.max
);
MarketUtils.validatePoolAmount(
params.dataStore,
_params.market,
_params.tokenIn
);
MarketToken(payable(_params.market.marketToken)).mint(_params.receiver, mintAmount);
return mintAmount;
}
function swap(
ExecuteDepositParams memory params,
address[] memory swapPath,
address initialToken,
uint256 inputAmount,
address market,
address expectedOutputToken,
address uiFeeReceiver
) internal returns (uint256) {
Market.Props[] memory swapPathMarkets = MarketUtils.getSwapPathMarkets(
params.dataStore,
swapPath
);
(address outputToken, uint256 outputAmount) = SwapUtils.swap(
SwapUtils.SwapParams(
params.dataStore,
params.eventEmitter,
params.oracle,
params.depositVault,
params.key,
initialToken,
inputAmount,
swapPathMarkets,
0,
market,
uiFeeReceiver,
false
)
);
if (outputToken != expectedOutputToken) {
revert Errors.InvalidSwapOutputToken(outputToken, expectedOutputToken);
}
MarketUtils.validateMarketTokenBalance(params.dataStore, swapPathMarkets);
return outputAmount;
}
function _validateFirstDeposit(
ExecuteDepositParams memory params,
Deposit.Props memory deposit,
Market.Props memory market
) internal view {
uint256 initialMarketTokensSupply = MarketUtils.getMarketTokenSupply(MarketToken(payable(market.marketToken)));
if (initialMarketTokensSupply != 0) { return; }
uint256 minMarketTokens = params.dataStore.getUint(Keys.minMarketTokensForFirstDepositKey(market.marketToken));
if (minMarketTokens == 0) { return; }
if (deposit.receiver() != RECEIVER_FOR_FIRST_DEPOSIT) {
revert Errors.InvalidReceiverForFirstDeposit(deposit.receiver(), RECEIVER_FOR_FIRST_DEPOSIT);
}
if (deposit.minMarketTokens() < minMarketTokens) {
revert Errors.InvalidMinMarketTokensForFirstDeposit(deposit.minMarketTokens(), minMarketTokens);
}
}
}
文件 32 的 108:ExecuteWithdrawalUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "./WithdrawalVault.sol";
import "./WithdrawalStoreUtils.sol";
import "./WithdrawalEventUtils.sol";
import "../pricing/SwapPricingUtils.sol";
import "../oracle/Oracle.sol";
import "../position/PositionUtils.sol";
import "../gas/GasUtils.sol";
import "../callback/CallbackUtils.sol";
import "../utils/Array.sol";
library ExecuteWithdrawalUtils {
using SafeCast for uint256;
using SafeCast for int256;
using Array for uint256[];
using Price for Price.Props;
using Withdrawal for Withdrawal.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct ExecuteWithdrawalParams {
DataStore dataStore;
EventEmitter eventEmitter;
WithdrawalVault withdrawalVault;
Oracle oracle;
bytes32 key;
address keeper;
uint256 startingGas;
ISwapPricingUtils.SwapPricingType swapPricingType;
}
struct ExecuteWithdrawalCache {
uint256 requestExpirationTime;
uint256 maxOracleTimestamp;
uint256 marketTokensBalance;
uint256 oraclePriceCount;
Market.Props market;
MarketUtils.MarketPrices prices;
ExecuteWithdrawalResult result;
}
struct _ExecuteWithdrawalCache {
uint256 longTokenOutputAmount;
uint256 shortTokenOutputAmount;
SwapPricingUtils.SwapFees longTokenFees;
SwapPricingUtils.SwapFees shortTokenFees;
uint256 longTokenPoolAmountDelta;
uint256 shortTokenPoolAmountDelta;
}
struct ExecuteWithdrawalResult {
address outputToken;
uint256 outputAmount;
address secondaryOutputToken;
uint256 secondaryOutputAmount;
}
struct SwapCache {
Market.Props[] swapPathMarkets;
SwapUtils.SwapParams swapParams;
address outputToken;
uint256 outputAmount;
}
function executeWithdrawal(
ExecuteWithdrawalParams memory params,
Withdrawal.Props memory withdrawal
) external returns (ExecuteWithdrawalResult memory) {
params.startingGas -= gasleft() / 63;
WithdrawalStoreUtils.remove(params.dataStore, params.key, withdrawal.account());
if (withdrawal.account() == address(0)) {
revert Errors.EmptyWithdrawal();
}
if (withdrawal.marketTokenAmount() == 0) {
revert Errors.EmptyWithdrawalAmount();
}
if (params.oracle.minTimestamp() < withdrawal.updatedAtTime()) {
revert Errors.OracleTimestampsAreSmallerThanRequired(
params.oracle.minTimestamp(),
withdrawal.updatedAtTime()
);
}
ExecuteWithdrawalCache memory cache;
cache.requestExpirationTime = params.dataStore.getUint(Keys.REQUEST_EXPIRATION_TIME);
cache.maxOracleTimestamp = params.oracle.maxTimestamp();
if (cache.maxOracleTimestamp > withdrawal.updatedAtTime() + cache.requestExpirationTime) {
revert Errors.OracleTimestampsAreLargerThanRequestExpirationTime(
cache.maxOracleTimestamp,
withdrawal.updatedAtTime(),
cache.requestExpirationTime
);
}
MarketUtils.distributePositionImpactPool(params.dataStore, params.eventEmitter, withdrawal.market());
cache.market = MarketUtils.getEnabledMarket(params.dataStore, withdrawal.market());
cache.prices = MarketUtils.getMarketPrices(params.oracle, cache.market);
PositionUtils.updateFundingAndBorrowingState(params.dataStore, params.eventEmitter, cache.market, cache.prices);
cache.marketTokensBalance = MarketToken(payable(withdrawal.market())).balanceOf(
address(params.withdrawalVault)
);
if (cache.marketTokensBalance < withdrawal.marketTokenAmount()) {
revert Errors.InsufficientMarketTokens(cache.marketTokensBalance, withdrawal.marketTokenAmount());
}
cache.result = _executeWithdrawal(params, withdrawal, cache.market, cache.prices);
WithdrawalEventUtils.emitWithdrawalExecuted(
params.eventEmitter,
params.key,
withdrawal.account(),
params.swapPricingType
);
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "outputToken", cache.result.outputToken);
eventData.addressItems.setItem(1, "secondaryOutputToken", cache.result.secondaryOutputToken);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "outputAmount", cache.result.outputAmount);
eventData.uintItems.setItem(1, "secondaryOutputAmount", cache.result.secondaryOutputAmount);
CallbackUtils.afterWithdrawalExecution(params.key, withdrawal, eventData);
cache.oraclePriceCount = GasUtils.estimateWithdrawalOraclePriceCount(
withdrawal.longTokenSwapPath().length + withdrawal.shortTokenSwapPath().length
);
GasUtils.payExecutionFee(
params.dataStore,
params.eventEmitter,
params.withdrawalVault,
params.key,
withdrawal.callbackContract(),
withdrawal.executionFee(),
params.startingGas,
cache.oraclePriceCount,
params.keeper,
withdrawal.receiver()
);
return cache.result;
}
function _executeWithdrawal(
ExecuteWithdrawalParams memory params,
Withdrawal.Props memory withdrawal,
Market.Props memory market,
MarketUtils.MarketPrices memory prices
) internal returns (ExecuteWithdrawalResult memory) {
_ExecuteWithdrawalCache memory cache;
(cache.longTokenOutputAmount, cache.shortTokenOutputAmount) = _getOutputAmounts(
params,
market,
prices,
withdrawal.marketTokenAmount()
);
cache.longTokenFees = SwapPricingUtils.getSwapFees(
params.dataStore,
market.marketToken,
cache.longTokenOutputAmount,
false,
withdrawal.uiFeeReceiver(),
params.swapPricingType
);
FeeUtils.incrementClaimableFeeAmount(
params.dataStore,
params.eventEmitter,
market.marketToken,
market.longToken,
cache.longTokenFees.feeReceiverAmount,
Keys.WITHDRAWAL_FEE_TYPE
);
FeeUtils.incrementClaimableUiFeeAmount(
params.dataStore,
params.eventEmitter,
withdrawal.uiFeeReceiver(),
market.marketToken,
market.longToken,
cache.longTokenFees.uiFeeAmount,
Keys.UI_WITHDRAWAL_FEE_TYPE
);
cache.shortTokenFees = SwapPricingUtils.getSwapFees(
params.dataStore,
market.marketToken,
cache.shortTokenOutputAmount,
false,
withdrawal.uiFeeReceiver(),
params.swapPricingType
);
FeeUtils.incrementClaimableFeeAmount(
params.dataStore,
params.eventEmitter,
market.marketToken,
market.shortToken,
cache.shortTokenFees.feeReceiverAmount,
Keys.WITHDRAWAL_FEE_TYPE
);
FeeUtils.incrementClaimableUiFeeAmount(
params.dataStore,
params.eventEmitter,
withdrawal.uiFeeReceiver(),
market.marketToken,
market.shortToken,
cache.shortTokenFees.uiFeeAmount,
Keys.UI_WITHDRAWAL_FEE_TYPE
);
cache.longTokenPoolAmountDelta = cache.longTokenOutputAmount - cache.longTokenFees.feeAmountForPool;
cache.longTokenOutputAmount = cache.longTokenFees.amountAfterFees;
cache.shortTokenPoolAmountDelta = cache.shortTokenOutputAmount - cache.shortTokenFees.feeAmountForPool;
cache.shortTokenOutputAmount = cache.shortTokenFees.amountAfterFees;
MarketUtils.applyDeltaToPoolAmount(
params.dataStore,
params.eventEmitter,
market,
market.longToken,
-cache.longTokenPoolAmountDelta.toInt256()
);
MarketUtils.applyDeltaToPoolAmount(
params.dataStore,
params.eventEmitter,
market,
market.shortToken,
-cache.shortTokenPoolAmountDelta.toInt256()
);
MarketUtils.validateReserve(params.dataStore, market, prices, true);
MarketUtils.validateReserve(params.dataStore, market, prices, false);
MarketUtils.validateMaxPnl(
params.dataStore,
market,
prices,
Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS,
Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS
);
MarketToken(payable(market.marketToken)).burn(address(params.withdrawalVault), withdrawal.marketTokenAmount());
params.withdrawalVault.syncTokenBalance(market.marketToken);
ExecuteWithdrawalResult memory result;
(result.outputToken, result.outputAmount) = _swap(
params,
market,
market.longToken,
cache.longTokenOutputAmount,
withdrawal.longTokenSwapPath(),
withdrawal.minLongTokenAmount(),
withdrawal.receiver(),
withdrawal.uiFeeReceiver(),
withdrawal.shouldUnwrapNativeToken()
);
(result.secondaryOutputToken, result.secondaryOutputAmount) = _swap(
params,
market,
market.shortToken,
cache.shortTokenOutputAmount,
withdrawal.shortTokenSwapPath(),
withdrawal.minShortTokenAmount(),
withdrawal.receiver(),
withdrawal.uiFeeReceiver(),
withdrawal.shouldUnwrapNativeToken()
);
SwapPricingUtils.emitSwapFeesCollected(
params.eventEmitter,
params.key,
market.marketToken,
market.longToken,
prices.longTokenPrice.min,
Keys.WITHDRAWAL_FEE_TYPE,
cache.longTokenFees
);
SwapPricingUtils.emitSwapFeesCollected(
params.eventEmitter,
params.key,
market.marketToken,
market.shortToken,
prices.shortTokenPrice.min,
Keys.WITHDRAWAL_FEE_TYPE,
cache.shortTokenFees
);
MarketUtils.validateMarketTokenBalance(params.dataStore, market);
MarketPoolValueInfo.Props memory poolValueInfo = MarketUtils.getPoolValueInfo(
params.dataStore,
market,
prices.indexTokenPrice,
prices.longTokenPrice,
prices.shortTokenPrice,
Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS,
false
);
uint256 marketTokensSupply = MarketUtils.getMarketTokenSupply(MarketToken(payable(market.marketToken)));
MarketEventUtils.emitMarketPoolValueUpdated(
params.eventEmitter,
keccak256(abi.encode("WITHDRAWAL")),
params.key,
market.marketToken,
poolValueInfo,
marketTokensSupply
);
return result;
}
function _swap(
ExecuteWithdrawalParams memory params,
Market.Props memory market,
address tokenIn,
uint256 amountIn,
address[] memory swapPath,
uint256 minOutputAmount,
address receiver,
address uiFeeReceiver,
bool shouldUnwrapNativeToken
) internal returns (address, uint256) {
SwapCache memory cache;
cache.swapPathMarkets = MarketUtils.getSwapPathMarkets(params.dataStore, swapPath);
cache.swapParams.dataStore = params.dataStore;
cache.swapParams.eventEmitter = params.eventEmitter;
cache.swapParams.oracle = params.oracle;
cache.swapParams.bank = Bank(payable(market.marketToken));
cache.swapParams.key = params.key;
cache.swapParams.tokenIn = tokenIn;
cache.swapParams.amountIn = amountIn;
cache.swapParams.swapPathMarkets = cache.swapPathMarkets;
cache.swapParams.minOutputAmount = minOutputAmount;
cache.swapParams.receiver = receiver;
cache.swapParams.uiFeeReceiver = uiFeeReceiver;
cache.swapParams.shouldUnwrapNativeToken = shouldUnwrapNativeToken;
(cache.outputToken, cache.outputAmount) = SwapUtils.swap(cache.swapParams);
MarketUtils.validateMarketTokenBalance(params.dataStore, cache.swapPathMarkets);
return (cache.outputToken, cache.outputAmount);
}
function _getOutputAmounts(
ExecuteWithdrawalParams memory params,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
uint256 marketTokenAmount
) internal returns (uint256, uint256) {
MarketPoolValueInfo.Props memory poolValueInfo = MarketUtils.getPoolValueInfo(
params.dataStore,
market,
params.oracle.getPrimaryPrice(market.indexToken),
prices.longTokenPrice,
prices.shortTokenPrice,
Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS,
false
);
if (poolValueInfo.poolValue <= 0) {
revert Errors.InvalidPoolValueForWithdrawal(poolValueInfo.poolValue);
}
uint256 poolValue = poolValueInfo.poolValue.toUint256();
uint256 marketTokensSupply = MarketUtils.getMarketTokenSupply(MarketToken(payable(market.marketToken)));
MarketEventUtils.emitMarketPoolValueInfo(
params.eventEmitter,
params.key,
market.marketToken,
poolValueInfo,
marketTokensSupply
);
uint256 longTokenPoolAmount = MarketUtils.getPoolAmount(params.dataStore, market, market.longToken);
uint256 shortTokenPoolAmount = MarketUtils.getPoolAmount(params.dataStore, market, market.shortToken);
uint256 longTokenPoolUsd = longTokenPoolAmount * prices.longTokenPrice.max;
uint256 shortTokenPoolUsd = shortTokenPoolAmount * prices.shortTokenPrice.max;
uint256 totalPoolUsd = longTokenPoolUsd + shortTokenPoolUsd;
uint256 marketTokensUsd = MarketUtils.marketTokenAmountToUsd(marketTokenAmount, poolValue, marketTokensSupply);
uint256 longTokenOutputUsd = Precision.mulDiv(marketTokensUsd, longTokenPoolUsd, totalPoolUsd);
uint256 shortTokenOutputUsd = Precision.mulDiv(marketTokensUsd, shortTokenPoolUsd, totalPoolUsd);
return (longTokenOutputUsd / prices.longTokenPrice.max, shortTokenOutputUsd / prices.shortTokenPrice.max);
}
}
文件 33 的 108:FeatureUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
library FeatureUtils {
function isFeatureDisabled(DataStore dataStore, bytes32 key) internal view returns (bool) {
return dataStore.getBool(key);
}
function validateFeature(DataStore dataStore, bytes32 key) internal view {
if (isFeatureDisabled(dataStore, key)) {
revert Errors.DisabledFeature(key);
}
}
}
文件 34 的 108:FeeUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Cast.sol";
import "../utils/AccountUtils.sol";
import "../market/MarketUtils.sol";
import "../market/MarketToken.sol";
library FeeUtils {
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
function incrementClaimableFeeAmount(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
uint256 delta,
bytes32 feeType
) external {
if (delta == 0) {
return;
}
bytes32 key = Keys.claimableFeeAmountKey(market, token);
uint256 nextValue = dataStore.incrementUint(
key,
delta
);
emitClaimableFeeAmountUpdated(
eventEmitter,
market,
token,
delta,
nextValue,
feeType
);
}
function incrementClaimableUiFeeAmount(
DataStore dataStore,
EventEmitter eventEmitter,
address uiFeeReceiver,
address market,
address token,
uint256 delta,
bytes32 feeType
) external {
if (delta == 0) {
return;
}
uint256 nextValue = dataStore.incrementUint(
Keys.claimableUiFeeAmountKey(market, token, uiFeeReceiver),
delta
);
uint256 nextPoolValue = dataStore.incrementUint(
Keys.claimableUiFeeAmountKey(market, token),
delta
);
emitClaimableUiFeeAmountUpdated(
eventEmitter,
uiFeeReceiver,
market,
token,
delta,
nextValue,
nextPoolValue,
feeType
);
}
function claimFees(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
address receiver
) internal returns (uint256) {
AccountUtils.validateReceiver(receiver);
bytes32 key = Keys.claimableFeeAmountKey(market, token);
uint256 feeAmount = dataStore.getUint(key);
dataStore.setUint(key, 0);
MarketToken(payable(market)).transferOut(
token,
receiver,
feeAmount
);
MarketUtils.validateMarketTokenBalance(dataStore, market);
emitFeesClaimed(
eventEmitter,
market,
receiver,
feeAmount
);
return feeAmount;
}
function claimUiFees(
DataStore dataStore,
EventEmitter eventEmitter,
address uiFeeReceiver,
address market,
address token,
address receiver
) external returns (uint256) {
AccountUtils.validateReceiver(receiver);
bytes32 key = Keys.claimableUiFeeAmountKey(market, token, uiFeeReceiver);
uint256 feeAmount = dataStore.getUint(key);
dataStore.setUint(key, 0);
uint256 nextPoolValue = dataStore.decrementUint(
Keys.claimableUiFeeAmountKey(market, token),
feeAmount
);
MarketToken(payable(market)).transferOut(
token,
receiver,
feeAmount
);
MarketUtils.validateMarketTokenBalance(dataStore, market);
emitUiFeesClaimed(
eventEmitter,
uiFeeReceiver,
market,
receiver,
feeAmount,
nextPoolValue
);
return feeAmount;
}
function emitClaimableFeeAmountUpdated(
EventEmitter eventEmitter,
address market,
address token,
uint256 delta,
uint256 nextValue,
bytes32 feeType
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "nextValue", nextValue);
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "feeType", feeType);
eventEmitter.emitEventLog2(
"ClaimableFeeAmountUpdated",
Cast.toBytes32(market),
feeType,
eventData
);
}
function emitClaimableUiFeeAmountUpdated(
EventEmitter eventEmitter,
address uiFeeReceiver,
address market,
address token,
uint256 delta,
uint256 nextValue,
uint256 nextPoolValue,
bytes32 feeType
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "uiFeeReceiver", uiFeeReceiver);
eventData.addressItems.setItem(1, "market", market);
eventData.addressItems.setItem(2, "token", token);
eventData.uintItems.initItems(3);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "nextValue", nextValue);
eventData.uintItems.setItem(2, "nextPoolValue", nextPoolValue);
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "feeType", feeType);
eventEmitter.emitEventLog2(
"ClaimableUiFeeAmountUpdated",
Cast.toBytes32(market),
feeType,
eventData
);
}
function emitFeesClaimed(
EventEmitter eventEmitter,
address market,
address receiver,
uint256 feeAmount
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "receiver", receiver);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "feeAmount", feeAmount);
eventEmitter.emitEventLog1(
"FeesClaimed",
Cast.toBytes32(market),
eventData
);
}
function emitUiFeesClaimed(
EventEmitter eventEmitter,
address uiFeeReceiver,
address market,
address receiver,
uint256 feeAmount,
uint256 nextPoolValue
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "uiFeeReceiver", uiFeeReceiver);
eventData.addressItems.setItem(1, "market", market);
eventData.addressItems.setItem(2, "receiver", receiver);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "feeAmount", feeAmount);
eventData.uintItems.setItem(1, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog1(
"UiFeesClaimed",
Cast.toBytes32(market),
eventData
);
}
}
文件 35 的 108:GasUtils.sol
pragma solidity ^0.8.0;
import "../callback/CallbackUtils.sol";
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../utils/Precision.sol";
import "../deposit/Deposit.sol";
import "../withdrawal/Withdrawal.sol";
import "../shift/Shift.sol";
import "../order/Order.sol";
import "../order/BaseOrderUtils.sol";
import "../glv/glvWithdrawal/GlvWithdrawal.sol";
import "../bank/StrictBank.sol";
library GasUtils {
using Deposit for Deposit.Props;
using Withdrawal for Withdrawal.Props;
using Shift for Shift.Props;
using Order for Order.Props;
using GlvDeposit for GlvDeposit.Props;
using GlvWithdrawal for GlvWithdrawal.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
event KeeperExecutionFee(address keeper, uint256 amount);
event UserRefundFee(address user, uint256 amount);
function getMinHandleExecutionErrorGas(DataStore dataStore) internal view returns (uint256) {
return dataStore.getUint(Keys.MIN_HANDLE_EXECUTION_ERROR_GAS);
}
function getMinHandleExecutionErrorGasToForward(DataStore dataStore) internal view returns (uint256) {
return dataStore.getUint(Keys.MIN_HANDLE_EXECUTION_ERROR_GAS_TO_FORWARD);
}
function getMinAdditionalGasForExecution(DataStore dataStore) internal view returns (uint256) {
return dataStore.getUint(Keys.MIN_ADDITIONAL_GAS_FOR_EXECUTION);
}
function getExecutionGas(DataStore dataStore, uint256 startingGas) internal view returns (uint256) {
uint256 minHandleExecutionErrorGasToForward = GasUtils.getMinHandleExecutionErrorGasToForward(dataStore);
if (startingGas < minHandleExecutionErrorGasToForward) {
revert Errors.InsufficientExecutionGasForErrorHandling(startingGas, minHandleExecutionErrorGasToForward);
}
return startingGas - minHandleExecutionErrorGasToForward;
}
function validateExecutionGas(DataStore dataStore, uint256 startingGas, uint256 estimatedGasLimit) internal view {
uint256 minAdditionalGasForExecution = getMinAdditionalGasForExecution(dataStore);
if (startingGas < estimatedGasLimit + minAdditionalGasForExecution) {
revert Errors.InsufficientExecutionGas(startingGas, estimatedGasLimit, minAdditionalGasForExecution);
}
}
function validateExecutionErrorGas(DataStore dataStore, bytes memory reasonBytes) internal view {
if (reasonBytes.length != 0 || tx.origin != address(0)) { return; }
uint256 gas = gasleft();
uint256 minHandleExecutionErrorGas = getMinHandleExecutionErrorGas(dataStore);
if (gas < minHandleExecutionErrorGas) {
revert Errors.InsufficientHandleExecutionErrorGas(gas, minHandleExecutionErrorGas);
}
}
struct PayExecutionFeeCache {
uint256 refundFeeAmount;
bool refundWasSent;
}
function payExecutionFee(
DataStore dataStore,
EventEmitter eventEmitter,
StrictBank bank,
bytes32 key,
address callbackContract,
uint256 executionFee,
uint256 startingGas,
uint256 oraclePriceCount,
address keeper,
address refundReceiver
) external {
if (executionFee == 0) {
return;
}
startingGas -= gasleft() / 63;
uint256 gasUsed = startingGas - gasleft();
uint256 executionFeeForKeeper = adjustGasUsage(dataStore, gasUsed, oraclePriceCount) * tx.gasprice;
if (executionFeeForKeeper > executionFee) {
executionFeeForKeeper = executionFee;
}
bank.transferOutNativeToken(
keeper,
executionFeeForKeeper
);
emitKeeperExecutionFee(eventEmitter, keeper, executionFeeForKeeper);
PayExecutionFeeCache memory cache;
cache.refundFeeAmount = executionFee - executionFeeForKeeper;
if (cache.refundFeeAmount == 0) {
return;
}
address _wnt = dataStore.getAddress(Keys.WNT);
bank.transferOut(
_wnt,
address(this),
cache.refundFeeAmount
);
IWNT(_wnt).withdraw(cache.refundFeeAmount);
EventUtils.EventLogData memory eventData;
cache.refundWasSent = CallbackUtils.refundExecutionFee(dataStore, key, callbackContract, cache.refundFeeAmount, eventData);
if (cache.refundWasSent) {
emitExecutionFeeRefundCallback(eventEmitter, callbackContract, cache.refundFeeAmount);
} else {
TokenUtils.sendNativeToken(dataStore, refundReceiver, cache.refundFeeAmount);
emitExecutionFeeRefund(eventEmitter, refundReceiver, cache.refundFeeAmount);
}
}
function validateExecutionFee(DataStore dataStore, uint256 estimatedGasLimit, uint256 executionFee, uint256 oraclePriceCount) internal view {
uint256 gasLimit = adjustGasLimitForEstimate(dataStore, estimatedGasLimit, oraclePriceCount);
uint256 minExecutionFee = gasLimit * tx.gasprice;
if (executionFee < minExecutionFee) {
revert Errors.InsufficientExecutionFee(minExecutionFee, executionFee);
}
}
function adjustGasUsage(DataStore dataStore, uint256 gasUsed, uint256 oraclePriceCount) internal view returns (uint256) {
uint256 baseGasLimit = dataStore.getUint(Keys.EXECUTION_GAS_FEE_BASE_AMOUNT_V2_1);
baseGasLimit += dataStore.getUint(Keys.EXECUTION_GAS_FEE_PER_ORACLE_PRICE) * oraclePriceCount;
uint256 multiplierFactor = dataStore.getUint(Keys.EXECUTION_GAS_FEE_MULTIPLIER_FACTOR);
uint256 gasLimit = baseGasLimit + Precision.applyFactor(gasUsed, multiplierFactor);
return gasLimit;
}
function adjustGasLimitForEstimate(DataStore dataStore, uint256 estimatedGasLimit, uint256 oraclePriceCount) internal view returns (uint256) {
uint256 baseGasLimit = dataStore.getUint(Keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1);
baseGasLimit += dataStore.getUint(Keys.ESTIMATED_GAS_FEE_PER_ORACLE_PRICE) * oraclePriceCount;
uint256 multiplierFactor = dataStore.getUint(Keys.ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR);
uint256 gasLimit = baseGasLimit + Precision.applyFactor(estimatedGasLimit, multiplierFactor);
return gasLimit;
}
function estimateDepositOraclePriceCount(uint256 swapsCount) internal pure returns (uint256) {
return 3 + swapsCount;
}
function estimateWithdrawalOraclePriceCount(uint256 swapsCount) internal pure returns (uint256) {
return 3 + swapsCount;
}
function estimateOrderOraclePriceCount(uint256 swapsCount) internal pure returns (uint256) {
return 3 + swapsCount;
}
function estimateShiftOraclePriceCount() internal pure returns (uint256) {
return 4;
}
function estimateGlvDepositOraclePriceCount(
uint256 marketCount,
uint256 swapsCount
) internal pure returns (uint256) {
return 2 + marketCount + swapsCount;
}
function estimateGlvWithdrawalOraclePriceCount(
uint256 marketCount,
uint256 swapsCount
) internal pure returns (uint256) {
return 2 + marketCount + swapsCount;
}
function estimateExecuteDepositGasLimit(DataStore dataStore, Deposit.Props memory deposit) internal view returns (uint256) {
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
uint256 swapCount = deposit.longTokenSwapPath().length + deposit.shortTokenSwapPath().length;
uint256 gasForSwaps = swapCount * gasPerSwap;
return dataStore.getUint(Keys.depositGasLimitKey()) + deposit.callbackGasLimit() + gasForSwaps;
}
function estimateExecuteWithdrawalGasLimit(DataStore dataStore, Withdrawal.Props memory withdrawal) internal view returns (uint256) {
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
uint256 swapCount = withdrawal.longTokenSwapPath().length + withdrawal.shortTokenSwapPath().length;
uint256 gasForSwaps = swapCount * gasPerSwap;
return dataStore.getUint(Keys.withdrawalGasLimitKey()) + withdrawal.callbackGasLimit() + gasForSwaps;
}
function estimateExecuteShiftGasLimit(DataStore dataStore, Shift.Props memory shift) internal view returns (uint256) {
return dataStore.getUint(Keys.shiftGasLimitKey()) + shift.callbackGasLimit();
}
function estimateExecuteOrderGasLimit(DataStore dataStore, Order.Props memory order) internal view returns (uint256) {
if (BaseOrderUtils.isIncreaseOrder(order.orderType())) {
return estimateExecuteIncreaseOrderGasLimit(dataStore, order);
}
if (BaseOrderUtils.isDecreaseOrder(order.orderType())) {
return estimateExecuteDecreaseOrderGasLimit(dataStore, order);
}
if (BaseOrderUtils.isSwapOrder(order.orderType())) {
return estimateExecuteSwapOrderGasLimit(dataStore, order);
}
revert Errors.UnsupportedOrderType(uint256(order.orderType()));
}
function estimateExecuteIncreaseOrderGasLimit(DataStore dataStore, Order.Props memory order) internal view returns (uint256) {
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
return dataStore.getUint(Keys.increaseOrderGasLimitKey()) + gasPerSwap * order.swapPath().length + order.callbackGasLimit();
}
function estimateExecuteDecreaseOrderGasLimit(DataStore dataStore, Order.Props memory order) internal view returns (uint256) {
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
uint256 swapCount = order.swapPath().length;
if (order.decreasePositionSwapType() != Order.DecreasePositionSwapType.NoSwap) {
swapCount += 1;
}
return dataStore.getUint(Keys.decreaseOrderGasLimitKey()) + gasPerSwap * swapCount + order.callbackGasLimit();
}
function estimateExecuteSwapOrderGasLimit(DataStore dataStore, Order.Props memory order) internal view returns (uint256) {
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
return dataStore.getUint(Keys.swapOrderGasLimitKey()) + gasPerSwap * order.swapPath().length + order.callbackGasLimit();
}
function estimateExecuteGlvDepositGasLimit(DataStore dataStore, GlvDeposit.Props memory glvDeposit, uint256 marketCount) internal view returns (uint256) {
uint256 gasPerGlvPerMarket = dataStore.getUint(Keys.glvPerMarketGasLimitKey());
uint256 gasForGlvMarkets = gasPerGlvPerMarket * marketCount;
uint256 glvDepositGasLimit = dataStore.getUint(Keys.glvDepositGasLimitKey());
uint256 gasLimit = glvDepositGasLimit + glvDeposit.callbackGasLimit() + gasForGlvMarkets;
if (glvDeposit.isMarketTokenDeposit()) {
return gasLimit;
}
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
uint256 swapCount = glvDeposit.longTokenSwapPath().length + glvDeposit.shortTokenSwapPath().length;
uint256 gasForSwaps = swapCount * gasPerSwap;
return gasLimit + dataStore.getUint(Keys.depositGasLimitKey()) + gasForSwaps;
}
function estimateExecuteGlvWithdrawalGasLimit(DataStore dataStore, GlvWithdrawal.Props memory glvWithdrawal, uint256 marketCount) internal view returns (uint256) {
uint256 gasPerGlvPerMarket = dataStore.getUint(Keys.glvPerMarketGasLimitKey());
uint256 gasForGlvMarkets = gasPerGlvPerMarket * marketCount;
uint256 glvWithdrawalGasLimit = dataStore.getUint(Keys.glvWithdrawalGasLimitKey());
uint256 gasLimit = glvWithdrawalGasLimit + glvWithdrawal.callbackGasLimit() + gasForGlvMarkets;
uint256 gasPerSwap = dataStore.getUint(Keys.singleSwapGasLimitKey());
uint256 swapCount = glvWithdrawal.longTokenSwapPath().length + glvWithdrawal.shortTokenSwapPath().length;
uint256 gasForSwaps = swapCount * gasPerSwap;
return gasLimit + dataStore.getUint(Keys.withdrawalGasLimitKey()) + gasForSwaps;
}
function estimateExecuteGlvShiftGasLimit(DataStore dataStore) internal view returns (uint256) {
return dataStore.getUint(Keys.glvShiftGasLimitKey());
}
function emitKeeperExecutionFee(
EventEmitter eventEmitter,
address keeper,
uint256 executionFeeAmount
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "keeper", keeper);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "executionFeeAmount", executionFeeAmount);
eventEmitter.emitEventLog1(
"KeeperExecutionFee",
Cast.toBytes32(keeper),
eventData
);
}
function emitExecutionFeeRefund(
EventEmitter eventEmitter,
address receiver,
uint256 refundFeeAmount
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "receiver", receiver);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "refundFeeAmount", refundFeeAmount);
eventEmitter.emitEventLog1(
"ExecutionFeeRefund",
Cast.toBytes32(receiver),
eventData
);
}
function emitExecutionFeeRefundCallback(
EventEmitter eventEmitter,
address callbackContract,
uint256 refundFeeAmount
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "callbackContract", callbackContract);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "refundFeeAmount", refundFeeAmount);
eventEmitter.emitEventLog1(
"ExecutionFeeRefundCallback",
Cast.toBytes32(callbackContract),
eventData
);
}
}
文件 36 的 108:GlvDeposit.sol
pragma solidity ^0.8.0;
library GlvDeposit {
struct Props {
Addresses addresses;
Numbers numbers;
Flags flags;
}
struct Addresses {
address glv;
address account;
address receiver;
address callbackContract;
address uiFeeReceiver;
address market;
address initialLongToken;
address initialShortToken;
address[] longTokenSwapPath;
address[] shortTokenSwapPath;
}
struct Numbers {
uint256 marketTokenAmount;
uint256 initialLongTokenAmount;
uint256 initialShortTokenAmount;
uint256 minGlvTokens;
uint256 updatedAtTime;
uint256 executionFee;
uint256 callbackGasLimit;
}
struct Flags {
bool shouldUnwrapNativeToken;
bool isMarketTokenDeposit;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function receiver(Props memory props) internal pure returns (address) {
return props.addresses.receiver;
}
function setReceiver(Props memory props, address value) internal pure {
props.addresses.receiver = value;
}
function callbackContract(Props memory props) internal pure returns (address) {
return props.addresses.callbackContract;
}
function setCallbackContract(Props memory props, address value) internal pure {
props.addresses.callbackContract = value;
}
function uiFeeReceiver(Props memory props) internal pure returns (address) {
return props.addresses.uiFeeReceiver;
}
function setUiFeeReceiver(Props memory props, address value) internal pure {
props.addresses.uiFeeReceiver = value;
}
function glv(Props memory props) internal pure returns (address) {
return props.addresses.glv;
}
function setGlv(Props memory props, address value) internal pure {
props.addresses.glv = value;
}
function market(Props memory props) internal pure returns (address) {
return props.addresses.market;
}
function setMarket(Props memory props, address value) internal pure {
props.addresses.market = value;
}
function initialLongToken(Props memory props) internal pure returns (address) {
return props.addresses.initialLongToken;
}
function setInitialLongToken(Props memory props, address value) internal pure {
props.addresses.initialLongToken = value;
}
function initialShortToken(Props memory props) internal pure returns (address) {
return props.addresses.initialShortToken;
}
function setInitialShortToken(Props memory props, address value) internal pure {
props.addresses.initialShortToken = value;
}
function longTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.longTokenSwapPath;
}
function setLongTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.longTokenSwapPath = value;
}
function shortTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.shortTokenSwapPath;
}
function setShortTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.shortTokenSwapPath = value;
}
function marketTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.marketTokenAmount;
}
function setMarketTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.marketTokenAmount = value;
}
function initialLongTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.initialLongTokenAmount;
}
function setInitialLongTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.initialLongTokenAmount = value;
}
function initialShortTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.initialShortTokenAmount;
}
function setInitialShortTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.initialShortTokenAmount = value;
}
function minGlvTokens(Props memory props) internal pure returns (uint256) {
return props.numbers.minGlvTokens;
}
function setMinGlvTokens(Props memory props, uint256 value) internal pure {
props.numbers.minGlvTokens = value;
}
function updatedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.updatedAtTime;
}
function setUpdatedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.updatedAtTime = value;
}
function executionFee(Props memory props) internal pure returns (uint256) {
return props.numbers.executionFee;
}
function setExecutionFee(Props memory props, uint256 value) internal pure {
props.numbers.executionFee = value;
}
function callbackGasLimit(Props memory props) internal pure returns (uint256) {
return props.numbers.callbackGasLimit;
}
function setCallbackGasLimit(Props memory props, uint256 value) internal pure {
props.numbers.callbackGasLimit = value;
}
function shouldUnwrapNativeToken(Props memory props) internal pure returns (bool) {
return props.flags.shouldUnwrapNativeToken;
}
function setShouldUnwrapNativeToken(Props memory props, bool value) internal pure {
props.flags.shouldUnwrapNativeToken = value;
}
function isMarketTokenDeposit(Props memory props) internal pure returns (bool) {
return props.flags.isMarketTokenDeposit;
}
function setIsMarketTokenDeposit(Props memory props, bool value) internal pure {
props.flags.isMarketTokenDeposit = value;
}
}
文件 37 的 108:GlvWithdrawal.sol
pragma solidity ^0.8.0;
library GlvWithdrawal {
struct Props {
Addresses addresses;
Numbers numbers;
Flags flags;
}
struct Addresses {
address glv;
address market;
address account;
address receiver;
address callbackContract;
address uiFeeReceiver;
address[] longTokenSwapPath;
address[] shortTokenSwapPath;
}
struct Numbers {
uint256 glvTokenAmount;
uint256 minLongTokenAmount;
uint256 minShortTokenAmount;
uint256 updatedAtTime;
uint256 executionFee;
uint256 callbackGasLimit;
}
struct Flags {
bool shouldUnwrapNativeToken;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function receiver(Props memory props) internal pure returns (address) {
return props.addresses.receiver;
}
function setReceiver(Props memory props, address value) internal pure {
props.addresses.receiver = value;
}
function callbackContract(Props memory props) internal pure returns (address) {
return props.addresses.callbackContract;
}
function setCallbackContract(Props memory props, address value) internal pure {
props.addresses.callbackContract = value;
}
function uiFeeReceiver(Props memory props) internal pure returns (address) {
return props.addresses.uiFeeReceiver;
}
function setUiFeeReceiver(Props memory props, address value) internal pure {
props.addresses.uiFeeReceiver = value;
}
function market(Props memory props) internal pure returns (address) {
return props.addresses.market;
}
function setMarket(Props memory props, address value) internal pure {
props.addresses.market = value;
}
function glv(Props memory props) internal pure returns (address) {
return props.addresses.glv;
}
function setGlv(Props memory props, address value) internal pure {
props.addresses.glv = value;
}
function longTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.longTokenSwapPath;
}
function setLongTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.longTokenSwapPath = value;
}
function shortTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.shortTokenSwapPath;
}
function setShortTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.shortTokenSwapPath = value;
}
function glvTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.glvTokenAmount;
}
function setGlvTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.glvTokenAmount = value;
}
function minLongTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.minLongTokenAmount;
}
function setMinLongTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.minLongTokenAmount = value;
}
function minShortTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.minShortTokenAmount;
}
function setMinShortTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.minShortTokenAmount = value;
}
function updatedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.updatedAtTime;
}
function setUpdatedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.updatedAtTime = value;
}
function executionFee(Props memory props) internal pure returns (uint256) {
return props.numbers.executionFee;
}
function setExecutionFee(Props memory props, uint256 value) internal pure {
props.numbers.executionFee = value;
}
function callbackGasLimit(Props memory props) internal pure returns (uint256) {
return props.numbers.callbackGasLimit;
}
function setCallbackGasLimit(Props memory props, uint256 value) internal pure {
props.numbers.callbackGasLimit = value;
}
function shouldUnwrapNativeToken(Props memory props) internal pure returns (bool) {
return props.flags.shouldUnwrapNativeToken;
}
function setShouldUnwrapNativeToken(Props memory props, bool value) internal pure {
props.flags.shouldUnwrapNativeToken = value;
}
}
文件 38 的 108:IBaseOrderUtils.sol
pragma solidity ^0.8.0;
import "./Order.sol";
interface IBaseOrderUtils {
struct CreateOrderParams {
CreateOrderParamsAddresses addresses;
CreateOrderParamsNumbers numbers;
Order.OrderType orderType;
Order.DecreasePositionSwapType decreasePositionSwapType;
bool isLong;
bool shouldUnwrapNativeToken;
bool autoCancel;
bytes32 referralCode;
}
struct CreateOrderParamsAddresses {
address receiver;
address cancellationReceiver;
address callbackContract;
address uiFeeReceiver;
address market;
address initialCollateralToken;
address[] swapPath;
}
struct CreateOrderParamsNumbers {
uint256 sizeDeltaUsd;
uint256 initialCollateralDeltaAmount;
uint256 triggerPrice;
uint256 acceptablePrice;
uint256 executionFee;
uint256 callbackGasLimit;
uint256 minOutputAmount;
uint256 validFromTime;
}
}
文件 39 的 108:IDepositCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
import "../deposit/Deposit.sol";
interface IDepositCallbackReceiver {
function afterDepositExecution(bytes32 key, Deposit.Props memory deposit, EventUtils.EventLogData memory eventData) external;
function afterDepositCancellation(bytes32 key, Deposit.Props memory deposit, EventUtils.EventLogData memory eventData) external;
}
文件 40 的 108:IDepositHandler.sol
pragma solidity ^0.8.0;
import "../deposit/DepositUtils.sol";
import "../oracle/OracleUtils.sol";
interface IDepositHandler {
function createDeposit(address account, DepositUtils.CreateDepositParams calldata params) external returns (bytes32);
function cancelDeposit(bytes32 key) external;
function simulateExecuteDeposit(
bytes32 key,
OracleUtils.SimulatePricesParams memory params
) external;
}
文件 41 的 108:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 42 的 108:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 43 的 108:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 44 的 108:IExchangeRouter.sol
pragma solidity ^0.8.0;
import "../deposit/DepositUtils.sol";
import "../withdrawal/WithdrawalUtils.sol";
import "../oracle/OracleUtils.sol";
import "../shift/ShiftUtils.sol";
import "../order/IBaseOrderUtils.sol";
interface IExchangeRouter {
function createDeposit(
DepositUtils.CreateDepositParams calldata params
) external payable returns (bytes32);
function cancelDeposit(bytes32 key) external payable;
function createWithdrawal(
WithdrawalUtils.CreateWithdrawalParams calldata params
) external payable returns (bytes32);
function cancelWithdrawal(bytes32 key) external payable;
function executeAtomicWithdrawal(
WithdrawalUtils.CreateWithdrawalParams calldata params,
OracleUtils.SetPricesParams calldata oracleParams
) external payable;
function createShift(
ShiftUtils.CreateShiftParams calldata params
) external payable returns (bytes32);
function cancelShift(bytes32 key) external payable;
function createOrder(
IBaseOrderUtils.CreateOrderParams calldata params
) external payable returns (bytes32);
function updateOrder(
bytes32 key,
uint256 sizeDeltaUsd,
uint256 acceptablePrice,
uint256 triggerPrice,
uint256 minOutputAmount,
uint256 validFromTime,
bool autoCancel
) external payable;
function cancelOrder(bytes32 key) external payable;
}
文件 45 的 108:IExternalHandler.sol
pragma solidity ^0.8.0;
interface IExternalHandler {
function makeExternalCalls(
address[] memory targets,
bytes[] memory dataList,
address[] memory refundTokens,
address[] memory refundReceivers
) external;
}
文件 46 的 108:IGasFeeCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
interface IGasFeeCallbackReceiver {
function refundExecutionFee(bytes32 key, EventUtils.EventLogData memory eventData) external payable;
}
文件 47 的 108:IGlvDepositCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
import "../glv/glvDeposit/GlvDeposit.sol";
interface IGlvDepositCallbackReceiver {
function afterGlvDepositExecution(
bytes32 key,
GlvDeposit.Props memory glvDeposit,
EventUtils.EventLogData memory eventData
) external;
function afterGlvDepositCancellation(
bytes32 key,
GlvDeposit.Props memory glvDeposit,
EventUtils.EventLogData memory eventData
) external;
}
文件 48 的 108:IGlvWithdrawalCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
import "../glv/glvWithdrawal/GlvWithdrawal.sol";
interface IGlvWithdrawalCallbackReceiver {
function afterGlvWithdrawalExecution(
bytes32 key,
GlvWithdrawal.Props memory glvWithdrawal,
EventUtils.EventLogData memory eventData
) external;
function afterGlvWithdrawalCancellation(
bytes32 key,
GlvWithdrawal.Props memory glvWithdrawal,
EventUtils.EventLogData memory eventData
) external;
}
文件 49 的 108:IOracleProvider.sol
pragma solidity ^0.8.0;
import "./OracleUtils.sol";
interface IOracleProvider {
function getOraclePrice(
address token,
bytes memory data
) external returns (OracleUtils.ValidatedPrice memory);
}
文件 50 的 108:IOrderCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
import "../order/Order.sol";
interface IOrderCallbackReceiver {
function afterOrderExecution(bytes32 key, Order.Props memory order, EventUtils.EventLogData memory eventData) external;
function afterOrderCancellation(bytes32 key, Order.Props memory order, EventUtils.EventLogData memory eventData) external;
function afterOrderFrozen(bytes32 key, Order.Props memory order, EventUtils.EventLogData memory eventData) external;
}
文件 51 的 108:IOrderHandler.sol
pragma solidity ^0.8.0;
import "../order/IBaseOrderUtils.sol";
import "../oracle/OracleUtils.sol";
interface IOrderHandler {
function createOrder(address account, IBaseOrderUtils.CreateOrderParams calldata params) external returns (bytes32);
function simulateExecuteOrder(bytes32 key, OracleUtils.SimulatePricesParams memory params) external;
function updateOrder(
bytes32 key,
uint256 sizeDeltaUsd,
uint256 acceptablePrice,
uint256 triggerPrice,
uint256 minOutputAmount,
uint256 validFromTime,
bool autoCancel,
Order.Props memory order
) external;
function cancelOrder(bytes32 key) external;
}
文件 52 的 108:IPriceFeed.sol
pragma solidity ^0.8.0;
interface IPriceFeed {
function latestRoundData() external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 53 的 108:IReferralStorage.sol
pragma solidity ^0.8.0;
interface IReferralStorage {
function codeOwners(bytes32 _code) external view returns (address);
function traderReferralCodes(address _account) external view returns (bytes32);
function referrerDiscountShares(address _account) external view returns (uint256);
function referrerTiers(address _account) external view returns (uint256);
function getTraderReferralInfo(address _account) external view returns (bytes32, address);
function setTraderReferralCode(address _account, bytes32 _code) external;
function setTier(uint256 _tierId, uint256 _totalRebate, uint256 _discountShare) external;
function setReferrerTier(address _referrer, uint256 _tierId) external;
function govSetCodeOwner(bytes32 _code, address _newAccount) external;
function tiers(uint256 _tierLevel) external view returns (uint256, uint256);
}
文件 54 的 108:IShiftCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
import "../shift/Shift.sol";
interface IShiftCallbackReceiver {
function afterShiftExecution(bytes32 key, Shift.Props memory shift, EventUtils.EventLogData memory eventData) external;
function afterShiftCancellation(bytes32 key, Shift.Props memory shift, EventUtils.EventLogData memory eventData) external;
}
文件 55 的 108:IShiftHandler.sol
pragma solidity ^0.8.0;
import "../shift/ShiftUtils.sol";
import "../oracle/OracleUtils.sol";
interface IShiftHandler {
function createShift(address account, ShiftUtils.CreateShiftParams calldata params) external returns (bytes32);
function cancelShift(bytes32 key) external;
function simulateExecuteShift(bytes32 key, OracleUtils.SimulatePricesParams memory params) external;
}
文件 56 的 108:ISwapPricingUtils.sol
pragma solidity ^0.8.0;
interface ISwapPricingUtils {
enum SwapPricingType {
Swap,
Shift,
Atomic,
Deposit,
Withdrawal
}
}
文件 57 的 108:IWNT.sol
pragma solidity ^0.8.0;
interface IWNT {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
文件 58 的 108:IWithdrawalCallbackReceiver.sol
pragma solidity ^0.8.0;
import "../event/EventUtils.sol";
import "../withdrawal/Withdrawal.sol";
interface IWithdrawalCallbackReceiver {
function afterWithdrawalExecution(bytes32 key, Withdrawal.Props memory withdrawal, EventUtils.EventLogData memory eventData) external;
function afterWithdrawalCancellation(bytes32 key, Withdrawal.Props memory withdrawal, EventUtils.EventLogData memory eventData) external;
}
文件 59 的 108:IWithdrawalHandler.sol
pragma solidity ^0.8.0;
import "../withdrawal/WithdrawalUtils.sol";
import "../oracle/OracleUtils.sol";
import "../pricing/ISwapPricingUtils.sol";
interface IWithdrawalHandler {
function createWithdrawal(address account, WithdrawalUtils.CreateWithdrawalParams calldata params) external returns (bytes32);
function cancelWithdrawal(bytes32 key) external;
function executeAtomicWithdrawal(
address account,
WithdrawalUtils.CreateWithdrawalParams calldata params,
OracleUtils.SetPricesParams calldata oracleParams
) external;
function simulateExecuteWithdrawal(
bytes32 key,
OracleUtils.SimulatePricesParams memory params,
ISwapPricingUtils.SwapPricingType swapPricingType
) external;
}
文件 60 的 108:Keys.sol
pragma solidity ^0.8.0;
library Keys {
bytes32 public constant WNT = keccak256(abi.encode("WNT"));
bytes32 public constant NONCE = keccak256(abi.encode("NONCE"));
bytes32 public constant FEE_RECEIVER = keccak256(abi.encode("FEE_RECEIVER"));
bytes32 public constant HOLDING_ADDRESS = keccak256(abi.encode("HOLDING_ADDRESS"));
bytes32 public constant MIN_HANDLE_EXECUTION_ERROR_GAS = keccak256(abi.encode("MIN_HANDLE_EXECUTION_ERROR_GAS"));
bytes32 public constant MIN_HANDLE_EXECUTION_ERROR_GAS_TO_FORWARD = keccak256(abi.encode("MIN_HANDLE_EXECUTION_ERROR_GAS_TO_FORWARD"));
bytes32 public constant MIN_ADDITIONAL_GAS_FOR_EXECUTION = keccak256(abi.encode("MIN_ADDITIONAL_GAS_FOR_EXECUTION"));
bytes32 public constant REENTRANCY_GUARD_STATUS = keccak256(abi.encode("REENTRANCY_GUARD_STATUS"));
bytes32 public constant DEPOSIT_FEE_TYPE = keccak256(abi.encode("DEPOSIT_FEE_TYPE"));
bytes32 public constant WITHDRAWAL_FEE_TYPE = keccak256(abi.encode("WITHDRAWAL_FEE_TYPE"));
bytes32 public constant SWAP_FEE_TYPE = keccak256(abi.encode("SWAP_FEE_TYPE"));
bytes32 public constant POSITION_FEE_TYPE = keccak256(abi.encode("POSITION_FEE_TYPE"));
bytes32 public constant UI_DEPOSIT_FEE_TYPE = keccak256(abi.encode("UI_DEPOSIT_FEE_TYPE"));
bytes32 public constant UI_WITHDRAWAL_FEE_TYPE = keccak256(abi.encode("UI_WITHDRAWAL_FEE_TYPE"));
bytes32 public constant UI_SWAP_FEE_TYPE = keccak256(abi.encode("UI_SWAP_FEE_TYPE"));
bytes32 public constant UI_POSITION_FEE_TYPE = keccak256(abi.encode("UI_POSITION_FEE_TYPE"));
bytes32 public constant UI_FEE_FACTOR = keccak256(abi.encode("UI_FEE_FACTOR"));
bytes32 public constant MAX_UI_FEE_FACTOR = keccak256(abi.encode("MAX_UI_FEE_FACTOR"));
bytes32 public constant CLAIMABLE_FEE_AMOUNT = keccak256(abi.encode("CLAIMABLE_FEE_AMOUNT"));
bytes32 public constant CLAIMABLE_UI_FEE_AMOUNT = keccak256(abi.encode("CLAIMABLE_UI_FEE_AMOUNT"));
bytes32 public constant MAX_AUTO_CANCEL_ORDERS = keccak256(abi.encode("MAX_AUTO_CANCEL_ORDERS"));
bytes32 public constant MAX_TOTAL_CALLBACK_GAS_LIMIT_FOR_AUTO_CANCEL_ORDERS = keccak256(abi.encode("MAX_TOTAL_CALLBACK_GAS_LIMIT_FOR_AUTO_CANCEL_ORDERS"));
bytes32 public constant MARKET_LIST = keccak256(abi.encode("MARKET_LIST"));
bytes32 public constant FEE_BATCH_LIST = keccak256(abi.encode("FEE_BATCH_LIST"));
bytes32 public constant DEPOSIT_LIST = keccak256(abi.encode("DEPOSIT_LIST"));
bytes32 public constant ACCOUNT_DEPOSIT_LIST = keccak256(abi.encode("ACCOUNT_DEPOSIT_LIST"));
bytes32 public constant WITHDRAWAL_LIST = keccak256(abi.encode("WITHDRAWAL_LIST"));
bytes32 public constant ACCOUNT_WITHDRAWAL_LIST = keccak256(abi.encode("ACCOUNT_WITHDRAWAL_LIST"));
bytes32 public constant SHIFT_LIST = keccak256(abi.encode("SHIFT_LIST"));
bytes32 public constant ACCOUNT_SHIFT_LIST = keccak256(abi.encode("ACCOUNT_SHIFT_LIST"));
bytes32 public constant GLV_LIST = keccak256(abi.encode("GLV_LIST"));
bytes32 public constant GLV_DEPOSIT_LIST = keccak256(abi.encode("GLV_DEPOSIT_LIST"));
bytes32 public constant GLV_SHIFT_LIST = keccak256(abi.encode("GLV_SHIFT_LIST"));
bytes32 public constant ACCOUNT_GLV_DEPOSIT_LIST = keccak256(abi.encode("ACCOUNT_GLV_DEPOSIT_LIST"));
bytes32 public constant GLV_WITHDRAWAL_LIST = keccak256(abi.encode("GLV_WITHDRAWAL_LIST"));
bytes32 public constant ACCOUNT_GLV_WITHDRAWAL_LIST = keccak256(abi.encode("ACCOUNT_GLV_WITHDRAWAL_LIST"));
bytes32 public constant GLV_SUPPORTED_MARKET_LIST = keccak256(abi.encode("GLV_SUPPORTED_MARKET_LIST"));
bytes32 public constant POSITION_LIST = keccak256(abi.encode("POSITION_LIST"));
bytes32 public constant ACCOUNT_POSITION_LIST = keccak256(abi.encode("ACCOUNT_POSITION_LIST"));
bytes32 public constant ORDER_LIST = keccak256(abi.encode("ORDER_LIST"));
bytes32 public constant ACCOUNT_ORDER_LIST = keccak256(abi.encode("ACCOUNT_ORDER_LIST"));
bytes32 public constant SUBACCOUNT_LIST = keccak256(abi.encode("SUBACCOUNT_LIST"));
bytes32 public constant AUTO_CANCEL_ORDER_LIST = keccak256(abi.encode("AUTO_CANCEL_ORDER_LIST"));
bytes32 public constant IS_MARKET_DISABLED = keccak256(abi.encode("IS_MARKET_DISABLED"));
bytes32 public constant MAX_SWAP_PATH_LENGTH = keccak256(abi.encode("MAX_SWAP_PATH_LENGTH"));
bytes32 public constant SWAP_PATH_MARKET_FLAG = keccak256(abi.encode("SWAP_PATH_MARKET_FLAG"));
bytes32 public constant MIN_MARKET_TOKENS_FOR_FIRST_DEPOSIT = keccak256(abi.encode("MIN_MARKET_TOKENS_FOR_FIRST_DEPOSIT"));
bytes32 public constant CREATE_GLV_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("CREATE_GLV_DEPOSIT_FEATURE_DISABLED"));
bytes32 public constant CANCEL_GLV_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("CANCEL_GLV_DEPOSIT_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_GLV_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_GLV_DEPOSIT_FEATURE_DISABLED"));
bytes32 public constant CREATE_GLV_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("CREATE_GLV_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant CANCEL_GLV_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("CANCEL_GLV_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_GLV_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_GLV_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant CREATE_GLV_SHIFT_FEATURE_DISABLED = keccak256(abi.encode("CREATE_GLV_SHIFT_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_GLV_SHIFT_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_GLV_SHIFT_FEATURE_DISABLED"));
bytes32 public constant CREATE_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("CREATE_DEPOSIT_FEATURE_DISABLED"));
bytes32 public constant CANCEL_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("CANCEL_DEPOSIT_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_DEPOSIT_FEATURE_DISABLED"));
bytes32 public constant CREATE_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("CREATE_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant CANCEL_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("CANCEL_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_ATOMIC_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_ATOMIC_WITHDRAWAL_FEATURE_DISABLED"));
bytes32 public constant CREATE_SHIFT_FEATURE_DISABLED = keccak256(abi.encode("CREATE_SHIFT_FEATURE_DISABLED"));
bytes32 public constant CANCEL_SHIFT_FEATURE_DISABLED = keccak256(abi.encode("CANCEL_SHIFT_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_SHIFT_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_SHIFT_FEATURE_DISABLED"));
bytes32 public constant CREATE_ORDER_FEATURE_DISABLED = keccak256(abi.encode("CREATE_ORDER_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_ORDER_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_ORDER_FEATURE_DISABLED"));
bytes32 public constant EXECUTE_ADL_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_ADL_FEATURE_DISABLED"));
bytes32 public constant UPDATE_ORDER_FEATURE_DISABLED = keccak256(abi.encode("UPDATE_ORDER_FEATURE_DISABLED"));
bytes32 public constant CANCEL_ORDER_FEATURE_DISABLED = keccak256(abi.encode("CANCEL_ORDER_FEATURE_DISABLED"));
bytes32 public constant CLAIM_FUNDING_FEES_FEATURE_DISABLED = keccak256(abi.encode("CLAIM_FUNDING_FEES_FEATURE_DISABLED"));
bytes32 public constant CLAIM_COLLATERAL_FEATURE_DISABLED = keccak256(abi.encode("CLAIM_COLLATERAL_FEATURE_DISABLED"));
bytes32 public constant CLAIM_AFFILIATE_REWARDS_FEATURE_DISABLED = keccak256(abi.encode("CLAIM_AFFILIATE_REWARDS_FEATURE_DISABLED"));
bytes32 public constant CLAIM_UI_FEES_FEATURE_DISABLED = keccak256(abi.encode("CLAIM_UI_FEES_FEATURE_DISABLED"));
bytes32 public constant SUBACCOUNT_FEATURE_DISABLED = keccak256(abi.encode("SUBACCOUNT_FEATURE_DISABLED"));
bytes32 public constant MIN_ORACLE_SIGNERS = keccak256(abi.encode("MIN_ORACLE_SIGNERS"));
bytes32 public constant MIN_ORACLE_BLOCK_CONFIRMATIONS = keccak256(abi.encode("MIN_ORACLE_BLOCK_CONFIRMATIONS"));
bytes32 public constant MAX_ORACLE_PRICE_AGE = keccak256(abi.encode("MAX_ORACLE_PRICE_AGE"));
bytes32 public constant MAX_ORACLE_TIMESTAMP_RANGE = keccak256(abi.encode("MAX_ORACLE_TIMESTAMP_RANGE"));
bytes32 public constant MAX_ORACLE_REF_PRICE_DEVIATION_FACTOR = keccak256(abi.encode("MAX_ORACLE_REF_PRICE_DEVIATION_FACTOR"));
bytes32 public constant IS_ORACLE_PROVIDER_ENABLED = keccak256(abi.encode("IS_ORACLE_PROVIDER_ENABLED"));
bytes32 public constant IS_ATOMIC_ORACLE_PROVIDER = keccak256(abi.encode("IS_ATOMIC_ORACLE_PROVIDER"));
bytes32 public constant ORACLE_TIMESTAMP_ADJUSTMENT = keccak256(abi.encode("ORACLE_TIMESTAMP_ADJUSTMENT"));
bytes32 public constant ORACLE_PROVIDER_FOR_TOKEN = keccak256(abi.encode("ORACLE_PROVIDER_FOR_TOKEN"));
bytes32 public constant CHAINLINK_PAYMENT_TOKEN = keccak256(abi.encode("CHAINLINK_PAYMENT_TOKEN"));
bytes32 public constant SEQUENCER_GRACE_DURATION = keccak256(abi.encode("SEQUENCER_GRACE_DURATION"));
bytes32 public constant POSITION_FEE_RECEIVER_FACTOR = keccak256(abi.encode("POSITION_FEE_RECEIVER_FACTOR"));
bytes32 public constant LIQUIDATION_FEE_RECEIVER_FACTOR = keccak256(abi.encode("LIQUIDATION_FEE_RECEIVER_FACTOR"));
bytes32 public constant SWAP_FEE_RECEIVER_FACTOR = keccak256(abi.encode("SWAP_FEE_RECEIVER_FACTOR"));
bytes32 public constant BORROWING_FEE_RECEIVER_FACTOR = keccak256(abi.encode("BORROWING_FEE_RECEIVER_FACTOR"));
bytes32 public constant ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1 = keccak256(abi.encode("ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1"));
bytes32 public constant ESTIMATED_GAS_FEE_PER_ORACLE_PRICE = keccak256(abi.encode("ESTIMATED_GAS_FEE_PER_ORACLE_PRICE"));
bytes32 public constant ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR = keccak256(abi.encode("ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR"));
bytes32 public constant EXECUTION_GAS_FEE_BASE_AMOUNT_V2_1 = keccak256(abi.encode("EXECUTION_GAS_FEE_BASE_AMOUNT_V2_1"));
bytes32 public constant EXECUTION_GAS_FEE_PER_ORACLE_PRICE = keccak256(abi.encode("EXECUTION_GAS_FEE_PER_ORACLE_PRICE"));
bytes32 public constant EXECUTION_GAS_FEE_MULTIPLIER_FACTOR = keccak256(abi.encode("EXECUTION_GAS_FEE_MULTIPLIER_FACTOR"));
bytes32 public constant DEPOSIT_GAS_LIMIT = keccak256(abi.encode("DEPOSIT_GAS_LIMIT"));
bytes32 public constant WITHDRAWAL_GAS_LIMIT = keccak256(abi.encode("WITHDRAWAL_GAS_LIMIT"));
bytes32 public constant GLV_DEPOSIT_GAS_LIMIT = keccak256(abi.encode("GLV_DEPOSIT_GAS_LIMIT"));
bytes32 public constant GLV_WITHDRAWAL_GAS_LIMIT = keccak256(abi.encode("GLV_WITHDRAWAL_GAS_LIMIT"));
bytes32 public constant GLV_SHIFT_GAS_LIMIT = keccak256(abi.encode("GLV_SHIFT_GAS_LIMIT"));
bytes32 public constant GLV_PER_MARKET_GAS_LIMIT = keccak256(abi.encode("GLV_PER_MARKET_GAS_LIMIT"));
bytes32 public constant SHIFT_GAS_LIMIT = keccak256(abi.encode("SHIFT_GAS_LIMIT"));
bytes32 public constant SINGLE_SWAP_GAS_LIMIT = keccak256(abi.encode("SINGLE_SWAP_GAS_LIMIT"));
bytes32 public constant INCREASE_ORDER_GAS_LIMIT = keccak256(abi.encode("INCREASE_ORDER_GAS_LIMIT"));
bytes32 public constant DECREASE_ORDER_GAS_LIMIT = keccak256(abi.encode("DECREASE_ORDER_GAS_LIMIT"));
bytes32 public constant SWAP_ORDER_GAS_LIMIT = keccak256(abi.encode("SWAP_ORDER_GAS_LIMIT"));
bytes32 public constant TOKEN_TRANSFER_GAS_LIMIT = keccak256(abi.encode("TOKEN_TRANSFER_GAS_LIMIT"));
bytes32 public constant NATIVE_TOKEN_TRANSFER_GAS_LIMIT = keccak256(abi.encode("NATIVE_TOKEN_TRANSFER_GAS_LIMIT"));
bytes32 public constant REQUEST_EXPIRATION_TIME = keccak256(abi.encode("REQUEST_EXPIRATION_TIME"));
bytes32 public constant MAX_CALLBACK_GAS_LIMIT = keccak256(abi.encode("MAX_CALLBACK_GAS_LIMIT"));
bytes32 public constant REFUND_EXECUTION_FEE_GAS_LIMIT = keccak256(abi.encode("REFUND_EXECUTION_FEE_GAS_LIMIT"));
bytes32 public constant SAVED_CALLBACK_CONTRACT = keccak256(abi.encode("SAVED_CALLBACK_CONTRACT"));
bytes32 public constant MIN_COLLATERAL_FACTOR = keccak256(abi.encode("MIN_COLLATERAL_FACTOR"));
bytes32 public constant MIN_COLLATERAL_FACTOR_FOR_OPEN_INTEREST_MULTIPLIER = keccak256(abi.encode("MIN_COLLATERAL_FACTOR_FOR_OPEN_INTEREST_MULTIPLIER"));
bytes32 public constant MIN_COLLATERAL_USD = keccak256(abi.encode("MIN_COLLATERAL_USD"));
bytes32 public constant MIN_POSITION_SIZE_USD = keccak256(abi.encode("MIN_POSITION_SIZE_USD"));
bytes32 public constant VIRTUAL_TOKEN_ID = keccak256(abi.encode("VIRTUAL_TOKEN_ID"));
bytes32 public constant VIRTUAL_MARKET_ID = keccak256(abi.encode("VIRTUAL_MARKET_ID"));
bytes32 public constant VIRTUAL_INVENTORY_FOR_SWAPS = keccak256(abi.encode("VIRTUAL_INVENTORY_FOR_SWAPS"));
bytes32 public constant VIRTUAL_INVENTORY_FOR_POSITIONS = keccak256(abi.encode("VIRTUAL_INVENTORY_FOR_POSITIONS"));
bytes32 public constant POSITION_IMPACT_FACTOR = keccak256(abi.encode("POSITION_IMPACT_FACTOR"));
bytes32 public constant POSITION_IMPACT_EXPONENT_FACTOR = keccak256(abi.encode("POSITION_IMPACT_EXPONENT_FACTOR"));
bytes32 public constant MAX_POSITION_IMPACT_FACTOR = keccak256(abi.encode("MAX_POSITION_IMPACT_FACTOR"));
bytes32 public constant MAX_POSITION_IMPACT_FACTOR_FOR_LIQUIDATIONS = keccak256(abi.encode("MAX_POSITION_IMPACT_FACTOR_FOR_LIQUIDATIONS"));
bytes32 public constant POSITION_FEE_FACTOR = keccak256(abi.encode("POSITION_FEE_FACTOR"));
bytes32 public constant PRO_TRADER_TIER = keccak256(abi.encode("PRO_TRADER_TIER"));
bytes32 public constant PRO_DISCOUNT_FACTOR = keccak256(abi.encode("PRO_DISCOUNT_FACTOR"));
bytes32 public constant LIQUIDATION_FEE_FACTOR = keccak256(abi.encode("LIQUIDATION_FEE_FACTOR"));
bytes32 public constant SWAP_IMPACT_FACTOR = keccak256(abi.encode("SWAP_IMPACT_FACTOR"));
bytes32 public constant SWAP_IMPACT_EXPONENT_FACTOR = keccak256(abi.encode("SWAP_IMPACT_EXPONENT_FACTOR"));
bytes32 public constant SWAP_FEE_FACTOR = keccak256(abi.encode("SWAP_FEE_FACTOR"));
bytes32 public constant ATOMIC_SWAP_FEE_FACTOR = keccak256(abi.encode("ATOMIC_SWAP_FEE_FACTOR"));
bytes32 public constant DEPOSIT_FEE_FACTOR = keccak256(abi.encode("DEPOSIT_FEE_FACTOR"));
bytes32 public constant WITHDRAWAL_FEE_FACTOR = keccak256(abi.encode("WITHDRAWAL_FEE_FACTOR"));
bytes32 public constant ORACLE_TYPE = keccak256(abi.encode("ORACLE_TYPE"));
bytes32 public constant OPEN_INTEREST = keccak256(abi.encode("OPEN_INTEREST"));
bytes32 public constant OPEN_INTEREST_IN_TOKENS = keccak256(abi.encode("OPEN_INTEREST_IN_TOKENS"));
bytes32 public constant COLLATERAL_SUM = keccak256(abi.encode("COLLATERAL_SUM"));
bytes32 public constant POOL_AMOUNT = keccak256(abi.encode("POOL_AMOUNT"));
bytes32 public constant MAX_POOL_AMOUNT = keccak256(abi.encode("MAX_POOL_AMOUNT"));
bytes32 public constant MAX_POOL_USD_FOR_DEPOSIT = keccak256(abi.encode("MAX_POOL_USD_FOR_DEPOSIT"));
bytes32 public constant MAX_OPEN_INTEREST = keccak256(abi.encode("MAX_OPEN_INTEREST"));
bytes32 public constant POSITION_IMPACT_POOL_AMOUNT = keccak256(abi.encode("POSITION_IMPACT_POOL_AMOUNT"));
bytes32 public constant MIN_POSITION_IMPACT_POOL_AMOUNT = keccak256(abi.encode("MIN_POSITION_IMPACT_POOL_AMOUNT"));
bytes32 public constant POSITION_IMPACT_POOL_DISTRIBUTION_RATE = keccak256(abi.encode("POSITION_IMPACT_POOL_DISTRIBUTION_RATE"));
bytes32 public constant POSITION_IMPACT_POOL_DISTRIBUTED_AT = keccak256(abi.encode("POSITION_IMPACT_POOL_DISTRIBUTED_AT"));
bytes32 public constant SWAP_IMPACT_POOL_AMOUNT = keccak256(abi.encode("SWAP_IMPACT_POOL_AMOUNT"));
bytes32 public constant PRICE_FEED = keccak256(abi.encode("PRICE_FEED"));
bytes32 public constant PRICE_FEED_MULTIPLIER = keccak256(abi.encode("PRICE_FEED_MULTIPLIER"));
bytes32 public constant PRICE_FEED_HEARTBEAT_DURATION = keccak256(abi.encode("PRICE_FEED_HEARTBEAT_DURATION"));
bytes32 public constant DATA_STREAM_ID = keccak256(abi.encode("DATA_STREAM_ID"));
bytes32 public constant DATA_STREAM_MULTIPLIER = keccak256(abi.encode("DATA_STREAM_MULTIPLIER"));
bytes32 public constant STABLE_PRICE = keccak256(abi.encode("STABLE_PRICE"));
bytes32 public constant RESERVE_FACTOR = keccak256(abi.encode("RESERVE_FACTOR"));
bytes32 public constant OPEN_INTEREST_RESERVE_FACTOR = keccak256(abi.encode("OPEN_INTEREST_RESERVE_FACTOR"));
bytes32 public constant MAX_PNL_FACTOR = keccak256(abi.encode("MAX_PNL_FACTOR"));
bytes32 public constant MAX_PNL_FACTOR_FOR_TRADERS = keccak256(abi.encode("MAX_PNL_FACTOR_FOR_TRADERS"));
bytes32 public constant MAX_PNL_FACTOR_FOR_ADL = keccak256(abi.encode("MAX_PNL_FACTOR_FOR_ADL"));
bytes32 public constant MIN_PNL_FACTOR_AFTER_ADL = keccak256(abi.encode("MIN_PNL_FACTOR_AFTER_ADL"));
bytes32 public constant MAX_PNL_FACTOR_FOR_DEPOSITS = keccak256(abi.encode("MAX_PNL_FACTOR_FOR_DEPOSITS"));
bytes32 public constant MAX_PNL_FACTOR_FOR_WITHDRAWALS = keccak256(abi.encode("MAX_PNL_FACTOR_FOR_WITHDRAWALS"));
bytes32 public constant LATEST_ADL_AT = keccak256(abi.encode("LATEST_ADL_AT"));
bytes32 public constant IS_ADL_ENABLED = keccak256(abi.encode("IS_ADL_ENABLED"));
bytes32 public constant FUNDING_FACTOR = keccak256(abi.encode("FUNDING_FACTOR"));
bytes32 public constant FUNDING_EXPONENT_FACTOR = keccak256(abi.encode("FUNDING_EXPONENT_FACTOR"));
bytes32 public constant SAVED_FUNDING_FACTOR_PER_SECOND = keccak256(abi.encode("SAVED_FUNDING_FACTOR_PER_SECOND"));
bytes32 public constant FUNDING_INCREASE_FACTOR_PER_SECOND = keccak256(abi.encode("FUNDING_INCREASE_FACTOR_PER_SECOND"));
bytes32 public constant FUNDING_DECREASE_FACTOR_PER_SECOND = keccak256(abi.encode("FUNDING_DECREASE_FACTOR_PER_SECOND"));
bytes32 public constant MIN_FUNDING_FACTOR_PER_SECOND = keccak256(abi.encode("MIN_FUNDING_FACTOR_PER_SECOND"));
bytes32 public constant MAX_FUNDING_FACTOR_PER_SECOND = keccak256(abi.encode("MAX_FUNDING_FACTOR_PER_SECOND"));
bytes32 public constant THRESHOLD_FOR_STABLE_FUNDING = keccak256(abi.encode("THRESHOLD_FOR_STABLE_FUNDING"));
bytes32 public constant THRESHOLD_FOR_DECREASE_FUNDING = keccak256(abi.encode("THRESHOLD_FOR_DECREASE_FUNDING"));
bytes32 public constant FUNDING_FEE_AMOUNT_PER_SIZE = keccak256(abi.encode("FUNDING_FEE_AMOUNT_PER_SIZE"));
bytes32 public constant CLAIMABLE_FUNDING_AMOUNT_PER_SIZE = keccak256(abi.encode("CLAIMABLE_FUNDING_AMOUNT_PER_SIZE"));
bytes32 public constant FUNDING_UPDATED_AT = keccak256(abi.encode("FUNDING_UPDATED_AT"));
bytes32 public constant CLAIMABLE_FUNDING_AMOUNT = keccak256(abi.encode("CLAIMABLE_FUNDING_AMOUNT"));
bytes32 public constant CLAIMABLE_COLLATERAL_AMOUNT = keccak256(abi.encode("CLAIMABLE_COLLATERAL_AMOUNT"));
bytes32 public constant CLAIMABLE_COLLATERAL_FACTOR = keccak256(abi.encode("CLAIMABLE_COLLATERAL_FACTOR"));
bytes32 public constant CLAIMABLE_COLLATERAL_TIME_DIVISOR = keccak256(abi.encode("CLAIMABLE_COLLATERAL_TIME_DIVISOR"));
bytes32 public constant CLAIMED_COLLATERAL_AMOUNT = keccak256(abi.encode("CLAIMED_COLLATERAL_AMOUNT"));
bytes32 public constant IGNORE_OPEN_INTEREST_FOR_USAGE_FACTOR = keccak256(abi.encode("IGNORE_OPEN_INTEREST_FOR_USAGE_FACTOR"));
bytes32 public constant OPTIMAL_USAGE_FACTOR = keccak256(abi.encode("OPTIMAL_USAGE_FACTOR"));
bytes32 public constant BASE_BORROWING_FACTOR = keccak256(abi.encode("BASE_BORROWING_FACTOR"));
bytes32 public constant ABOVE_OPTIMAL_USAGE_BORROWING_FACTOR = keccak256(abi.encode("ABOVE_OPTIMAL_USAGE_BORROWING_FACTOR"));
bytes32 public constant BORROWING_FACTOR = keccak256(abi.encode("BORROWING_FACTOR"));
bytes32 public constant BORROWING_EXPONENT_FACTOR = keccak256(abi.encode("BORROWING_EXPONENT_FACTOR"));
bytes32 public constant SKIP_BORROWING_FEE_FOR_SMALLER_SIDE = keccak256(abi.encode("SKIP_BORROWING_FEE_FOR_SMALLER_SIDE"));
bytes32 public constant CUMULATIVE_BORROWING_FACTOR = keccak256(abi.encode("CUMULATIVE_BORROWING_FACTOR"));
bytes32 public constant CUMULATIVE_BORROWING_FACTOR_UPDATED_AT = keccak256(abi.encode("CUMULATIVE_BORROWING_FACTOR_UPDATED_AT"));
bytes32 public constant TOTAL_BORROWING = keccak256(abi.encode("TOTAL_BORROWING"));
bytes32 public constant MIN_AFFILIATE_REWARD_FACTOR = keccak256(abi.encode("MIN_AFFILIATE_REWARD_FACTOR"));
bytes32 public constant AFFILIATE_REWARD = keccak256(abi.encode("AFFILIATE_REWARD"));
bytes32 public constant MAX_ALLOWED_SUBACCOUNT_ACTION_COUNT = keccak256(abi.encode("MAX_ALLOWED_SUBACCOUNT_ACTION_COUNT"));
bytes32 public constant SUBACCOUNT_ACTION_COUNT = keccak256(abi.encode("SUBACCOUNT_ACTION_COUNT"));
bytes32 public constant SUBACCOUNT_AUTO_TOP_UP_AMOUNT = keccak256(abi.encode("SUBACCOUNT_AUTO_TOP_UP_AMOUNT"));
bytes32 public constant SUBACCOUNT_ORDER_ACTION = keccak256(abi.encode("SUBACCOUNT_ORDER_ACTION"));
bytes32 public constant FEE_DISTRIBUTOR_SWAP_TOKEN_INDEX = keccak256(abi.encode("FEE_DISTRIBUTOR_SWAP_TOKEN_INDEX"));
bytes32 public constant FEE_DISTRIBUTOR_SWAP_FEE_BATCH = keccak256(abi.encode("FEE_DISTRIBUTOR_SWAP_FEE_BATCH"));
bytes32 public constant GLV_MAX_MARKET_COUNT = keccak256(abi.encode("GLV_MAX_MARKET_COUNT"));
bytes32 public constant GLV_MAX_MARKET_TOKEN_BALANCE_USD = keccak256(abi.encode("GLV_MAX_MARKET_TOKEN_BALANCE_USD"));
bytes32 public constant GLV_MAX_MARKET_TOKEN_BALANCE_AMOUNT = keccak256(abi.encode("GLV_MAX_MARKET_TOKEN_BALANCE_AMOUNT"));
bytes32 public constant IS_GLV_MARKET_DISABLED = keccak256(abi.encode("IS_GLV_MARKET_DISABLED"));
bytes32 public constant GLV_SHIFT_MAX_PRICE_IMPACT_FACTOR = keccak256(abi.encode("GLV_SHIFT_MAX_PRICE_IMPACT_FACTOR"));
bytes32 public constant GLV_SHIFT_LAST_EXECUTED_AT = keccak256(abi.encode("GLV_SHIFT_LAST_EXECUTED_AT"));
bytes32 public constant GLV_SHIFT_MIN_INTERVAL = keccak256(abi.encode("GLV_SHIFT_MIN_INTERVAL"));
bytes32 public constant MIN_GLV_TOKENS_FOR_FIRST_DEPOSIT = keccak256(abi.encode("MIN_GLV_TOKENS_FOR_FIRST_DEPOSIT"));
bytes32 public constant SYNC_CONFIG_FEATURE_DISABLED = keccak256(abi.encode("SYNC_CONFIG_FEATURE_DISABLED"));
bytes32 public constant SYNC_CONFIG_MARKET_DISABLED = keccak256(abi.encode("SYNC_CONFIG_MARKET_DISABLED"));
bytes32 public constant SYNC_CONFIG_PARAMETER_DISABLED = keccak256(abi.encode("SYNC_CONFIG_PARAMETER_DISABLED"));
bytes32 public constant SYNC_CONFIG_MARKET_PARAMETER_DISABLED = keccak256(abi.encode("SYNC_CONFIG_MARKET_PARAMETER_DISABLED"));
bytes32 public constant SYNC_CONFIG_UPDATE_COMPLETED = keccak256(abi.encode("SYNC_CONFIG_UPDATE_COMPLETED"));
bytes32 public constant SYNC_CONFIG_LATEST_UPDATE_ID = keccak256(abi.encode("SYNC_CONFIG_LATEST_UPDATE_ID"));
bytes32 public constant CONTRIBUTOR_ACCOUNT_LIST = keccak256(abi.encode("CONTRIBUTOR_ACCOUNT_LIST"));
bytes32 public constant CONTRIBUTOR_TOKEN_LIST = keccak256(abi.encode("CONTRIBUTOR_TOKEN_LIST"));
bytes32 public constant CONTRIBUTOR_TOKEN_AMOUNT = keccak256(abi.encode("CONTRIBUTOR_TOKEN_AMOUNT"));
bytes32 public constant MAX_TOTAL_CONTRIBUTOR_TOKEN_AMOUNT = keccak256(abi.encode("MAX_TOTAL_CONTRIBUTOR_TOKEN_AMOUNT"));
bytes32 public constant CONTRIBUTOR_TOKEN_VAULT = keccak256(abi.encode("CONTRIBUTOR_TOKEN_VAULT"));
bytes32 public constant CONTRIBUTOR_LAST_PAYMENT_AT = keccak256(abi.encode("CONTRIBUTOR_LAST_PAYMENT_AT"));
bytes32 public constant MIN_CONTRIBUTOR_PAYMENT_INTERVAL = keccak256(abi.encode("MIN_CONTRIBUTOR_PAYMENT_INTERVAL"));
bytes32 public constant BUYBACK_BATCH_AMOUNT = keccak256(abi.encode("BUYBACK_BATCH_AMOUNT"));
bytes32 public constant BUYBACK_AVAILABLE_FEE_AMOUNT = keccak256(abi.encode("BUYBACK_AVAILABLE_FEE_AMOUNT"));
bytes32 public constant BUYBACK_GMX_FACTOR = keccak256(abi.encode("BUYBACK_GMX_FACTOR"));
bytes32 public constant BUYBACK_MAX_PRICE_IMPACT_FACTOR = keccak256(abi.encode("BUYBACK_MAX_PRICE_IMPACT_FACTOR"));
bytes32 public constant BUYBACK_MAX_PRICE_AGE = keccak256(abi.encode("BUYBACK_MAX_PRICE_AGE"));
bytes32 public constant WITHDRAWABLE_BUYBACK_TOKEN_AMOUNT = keccak256(abi.encode("WITHDRAWABLE_BUYBACK_TOKEN_AMOUNT"));
string public constant USER_INITIATED_CANCEL = "USER_INITIATED_CANCEL";
function getFullKey(bytes32 baseKey, bytes memory data) internal pure returns (bytes32) {
if (data.length == 0) {
return baseKey;
}
return keccak256(bytes.concat(baseKey, data));
}
function accountDepositListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_DEPOSIT_LIST, account));
}
function accountWithdrawalListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_WITHDRAWAL_LIST, account));
}
function accountShiftListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_SHIFT_LIST, account));
}
function accountGlvDepositListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_GLV_DEPOSIT_LIST, account));
}
function accountGlvWithdrawalListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_GLV_WITHDRAWAL_LIST, account));
}
function glvSupportedMarketListKey(address glv) internal pure returns (bytes32) {
return keccak256(abi.encode(GLV_SUPPORTED_MARKET_LIST, glv));
}
function accountPositionListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_POSITION_LIST, account));
}
function accountOrderListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(ACCOUNT_ORDER_LIST, account));
}
function subaccountListKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(SUBACCOUNT_LIST, account));
}
function autoCancelOrderListKey(bytes32 positionKey) internal pure returns (bytes32) {
return keccak256(abi.encode(AUTO_CANCEL_ORDER_LIST, positionKey));
}
function claimableFeeAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(CLAIMABLE_FEE_AMOUNT, market, token));
}
function claimableUiFeeAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(CLAIMABLE_UI_FEE_AMOUNT, market, token));
}
function claimableUiFeeAmountKey(address market, address token, address account) internal pure returns (bytes32) {
return keccak256(abi.encode(CLAIMABLE_UI_FEE_AMOUNT, market, token, account));
}
function depositGasLimitKey() internal pure returns (bytes32) {
return DEPOSIT_GAS_LIMIT;
}
function withdrawalGasLimitKey() internal pure returns (bytes32) {
return WITHDRAWAL_GAS_LIMIT;
}
function shiftGasLimitKey() internal pure returns (bytes32) {
return SHIFT_GAS_LIMIT;
}
function glvDepositGasLimitKey() internal pure returns (bytes32) {
return GLV_DEPOSIT_GAS_LIMIT;
}
function glvWithdrawalGasLimitKey() internal pure returns (bytes32) {
return GLV_WITHDRAWAL_GAS_LIMIT;
}
function glvShiftGasLimitKey() internal pure returns (bytes32) {
return GLV_SHIFT_GAS_LIMIT;
}
function glvPerMarketGasLimitKey() internal pure returns (bytes32) {
return GLV_PER_MARKET_GAS_LIMIT;
}
function singleSwapGasLimitKey() internal pure returns (bytes32) {
return SINGLE_SWAP_GAS_LIMIT;
}
function increaseOrderGasLimitKey() internal pure returns (bytes32) {
return INCREASE_ORDER_GAS_LIMIT;
}
function decreaseOrderGasLimitKey() internal pure returns (bytes32) {
return DECREASE_ORDER_GAS_LIMIT;
}
function swapOrderGasLimitKey() internal pure returns (bytes32) {
return SWAP_ORDER_GAS_LIMIT;
}
function swapPathMarketFlagKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
SWAP_PATH_MARKET_FLAG,
market
));
}
function createGlvDepositFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_GLV_DEPOSIT_FEATURE_DISABLED,
module
));
}
function cancelGlvDepositFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CANCEL_GLV_DEPOSIT_FEATURE_DISABLED,
module
));
}
function executeGlvDepositFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_GLV_DEPOSIT_FEATURE_DISABLED,
module
));
}
function createGlvWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_GLV_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function cancelGlvWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CANCEL_GLV_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function executeGlvWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_GLV_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function createGlvShiftFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_GLV_SHIFT_FEATURE_DISABLED,
module
));
}
function executeGlvShiftFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_GLV_SHIFT_FEATURE_DISABLED,
module
));
}
function createDepositFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_DEPOSIT_FEATURE_DISABLED,
module
));
}
function cancelDepositFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CANCEL_DEPOSIT_FEATURE_DISABLED,
module
));
}
function executeDepositFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_DEPOSIT_FEATURE_DISABLED,
module
));
}
function createWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function cancelWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CANCEL_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function executeWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function executeAtomicWithdrawalFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_ATOMIC_WITHDRAWAL_FEATURE_DISABLED,
module
));
}
function createShiftFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_SHIFT_FEATURE_DISABLED,
module
));
}
function cancelShiftFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CANCEL_SHIFT_FEATURE_DISABLED,
module
));
}
function executeShiftFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_SHIFT_FEATURE_DISABLED,
module
));
}
function createOrderFeatureDisabledKey(address module, uint256 orderType) internal pure returns (bytes32) {
return keccak256(abi.encode(
CREATE_ORDER_FEATURE_DISABLED,
module,
orderType
));
}
function executeOrderFeatureDisabledKey(address module, uint256 orderType) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_ORDER_FEATURE_DISABLED,
module,
orderType
));
}
function executeAdlFeatureDisabledKey(address module, uint256 orderType) internal pure returns (bytes32) {
return keccak256(abi.encode(
EXECUTE_ADL_FEATURE_DISABLED,
module,
orderType
));
}
function updateOrderFeatureDisabledKey(address module, uint256 orderType) internal pure returns (bytes32) {
return keccak256(abi.encode(
UPDATE_ORDER_FEATURE_DISABLED,
module,
orderType
));
}
function cancelOrderFeatureDisabledKey(address module, uint256 orderType) internal pure returns (bytes32) {
return keccak256(abi.encode(
CANCEL_ORDER_FEATURE_DISABLED,
module,
orderType
));
}
function claimFundingFeesFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIM_FUNDING_FEES_FEATURE_DISABLED,
module
));
}
function claimCollateralFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIM_COLLATERAL_FEATURE_DISABLED,
module
));
}
function claimAffiliateRewardsFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIM_AFFILIATE_REWARDS_FEATURE_DISABLED,
module
));
}
function claimUiFeesFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIM_UI_FEES_FEATURE_DISABLED,
module
));
}
function subaccountFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
SUBACCOUNT_FEATURE_DISABLED,
module
));
}
function uiFeeFactorKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
UI_FEE_FACTOR,
account
));
}
function isOracleProviderEnabledKey(address provider) internal pure returns (bytes32) {
return keccak256(abi.encode(
IS_ORACLE_PROVIDER_ENABLED,
provider
));
}
function isAtomicOracleProviderKey(address provider) internal pure returns (bytes32) {
return keccak256(abi.encode(
IS_ATOMIC_ORACLE_PROVIDER,
provider
));
}
function oracleTimestampAdjustmentKey(address provider, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
ORACLE_TIMESTAMP_ADJUSTMENT,
provider,
token
));
}
function oracleProviderForTokenKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
ORACLE_PROVIDER_FOR_TOKEN,
token
));
}
function tokenTransferGasLimit(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
TOKEN_TRANSFER_GAS_LIMIT,
token
));
}
function savedCallbackContract(address account, address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
SAVED_CALLBACK_CONTRACT,
account,
market
));
}
function minCollateralFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_COLLATERAL_FACTOR,
market
));
}
function minCollateralFactorForOpenInterestMultiplierKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_COLLATERAL_FACTOR_FOR_OPEN_INTEREST_MULTIPLIER,
market,
isLong
));
}
function virtualTokenIdKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
VIRTUAL_TOKEN_ID,
token
));
}
function virtualMarketIdKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
VIRTUAL_MARKET_ID,
market
));
}
function virtualInventoryForPositionsKey(bytes32 virtualTokenId) internal pure returns (bytes32) {
return keccak256(abi.encode(
VIRTUAL_INVENTORY_FOR_POSITIONS,
virtualTokenId
));
}
function virtualInventoryForSwapsKey(bytes32 virtualMarketId, bool isLongToken) internal pure returns (bytes32) {
return keccak256(abi.encode(
VIRTUAL_INVENTORY_FOR_SWAPS,
virtualMarketId,
isLongToken
));
}
function positionImpactFactorKey(address market, bool isPositive) internal pure returns (bytes32) {
return keccak256(abi.encode(
POSITION_IMPACT_FACTOR,
market,
isPositive
));
}
function positionImpactExponentFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
POSITION_IMPACT_EXPONENT_FACTOR,
market
));
}
function maxPositionImpactFactorKey(address market, bool isPositive) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_POSITION_IMPACT_FACTOR,
market,
isPositive
));
}
function maxPositionImpactFactorForLiquidationsKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_POSITION_IMPACT_FACTOR_FOR_LIQUIDATIONS,
market
));
}
function positionFeeFactorKey(address market, bool forPositiveImpact) internal pure returns (bytes32) {
return keccak256(abi.encode(
POSITION_FEE_FACTOR,
market,
forPositiveImpact
));
}
function proTraderTierKey(address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
PRO_TRADER_TIER,
account
));
}
function proDiscountFactorKey(uint256 proTier) internal pure returns (bytes32) {
return keccak256(abi.encode(
PRO_DISCOUNT_FACTOR,
proTier
));
}
function liquidationFeeFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
LIQUIDATION_FEE_FACTOR,
market
));
}
function swapImpactFactorKey(address market, bool isPositive) internal pure returns (bytes32) {
return keccak256(abi.encode(
SWAP_IMPACT_FACTOR,
market,
isPositive
));
}
function swapImpactExponentFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
SWAP_IMPACT_EXPONENT_FACTOR,
market
));
}
function swapFeeFactorKey(address market, bool forPositiveImpact) internal pure returns (bytes32) {
return keccak256(abi.encode(
SWAP_FEE_FACTOR,
market,
forPositiveImpact
));
}
function atomicSwapFeeFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
ATOMIC_SWAP_FEE_FACTOR,
market
));
}
function depositFeeFactorKey(address market, bool forPositiveImpact) internal pure returns (bytes32) {
return keccak256(abi.encode(
DEPOSIT_FEE_FACTOR,
market,
forPositiveImpact
));
}
function withdrawalFeeFactorKey(address market, bool forPositiveImpact) internal pure returns (bytes32) {
return keccak256(abi.encode(
WITHDRAWAL_FEE_FACTOR,
market,
forPositiveImpact
));
}
function oracleTypeKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
ORACLE_TYPE,
token
));
}
function openInterestKey(address market, address collateralToken, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
OPEN_INTEREST,
market,
collateralToken,
isLong
));
}
function openInterestInTokensKey(address market, address collateralToken, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
OPEN_INTEREST_IN_TOKENS,
market,
collateralToken,
isLong
));
}
function collateralSumKey(address market, address collateralToken, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
COLLATERAL_SUM,
market,
collateralToken,
isLong
));
}
function poolAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
POOL_AMOUNT,
market,
token
));
}
function maxPoolAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_POOL_AMOUNT,
market,
token
));
}
function maxPoolUsdForDepositKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_POOL_USD_FOR_DEPOSIT,
market,
token
));
}
function maxOpenInterestKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_OPEN_INTEREST,
market,
isLong
));
}
function positionImpactPoolAmountKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
POSITION_IMPACT_POOL_AMOUNT,
market
));
}
function minPositionImpactPoolAmountKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_POSITION_IMPACT_POOL_AMOUNT,
market
));
}
function positionImpactPoolDistributionRateKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
POSITION_IMPACT_POOL_DISTRIBUTION_RATE,
market
));
}
function positionImpactPoolDistributedAtKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
POSITION_IMPACT_POOL_DISTRIBUTED_AT,
market
));
}
function swapImpactPoolAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
SWAP_IMPACT_POOL_AMOUNT,
market,
token
));
}
function reserveFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
RESERVE_FACTOR,
market,
isLong
));
}
function openInterestReserveFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
OPEN_INTEREST_RESERVE_FACTOR,
market,
isLong
));
}
function maxPnlFactorKey(bytes32 pnlFactorType, address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_PNL_FACTOR,
pnlFactorType,
market,
isLong
));
}
function minPnlFactorAfterAdlKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_PNL_FACTOR_AFTER_ADL,
market,
isLong
));
}
function latestAdlAtKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
LATEST_ADL_AT,
market,
isLong
));
}
function isAdlEnabledKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
IS_ADL_ENABLED,
market,
isLong
));
}
function fundingFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
FUNDING_FACTOR,
market
));
}
function fundingExponentFactorKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
FUNDING_EXPONENT_FACTOR,
market
));
}
function savedFundingFactorPerSecondKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
SAVED_FUNDING_FACTOR_PER_SECOND,
market
));
}
function fundingIncreaseFactorPerSecondKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
FUNDING_INCREASE_FACTOR_PER_SECOND,
market
));
}
function fundingDecreaseFactorPerSecondKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
FUNDING_DECREASE_FACTOR_PER_SECOND,
market
));
}
function minFundingFactorPerSecondKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_FUNDING_FACTOR_PER_SECOND,
market
));
}
function maxFundingFactorPerSecondKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_FUNDING_FACTOR_PER_SECOND,
market
));
}
function thresholdForStableFundingKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
THRESHOLD_FOR_STABLE_FUNDING,
market
));
}
function thresholdForDecreaseFundingKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
THRESHOLD_FOR_DECREASE_FUNDING,
market
));
}
function fundingFeeAmountPerSizeKey(address market, address collateralToken, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
FUNDING_FEE_AMOUNT_PER_SIZE,
market,
collateralToken,
isLong
));
}
function claimableFundingAmountPerSizeKey(address market, address collateralToken, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_FUNDING_AMOUNT_PER_SIZE,
market,
collateralToken,
isLong
));
}
function fundingUpdatedAtKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
FUNDING_UPDATED_AT,
market
));
}
function claimableFundingAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_FUNDING_AMOUNT,
market,
token
));
}
function claimableFundingAmountKey(address market, address token, address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_FUNDING_AMOUNT,
market,
token,
account
));
}
function claimableCollateralAmountKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_COLLATERAL_AMOUNT,
market,
token
));
}
function claimableCollateralAmountKey(address market, address token, uint256 timeKey, address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_COLLATERAL_AMOUNT,
market,
token,
timeKey,
account
));
}
function claimableCollateralFactorKey(address market, address token, uint256 timeKey) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_COLLATERAL_FACTOR,
market,
token,
timeKey
));
}
function claimableCollateralFactorKey(address market, address token, uint256 timeKey, address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMABLE_COLLATERAL_FACTOR,
market,
token,
timeKey,
account
));
}
function claimedCollateralAmountKey(address market, address token, uint256 timeKey, address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
CLAIMED_COLLATERAL_AMOUNT,
market,
token,
timeKey,
account
));
}
function optimalUsageFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
OPTIMAL_USAGE_FACTOR,
market,
isLong
));
}
function baseBorrowingFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
BASE_BORROWING_FACTOR,
market,
isLong
));
}
function aboveOptimalUsageBorrowingFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
ABOVE_OPTIMAL_USAGE_BORROWING_FACTOR,
market,
isLong
));
}
function borrowingFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
BORROWING_FACTOR,
market,
isLong
));
}
function borrowingExponentFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
BORROWING_EXPONENT_FACTOR,
market,
isLong
));
}
function cumulativeBorrowingFactorKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
CUMULATIVE_BORROWING_FACTOR,
market,
isLong
));
}
function cumulativeBorrowingFactorUpdatedAtKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
CUMULATIVE_BORROWING_FACTOR_UPDATED_AT,
market,
isLong
));
}
function totalBorrowingKey(address market, bool isLong) internal pure returns (bytes32) {
return keccak256(abi.encode(
TOTAL_BORROWING,
market,
isLong
));
}
function affiliateRewardKey(address market, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
AFFILIATE_REWARD,
market,
token
));
}
function minAffiliateRewardFactorKey(uint256 referralTierLevel) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_AFFILIATE_REWARD_FACTOR,
referralTierLevel
));
}
function maxAllowedSubaccountActionCountKey(address account, address subaccount, bytes32 actionType) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_ALLOWED_SUBACCOUNT_ACTION_COUNT,
account,
subaccount,
actionType
));
}
function subaccountActionCountKey(address account, address subaccount, bytes32 actionType) internal pure returns (bytes32) {
return keccak256(abi.encode(
SUBACCOUNT_ACTION_COUNT,
account,
subaccount,
actionType
));
}
function subaccountAutoTopUpAmountKey(address account, address subaccount) internal pure returns (bytes32) {
return keccak256(abi.encode(
SUBACCOUNT_AUTO_TOP_UP_AMOUNT,
account,
subaccount
));
}
function affiliateRewardKey(address market, address token, address account) internal pure returns (bytes32) {
return keccak256(abi.encode(
AFFILIATE_REWARD,
market,
token,
account
));
}
function isMarketDisabledKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
IS_MARKET_DISABLED,
market
));
}
function minMarketTokensForFirstDepositKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_MARKET_TOKENS_FOR_FIRST_DEPOSIT,
market
));
}
function priceFeedKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
PRICE_FEED,
token
));
}
function dataStreamIdKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
DATA_STREAM_ID,
token
));
}
function dataStreamMultiplierKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
DATA_STREAM_MULTIPLIER,
token
));
}
function priceFeedMultiplierKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
PRICE_FEED_MULTIPLIER,
token
));
}
function priceFeedHeartbeatDurationKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
PRICE_FEED_HEARTBEAT_DURATION,
token
));
}
function stablePriceKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
STABLE_PRICE,
token
));
}
function feeDistributorSwapTokenIndexKey(bytes32 orderKey) internal pure returns (bytes32) {
return keccak256(abi.encode(
FEE_DISTRIBUTOR_SWAP_TOKEN_INDEX,
orderKey
));
}
function feeDistributorSwapFeeBatchKey(bytes32 orderKey) internal pure returns (bytes32) {
return keccak256(abi.encode(
FEE_DISTRIBUTOR_SWAP_FEE_BATCH,
orderKey
));
}
function glvMaxMarketTokenBalanceUsdKey(address glv, address market) internal pure returns (bytes32) {
return keccak256(abi.encode(GLV_MAX_MARKET_TOKEN_BALANCE_USD, glv, market));
}
function glvMaxMarketTokenBalanceAmountKey(address glv, address market) internal pure returns (bytes32) {
return keccak256(abi.encode(GLV_MAX_MARKET_TOKEN_BALANCE_AMOUNT, glv, market));
}
function isGlvMarketDisabledKey(address glv, address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
IS_GLV_MARKET_DISABLED,
glv,
market
));
}
function glvShiftMaxPriceImpactFactorKey(address glv) internal pure returns (bytes32) {
return keccak256(abi.encode(
GLV_SHIFT_MAX_PRICE_IMPACT_FACTOR,
glv
));
}
function glvShiftLastExecutedAtKey(address glv) internal pure returns (bytes32) {
return keccak256(abi.encode(
GLV_SHIFT_LAST_EXECUTED_AT,
glv
));
}
function glvShiftMinIntervalKey(address glv) internal pure returns (bytes32) {
return keccak256(abi.encode(
GLV_SHIFT_MIN_INTERVAL,
glv
));
}
function minGlvTokensForFirstGlvDepositKey(address glv) internal pure returns (bytes32) {
return keccak256(abi.encode(
MIN_GLV_TOKENS_FOR_FIRST_DEPOSIT,
glv
));
}
function syncConfigFeatureDisabledKey(address module) internal pure returns (bytes32) {
return keccak256(abi.encode(
SYNC_CONFIG_FEATURE_DISABLED,
module
));
}
function syncConfigMarketDisabledKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
SYNC_CONFIG_MARKET_DISABLED,
market
));
}
function syncConfigParameterDisabledKey(string memory parameter) internal pure returns (bytes32) {
return keccak256(abi.encode(
SYNC_CONFIG_PARAMETER_DISABLED,
parameter
));
}
function syncConfigMarketParameterDisabledKey(address market, string memory parameter) internal pure returns (bytes32) {
return keccak256(abi.encode(
SYNC_CONFIG_MARKET_PARAMETER_DISABLED,
market,
parameter
));
}
function syncConfigUpdateCompletedKey(uint256 updateId) internal pure returns (bytes32) {
return keccak256(abi.encode(
SYNC_CONFIG_UPDATE_COMPLETED,
updateId
));
}
function syncConfigLatestUpdateIdKey() internal pure returns (bytes32) {
return SYNC_CONFIG_LATEST_UPDATE_ID;
}
function contributorTokenAmountKey(address account, address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
CONTRIBUTOR_TOKEN_AMOUNT,
account,
token
));
}
function maxTotalContributorTokenAmountKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
MAX_TOTAL_CONTRIBUTOR_TOKEN_AMOUNT,
token
));
}
function contributorTokenVaultKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
CONTRIBUTOR_TOKEN_VAULT,
token
));
}
function buybackBatchAmountKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
BUYBACK_BATCH_AMOUNT,
token
));
}
function buybackAvailableFeeAmountKey(address feeToken, address swapToken) internal pure returns (bytes32) {
return keccak256(abi.encode(
BUYBACK_AVAILABLE_FEE_AMOUNT,
feeToken,
swapToken
));
}
function withdrawableBuybackTokenAmountKey(address buybackToken) internal pure returns (bytes32) {
return keccak256(abi.encode(
WITHDRAWABLE_BUYBACK_TOKEN_AMOUNT,
buybackToken
));
}
function buybackGmxFactorKey(uint256 version) internal pure returns (bytes32) {
return keccak256(abi.encode(
BUYBACK_GMX_FACTOR,
version
));
}
function buybackMaxPriceImpactFactorKey(address token) internal pure returns (bytes32) {
return keccak256(abi.encode(
BUYBACK_MAX_PRICE_IMPACT_FACTOR,
token
));
}
}
文件 61 的 108:Market.sol
pragma solidity ^0.8.0;
library Market {
struct Props {
address marketToken;
address indexToken;
address longToken;
address shortToken;
}
}
文件 62 的 108:MarketEventUtils.sol
pragma solidity ^0.8.0;
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Cast.sol";
import "./MarketPoolValueInfo.sol";
library MarketEventUtils {
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
function emitMarketPoolValueInfo(
EventEmitter eventEmitter,
bytes32 tradeKey,
address market,
MarketPoolValueInfo.Props memory props,
uint256 marketTokensSupply
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "tradeKey", tradeKey);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);
eventData.intItems.initItems(4);
eventData.intItems.setItem(0, "poolValue", props.poolValue);
eventData.intItems.setItem(1, "longPnl", props.longPnl);
eventData.intItems.setItem(2, "shortPnl", props.shortPnl);
eventData.intItems.setItem(3, "netPnl", props.netPnl);
eventData.uintItems.initItems(8);
eventData.uintItems.setItem(0, "longTokenAmount", props.longTokenAmount);
eventData.uintItems.setItem(1, "shortTokenAmount", props.shortTokenAmount);
eventData.uintItems.setItem(2, "longTokenUsd", props.longTokenUsd);
eventData.uintItems.setItem(3, "shortTokenUsd", props.shortTokenUsd);
eventData.uintItems.setItem(4, "totalBorrowingFees", props.totalBorrowingFees);
eventData.uintItems.setItem(5, "borrowingFeePoolFactor", props.borrowingFeePoolFactor);
eventData.uintItems.setItem(6, "impactPoolAmount", props.impactPoolAmount);
eventData.uintItems.setItem(7, "marketTokensSupply", marketTokensSupply);
eventEmitter.emitEventLog1(
"MarketPoolValueInfo",
Cast.toBytes32(market),
eventData
);
}
function emitMarketPoolValueUpdated(
EventEmitter eventEmitter,
bytes32 actionType,
bytes32 tradeKey,
address market,
MarketPoolValueInfo.Props memory props,
uint256 marketTokensSupply
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(2);
eventData.bytes32Items.setItem(0, "actionType", actionType);
eventData.bytes32Items.setItem(1, "tradeKey", tradeKey);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);
eventData.intItems.initItems(4);
eventData.intItems.setItem(0, "poolValue", props.poolValue);
eventData.intItems.setItem(1, "longPnl", props.longPnl);
eventData.intItems.setItem(2, "shortPnl", props.shortPnl);
eventData.intItems.setItem(3, "netPnl", props.netPnl);
eventData.uintItems.initItems(8);
eventData.uintItems.setItem(0, "longTokenAmount", props.longTokenAmount);
eventData.uintItems.setItem(1, "shortTokenAmount", props.shortTokenAmount);
eventData.uintItems.setItem(2, "longTokenUsd", props.longTokenUsd);
eventData.uintItems.setItem(3, "shortTokenUsd", props.shortTokenUsd);
eventData.uintItems.setItem(4, "totalBorrowingFees", props.totalBorrowingFees);
eventData.uintItems.setItem(5, "borrowingFeePoolFactor", props.borrowingFeePoolFactor);
eventData.uintItems.setItem(6, "impactPoolAmount", props.impactPoolAmount);
eventData.uintItems.setItem(7, "marketTokensSupply", marketTokensSupply);
eventEmitter.emitEventLog1(
"MarketPoolValueUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitPoolAmountUpdated(
EventEmitter eventEmitter,
address market,
address token,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"PoolAmountUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitSwapImpactPoolAmountUpdated(
EventEmitter eventEmitter,
address market,
address token,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"SwapImpactPoolAmountUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitPositionImpactPoolDistributed(
EventEmitter eventEmitter,
address market,
uint256 distributionAmount,
uint256 nextPositionImpactPoolAmount
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "distributionAmount", distributionAmount);
eventData.uintItems.setItem(1, "nextPositionImpactPoolAmount", nextPositionImpactPoolAmount);
eventEmitter.emitEventLog1(
"PositionImpactPoolDistributed",
Cast.toBytes32(market),
eventData
);
}
function emitPositionImpactPoolAmountUpdated(
EventEmitter eventEmitter,
address market,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"PositionImpactPoolAmountUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitOpenInterestUpdated(
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "collateralToken", collateralToken);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLong", isLong);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"OpenInterestUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitVirtualSwapInventoryUpdated(
EventEmitter eventEmitter,
address market,
bool isLongToken,
bytes32 virtualMarketId,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLongToken", isLongToken);
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "virtualMarketId", virtualMarketId);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog2(
"VirtualSwapInventoryUpdated",
Cast.toBytes32(market),
virtualMarketId,
eventData
);
}
function emitVirtualPositionInventoryUpdated(
EventEmitter eventEmitter,
address token,
bytes32 virtualTokenId,
int256 delta,
int256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "token", token);
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "virtualTokenId", virtualTokenId);
eventData.intItems.initItems(2);
eventData.intItems.setItem(0, "delta", delta);
eventData.intItems.setItem(1, "nextValue", nextValue);
eventEmitter.emitEventLog2(
"VirtualPositionInventoryUpdated",
Cast.toBytes32(token),
virtualTokenId,
eventData
);
}
function emitOpenInterestInTokensUpdated(
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "collateralToken", collateralToken);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLong", isLong);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"OpenInterestInTokensUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitCollateralSumUpdated(
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
int256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "collateralToken", collateralToken);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLong", isLong);
eventData.intItems.initItems(1);
eventData.intItems.setItem(0, "delta", delta);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"CollateralSumUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitBorrowingFactorUpdated(
EventEmitter eventEmitter,
address market,
bool isLong,
uint256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLong", isLong);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"CumulativeBorrowingFactorUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitFundingFeeAmountPerSizeUpdated(
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
uint256 delta,
uint256 value
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "collateralToken", collateralToken);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLong", isLong);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "value", value);
eventEmitter.emitEventLog1(
"FundingFeeAmountPerSizeUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitClaimableFundingAmountPerSizeUpdated(
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
uint256 delta,
uint256 value
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "collateralToken", collateralToken);
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "isLong", isLong);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "value", value);
eventEmitter.emitEventLog1(
"ClaimableFundingAmountPerSizeUpdated",
Cast.toBytes32(market),
eventData
);
}
function emitClaimableFundingUpdated(
EventEmitter eventEmitter,
address market,
address token,
address account,
uint256 delta,
uint256 nextValue,
uint256 nextPoolValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "account", account);
eventData.uintItems.initItems(3);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "nextValue", nextValue);
eventData.uintItems.setItem(2, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog1(
"ClaimableFundingUpdated",
Cast.toBytes32(account),
eventData
);
}
function emitFundingFeesClaimed(
EventEmitter eventEmitter,
address market,
address token,
address account,
address receiver,
uint256 amount,
uint256 nextPoolValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(4);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "account", account);
eventData.addressItems.setItem(3, "receiver", receiver);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "amount", amount);
eventData.uintItems.setItem(1, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog1(
"FundingFeesClaimed",
Cast.toBytes32(account),
eventData
);
}
function emitClaimableFundingUpdated(
EventEmitter eventEmitter,
address market,
address token,
uint256 timeKey,
address account,
uint256 delta,
uint256 nextValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "account", account);
eventData.uintItems.initItems(3);
eventData.uintItems.setItem(0, "timeKey", timeKey);
eventData.uintItems.setItem(1, "delta", delta);
eventData.uintItems.setItem(2, "nextValue", nextValue);
eventEmitter.emitEventLog1(
"ClaimableFundingUpdated",
Cast.toBytes32(account),
eventData
);
}
function emitClaimableCollateralUpdated(
EventEmitter eventEmitter,
address market,
address token,
uint256 timeKey,
address account,
uint256 delta,
uint256 nextValue,
uint256 nextPoolValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "account", account);
eventData.uintItems.initItems(4);
eventData.uintItems.setItem(0, "timeKey", timeKey);
eventData.uintItems.setItem(1, "delta", delta);
eventData.uintItems.setItem(2, "nextValue", nextValue);
eventData.uintItems.setItem(3, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog1(
"ClaimableCollateralUpdated",
Cast.toBytes32(account),
eventData
);
}
function emitCollateralClaimed(
EventEmitter eventEmitter,
address market,
address token,
uint256 timeKey,
address account,
address receiver,
uint256 amount,
uint256 nextPoolValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(4);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "account", account);
eventData.addressItems.setItem(3, "receiver", receiver);
eventData.uintItems.initItems(3);
eventData.uintItems.setItem(0, "timeKey", timeKey);
eventData.uintItems.setItem(1, "amount", amount);
eventData.uintItems.setItem(2, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog1(
"CollateralClaimed",
Cast.toBytes32(account),
eventData
);
}
function emitUiFeeFactorUpdated(
EventEmitter eventEmitter,
address account,
uint256 uiFeeFactor
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "uiFeeFactor", uiFeeFactor);
eventEmitter.emitEventLog1(
"UiFeeFactorUpdated",
Cast.toBytes32(account),
eventData
);
}
}
文件 63 的 108:MarketPoolValueInfo.sol
pragma solidity ^0.8.0;
library MarketPoolValueInfo {
struct Props {
int256 poolValue;
int256 longPnl;
int256 shortPnl;
int256 netPnl;
uint256 longTokenAmount;
uint256 shortTokenAmount;
uint256 longTokenUsd;
uint256 shortTokenUsd;
uint256 totalBorrowingFees;
uint256 borrowingFeePoolFactor;
uint256 impactPoolAmount;
}
}
文件 64 的 108:MarketStoreUtils.sol
pragma solidity ^0.8.0;
import "../data/Keys.sol";
import "../data/DataStore.sol";
import "./Market.sol";
library MarketStoreUtils {
using Market for Market.Props;
bytes32 public constant MARKET_SALT = keccak256(abi.encode("MARKET_SALT"));
bytes32 public constant MARKET_KEY = keccak256(abi.encode("MARKET_KEY"));
bytes32 public constant MARKET_TOKEN = keccak256(abi.encode("MARKET_TOKEN"));
bytes32 public constant INDEX_TOKEN = keccak256(abi.encode("INDEX_TOKEN"));
bytes32 public constant LONG_TOKEN = keccak256(abi.encode("LONG_TOKEN"));
bytes32 public constant SHORT_TOKEN = keccak256(abi.encode("SHORT_TOKEN"));
function get(DataStore dataStore, address key) public view returns (Market.Props memory) {
Market.Props memory market;
if (!dataStore.containsAddress(Keys.MARKET_LIST, key)) {
return market;
}
market.marketToken = dataStore.getAddress(
keccak256(abi.encode(key, MARKET_TOKEN))
);
market.indexToken = dataStore.getAddress(
keccak256(abi.encode(key, INDEX_TOKEN))
);
market.longToken = dataStore.getAddress(
keccak256(abi.encode(key, LONG_TOKEN))
);
market.shortToken = dataStore.getAddress(
keccak256(abi.encode(key, SHORT_TOKEN))
);
return market;
}
function getBySalt(DataStore dataStore, bytes32 salt) external view returns (Market.Props memory) {
address key = dataStore.getAddress(getMarketSaltHash(salt));
return get(dataStore, key);
}
function set(DataStore dataStore, address key, bytes32 salt, Market.Props memory market) external {
dataStore.addAddress(
Keys.MARKET_LIST,
key
);
dataStore.setAddress(
getMarketSaltHash(salt),
key
);
dataStore.setAddress(
keccak256(abi.encode(key, MARKET_TOKEN)),
market.marketToken
);
dataStore.setAddress(
keccak256(abi.encode(key, INDEX_TOKEN)),
market.indexToken
);
dataStore.setAddress(
keccak256(abi.encode(key, LONG_TOKEN)),
market.longToken
);
dataStore.setAddress(
keccak256(abi.encode(key, SHORT_TOKEN)),
market.shortToken
);
}
function remove(DataStore dataStore, address key) external {
if (!dataStore.containsAddress(Keys.MARKET_LIST, key)) {
revert Errors.MarketNotFound(key);
}
dataStore.removeAddress(
Keys.MARKET_LIST,
key
);
dataStore.removeAddress(
keccak256(abi.encode(key, MARKET_TOKEN))
);
dataStore.removeAddress(
keccak256(abi.encode(key, INDEX_TOKEN))
);
dataStore.removeAddress(
keccak256(abi.encode(key, LONG_TOKEN))
);
dataStore.removeAddress(
keccak256(abi.encode(key, SHORT_TOKEN))
);
}
function getMarketSaltHash(bytes32 salt) internal pure returns (bytes32) {
return keccak256(abi.encode(MARKET_SALT, salt));
}
function getMarketCount(DataStore dataStore) internal view returns (uint256) {
return dataStore.getAddressCount(Keys.MARKET_LIST);
}
function getMarketKeys(DataStore dataStore, uint256 start, uint256 end) internal view returns (address[] memory) {
return dataStore.getAddressValuesAt(Keys.MARKET_LIST, start, end);
}
}
文件 65 的 108:MarketToken.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../bank/Bank.sol";
contract MarketToken is ERC20, Bank {
constructor(RoleStore _roleStore, DataStore _dataStore) ERC20("GMX Market", "GM") Bank(_roleStore, _dataStore) {
}
function mint(address account, uint256 amount) external onlyController {
_mint(account, amount);
}
function burn(address account, uint256 amount) external onlyController {
_burn(account, amount);
}
}
文件 66 的 108:MarketUtils.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "./Market.sol";
import "./MarketPoolValueInfo.sol";
import "./MarketToken.sol";
import "./MarketEventUtils.sol";
import "./MarketStoreUtils.sol";
import "../position/Position.sol";
import "../order/Order.sol";
import "../oracle/Oracle.sol";
import "../price/Price.sol";
import "../utils/Calc.sol";
import "../utils/Precision.sol";
library MarketUtils {
using SignedMath for int256;
using SafeCast for int256;
using SafeCast for uint256;
using Market for Market.Props;
using Position for Position.Props;
using Order for Order.Props;
using Price for Price.Props;
enum FundingRateChangeType {
NoChange,
Increase,
Decrease
}
struct MarketPrices {
Price.Props indexTokenPrice;
Price.Props longTokenPrice;
Price.Props shortTokenPrice;
}
struct CollateralType {
uint256 longToken;
uint256 shortToken;
}
struct PositionType {
CollateralType long;
CollateralType short;
}
struct GetNextFundingAmountPerSizeResult {
bool longsPayShorts;
uint256 fundingFactorPerSecond;
int256 nextSavedFundingFactorPerSecond;
PositionType fundingFeeAmountPerSizeDelta;
PositionType claimableFundingAmountPerSizeDelta;
}
struct GetNextFundingAmountPerSizeCache {
PositionType openInterest;
uint256 longOpenInterest;
uint256 shortOpenInterest;
uint256 durationInSeconds;
uint256 sizeOfLargerSide;
uint256 fundingUsd;
uint256 fundingUsdForLongCollateral;
uint256 fundingUsdForShortCollateral;
}
struct GetNextFundingFactorPerSecondCache {
uint256 diffUsd;
uint256 totalOpenInterest;
uint256 fundingFactor;
uint256 fundingExponentFactor;
uint256 diffUsdAfterExponent;
uint256 diffUsdToOpenInterestFactor;
int256 savedFundingFactorPerSecond;
uint256 savedFundingFactorPerSecondMagnitude;
int256 nextSavedFundingFactorPerSecond;
int256 nextSavedFundingFactorPerSecondWithMinBound;
}
struct FundingConfigCache {
uint256 thresholdForStableFunding;
uint256 thresholdForDecreaseFunding;
uint256 fundingIncreaseFactorPerSecond;
uint256 fundingDecreaseFactorPerSecond;
uint256 minFundingFactorPerSecond;
uint256 maxFundingFactorPerSecond;
}
struct GetExpectedMinTokenBalanceCache {
uint256 poolAmount;
uint256 swapImpactPoolAmount;
uint256 claimableCollateralAmount;
uint256 claimableFeeAmount;
uint256 claimableUiFeeAmount;
uint256 affiliateRewardAmount;
}
function getMarketTokenPrice(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
Price.Props memory longTokenPrice,
Price.Props memory shortTokenPrice,
bytes32 pnlFactorType,
bool maximize
) external view returns (int256, MarketPoolValueInfo.Props memory) {
uint256 supply = getMarketTokenSupply(MarketToken(payable(market.marketToken)));
MarketPoolValueInfo.Props memory poolValueInfo = getPoolValueInfo(
dataStore,
market,
indexTokenPrice,
longTokenPrice,
shortTokenPrice,
pnlFactorType,
maximize
);
if (supply == 0) {
return (Precision.FLOAT_PRECISION.toInt256(), poolValueInfo);
}
if (poolValueInfo.poolValue == 0) { return (0, poolValueInfo); }
int256 marketTokenPrice = Precision.mulDiv(Precision.WEI_PRECISION, poolValueInfo.poolValue, supply);
return (marketTokenPrice, poolValueInfo);
}
function getMarketTokenSupply(MarketToken marketToken) internal view returns (uint256) {
return marketToken.totalSupply();
}
function getOppositeToken(address inputToken, Market.Props memory market) internal pure returns (address) {
if (inputToken == market.longToken) {
return market.shortToken;
}
if (inputToken == market.shortToken) {
return market.longToken;
}
revert Errors.UnableToGetOppositeToken(inputToken, market.marketToken);
}
function validateSwapMarket(DataStore dataStore, address marketAddress) internal view {
Market.Props memory market = MarketStoreUtils.get(dataStore, marketAddress);
validateSwapMarket(dataStore, market);
}
function validateSwapMarket(DataStore dataStore, Market.Props memory market) internal view {
validateEnabledMarket(dataStore, market);
if (market.longToken == market.shortToken) {
revert Errors.InvalidSwapMarket(market.marketToken);
}
}
function getCachedTokenPrice(address token, Market.Props memory market, MarketPrices memory prices) internal pure returns (Price.Props memory) {
if (token == market.longToken) {
return prices.longTokenPrice;
}
if (token == market.shortToken) {
return prices.shortTokenPrice;
}
if (token == market.indexToken) {
return prices.indexTokenPrice;
}
revert Errors.UnableToGetCachedTokenPrice(token, market.marketToken);
}
function getMarketPrices(Oracle oracle, Market.Props memory market) internal view returns (MarketPrices memory) {
return MarketPrices(
oracle.getPrimaryPrice(market.indexToken),
oracle.getPrimaryPrice(market.longToken),
oracle.getPrimaryPrice(market.shortToken)
);
}
function getPoolUsdWithoutPnl(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong,
bool maximize
) internal view returns (uint256) {
address token = isLong ? market.longToken : market.shortToken;
uint256 poolAmount = getPoolAmount(dataStore, market, token);
uint256 tokenPrice;
if (maximize) {
tokenPrice = isLong ? prices.longTokenPrice.max : prices.shortTokenPrice.max;
} else {
tokenPrice = isLong ? prices.longTokenPrice.min : prices.shortTokenPrice.min;
}
return poolAmount * tokenPrice;
}
function getPoolValueInfo(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
Price.Props memory longTokenPrice,
Price.Props memory shortTokenPrice,
bytes32 pnlFactorType,
bool maximize
) public view returns (MarketPoolValueInfo.Props memory) {
MarketPoolValueInfo.Props memory result;
result.longTokenAmount = getPoolAmount(dataStore, market, market.longToken);
result.shortTokenAmount = getPoolAmount(dataStore, market, market.shortToken);
result.longTokenUsd = result.longTokenAmount * longTokenPrice.pickPrice(maximize);
result.shortTokenUsd = result.shortTokenAmount * shortTokenPrice.pickPrice(maximize);
result.poolValue = (result.longTokenUsd + result.shortTokenUsd).toInt256();
MarketPrices memory prices = MarketPrices(
indexTokenPrice,
longTokenPrice,
shortTokenPrice
);
result.totalBorrowingFees = getTotalPendingBorrowingFees(
dataStore,
market,
prices,
true
);
result.totalBorrowingFees += getTotalPendingBorrowingFees(
dataStore,
market,
prices,
false
);
result.borrowingFeePoolFactor = Precision.FLOAT_PRECISION - dataStore.getUint(Keys.BORROWING_FEE_RECEIVER_FACTOR);
result.poolValue += Precision.applyFactor(result.totalBorrowingFees, result.borrowingFeePoolFactor).toInt256();
result.longPnl = getPnl(
dataStore,
market,
indexTokenPrice,
true,
!maximize
);
result.longPnl = getCappedPnl(
dataStore,
market.marketToken,
true,
result.longPnl,
result.longTokenUsd,
pnlFactorType
);
result.shortPnl = getPnl(
dataStore,
market,
indexTokenPrice,
false,
!maximize
);
result.shortPnl = getCappedPnl(
dataStore,
market.marketToken,
false,
result.shortPnl,
result.shortTokenUsd,
pnlFactorType
);
result.netPnl = result.longPnl + result.shortPnl;
result.poolValue = result.poolValue - result.netPnl;
result.impactPoolAmount = getNextPositionImpactPoolAmount(dataStore, market.marketToken);
uint256 impactPoolUsd = result.impactPoolAmount * indexTokenPrice.pickPrice(!maximize);
result.poolValue -= impactPoolUsd.toInt256();
return result;
}
function getNetPnl(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
bool maximize
) internal view returns (int256) {
int256 longPnl = getPnl(dataStore, market, indexTokenPrice, true, maximize);
int256 shortPnl = getPnl(dataStore, market, indexTokenPrice, false, maximize);
return longPnl + shortPnl;
}
function getCappedPnl(
DataStore dataStore,
address market,
bool isLong,
int256 pnl,
uint256 poolUsd,
bytes32 pnlFactorType
) internal view returns (int256) {
if (pnl < 0) { return pnl; }
uint256 maxPnlFactor = getMaxPnlFactor(dataStore, pnlFactorType, market, isLong);
int256 maxPnl = Precision.applyFactor(poolUsd, maxPnlFactor).toInt256();
return pnl > maxPnl ? maxPnl : pnl;
}
function getPnl(
DataStore dataStore,
Market.Props memory market,
uint256 indexTokenPrice,
bool isLong,
bool maximize
) internal view returns (int256) {
Price.Props memory _indexTokenPrice = Price.Props(indexTokenPrice, indexTokenPrice);
return getPnl(
dataStore,
market,
_indexTokenPrice,
isLong,
maximize
);
}
function getPnl(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
bool isLong,
bool maximize
) internal view returns (int256) {
int256 openInterest = getOpenInterest(dataStore, market, isLong).toInt256();
uint256 openInterestInTokens = getOpenInterestInTokens(dataStore, market, isLong);
if (openInterest == 0 || openInterestInTokens == 0) {
return 0;
}
uint256 price = indexTokenPrice.pickPriceForPnl(isLong, maximize);
int256 openInterestValue = (openInterestInTokens * price).toInt256();
int256 pnl = isLong ? openInterestValue - openInterest : openInterest - openInterestValue;
return pnl;
}
function getPoolAmount(DataStore dataStore, Market.Props memory market, address token) internal view returns (uint256) {
uint256 divisor = getPoolDivisor(market.longToken, market.shortToken);
return dataStore.getUint(Keys.poolAmountKey(market.marketToken, token)) / divisor;
}
function getMaxPoolAmount(DataStore dataStore, address market, address token) internal view returns (uint256) {
return dataStore.getUint(Keys.maxPoolAmountKey(market, token));
}
function getMaxPoolUsdForDeposit(DataStore dataStore, address market, address token) internal view returns (uint256) {
return dataStore.getUint(Keys.maxPoolUsdForDepositKey(market, token));
}
function getUsageFactor(
DataStore dataStore,
Market.Props memory market,
bool isLong,
uint256 reservedUsd,
uint256 poolUsd
) internal view returns (uint256) {
uint256 reserveFactor = getOpenInterestReserveFactor(dataStore, market.marketToken, isLong);
uint256 maxReservedUsd = Precision.applyFactor(poolUsd, reserveFactor);
uint256 reserveUsageFactor = Precision.toFactor(reservedUsd, maxReservedUsd);
if (dataStore.getBool(Keys.IGNORE_OPEN_INTEREST_FOR_USAGE_FACTOR)) {
return reserveUsageFactor;
}
uint256 maxOpenInterest = getMaxOpenInterest(dataStore, market.marketToken, isLong);
uint256 openInterest = getOpenInterest(dataStore, market, isLong);
uint256 openInterestUsageFactor = Precision.toFactor(openInterest, maxOpenInterest);
return reserveUsageFactor > openInterestUsageFactor ? reserveUsageFactor : openInterestUsageFactor;
}
function getMaxOpenInterest(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.maxOpenInterestKey(market, isLong));
}
function incrementClaimableCollateralAmount(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
address account,
uint256 delta
) internal {
uint256 divisor = dataStore.getUint(Keys.CLAIMABLE_COLLATERAL_TIME_DIVISOR);
uint256 timeKey = Chain.currentTimestamp() / divisor;
uint256 nextValue = dataStore.incrementUint(
Keys.claimableCollateralAmountKey(market, token, timeKey, account),
delta
);
uint256 nextPoolValue = dataStore.incrementUint(
Keys.claimableCollateralAmountKey(market, token),
delta
);
MarketEventUtils.emitClaimableCollateralUpdated(
eventEmitter,
market,
token,
timeKey,
account,
delta,
nextValue,
nextPoolValue
);
}
function incrementClaimableFundingAmount(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
address account,
uint256 delta
) internal {
uint256 nextValue = dataStore.incrementUint(
Keys.claimableFundingAmountKey(market, token, account),
delta
);
uint256 nextPoolValue = dataStore.incrementUint(
Keys.claimableFundingAmountKey(market, token),
delta
);
MarketEventUtils.emitClaimableFundingUpdated(
eventEmitter,
market,
token,
account,
delta,
nextValue,
nextPoolValue
);
}
function claimFundingFees(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
address account,
address receiver
) internal returns (uint256) {
bytes32 key = Keys.claimableFundingAmountKey(market, token, account);
uint256 claimableAmount = dataStore.getUint(key);
dataStore.setUint(key, 0);
uint256 nextPoolValue = dataStore.decrementUint(
Keys.claimableFundingAmountKey(market, token),
claimableAmount
);
MarketToken(payable(market)).transferOut(
token,
receiver,
claimableAmount
);
validateMarketTokenBalance(dataStore, market);
MarketEventUtils.emitFundingFeesClaimed(
eventEmitter,
market,
token,
account,
receiver,
claimableAmount,
nextPoolValue
);
return claimableAmount;
}
function claimCollateral(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
uint256 timeKey,
address account,
address receiver
) internal returns (uint256) {
uint256 claimableAmount = dataStore.getUint(Keys.claimableCollateralAmountKey(market, token, timeKey, account));
uint256 claimableFactor;
{
uint256 claimableFactorForTime = dataStore.getUint(Keys.claimableCollateralFactorKey(market, token, timeKey));
uint256 claimableFactorForAccount = dataStore.getUint(Keys.claimableCollateralFactorKey(market, token, timeKey, account));
claimableFactor = claimableFactorForTime > claimableFactorForAccount ? claimableFactorForTime : claimableFactorForAccount;
}
if (claimableFactor > Precision.FLOAT_PRECISION) {
revert Errors.InvalidClaimableFactor(claimableFactor);
}
uint256 claimedAmount = dataStore.getUint(Keys.claimedCollateralAmountKey(market, token, timeKey, account));
uint256 adjustedClaimableAmount = Precision.applyFactor(claimableAmount, claimableFactor);
if (adjustedClaimableAmount <= claimedAmount) {
revert Errors.CollateralAlreadyClaimed(adjustedClaimableAmount, claimedAmount);
}
uint256 amountToBeClaimed = adjustedClaimableAmount - claimedAmount;
dataStore.setUint(
Keys.claimedCollateralAmountKey(market, token, timeKey, account),
adjustedClaimableAmount
);
uint256 nextPoolValue = dataStore.decrementUint(
Keys.claimableCollateralAmountKey(market, token),
amountToBeClaimed
);
MarketToken(payable(market)).transferOut(
token,
receiver,
amountToBeClaimed
);
validateMarketTokenBalance(dataStore, market);
MarketEventUtils.emitCollateralClaimed(
eventEmitter,
market,
token,
timeKey,
account,
receiver,
amountToBeClaimed,
nextPoolValue
);
return amountToBeClaimed;
}
function applyDeltaToPoolAmount(
DataStore dataStore,
EventEmitter eventEmitter,
Market.Props memory market,
address token,
int256 delta
) internal returns (uint256) {
uint256 nextValue = dataStore.applyDeltaToUint(
Keys.poolAmountKey(market.marketToken, token),
delta,
"Invalid state, negative poolAmount"
);
applyDeltaToVirtualInventoryForSwaps(
dataStore,
eventEmitter,
market,
token,
delta
);
MarketEventUtils.emitPoolAmountUpdated(eventEmitter, market.marketToken, token, delta, nextValue);
return nextValue;
}
function getAdjustedSwapImpactFactor(DataStore dataStore, address market, bool isPositive) internal view returns (uint256) {
(uint256 positiveImpactFactor, uint256 negativeImpactFactor) = getAdjustedSwapImpactFactors(dataStore, market);
return isPositive ? positiveImpactFactor : negativeImpactFactor;
}
function getAdjustedSwapImpactFactors(DataStore dataStore, address market) internal view returns (uint256, uint256) {
uint256 positiveImpactFactor = dataStore.getUint(Keys.swapImpactFactorKey(market, true));
uint256 negativeImpactFactor = dataStore.getUint(Keys.swapImpactFactorKey(market, false));
if (positiveImpactFactor > negativeImpactFactor) {
positiveImpactFactor = negativeImpactFactor;
}
return (positiveImpactFactor, negativeImpactFactor);
}
function getAdjustedPositionImpactFactor(DataStore dataStore, address market, bool isPositive) internal view returns (uint256) {
(uint256 positiveImpactFactor, uint256 negativeImpactFactor) = getAdjustedPositionImpactFactors(dataStore, market);
return isPositive ? positiveImpactFactor : negativeImpactFactor;
}
function getAdjustedPositionImpactFactors(DataStore dataStore, address market) internal view returns (uint256, uint256) {
uint256 positiveImpactFactor = dataStore.getUint(Keys.positionImpactFactorKey(market, true));
uint256 negativeImpactFactor = dataStore.getUint(Keys.positionImpactFactorKey(market, false));
if (positiveImpactFactor > negativeImpactFactor) {
positiveImpactFactor = negativeImpactFactor;
}
return (positiveImpactFactor, negativeImpactFactor);
}
function getCappedPositionImpactUsd(
DataStore dataStore,
address market,
Price.Props memory indexTokenPrice,
int256 priceImpactUsd,
uint256 sizeDeltaUsd
) internal view returns (int256) {
if (priceImpactUsd < 0) {
return priceImpactUsd;
}
uint256 impactPoolAmount = getPositionImpactPoolAmount(dataStore, market);
int256 maxPriceImpactUsdBasedOnImpactPool = (impactPoolAmount * indexTokenPrice.min).toInt256();
if (priceImpactUsd > maxPriceImpactUsdBasedOnImpactPool) {
priceImpactUsd = maxPriceImpactUsdBasedOnImpactPool;
}
uint256 maxPriceImpactFactor = getMaxPositionImpactFactor(dataStore, market, true);
int256 maxPriceImpactUsdBasedOnMaxPriceImpactFactor = Precision.applyFactor(sizeDeltaUsd, maxPriceImpactFactor).toInt256();
if (priceImpactUsd > maxPriceImpactUsdBasedOnMaxPriceImpactFactor) {
priceImpactUsd = maxPriceImpactUsdBasedOnMaxPriceImpactFactor;
}
return priceImpactUsd;
}
function getPositionImpactPoolAmount(DataStore dataStore, address market) internal view returns (uint256) {
return dataStore.getUint(Keys.positionImpactPoolAmountKey(market));
}
function getSwapImpactPoolAmount(DataStore dataStore, address market, address token) internal view returns (uint256) {
return dataStore.getUint(Keys.swapImpactPoolAmountKey(market, token));
}
function applyDeltaToSwapImpactPool(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
int256 delta
) internal returns (uint256) {
uint256 nextValue = dataStore.applyBoundedDeltaToUint(
Keys.swapImpactPoolAmountKey(market, token),
delta
);
MarketEventUtils.emitSwapImpactPoolAmountUpdated(eventEmitter, market, token, delta, nextValue);
return nextValue;
}
function applyDeltaToPositionImpactPool(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
int256 delta
) internal returns (uint256) {
uint256 nextValue = dataStore.applyBoundedDeltaToUint(
Keys.positionImpactPoolAmountKey(market),
delta
);
MarketEventUtils.emitPositionImpactPoolAmountUpdated(eventEmitter, market, delta, nextValue);
return nextValue;
}
function applyDeltaToOpenInterest(
DataStore dataStore,
EventEmitter eventEmitter,
Market.Props memory market,
address collateralToken,
bool isLong,
int256 delta
) internal returns (uint256) {
if (market.indexToken == address(0)) {
revert Errors.OpenInterestCannotBeUpdatedForSwapOnlyMarket(market.marketToken);
}
uint256 nextValue = dataStore.applyDeltaToUint(
Keys.openInterestKey(market.marketToken, collateralToken, isLong),
delta,
"Invalid state: negative open interest"
);
applyDeltaToVirtualInventoryForPositions(
dataStore,
eventEmitter,
market.indexToken,
isLong ? -delta : delta
);
if (delta > 0) {
validateOpenInterest(
dataStore,
market,
isLong
);
}
MarketEventUtils.emitOpenInterestUpdated(eventEmitter, market.marketToken, collateralToken, isLong, delta, nextValue);
return nextValue;
}
function applyDeltaToOpenInterestInTokens(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
int256 delta
) internal returns (uint256) {
uint256 nextValue = dataStore.applyDeltaToUint(
Keys.openInterestInTokensKey(market, collateralToken, isLong),
delta,
"Invalid state: negative open interest in tokens"
);
MarketEventUtils.emitOpenInterestInTokensUpdated(eventEmitter, market, collateralToken, isLong, delta, nextValue);
return nextValue;
}
function applyDeltaToCollateralSum(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
int256 delta
) internal returns (uint256) {
uint256 nextValue = dataStore.applyDeltaToUint(
Keys.collateralSumKey(market, collateralToken, isLong),
delta,
"Invalid state: negative collateralSum"
);
MarketEventUtils.emitCollateralSumUpdated(eventEmitter, market, collateralToken, isLong, delta, nextValue);
return nextValue;
}
function updateFundingState(
DataStore dataStore,
EventEmitter eventEmitter,
Market.Props memory market,
MarketPrices memory prices
) external {
GetNextFundingAmountPerSizeResult memory result = getNextFundingAmountPerSize(dataStore, market, prices);
applyDeltaToFundingFeeAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.longToken,
true,
result.fundingFeeAmountPerSizeDelta.long.longToken
);
applyDeltaToFundingFeeAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.longToken,
false,
result.fundingFeeAmountPerSizeDelta.short.longToken
);
applyDeltaToFundingFeeAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.shortToken,
true,
result.fundingFeeAmountPerSizeDelta.long.shortToken
);
applyDeltaToFundingFeeAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.shortToken,
false,
result.fundingFeeAmountPerSizeDelta.short.shortToken
);
applyDeltaToClaimableFundingAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.longToken,
true,
result.claimableFundingAmountPerSizeDelta.long.longToken
);
applyDeltaToClaimableFundingAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.longToken,
false,
result.claimableFundingAmountPerSizeDelta.short.longToken
);
applyDeltaToClaimableFundingAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.shortToken,
true,
result.claimableFundingAmountPerSizeDelta.long.shortToken
);
applyDeltaToClaimableFundingAmountPerSize(
dataStore,
eventEmitter,
market.marketToken,
market.shortToken,
false,
result.claimableFundingAmountPerSizeDelta.short.shortToken
);
setSavedFundingFactorPerSecond(dataStore, market.marketToken, result.nextSavedFundingFactorPerSecond);
dataStore.setUint(Keys.fundingUpdatedAtKey(market.marketToken), Chain.currentTimestamp());
}
function getNextFundingAmountPerSize(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices
) internal view returns (GetNextFundingAmountPerSizeResult memory) {
GetNextFundingAmountPerSizeResult memory result;
GetNextFundingAmountPerSizeCache memory cache;
uint256 divisor = getPoolDivisor(market.longToken, market.shortToken);
cache.openInterest.long.longToken = getOpenInterest(dataStore, market.marketToken, market.longToken, true, divisor);
cache.openInterest.long.shortToken = getOpenInterest(dataStore, market.marketToken, market.shortToken, true, divisor);
cache.openInterest.short.longToken = getOpenInterest(dataStore, market.marketToken, market.longToken, false, divisor);
cache.openInterest.short.shortToken = getOpenInterest(dataStore, market.marketToken, market.shortToken, false, divisor);
cache.longOpenInterest = cache.openInterest.long.longToken + cache.openInterest.long.shortToken;
cache.shortOpenInterest = cache.openInterest.short.longToken + cache.openInterest.short.shortToken;
if (cache.longOpenInterest == 0 || cache.shortOpenInterest == 0) {
return result;
}
cache.durationInSeconds = getSecondsSinceFundingUpdated(dataStore, market.marketToken);
cache.sizeOfLargerSide = cache.longOpenInterest > cache.shortOpenInterest ? cache.longOpenInterest : cache.shortOpenInterest;
(result.fundingFactorPerSecond, result.longsPayShorts, result.nextSavedFundingFactorPerSecond) = getNextFundingFactorPerSecond(
dataStore,
market.marketToken,
cache.longOpenInterest,
cache.shortOpenInterest,
cache.durationInSeconds
);
cache.fundingUsd = Precision.applyFactor(cache.sizeOfLargerSide, cache.durationInSeconds * result.fundingFactorPerSecond);
cache.fundingUsd = cache.fundingUsd / divisor;
if (result.longsPayShorts) {
cache.fundingUsdForLongCollateral = Precision.mulDiv(cache.fundingUsd, cache.openInterest.long.longToken, cache.longOpenInterest);
cache.fundingUsdForShortCollateral = Precision.mulDiv(cache.fundingUsd, cache.openInterest.long.shortToken, cache.longOpenInterest);
} else {
cache.fundingUsdForLongCollateral = Precision.mulDiv(cache.fundingUsd, cache.openInterest.short.longToken, cache.shortOpenInterest);
cache.fundingUsdForShortCollateral = Precision.mulDiv(cache.fundingUsd, cache.openInterest.short.shortToken, cache.shortOpenInterest);
}
if (result.longsPayShorts) {
result.fundingFeeAmountPerSizeDelta.long.longToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForLongCollateral,
cache.openInterest.long.longToken,
prices.longTokenPrice.max,
true
);
result.fundingFeeAmountPerSizeDelta.long.shortToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForShortCollateral,
cache.openInterest.long.shortToken,
prices.shortTokenPrice.max,
true
);
result.claimableFundingAmountPerSizeDelta.short.longToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForLongCollateral,
cache.shortOpenInterest,
prices.longTokenPrice.max,
false
);
result.claimableFundingAmountPerSizeDelta.short.shortToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForShortCollateral,
cache.shortOpenInterest,
prices.shortTokenPrice.max,
false
);
} else {
result.fundingFeeAmountPerSizeDelta.short.longToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForLongCollateral,
cache.openInterest.short.longToken,
prices.longTokenPrice.max,
true
);
result.fundingFeeAmountPerSizeDelta.short.shortToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForShortCollateral,
cache.openInterest.short.shortToken,
prices.shortTokenPrice.max,
true
);
result.claimableFundingAmountPerSizeDelta.long.longToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForLongCollateral,
cache.longOpenInterest,
prices.longTokenPrice.max,
false
);
result.claimableFundingAmountPerSizeDelta.long.shortToken = getFundingAmountPerSizeDelta(
cache.fundingUsdForShortCollateral,
cache.longOpenInterest,
prices.shortTokenPrice.max,
false
);
}
return result;
}
function getNextFundingFactorPerSecond(
DataStore dataStore,
address market,
uint256 longOpenInterest,
uint256 shortOpenInterest,
uint256 durationInSeconds
) internal view returns (uint256, bool, int256) {
GetNextFundingFactorPerSecondCache memory cache;
cache.diffUsd = Calc.diff(longOpenInterest, shortOpenInterest);
cache.totalOpenInterest = longOpenInterest + shortOpenInterest;
FundingConfigCache memory configCache;
configCache.fundingIncreaseFactorPerSecond = dataStore.getUint(Keys.fundingIncreaseFactorPerSecondKey(market));
if (cache.diffUsd == 0 && configCache.fundingIncreaseFactorPerSecond == 0) {
return (0, true, 0);
}
if (cache.totalOpenInterest == 0) {
revert Errors.UnableToGetFundingFactorEmptyOpenInterest();
}
cache.fundingExponentFactor = getFundingExponentFactor(dataStore, market);
cache.diffUsdAfterExponent = Precision.applyExponentFactor(cache.diffUsd, cache.fundingExponentFactor);
cache.diffUsdToOpenInterestFactor = Precision.toFactor(cache.diffUsdAfterExponent, cache.totalOpenInterest);
if (configCache.fundingIncreaseFactorPerSecond == 0) {
cache.fundingFactor = getFundingFactor(dataStore, market);
uint256 maxFundingFactorPerSecond = dataStore.getUint(Keys.maxFundingFactorPerSecondKey(market));
uint256 fundingFactorPerSecond = Precision.applyFactor(cache.diffUsdToOpenInterestFactor, cache.fundingFactor);
if (fundingFactorPerSecond > maxFundingFactorPerSecond) {
fundingFactorPerSecond = maxFundingFactorPerSecond;
}
return (
fundingFactorPerSecond,
longOpenInterest > shortOpenInterest,
0
);
}
cache.savedFundingFactorPerSecond = getSavedFundingFactorPerSecond(dataStore, market);
cache.savedFundingFactorPerSecondMagnitude = cache.savedFundingFactorPerSecond.abs();
configCache.thresholdForStableFunding = dataStore.getUint(Keys.thresholdForStableFundingKey(market));
configCache.thresholdForDecreaseFunding = dataStore.getUint(Keys.thresholdForDecreaseFundingKey(market));
cache.nextSavedFundingFactorPerSecond = cache.savedFundingFactorPerSecond;
FundingRateChangeType fundingRateChangeType;
bool isSkewTheSameDirectionAsFunding = (cache.savedFundingFactorPerSecond > 0 && longOpenInterest > shortOpenInterest) || (cache.savedFundingFactorPerSecond < 0 && shortOpenInterest > longOpenInterest);
if (isSkewTheSameDirectionAsFunding) {
if (cache.diffUsdToOpenInterestFactor > configCache.thresholdForStableFunding) {
fundingRateChangeType = FundingRateChangeType.Increase;
} else if (cache.diffUsdToOpenInterestFactor < configCache.thresholdForDecreaseFunding) {
fundingRateChangeType = FundingRateChangeType.Decrease;
}
} else {
fundingRateChangeType = FundingRateChangeType.Increase;
}
if (fundingRateChangeType == FundingRateChangeType.Increase) {
int256 increaseValue = Precision.applyFactor(cache.diffUsdToOpenInterestFactor, configCache.fundingIncreaseFactorPerSecond).toInt256() * durationInSeconds.toInt256();
if (longOpenInterest < shortOpenInterest) {
increaseValue = -increaseValue;
}
cache.nextSavedFundingFactorPerSecond = cache.savedFundingFactorPerSecond + increaseValue;
}
if (fundingRateChangeType == FundingRateChangeType.Decrease && cache.savedFundingFactorPerSecondMagnitude != 0) {
configCache.fundingDecreaseFactorPerSecond = dataStore.getUint(Keys.fundingDecreaseFactorPerSecondKey(market));
uint256 decreaseValue = configCache.fundingDecreaseFactorPerSecond * durationInSeconds;
if (cache.savedFundingFactorPerSecondMagnitude <= decreaseValue) {
cache.nextSavedFundingFactorPerSecond = cache.savedFundingFactorPerSecond / cache.savedFundingFactorPerSecondMagnitude.toInt256();
} else {
int256 sign = cache.savedFundingFactorPerSecond / cache.savedFundingFactorPerSecondMagnitude.toInt256();
cache.nextSavedFundingFactorPerSecond = (cache.savedFundingFactorPerSecondMagnitude - decreaseValue).toInt256() * sign;
}
}
configCache.minFundingFactorPerSecond = dataStore.getUint(Keys.minFundingFactorPerSecondKey(market));
configCache.maxFundingFactorPerSecond = dataStore.getUint(Keys.maxFundingFactorPerSecondKey(market));
cache.nextSavedFundingFactorPerSecond = Calc.boundMagnitude(
cache.nextSavedFundingFactorPerSecond,
0,
configCache.maxFundingFactorPerSecond
);
cache.nextSavedFundingFactorPerSecondWithMinBound = Calc.boundMagnitude(
cache.nextSavedFundingFactorPerSecond,
configCache.minFundingFactorPerSecond,
configCache.maxFundingFactorPerSecond
);
return (
cache.nextSavedFundingFactorPerSecondWithMinBound.abs(),
cache.nextSavedFundingFactorPerSecondWithMinBound > 0,
cache.nextSavedFundingFactorPerSecond
);
}
function getFundingAmountPerSizeDelta(
uint256 fundingUsd,
uint256 openInterest,
uint256 tokenPrice,
bool roundUpMagnitude
) internal pure returns (uint256) {
if (fundingUsd == 0 || openInterest == 0) { return 0; }
uint256 fundingUsdPerSize = Precision.mulDiv(
fundingUsd,
Precision.FLOAT_PRECISION * Precision.FLOAT_PRECISION_SQRT,
openInterest,
roundUpMagnitude
);
if (roundUpMagnitude) {
return Calc.roundUpDivision(fundingUsdPerSize, tokenPrice);
} else {
return fundingUsdPerSize / tokenPrice;
}
}
function updateCumulativeBorrowingFactor(
DataStore dataStore,
EventEmitter eventEmitter,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) external {
(, uint256 delta) = getNextCumulativeBorrowingFactor(
dataStore,
market,
prices,
isLong
);
incrementCumulativeBorrowingFactor(
dataStore,
eventEmitter,
market.marketToken,
isLong,
delta
);
dataStore.setUint(Keys.cumulativeBorrowingFactorUpdatedAtKey(market.marketToken, isLong), Chain.currentTimestamp());
}
function getPnlToPoolFactor(
DataStore dataStore,
Oracle oracle,
address market,
bool isLong,
bool maximize
) internal view returns (int256) {
Market.Props memory _market = getEnabledMarket(dataStore, market);
MarketPrices memory prices = MarketPrices(
oracle.getPrimaryPrice(_market.indexToken),
oracle.getPrimaryPrice(_market.longToken),
oracle.getPrimaryPrice(_market.shortToken)
);
return getPnlToPoolFactor(dataStore, _market, prices, isLong, maximize);
}
function getPnlToPoolFactor(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong,
bool maximize
) internal view returns (int256) {
uint256 poolUsd = getPoolUsdWithoutPnl(dataStore, market, prices, isLong, !maximize);
if (poolUsd == 0) {
return 0;
}
int256 pnl = getPnl(
dataStore,
market,
prices.indexTokenPrice,
isLong,
maximize
);
return Precision.toFactor(pnl, poolUsd);
}
function validateOpenInterest(
DataStore dataStore,
Market.Props memory market,
bool isLong
) internal view {
uint256 openInterest = getOpenInterest(dataStore, market, isLong);
uint256 maxOpenInterest = getMaxOpenInterest(dataStore, market.marketToken, isLong);
if (openInterest > maxOpenInterest) {
revert Errors.MaxOpenInterestExceeded(openInterest, maxOpenInterest);
}
}
function validatePoolAmount(
DataStore dataStore,
Market.Props memory market,
address token
) internal view {
uint256 poolAmount = getPoolAmount(dataStore, market, token);
uint256 maxPoolAmount = getMaxPoolAmount(dataStore, market.marketToken, token);
if (poolAmount > maxPoolAmount) {
revert Errors.MaxPoolAmountExceeded(poolAmount, maxPoolAmount);
}
}
function validatePoolUsdForDeposit(
DataStore dataStore,
Market.Props memory market,
address token,
uint256 tokenPrice
) internal view {
uint256 poolAmount = getPoolAmount(dataStore, market, token);
uint256 poolUsd = poolAmount * tokenPrice;
uint256 maxPoolUsd = getMaxPoolUsdForDeposit(dataStore, market.marketToken, token);
if (poolUsd > maxPoolUsd) {
revert Errors.MaxPoolUsdForDepositExceeded(poolUsd, maxPoolUsd);
}
}
function validateReserve(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) internal view {
uint256 poolUsd = getPoolUsdWithoutPnl(dataStore, market, prices, isLong, false);
uint256 reserveFactor = getReserveFactor(dataStore, market.marketToken, isLong);
uint256 maxReservedUsd = Precision.applyFactor(poolUsd, reserveFactor);
uint256 reservedUsd = getReservedUsd(
dataStore,
market,
prices,
isLong
);
if (reservedUsd > maxReservedUsd) {
revert Errors.InsufficientReserve(reservedUsd, maxReservedUsd);
}
}
function validateOpenInterestReserve(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) internal view {
uint256 poolUsd = getPoolUsdWithoutPnl(dataStore, market, prices, isLong, false);
uint256 reserveFactor = getOpenInterestReserveFactor(dataStore, market.marketToken, isLong);
uint256 maxReservedUsd = Precision.applyFactor(poolUsd, reserveFactor);
uint256 reservedUsd = getReservedUsd(
dataStore,
market,
prices,
isLong
);
if (reservedUsd > maxReservedUsd) {
revert Errors.InsufficientReserveForOpenInterest(reservedUsd, maxReservedUsd);
}
}
function applySwapImpactWithCap(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
Price.Props memory tokenPrice,
int256 priceImpactUsd
) internal returns (int256, uint256) {
(int256 impactAmount, uint256 cappedDiffUsd) = getSwapImpactAmountWithCap(
dataStore,
market,
token,
tokenPrice,
priceImpactUsd
);
applyDeltaToSwapImpactPool(
dataStore,
eventEmitter,
market,
token,
-impactAmount
);
return (impactAmount, cappedDiffUsd);
}
function getSwapImpactAmountWithCap(
DataStore dataStore,
address market,
address token,
Price.Props memory tokenPrice,
int256 priceImpactUsd
) internal view returns (int256, uint256) {
int256 impactAmount;
uint256 cappedDiffUsd;
if (priceImpactUsd > 0) {
impactAmount = priceImpactUsd / tokenPrice.max.toInt256();
int256 maxImpactAmount = getSwapImpactPoolAmount(dataStore, market, token).toInt256();
if (impactAmount > maxImpactAmount) {
cappedDiffUsd = (impactAmount - maxImpactAmount).toUint256() * tokenPrice.max;
impactAmount = maxImpactAmount;
}
} else {
impactAmount = Calc.roundUpMagnitudeDivision(priceImpactUsd, tokenPrice.min);
}
return (impactAmount, cappedDiffUsd);
}
function getFundingAmount(
uint256 latestFundingAmountPerSize,
uint256 positionFundingAmountPerSize,
uint256 positionSizeInUsd,
bool roundUpMagnitude
) internal pure returns (uint256) {
uint256 fundingDiffFactor = (latestFundingAmountPerSize - positionFundingAmountPerSize);
return Precision.mulDiv(
positionSizeInUsd,
fundingDiffFactor,
Precision.FLOAT_PRECISION * Precision.FLOAT_PRECISION_SQRT,
roundUpMagnitude
);
}
function getBorrowingFees(DataStore dataStore, Position.Props memory position) internal view returns (uint256) {
uint256 cumulativeBorrowingFactor = getCumulativeBorrowingFactor(dataStore, position.market(), position.isLong());
if (position.borrowingFactor() > cumulativeBorrowingFactor) {
revert Errors.UnexpectedBorrowingFactor(position.borrowingFactor(), cumulativeBorrowingFactor);
}
uint256 diffFactor = cumulativeBorrowingFactor - position.borrowingFactor();
return Precision.applyFactor(position.sizeInUsd(), diffFactor);
}
function getNextBorrowingFees(DataStore dataStore, Position.Props memory position, Market.Props memory market, MarketPrices memory prices) internal view returns (uint256) {
(uint256 nextCumulativeBorrowingFactor, ) = getNextCumulativeBorrowingFactor(
dataStore,
market,
prices,
position.isLong()
);
if (position.borrowingFactor() > nextCumulativeBorrowingFactor) {
revert Errors.UnexpectedBorrowingFactor(position.borrowingFactor(), nextCumulativeBorrowingFactor);
}
uint256 diffFactor = nextCumulativeBorrowingFactor - position.borrowingFactor();
return Precision.applyFactor(position.sizeInUsd(), diffFactor);
}
function getReservedUsd(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) internal view returns (uint256) {
uint256 reservedUsd;
if (isLong) {
uint256 openInterestInTokens = getOpenInterestInTokens(dataStore, market, isLong);
reservedUsd = openInterestInTokens * prices.indexTokenPrice.max;
} else {
reservedUsd = getOpenInterest(dataStore, market, isLong);
}
return reservedUsd;
}
function getVirtualInventoryForSwaps(DataStore dataStore, address market) internal view returns (bool, uint256, uint256) {
bytes32 virtualMarketId = dataStore.getBytes32(Keys.virtualMarketIdKey(market));
if (virtualMarketId == bytes32(0)) {
return (false, 0, 0);
}
return (
true,
dataStore.getUint(Keys.virtualInventoryForSwapsKey(virtualMarketId, true)),
dataStore.getUint(Keys.virtualInventoryForSwapsKey(virtualMarketId, false))
);
}
function getIsLongToken(Market.Props memory market, address token) internal pure returns (bool) {
if (token != market.longToken && token != market.shortToken) {
revert Errors.UnexpectedTokenForVirtualInventory(token, market.marketToken);
}
return token == market.longToken;
}
function getVirtualInventoryForPositions(DataStore dataStore, address token) internal view returns (bool, int256) {
bytes32 virtualTokenId = dataStore.getBytes32(Keys.virtualTokenIdKey(token));
if (virtualTokenId == bytes32(0)) {
return (false, 0);
}
return (true, dataStore.getInt(Keys.virtualInventoryForPositionsKey(virtualTokenId)));
}
function applyDeltaToVirtualInventoryForSwaps(
DataStore dataStore,
EventEmitter eventEmitter,
Market.Props memory market,
address token,
int256 delta
) internal returns (bool, uint256) {
bytes32 virtualMarketId = dataStore.getBytes32(Keys.virtualMarketIdKey(market.marketToken));
if (virtualMarketId == bytes32(0)) {
return (false, 0);
}
bool isLongToken = getIsLongToken(market, token);
uint256 nextValue = dataStore.applyBoundedDeltaToUint(
Keys.virtualInventoryForSwapsKey(virtualMarketId, isLongToken),
delta
);
MarketEventUtils.emitVirtualSwapInventoryUpdated(eventEmitter, market.marketToken, isLongToken, virtualMarketId, delta, nextValue);
return (true, nextValue);
}
function applyDeltaToVirtualInventoryForPositions(
DataStore dataStore,
EventEmitter eventEmitter,
address token,
int256 delta
) internal returns (bool, int256) {
bytes32 virtualTokenId = dataStore.getBytes32(Keys.virtualTokenIdKey(token));
if (virtualTokenId == bytes32(0)) {
return (false, 0);
}
int256 nextValue = dataStore.applyDeltaToInt(
Keys.virtualInventoryForPositionsKey(virtualTokenId),
delta
);
MarketEventUtils.emitVirtualPositionInventoryUpdated(eventEmitter, token, virtualTokenId, delta, nextValue);
return (true, nextValue);
}
function getOpenInterest(
DataStore dataStore,
Market.Props memory market
) internal view returns (uint256) {
uint256 longOpenInterest = getOpenInterest(dataStore, market, true);
uint256 shortOpenInterest = getOpenInterest(dataStore, market, false);
return longOpenInterest + shortOpenInterest;
}
function getOpenInterest(
DataStore dataStore,
Market.Props memory market,
bool isLong
) internal view returns (uint256) {
uint256 divisor = getPoolDivisor(market.longToken, market.shortToken);
uint256 openInterestUsingLongTokenAsCollateral = getOpenInterest(dataStore, market.marketToken, market.longToken, isLong, divisor);
uint256 openInterestUsingShortTokenAsCollateral = getOpenInterest(dataStore, market.marketToken, market.shortToken, isLong, divisor);
return openInterestUsingLongTokenAsCollateral + openInterestUsingShortTokenAsCollateral;
}
function getOpenInterest(
DataStore dataStore,
address market,
address collateralToken,
bool isLong,
uint256 divisor
) internal view returns (uint256) {
return dataStore.getUint(Keys.openInterestKey(market, collateralToken, isLong)) / divisor;
}
function getPoolDivisor(address longToken, address shortToken) internal pure returns (uint256) {
return longToken == shortToken ? 2 : 1;
}
function getOpenInterestInTokens(
DataStore dataStore,
Market.Props memory market,
bool isLong
) internal view returns (uint256) {
uint256 divisor = getPoolDivisor(market.longToken, market.shortToken);
uint256 openInterestUsingLongTokenAsCollateral = getOpenInterestInTokens(dataStore, market.marketToken, market.longToken, isLong, divisor);
uint256 openInterestUsingShortTokenAsCollateral = getOpenInterestInTokens(dataStore, market.marketToken, market.shortToken, isLong, divisor);
return openInterestUsingLongTokenAsCollateral + openInterestUsingShortTokenAsCollateral;
}
function getOpenInterestInTokens(
DataStore dataStore,
address market,
address collateralToken,
bool isLong,
uint256 divisor
) internal view returns (uint256) {
return dataStore.getUint(Keys.openInterestInTokensKey(market, collateralToken, isLong)) / divisor;
}
function getOpenInterestWithPnl(
DataStore dataStore,
Market.Props memory market,
Price.Props memory indexTokenPrice,
bool isLong,
bool maximize
) internal view returns (int256) {
uint256 openInterest = getOpenInterest(dataStore, market, isLong);
int256 pnl = getPnl(dataStore, market, indexTokenPrice, isLong, maximize);
return Calc.sumReturnInt256(openInterest, pnl);
}
function getMaxPositionImpactFactor(DataStore dataStore, address market, bool isPositive) internal view returns (uint256) {
(uint256 maxPositiveImpactFactor, uint256 maxNegativeImpactFactor) = getMaxPositionImpactFactors(dataStore, market);
return isPositive ? maxPositiveImpactFactor : maxNegativeImpactFactor;
}
function getMaxPositionImpactFactors(DataStore dataStore, address market) internal view returns (uint256, uint256) {
uint256 maxPositiveImpactFactor = dataStore.getUint(Keys.maxPositionImpactFactorKey(market, true));
uint256 maxNegativeImpactFactor = dataStore.getUint(Keys.maxPositionImpactFactorKey(market, false));
if (maxPositiveImpactFactor > maxNegativeImpactFactor) {
maxPositiveImpactFactor = maxNegativeImpactFactor;
}
return (maxPositiveImpactFactor, maxNegativeImpactFactor);
}
function getMaxPositionImpactFactorForLiquidations(DataStore dataStore, address market) internal view returns (uint256) {
return dataStore.getUint(Keys.maxPositionImpactFactorForLiquidationsKey(market));
}
function getMinCollateralFactor(DataStore dataStore, address market) internal view returns (uint256) {
return dataStore.getUint(Keys.minCollateralFactorKey(market));
}
function getMinCollateralFactorForOpenInterestMultiplier(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.minCollateralFactorForOpenInterestMultiplierKey(market, isLong));
}
function getMinCollateralFactorForOpenInterest(
DataStore dataStore,
Market.Props memory market,
int256 openInterestDelta,
bool isLong
) internal view returns (uint256) {
uint256 openInterest = getOpenInterest(dataStore, market, isLong);
openInterest = Calc.sumReturnUint256(openInterest, openInterestDelta);
uint256 multiplierFactor = getMinCollateralFactorForOpenInterestMultiplier(dataStore, market.marketToken, isLong);
return Precision.applyFactor(openInterest, multiplierFactor);
}
function getCollateralSum(DataStore dataStore, address market, address collateralToken, bool isLong, uint256 divisor) internal view returns (uint256) {
return dataStore.getUint(Keys.collateralSumKey(market, collateralToken, isLong)) / divisor;
}
function getReserveFactor(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.reserveFactorKey(market, isLong));
}
function getOpenInterestReserveFactor(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.openInterestReserveFactorKey(market, isLong));
}
function getMaxPnlFactor(DataStore dataStore, bytes32 pnlFactorType, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.maxPnlFactorKey(pnlFactorType, market, isLong));
}
function getMinPnlFactorAfterAdl(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.minPnlFactorAfterAdlKey(market, isLong));
}
function getFundingFactor(DataStore dataStore, address market) internal view returns (uint256) {
return dataStore.getUint(Keys.fundingFactorKey(market));
}
function getSavedFundingFactorPerSecond(DataStore dataStore, address market) internal view returns (int256) {
return dataStore.getInt(Keys.savedFundingFactorPerSecondKey(market));
}
function setSavedFundingFactorPerSecond(DataStore dataStore, address market, int256 value) internal returns (int256) {
return dataStore.setInt(Keys.savedFundingFactorPerSecondKey(market), value);
}
function getFundingExponentFactor(DataStore dataStore, address market) internal view returns (uint256) {
return dataStore.getUint(Keys.fundingExponentFactorKey(market));
}
function getFundingFeeAmountPerSize(DataStore dataStore, address market, address collateralToken, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.fundingFeeAmountPerSizeKey(market, collateralToken, isLong));
}
function getClaimableFundingAmountPerSize(DataStore dataStore, address market, address collateralToken, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.claimableFundingAmountPerSizeKey(market, collateralToken, isLong));
}
function applyDeltaToFundingFeeAmountPerSize(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
uint256 delta
) internal {
if (delta == 0) { return; }
uint256 nextValue = dataStore.applyDeltaToUint(
Keys.fundingFeeAmountPerSizeKey(market, collateralToken, isLong),
delta
);
MarketEventUtils.emitFundingFeeAmountPerSizeUpdated(
eventEmitter,
market,
collateralToken,
isLong,
delta,
nextValue
);
}
function applyDeltaToClaimableFundingAmountPerSize(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address collateralToken,
bool isLong,
uint256 delta
) internal {
if (delta == 0) { return; }
uint256 nextValue = dataStore.applyDeltaToUint(
Keys.claimableFundingAmountPerSizeKey(market, collateralToken, isLong),
delta
);
MarketEventUtils.emitClaimableFundingAmountPerSizeUpdated(
eventEmitter,
market,
collateralToken,
isLong,
delta,
nextValue
);
}
function getSecondsSinceFundingUpdated(DataStore dataStore, address market) internal view returns (uint256) {
uint256 updatedAt = dataStore.getUint(Keys.fundingUpdatedAtKey(market));
if (updatedAt == 0) { return 0; }
return Chain.currentTimestamp() - updatedAt;
}
function getBorrowingFactor(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.borrowingFactorKey(market, isLong));
}
function getOptimalUsageFactor(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.optimalUsageFactorKey(market, isLong));
}
function getBorrowingExponentFactor(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.borrowingExponentFactorKey(market, isLong));
}
function getCumulativeBorrowingFactor(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.cumulativeBorrowingFactorKey(market, isLong));
}
function incrementCumulativeBorrowingFactor(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
bool isLong,
uint256 delta
) internal {
uint256 nextCumulativeBorrowingFactor = dataStore.incrementUint(
Keys.cumulativeBorrowingFactorKey(market, isLong),
delta
);
MarketEventUtils.emitBorrowingFactorUpdated(
eventEmitter,
market,
isLong,
delta,
nextCumulativeBorrowingFactor
);
}
function getCumulativeBorrowingFactorUpdatedAt(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.cumulativeBorrowingFactorUpdatedAtKey(market, isLong));
}
function getSecondsSinceCumulativeBorrowingFactorUpdated(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
uint256 updatedAt = getCumulativeBorrowingFactorUpdatedAt(dataStore, market, isLong);
if (updatedAt == 0) { return 0; }
return Chain.currentTimestamp() - updatedAt;
}
function updateTotalBorrowing(
DataStore dataStore,
address market,
bool isLong,
uint256 prevPositionSizeInUsd,
uint256 prevPositionBorrowingFactor,
uint256 nextPositionSizeInUsd,
uint256 nextPositionBorrowingFactor
) external {
uint256 totalBorrowing = getNextTotalBorrowing(
dataStore,
market,
isLong,
prevPositionSizeInUsd,
prevPositionBorrowingFactor,
nextPositionSizeInUsd,
nextPositionBorrowingFactor
);
setTotalBorrowing(dataStore, market, isLong, totalBorrowing);
}
function getNextTotalBorrowing(
DataStore dataStore,
address market,
bool isLong,
uint256 prevPositionSizeInUsd,
uint256 prevPositionBorrowingFactor,
uint256 nextPositionSizeInUsd,
uint256 nextPositionBorrowingFactor
) internal view returns (uint256) {
uint256 totalBorrowing = getTotalBorrowing(dataStore, market, isLong);
totalBorrowing -= Precision.applyFactor(prevPositionSizeInUsd, prevPositionBorrowingFactor);
totalBorrowing += Precision.applyFactor(nextPositionSizeInUsd, nextPositionBorrowingFactor);
return totalBorrowing;
}
function getNextCumulativeBorrowingFactor(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) internal view returns (uint256, uint256) {
uint256 durationInSeconds = getSecondsSinceCumulativeBorrowingFactorUpdated(dataStore, market.marketToken, isLong);
uint256 borrowingFactorPerSecond = getBorrowingFactorPerSecond(
dataStore,
market,
prices,
isLong
);
uint256 cumulativeBorrowingFactor = getCumulativeBorrowingFactor(dataStore, market.marketToken, isLong);
uint256 delta = durationInSeconds * borrowingFactorPerSecond;
uint256 nextCumulativeBorrowingFactor = cumulativeBorrowingFactor + delta;
return (nextCumulativeBorrowingFactor, delta);
}
function getBorrowingFactorPerSecond(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) internal view returns (uint256) {
uint256 reservedUsd = getReservedUsd(
dataStore,
market,
prices,
isLong
);
if (reservedUsd == 0) { return 0; }
bool skipBorrowingFeeForSmallerSide = dataStore.getBool(Keys.SKIP_BORROWING_FEE_FOR_SMALLER_SIDE);
if (skipBorrowingFeeForSmallerSide) {
uint256 longOpenInterest = getOpenInterest(dataStore, market, true);
uint256 shortOpenInterest = getOpenInterest(dataStore, market, false);
if (isLong && longOpenInterest < shortOpenInterest) {
return 0;
}
if (!isLong && shortOpenInterest < longOpenInterest) {
return 0;
}
}
uint256 poolUsd = getPoolUsdWithoutPnl(dataStore, market, prices, isLong, false);
if (poolUsd == 0) {
revert Errors.UnableToGetBorrowingFactorEmptyPoolUsd();
}
uint256 optimalUsageFactor = getOptimalUsageFactor(dataStore, market.marketToken, isLong);
if (optimalUsageFactor != 0) {
return getKinkBorrowingFactor(
dataStore,
market,
isLong,
reservedUsd,
poolUsd,
optimalUsageFactor
);
}
uint256 borrowingExponentFactor = getBorrowingExponentFactor(dataStore, market.marketToken, isLong);
uint256 reservedUsdAfterExponent = Precision.applyExponentFactor(reservedUsd, borrowingExponentFactor);
uint256 reservedUsdToPoolFactor = Precision.toFactor(reservedUsdAfterExponent, poolUsd);
uint256 borrowingFactor = getBorrowingFactor(dataStore, market.marketToken, isLong);
return Precision.applyFactor(reservedUsdToPoolFactor, borrowingFactor);
}
function getKinkBorrowingFactor(
DataStore dataStore,
Market.Props memory market,
bool isLong,
uint256 reservedUsd,
uint256 poolUsd,
uint256 optimalUsageFactor
) internal view returns (uint256) {
uint256 usageFactor = getUsageFactor(
dataStore,
market,
isLong,
reservedUsd,
poolUsd
);
uint256 baseBorrowingFactor = dataStore.getUint(Keys.baseBorrowingFactorKey(market.marketToken, isLong));
uint256 borrowingFactorPerSecond = Precision.applyFactor(
usageFactor,
baseBorrowingFactor
);
if (usageFactor > optimalUsageFactor && Precision.FLOAT_PRECISION > optimalUsageFactor) {
uint256 diff = usageFactor - optimalUsageFactor;
uint256 aboveOptimalUsageBorrowingFactor = dataStore.getUint(Keys.aboveOptimalUsageBorrowingFactorKey(market.marketToken, isLong));
uint256 additionalBorrowingFactorPerSecond;
if (aboveOptimalUsageBorrowingFactor > baseBorrowingFactor) {
additionalBorrowingFactorPerSecond = aboveOptimalUsageBorrowingFactor - baseBorrowingFactor;
}
uint256 divisor = Precision.FLOAT_PRECISION - optimalUsageFactor;
borrowingFactorPerSecond += additionalBorrowingFactorPerSecond * diff / divisor;
}
return borrowingFactorPerSecond;
}
function distributePositionImpactPool(
DataStore dataStore,
EventEmitter eventEmitter,
address market
) external {
(uint256 distributionAmount, uint256 nextPositionImpactPoolAmount) = getPendingPositionImpactPoolDistributionAmount(dataStore, market);
if (distributionAmount != 0) {
applyDeltaToPositionImpactPool(
dataStore,
eventEmitter,
market,
-distributionAmount.toInt256()
);
MarketEventUtils.emitPositionImpactPoolDistributed(
eventEmitter,
market,
distributionAmount,
nextPositionImpactPoolAmount
);
}
dataStore.setUint(Keys.positionImpactPoolDistributedAtKey(market), Chain.currentTimestamp());
}
function getNextPositionImpactPoolAmount(
DataStore dataStore,
address market
) internal view returns (uint256) {
(, uint256 nextPositionImpactPoolAmount) = getPendingPositionImpactPoolDistributionAmount(dataStore, market);
return nextPositionImpactPoolAmount;
}
function getPendingPositionImpactPoolDistributionAmount(
DataStore dataStore,
address market
) internal view returns (uint256, uint256) {
uint256 positionImpactPoolAmount = getPositionImpactPoolAmount(dataStore, market);
if (positionImpactPoolAmount == 0) { return (0, positionImpactPoolAmount); }
uint256 distributionRate = dataStore.getUint(Keys.positionImpactPoolDistributionRateKey(market));
if (distributionRate == 0) { return (0, positionImpactPoolAmount); }
uint256 minPositionImpactPoolAmount = dataStore.getUint(Keys.minPositionImpactPoolAmountKey(market));
if (positionImpactPoolAmount <= minPositionImpactPoolAmount) { return (0, positionImpactPoolAmount); }
uint256 maxDistributionAmount = positionImpactPoolAmount - minPositionImpactPoolAmount;
uint256 durationInSeconds = getSecondsSincePositionImpactPoolDistributed(dataStore, market);
uint256 distributionAmount = Precision.applyFactor(durationInSeconds, distributionRate);
if (distributionAmount > maxDistributionAmount) {
distributionAmount = maxDistributionAmount;
}
return (distributionAmount, positionImpactPoolAmount - distributionAmount);
}
function getSecondsSincePositionImpactPoolDistributed(
DataStore dataStore,
address market
) internal view returns (uint256) {
uint256 distributedAt = dataStore.getUint(Keys.positionImpactPoolDistributedAtKey(market));
if (distributedAt == 0) { return 0; }
return Chain.currentTimestamp() - distributedAt;
}
function getTotalPendingBorrowingFees(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong
) internal view returns (uint256) {
uint256 openInterest = getOpenInterest(
dataStore,
market,
isLong
);
(uint256 nextCumulativeBorrowingFactor, ) = getNextCumulativeBorrowingFactor(
dataStore,
market,
prices,
isLong
);
uint256 totalBorrowing = getTotalBorrowing(dataStore, market.marketToken, isLong);
return Precision.applyFactor(openInterest, nextCumulativeBorrowingFactor) - totalBorrowing;
}
function getTotalBorrowing(DataStore dataStore, address market, bool isLong) internal view returns (uint256) {
return dataStore.getUint(Keys.totalBorrowingKey(market, isLong));
}
function setTotalBorrowing(DataStore dataStore, address market, bool isLong, uint256 value) internal returns (uint256) {
return dataStore.setUint(Keys.totalBorrowingKey(market, isLong), value);
}
function usdToMarketTokenAmount(
uint256 usdValue,
uint256 poolValue,
uint256 supply
) internal pure returns (uint256) {
if (supply == 0 && poolValue == 0) {
return Precision.floatToWei(usdValue);
}
if (supply == 0 && poolValue > 0) {
return Precision.floatToWei(poolValue + usdValue);
}
return Precision.mulDiv(supply, usdValue, poolValue);
}
function marketTokenAmountToUsd(
uint256 marketTokenAmount,
uint256 poolValue,
uint256 supply
) internal pure returns (uint256) {
if (supply == 0) { revert Errors.EmptyMarketTokenSupply(); }
return Precision.mulDiv(poolValue, marketTokenAmount, supply);
}
function validateEnabledMarket(DataStore dataStore, address marketAddress) internal view {
Market.Props memory market = MarketStoreUtils.get(dataStore, marketAddress);
validateEnabledMarket(dataStore, market);
}
function validateEnabledMarket(DataStore dataStore, Market.Props memory market) internal view {
if (market.marketToken == address(0)) {
revert Errors.EmptyMarket();
}
bool isMarketDisabled = dataStore.getBool(Keys.isMarketDisabledKey(market.marketToken));
if (isMarketDisabled) {
revert Errors.DisabledMarket(market.marketToken);
}
}
function validatePositionMarket(DataStore dataStore, Market.Props memory market) internal view {
validateEnabledMarket(dataStore, market);
if (isSwapOnlyMarket(market)) {
revert Errors.InvalidPositionMarket(market.marketToken);
}
}
function validatePositionMarket(DataStore dataStore, address marketAddress) internal view {
Market.Props memory market = MarketStoreUtils.get(dataStore, marketAddress);
validatePositionMarket(dataStore, market);
}
function isSwapOnlyMarket(Market.Props memory market) internal pure returns (bool) {
return market.indexToken == address(0);
}
function isMarketCollateralToken(Market.Props memory market, address token) internal pure returns (bool) {
return token == market.longToken || token == market.shortToken;
}
function validateMarketCollateralToken(Market.Props memory market, address token) internal pure {
if (!isMarketCollateralToken(market, token)) {
revert Errors.InvalidCollateralTokenForMarket(market.marketToken, token);
}
}
function getEnabledMarket(DataStore dataStore, address marketAddress) internal view returns (Market.Props memory) {
Market.Props memory market = MarketStoreUtils.get(dataStore, marketAddress);
validateEnabledMarket(dataStore, market);
return market;
}
function getSwapPathMarket(DataStore dataStore, address marketAddress) internal view returns (Market.Props memory) {
Market.Props memory market = MarketStoreUtils.get(dataStore, marketAddress);
validateSwapMarket(dataStore, market);
return market;
}
function getSwapPathMarkets(DataStore dataStore, address[] memory swapPath) internal view returns (Market.Props[] memory) {
Market.Props[] memory markets = new Market.Props[](swapPath.length);
for (uint256 i; i < swapPath.length; i++) {
address marketAddress = swapPath[i];
markets[i] = getSwapPathMarket(dataStore, marketAddress);
}
return markets;
}
function validateSwapPath(DataStore dataStore, address[] memory swapPath) internal view {
uint256 maxSwapPathLength = dataStore.getUint(Keys.MAX_SWAP_PATH_LENGTH);
if (swapPath.length > maxSwapPathLength) {
revert Errors.MaxSwapPathLengthExceeded(swapPath.length, maxSwapPathLength);
}
for (uint256 i; i < swapPath.length; i++) {
address marketAddress = swapPath[i];
validateSwapMarket(dataStore, marketAddress);
}
}
function validateMaxPnl(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bytes32 pnlFactorTypeForLongs,
bytes32 pnlFactorTypeForShorts
) internal view {
(bool isPnlFactorExceededForLongs, int256 pnlToPoolFactorForLongs, uint256 maxPnlFactorForLongs) = isPnlFactorExceeded(
dataStore,
market,
prices,
true,
pnlFactorTypeForLongs
);
if (isPnlFactorExceededForLongs) {
revert Errors.PnlFactorExceededForLongs(pnlToPoolFactorForLongs, maxPnlFactorForLongs);
}
(bool isPnlFactorExceededForShorts, int256 pnlToPoolFactorForShorts, uint256 maxPnlFactorForShorts) = isPnlFactorExceeded(
dataStore,
market,
prices,
false,
pnlFactorTypeForShorts
);
if (isPnlFactorExceededForShorts) {
revert Errors.PnlFactorExceededForShorts(pnlToPoolFactorForShorts, maxPnlFactorForShorts);
}
}
function isPnlFactorExceeded(
DataStore dataStore,
Oracle oracle,
address market,
bool isLong,
bytes32 pnlFactorType
) internal view returns (bool, int256, uint256) {
Market.Props memory _market = getEnabledMarket(dataStore, market);
MarketPrices memory prices = getMarketPrices(oracle, _market);
return isPnlFactorExceeded(
dataStore,
_market,
prices,
isLong,
pnlFactorType
);
}
function isPnlFactorExceeded(
DataStore dataStore,
Market.Props memory market,
MarketPrices memory prices,
bool isLong,
bytes32 pnlFactorType
) internal view returns (bool, int256, uint256) {
int256 pnlToPoolFactor = getPnlToPoolFactor(dataStore, market, prices, isLong, true);
uint256 maxPnlFactor = getMaxPnlFactor(dataStore, pnlFactorType, market.marketToken, isLong);
bool isExceeded = pnlToPoolFactor > 0 && pnlToPoolFactor.toUint256() > maxPnlFactor;
return (isExceeded, pnlToPoolFactor, maxPnlFactor);
}
function getUiFeeFactor(DataStore dataStore, address account) internal view returns (uint256) {
uint256 maxUiFeeFactor = dataStore.getUint(Keys.MAX_UI_FEE_FACTOR);
uint256 uiFeeFactor = dataStore.getUint(Keys.uiFeeFactorKey(account));
return uiFeeFactor < maxUiFeeFactor ? uiFeeFactor : maxUiFeeFactor;
}
function setUiFeeFactor(
DataStore dataStore,
EventEmitter eventEmitter,
address account,
uint256 uiFeeFactor
) internal {
uint256 maxUiFeeFactor = dataStore.getUint(Keys.MAX_UI_FEE_FACTOR);
if (uiFeeFactor > maxUiFeeFactor) {
revert Errors.InvalidUiFeeFactor(uiFeeFactor, maxUiFeeFactor);
}
dataStore.setUint(
Keys.uiFeeFactorKey(account),
uiFeeFactor
);
MarketEventUtils.emitUiFeeFactorUpdated(eventEmitter, account, uiFeeFactor);
}
function validateMarketTokenBalance(
DataStore dataStore,
Market.Props[] memory markets
) public view {
for (uint256 i; i < markets.length; i++) {
validateMarketTokenBalance(dataStore, markets[i]);
}
}
function validateMarketTokenBalance(
DataStore dataStore,
address _market
) public view {
Market.Props memory market = getEnabledMarket(dataStore, _market);
validateMarketTokenBalance(dataStore, market);
}
function validateMarketTokenBalance(
DataStore dataStore,
Market.Props memory market
) public view {
validateMarketTokenBalance(dataStore, market, market.longToken);
if (market.longToken == market.shortToken) {
return;
}
validateMarketTokenBalance(dataStore, market, market.shortToken);
}
function validateMarketTokenBalance(
DataStore dataStore,
Market.Props memory market,
address token
) internal view {
if (market.marketToken == address(0) || token == address(0)) {
revert Errors.EmptyAddressInMarketTokenBalanceValidation(market.marketToken, token);
}
uint256 balance = IERC20(token).balanceOf(market.marketToken);
uint256 expectedMinBalance = getExpectedMinTokenBalance(dataStore, market, token);
if (balance < expectedMinBalance) {
revert Errors.InvalidMarketTokenBalance(market.marketToken, token, balance, expectedMinBalance);
}
uint256 collateralAmount = getCollateralSum(dataStore, market.marketToken, token, true, 1);
collateralAmount += getCollateralSum(dataStore, market.marketToken, token, false, 1);
if (balance < collateralAmount) {
revert Errors.InvalidMarketTokenBalanceForCollateralAmount(market.marketToken, token, balance, collateralAmount);
}
uint256 claimableFundingFeeAmount = dataStore.getUint(Keys.claimableFundingAmountKey(market.marketToken, token));
if (balance < claimableFundingFeeAmount) {
revert Errors.InvalidMarketTokenBalanceForClaimableFunding(market.marketToken, token, balance, claimableFundingFeeAmount);
}
}
function getExpectedMinTokenBalance(
DataStore dataStore,
Market.Props memory market,
address token
) internal view returns (uint256) {
GetExpectedMinTokenBalanceCache memory cache;
cache.poolAmount = dataStore.getUint(Keys.poolAmountKey(market.marketToken, token));
cache.swapImpactPoolAmount = getSwapImpactPoolAmount(dataStore, market.marketToken, token);
cache.claimableCollateralAmount = dataStore.getUint(Keys.claimableCollateralAmountKey(market.marketToken, token));
cache.claimableFeeAmount = dataStore.getUint(Keys.claimableFeeAmountKey(market.marketToken, token));
cache.claimableUiFeeAmount = dataStore.getUint(Keys.claimableUiFeeAmountKey(market.marketToken, token));
cache.affiliateRewardAmount = dataStore.getUint(Keys.affiliateRewardKey(market.marketToken, token));
return
cache.poolAmount
+ cache.swapImpactPoolAmount
+ cache.claimableCollateralAmount
+ cache.claimableFeeAmount
+ cache.claimableUiFeeAmount
+ cache.affiliateRewardAmount;
}
}
文件 67 的 108:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 68 的 108:NonceUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../data/Keys.sol";
library NonceUtils {
function getCurrentNonce(DataStore dataStore) internal view returns (uint256) {
return dataStore.getUint(Keys.NONCE);
}
function incrementNonce(DataStore dataStore) internal returns (uint256) {
return dataStore.incrementUint(Keys.NONCE, 1);
}
function getNextKey(DataStore dataStore) internal returns (bytes32) {
uint256 nonce = incrementNonce(dataStore);
bytes32 key = getKey(dataStore, nonce);
return key;
}
function getCurrentKey(DataStore dataStore) internal view returns (bytes32) {
uint256 nonce = getCurrentNonce(dataStore);
bytes32 key = getKey(dataStore, nonce);
return key;
}
function getKey(DataStore dataStore, uint256 nonce) internal pure returns (bytes32) {
return keccak256(abi.encode(address(dataStore), nonce));
}
}
文件 69 的 108:Oracle.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { AggregatorV2V3Interface } from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol";
import "../role/RoleModule.sol";
import "./OracleUtils.sol";
import "./IOracleProvider.sol";
import "./ChainlinkPriceFeedUtils.sol";
import "../price/Price.sol";
import "../chain/Chain.sol";
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Precision.sol";
import "../utils/Cast.sol";
import "../utils/Uint256Mask.sol";
contract Oracle is RoleModule {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableValues for EnumerableSet.AddressSet;
using Price for Price.Props;
using Uint256Mask for Uint256Mask.Mask;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
DataStore public immutable dataStore;
EventEmitter public immutable eventEmitter;
AggregatorV2V3Interface public immutable sequencerUptimeFeed;
EnumerableSet.AddressSet internal tokensWithPrices;
mapping(address => Price.Props) public primaryPrices;
uint256 public minTimestamp;
uint256 public maxTimestamp;
constructor(
RoleStore _roleStore,
DataStore _dataStore,
EventEmitter _eventEmitter,
AggregatorV2V3Interface _sequencerUptimeFeed
) RoleModule(_roleStore) {
dataStore = _dataStore;
eventEmitter = _eventEmitter;
sequencerUptimeFeed = _sequencerUptimeFeed;
}
function validateSequencerUp() external view {
if (address(sequencerUptimeFeed) == address(0)) {
return;
}
(
,
int256 answer,
uint256 startedAt,
,
) = sequencerUptimeFeed.latestRoundData();
bool isSequencerUp = answer == 0;
if (!isSequencerUp) {
revert Errors.SequencerDown();
}
uint256 sequencerGraceDuration = dataStore.getUint(Keys.SEQUENCER_GRACE_DURATION);
uint256 timeSinceUp = block.timestamp - startedAt;
if (timeSinceUp <= sequencerGraceDuration) {
revert Errors.SequencerGraceDurationNotYetPassed(timeSinceUp, sequencerGraceDuration);
}
}
function setPrices(
OracleUtils.SetPricesParams memory params
) external onlyController {
OracleUtils.ValidatedPrice[] memory prices = _validatePrices(params, false);
_setPrices(prices);
}
function setPricesForAtomicAction(
OracleUtils.SetPricesParams memory params
) external onlyController {
OracleUtils.ValidatedPrice[] memory prices = _validatePrices(params, true);
_setPrices(prices);
}
function setPrimaryPrice(address token, Price.Props memory price) external onlyController {
_setPrimaryPrice(token, price);
}
function setTimestamps(uint256 _minTimestamp, uint256 _maxTimestamp) external onlyController {
minTimestamp = _minTimestamp;
maxTimestamp = _maxTimestamp;
}
function clearAllPrices() external onlyController {
uint256 length = tokensWithPrices.length();
for (uint256 i; i < length; i++) {
address token = tokensWithPrices.at(0);
_removePrimaryPrice(token);
}
minTimestamp = 0;
maxTimestamp = 0;
}
function getTokensWithPricesCount() external view returns (uint256) {
return tokensWithPrices.length();
}
function getTokensWithPrices(uint256 start, uint256 end) external view returns (address[] memory) {
return tokensWithPrices.valuesAt(start, end);
}
function getPrimaryPrice(address token) external view returns (Price.Props memory) {
if (token == address(0)) { return Price.Props(0, 0); }
Price.Props memory price = primaryPrices[token];
if (price.isEmpty()) {
revert Errors.EmptyPrimaryPrice(token);
}
return price;
}
function validatePrices(
OracleUtils.SetPricesParams memory params,
bool forAtomicAction
) external onlyController returns (OracleUtils.ValidatedPrice[] memory) {
return _validatePrices(params, forAtomicAction);
}
function _setPrices(
OracleUtils.ValidatedPrice[] memory prices
) internal returns (OracleUtils.ValidatedPrice[] memory) {
if (tokensWithPrices.length() != 0) {
revert Errors.NonEmptyTokensWithPrices(tokensWithPrices.length());
}
if (prices.length == 0) {
revert Errors.EmptyValidatedPrices();
}
uint256 _minTimestamp = prices[0].timestamp;
uint256 _maxTimestamp = prices[0].timestamp;
for (uint256 i; i < prices.length; i++) {
OracleUtils.ValidatedPrice memory validatedPrice = prices[i];
_setPrimaryPrice(validatedPrice.token, Price.Props(
validatedPrice.min,
validatedPrice.max
));
if (validatedPrice.timestamp < _minTimestamp) {
_minTimestamp = validatedPrice.timestamp;
}
if (validatedPrice.timestamp > _maxTimestamp) {
_maxTimestamp = validatedPrice.timestamp;
}
_emitOraclePriceUpdated(
validatedPrice.token,
validatedPrice.min,
validatedPrice.max,
validatedPrice.timestamp,
validatedPrice.provider
);
}
uint256 maxRange = dataStore.getUint(Keys.MAX_ORACLE_TIMESTAMP_RANGE);
if (_maxTimestamp - _minTimestamp > maxRange) {
revert Errors.MaxOracleTimestampRangeExceeded(_maxTimestamp - _minTimestamp, maxRange);
}
minTimestamp = _minTimestamp;
maxTimestamp = _maxTimestamp;
return prices;
}
function _validatePrices(
OracleUtils.SetPricesParams memory params,
bool forAtomicAction
) internal returns (OracleUtils.ValidatedPrice[] memory) {
if (params.tokens.length != params.providers.length) {
revert Errors.InvalidOracleSetPricesProvidersParam(params.tokens.length, params.providers.length);
}
if (params.tokens.length != params.data.length) {
revert Errors.InvalidOracleSetPricesDataParam(params.tokens.length, params.data.length);
}
OracleUtils.ValidatedPrice[] memory prices = new OracleUtils.ValidatedPrice[](params.tokens.length);
uint256 maxPriceAge = dataStore.getUint(Keys.MAX_ORACLE_PRICE_AGE);
uint256 maxRefPriceDeviationFactor = dataStore.getUint(Keys.MAX_ORACLE_REF_PRICE_DEVIATION_FACTOR);
for (uint256 i; i < params.tokens.length; i++) {
address provider = params.providers[i];
if (!dataStore.getBool(Keys.isOracleProviderEnabledKey(provider))) {
revert Errors.InvalidOracleProvider(provider);
}
address token = params.tokens[i];
bool isAtomicProvider = dataStore.getBool(Keys.isAtomicOracleProviderKey(provider));
if (forAtomicAction) {
if (!isAtomicProvider) {
revert Errors.NonAtomicOracleProvider(provider);
}
} else {
address expectedProvider = dataStore.getAddress(Keys.oracleProviderForTokenKey(token));
if (provider != expectedProvider) {
revert Errors.InvalidOracleProviderForToken(provider, expectedProvider);
}
}
bytes memory data = params.data[i];
OracleUtils.ValidatedPrice memory validatedPrice = IOracleProvider(provider).getOraclePrice(
token,
data
);
if (!isAtomicProvider) {
uint256 timestampAdjustment = dataStore.getUint(Keys.oracleTimestampAdjustmentKey(provider, token));
validatedPrice.timestamp -= timestampAdjustment;
}
if (validatedPrice.timestamp + maxPriceAge < Chain.currentTimestamp()) {
revert Errors.MaxPriceAgeExceeded(validatedPrice.timestamp, Chain.currentTimestamp());
}
if (!isAtomicProvider) {
(bool hasRefPrice, uint256 refPrice) = ChainlinkPriceFeedUtils.getPriceFeedPrice(dataStore, token);
if (hasRefPrice) {
_validateRefPrice(
token,
validatedPrice.min,
refPrice,
maxRefPriceDeviationFactor
);
_validateRefPrice(
token,
validatedPrice.max,
refPrice,
maxRefPriceDeviationFactor
);
}
}
prices[i] = validatedPrice;
}
return prices;
}
function _validateRefPrice(
address token,
uint256 price,
uint256 refPrice,
uint256 maxRefPriceDeviationFactor
) internal pure {
uint256 diff = Calc.diff(price, refPrice);
uint256 diffFactor = Precision.toFactor(diff, refPrice);
if (diffFactor > maxRefPriceDeviationFactor) {
revert Errors.MaxRefPriceDeviationExceeded(
token,
price,
refPrice,
maxRefPriceDeviationFactor
);
}
}
function _setPrimaryPrice(address token, Price.Props memory price) internal {
if (price.min > price.max) {
revert Errors.InvalidMinMaxForPrice(token, price.min, price.max);
}
Price.Props memory existingPrice = primaryPrices[token];
if (!existingPrice.isEmpty()) {
revert Errors.PriceAlreadySet(token, existingPrice.min, existingPrice.max);
}
primaryPrices[token] = price;
tokensWithPrices.add(token);
}
function _removePrimaryPrice(address token) internal {
delete primaryPrices[token];
tokensWithPrices.remove(token);
}
function _emitOraclePriceUpdated(
address token,
uint256 minPrice,
uint256 maxPrice,
uint256 timestamp,
address provider
) internal {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(2);
eventData.addressItems.setItem(0, "token", token);
eventData.addressItems.setItem(1, "provider", provider);
eventData.uintItems.initItems(3);
eventData.uintItems.setItem(0, "minPrice", minPrice);
eventData.uintItems.setItem(1, "maxPrice", maxPrice);
eventData.uintItems.setItem(2, "timestamp", timestamp);
eventEmitter.emitEventLog1(
"OraclePriceUpdate",
Cast.toBytes32(token),
eventData
);
}
}
文件 70 的 108:OracleUtils.sol
pragma solidity ^0.8.0;
import "../utils/Array.sol";
import "../price/Price.sol";
library OracleUtils {
using Array for uint256[];
struct SetPricesParams {
address[] tokens;
address[] providers;
bytes[] data;
}
struct ValidatedPrice {
address token;
uint256 min;
uint256 max;
uint256 timestamp;
address provider;
}
struct SimulatePricesParams {
address[] primaryTokens;
Price.Props[] primaryPrices;
uint256 minTimestamp;
uint256 maxTimestamp;
}
function isOracleError(bytes4 errorSelector) internal pure returns (bool) {
if (isOracleTimestampError(errorSelector)) {
return true;
}
if (isEmptyPriceError(errorSelector)) {
return true;
}
return false;
}
function isEmptyPriceError(bytes4 errorSelector) internal pure returns (bool) {
if (errorSelector == Errors.EmptyPrimaryPrice.selector) {
return true;
}
return false;
}
function isOracleTimestampError(bytes4 errorSelector) internal pure returns (bool) {
if (errorSelector == Errors.OracleTimestampsAreLargerThanRequestExpirationTime.selector) {
return true;
}
if (errorSelector == Errors.OracleTimestampsAreSmallerThanRequired.selector) {
return true;
}
return false;
}
}
文件 71 的 108:Order.sol
pragma solidity ^0.8.0;
import "../chain/Chain.sol";
library Order {
using Order for Props;
enum OrderType {
MarketSwap,
LimitSwap,
MarketIncrease,
LimitIncrease,
MarketDecrease,
LimitDecrease,
StopLossDecrease,
Liquidation,
StopIncrease
}
enum SecondaryOrderType {
None,
Adl
}
enum DecreasePositionSwapType {
NoSwap,
SwapPnlTokenToCollateralToken,
SwapCollateralTokenToPnlToken
}
struct Props {
Addresses addresses;
Numbers numbers;
Flags flags;
}
struct Addresses {
address account;
address receiver;
address cancellationReceiver;
address callbackContract;
address uiFeeReceiver;
address market;
address initialCollateralToken;
address[] swapPath;
}
struct Numbers {
OrderType orderType;
DecreasePositionSwapType decreasePositionSwapType;
uint256 sizeDeltaUsd;
uint256 initialCollateralDeltaAmount;
uint256 triggerPrice;
uint256 acceptablePrice;
uint256 executionFee;
uint256 callbackGasLimit;
uint256 minOutputAmount;
uint256 updatedAtTime;
uint256 validFromTime;
}
struct Flags {
bool isLong;
bool shouldUnwrapNativeToken;
bool isFrozen;
bool autoCancel;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function receiver(Props memory props) internal pure returns (address) {
return props.addresses.receiver;
}
function setReceiver(Props memory props, address value) internal pure {
props.addresses.receiver = value;
}
function cancellationReceiver(Props memory props) internal pure returns (address) {
return props.addresses.cancellationReceiver;
}
function setCancellationReceiver(Props memory props, address value) internal pure {
props.addresses.cancellationReceiver = value;
}
function callbackContract(Props memory props) internal pure returns (address) {
return props.addresses.callbackContract;
}
function setCallbackContract(Props memory props, address value) internal pure {
props.addresses.callbackContract = value;
}
function market(Props memory props) internal pure returns (address) {
return props.addresses.market;
}
function setMarket(Props memory props, address value) internal pure {
props.addresses.market = value;
}
function initialCollateralToken(Props memory props) internal pure returns (address) {
return props.addresses.initialCollateralToken;
}
function setInitialCollateralToken(Props memory props, address value) internal pure {
props.addresses.initialCollateralToken = value;
}
function uiFeeReceiver(Props memory props) internal pure returns (address) {
return props.addresses.uiFeeReceiver;
}
function setUiFeeReceiver(Props memory props, address value) internal pure {
props.addresses.uiFeeReceiver = value;
}
function swapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.swapPath;
}
function setSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.swapPath = value;
}
function orderType(Props memory props) internal pure returns (OrderType) {
return props.numbers.orderType;
}
function setOrderType(Props memory props, OrderType value) internal pure {
props.numbers.orderType = value;
}
function decreasePositionSwapType(Props memory props) internal pure returns (DecreasePositionSwapType) {
return props.numbers.decreasePositionSwapType;
}
function setDecreasePositionSwapType(Props memory props, DecreasePositionSwapType value) internal pure {
props.numbers.decreasePositionSwapType = value;
}
function sizeDeltaUsd(Props memory props) internal pure returns (uint256) {
return props.numbers.sizeDeltaUsd;
}
function setSizeDeltaUsd(Props memory props, uint256 value) internal pure {
props.numbers.sizeDeltaUsd = value;
}
function initialCollateralDeltaAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.initialCollateralDeltaAmount;
}
function setInitialCollateralDeltaAmount(Props memory props, uint256 value) internal pure {
props.numbers.initialCollateralDeltaAmount = value;
}
function triggerPrice(Props memory props) internal pure returns (uint256) {
return props.numbers.triggerPrice;
}
function setTriggerPrice(Props memory props, uint256 value) internal pure {
props.numbers.triggerPrice = value;
}
function acceptablePrice(Props memory props) internal pure returns (uint256) {
return props.numbers.acceptablePrice;
}
function setAcceptablePrice(Props memory props, uint256 value) internal pure {
props.numbers.acceptablePrice = value;
}
function setExecutionFee(Props memory props, uint256 value) internal pure {
props.numbers.executionFee = value;
}
function executionFee(Props memory props) internal pure returns (uint256) {
return props.numbers.executionFee;
}
function callbackGasLimit(Props memory props) internal pure returns (uint256) {
return props.numbers.callbackGasLimit;
}
function setCallbackGasLimit(Props memory props, uint256 value) internal pure {
props.numbers.callbackGasLimit = value;
}
function minOutputAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.minOutputAmount;
}
function setMinOutputAmount(Props memory props, uint256 value) internal pure {
props.numbers.minOutputAmount = value;
}
function updatedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.updatedAtTime;
}
function setUpdatedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.updatedAtTime = value;
}
function validFromTime(Props memory props) internal pure returns (uint256) {
return props.numbers.validFromTime;
}
function setValidFromTime(Props memory props, uint256 value) internal pure {
props.numbers.validFromTime = value;
}
function isLong(Props memory props) internal pure returns (bool) {
return props.flags.isLong;
}
function setIsLong(Props memory props, bool value) internal pure {
props.flags.isLong = value;
}
function shouldUnwrapNativeToken(Props memory props) internal pure returns (bool) {
return props.flags.shouldUnwrapNativeToken;
}
function setShouldUnwrapNativeToken(Props memory props, bool value) internal pure {
props.flags.shouldUnwrapNativeToken = value;
}
function isFrozen(Props memory props) internal pure returns (bool) {
return props.flags.isFrozen;
}
function setIsFrozen(Props memory props, bool value) internal pure {
props.flags.isFrozen = value;
}
function autoCancel(Props memory props) internal pure returns (bool) {
return props.flags.autoCancel;
}
function setAutoCancel(Props memory props, bool value) internal pure {
props.flags.autoCancel = value;
}
function touch(Props memory props) internal view {
props.setUpdatedAtTime(Chain.currentTimestamp());
}
}
文件 72 的 108:OrderStoreUtils.sol
pragma solidity ^0.8.0;
import "../data/Keys.sol";
import "../data/DataStore.sol";
import "./Order.sol";
library OrderStoreUtils {
using Order for Order.Props;
bytes32 public constant ACCOUNT = keccak256(abi.encode("ACCOUNT"));
bytes32 public constant RECEIVER = keccak256(abi.encode("RECEIVER"));
bytes32 public constant CANCELLATION_RECEIVER = keccak256(abi.encode("CANCELLATION_RECEIVER"));
bytes32 public constant CALLBACK_CONTRACT = keccak256(abi.encode("CALLBACK_CONTRACT"));
bytes32 public constant UI_FEE_RECEIVER = keccak256(abi.encode("UI_FEE_RECEIVER"));
bytes32 public constant MARKET = keccak256(abi.encode("MARKET"));
bytes32 public constant INITIAL_COLLATERAL_TOKEN = keccak256(abi.encode("INITIAL_COLLATERAL_TOKEN"));
bytes32 public constant SWAP_PATH = keccak256(abi.encode("SWAP_PATH"));
bytes32 public constant ORDER_TYPE = keccak256(abi.encode("ORDER_TYPE"));
bytes32 public constant DECREASE_POSITION_SWAP_TYPE = keccak256(abi.encode("DECREASE_POSITION_SWAP_TYPE"));
bytes32 public constant SIZE_DELTA_USD = keccak256(abi.encode("SIZE_DELTA_USD"));
bytes32 public constant INITIAL_COLLATERAL_DELTA_AMOUNT = keccak256(abi.encode("INITIAL_COLLATERAL_DELTA_AMOUNT"));
bytes32 public constant TRIGGER_PRICE = keccak256(abi.encode("TRIGGER_PRICE"));
bytes32 public constant ACCEPTABLE_PRICE = keccak256(abi.encode("ACCEPTABLE_PRICE"));
bytes32 public constant EXECUTION_FEE = keccak256(abi.encode("EXECUTION_FEE"));
bytes32 public constant CALLBACK_GAS_LIMIT = keccak256(abi.encode("CALLBACK_GAS_LIMIT"));
bytes32 public constant MIN_OUTPUT_AMOUNT = keccak256(abi.encode("MIN_OUTPUT_AMOUNT"));
bytes32 public constant VALID_FROM_TIME = keccak256(abi.encode("VALID_FROM_TIME"));
bytes32 public constant UPDATED_AT_TIME = keccak256(abi.encode("UPDATED_AT_TIME"));
bytes32 public constant IS_LONG = keccak256(abi.encode("IS_LONG"));
bytes32 public constant SHOULD_UNWRAP_NATIVE_TOKEN = keccak256(abi.encode("SHOULD_UNWRAP_NATIVE_TOKEN"));
bytes32 public constant IS_FROZEN = keccak256(abi.encode("IS_FROZEN"));
bytes32 public constant AUTO_CANCEL = keccak256(abi.encode("AUTO_CANCEL"));
function get(DataStore dataStore, bytes32 key) external view returns (Order.Props memory) {
Order.Props memory order;
if (!dataStore.containsBytes32(Keys.ORDER_LIST, key)) {
return order;
}
order.setAccount(dataStore.getAddress(
keccak256(abi.encode(key, ACCOUNT))
));
order.setReceiver(dataStore.getAddress(
keccak256(abi.encode(key, RECEIVER))
));
order.setCancellationReceiver(dataStore.getAddress(
keccak256(abi.encode(key, CANCELLATION_RECEIVER))
));
order.setCallbackContract(dataStore.getAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
));
order.setUiFeeReceiver(dataStore.getAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
));
order.setMarket(dataStore.getAddress(
keccak256(abi.encode(key, MARKET))
));
order.setInitialCollateralToken(dataStore.getAddress(
keccak256(abi.encode(key, INITIAL_COLLATERAL_TOKEN))
));
order.setSwapPath(dataStore.getAddressArray(
keccak256(abi.encode(key, SWAP_PATH))
));
order.setOrderType(Order.OrderType(dataStore.getUint(
keccak256(abi.encode(key, ORDER_TYPE))
)));
order.setDecreasePositionSwapType(Order.DecreasePositionSwapType(dataStore.getUint(
keccak256(abi.encode(key, DECREASE_POSITION_SWAP_TYPE))
)));
order.setSizeDeltaUsd(dataStore.getUint(
keccak256(abi.encode(key, SIZE_DELTA_USD))
));
order.setInitialCollateralDeltaAmount(dataStore.getUint(
keccak256(abi.encode(key, INITIAL_COLLATERAL_DELTA_AMOUNT))
));
order.setTriggerPrice(dataStore.getUint(
keccak256(abi.encode(key, TRIGGER_PRICE))
));
order.setAcceptablePrice(dataStore.getUint(
keccak256(abi.encode(key, ACCEPTABLE_PRICE))
));
order.setExecutionFee(dataStore.getUint(
keccak256(abi.encode(key, EXECUTION_FEE))
));
order.setCallbackGasLimit(dataStore.getUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
));
order.setMinOutputAmount(dataStore.getUint(
keccak256(abi.encode(key, MIN_OUTPUT_AMOUNT))
));
order.setValidFromTime(dataStore.getUint(
keccak256(abi.encode(key, VALID_FROM_TIME))
));
order.setUpdatedAtTime(dataStore.getUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
));
order.setIsLong(dataStore.getBool(
keccak256(abi.encode(key, IS_LONG))
));
order.setShouldUnwrapNativeToken(dataStore.getBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN))
));
order.setIsFrozen(dataStore.getBool(
keccak256(abi.encode(key, IS_FROZEN))
));
order.setAutoCancel(dataStore.getBool(
keccak256(abi.encode(key, AUTO_CANCEL))
));
return order;
}
function set(DataStore dataStore, bytes32 key, Order.Props memory order) external {
dataStore.addBytes32(
Keys.ORDER_LIST,
key
);
dataStore.addBytes32(
Keys.accountOrderListKey(order.account()),
key
);
dataStore.setAddress(
keccak256(abi.encode(key, ACCOUNT)),
order.account()
);
dataStore.setAddress(
keccak256(abi.encode(key, RECEIVER)),
order.receiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, CANCELLATION_RECEIVER)),
order.cancellationReceiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT)),
order.callbackContract()
);
dataStore.setAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER)),
order.uiFeeReceiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, MARKET)),
order.market()
);
dataStore.setAddress(
keccak256(abi.encode(key, INITIAL_COLLATERAL_TOKEN)),
order.initialCollateralToken()
);
dataStore.setAddressArray(
keccak256(abi.encode(key, SWAP_PATH)),
order.swapPath()
);
dataStore.setUint(
keccak256(abi.encode(key, ORDER_TYPE)),
uint256(order.orderType())
);
dataStore.setUint(
keccak256(abi.encode(key, DECREASE_POSITION_SWAP_TYPE)),
uint256(order.decreasePositionSwapType())
);
dataStore.setUint(
keccak256(abi.encode(key, SIZE_DELTA_USD)),
order.sizeDeltaUsd()
);
dataStore.setUint(
keccak256(abi.encode(key, INITIAL_COLLATERAL_DELTA_AMOUNT)),
order.initialCollateralDeltaAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, TRIGGER_PRICE)),
order.triggerPrice()
);
dataStore.setUint(
keccak256(abi.encode(key, ACCEPTABLE_PRICE)),
order.acceptablePrice()
);
dataStore.setUint(
keccak256(abi.encode(key, EXECUTION_FEE)),
order.executionFee()
);
dataStore.setUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT)),
order.callbackGasLimit()
);
dataStore.setUint(
keccak256(abi.encode(key, MIN_OUTPUT_AMOUNT)),
order.minOutputAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, VALID_FROM_TIME)),
order.validFromTime()
);
dataStore.setUint(
keccak256(abi.encode(key, UPDATED_AT_TIME)),
order.updatedAtTime()
);
dataStore.setBool(
keccak256(abi.encode(key, IS_LONG)),
order.isLong()
);
dataStore.setBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN)),
order.shouldUnwrapNativeToken()
);
dataStore.setBool(
keccak256(abi.encode(key, IS_FROZEN)),
order.isFrozen()
);
dataStore.setBool(
keccak256(abi.encode(key, AUTO_CANCEL)),
order.autoCancel()
);
}
function remove(DataStore dataStore, bytes32 key, address account) external {
if (!dataStore.containsBytes32(Keys.ORDER_LIST, key)) {
revert Errors.OrderNotFound(key);
}
dataStore.removeBytes32(
Keys.ORDER_LIST,
key
);
dataStore.removeBytes32(
Keys.accountOrderListKey(account),
key
);
dataStore.removeAddress(
keccak256(abi.encode(key, ACCOUNT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, CANCELLATION_RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, MARKET))
);
dataStore.removeAddress(
keccak256(abi.encode(key, INITIAL_COLLATERAL_TOKEN))
);
dataStore.removeAddressArray(
keccak256(abi.encode(key, SWAP_PATH))
);
dataStore.removeUint(
keccak256(abi.encode(key, ORDER_TYPE))
);
dataStore.removeUint(
keccak256(abi.encode(key, DECREASE_POSITION_SWAP_TYPE))
);
dataStore.removeUint(
keccak256(abi.encode(key, SIZE_DELTA_USD))
);
dataStore.removeUint(
keccak256(abi.encode(key, INITIAL_COLLATERAL_DELTA_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, TRIGGER_PRICE))
);
dataStore.removeUint(
keccak256(abi.encode(key, ACCEPTABLE_PRICE))
);
dataStore.removeUint(
keccak256(abi.encode(key, EXECUTION_FEE))
);
dataStore.removeUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
);
dataStore.removeUint(
keccak256(abi.encode(key, MIN_OUTPUT_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, VALID_FROM_TIME))
);
dataStore.removeUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
);
dataStore.removeBool(
keccak256(abi.encode(key, IS_LONG))
);
dataStore.removeBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN))
);
dataStore.removeBool(
keccak256(abi.encode(key, IS_FROZEN))
);
dataStore.removeBool(
keccak256(abi.encode(key, AUTO_CANCEL))
);
}
function getOrderCount(DataStore dataStore) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.ORDER_LIST);
}
function getOrderKeys(DataStore dataStore, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.ORDER_LIST, start, end);
}
function getAccountOrderCount(DataStore dataStore, address account) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.accountOrderListKey(account));
}
function getAccountOrderKeys(DataStore dataStore, address account, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.accountOrderListKey(account), start, end);
}
}
文件 73 的 108:OrderVault.sol
pragma solidity ^0.8.0;
import "../bank/StrictBank.sol";
contract OrderVault is StrictBank {
constructor(RoleStore _roleStore, DataStore _dataStore) StrictBank(_roleStore, _dataStore) {}
}
文件 74 的 108:PRBMath.sol
pragma solidity >=0.8.4;
error PRBMath__MulDivFixedPointOverflow(uint256 prod1);
error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);
error PRBMath__MulDivSignedInputTooSmall();
error PRBMath__MulDivSignedOverflow(uint256 rAbs);
error PRBMathSD59x18__AbsInputTooSmall();
error PRBMathSD59x18__CeilOverflow(int256 x);
error PRBMathSD59x18__DivInputTooSmall();
error PRBMathSD59x18__DivOverflow(uint256 rAbs);
error PRBMathSD59x18__ExpInputTooBig(int256 x);
error PRBMathSD59x18__Exp2InputTooBig(int256 x);
error PRBMathSD59x18__FloorUnderflow(int256 x);
error PRBMathSD59x18__FromIntOverflow(int256 x);
error PRBMathSD59x18__FromIntUnderflow(int256 x);
error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);
error PRBMathSD59x18__GmOverflow(int256 x, int256 y);
error PRBMathSD59x18__LogInputTooSmall(int256 x);
error PRBMathSD59x18__MulInputTooSmall();
error PRBMathSD59x18__MulOverflow(uint256 rAbs);
error PRBMathSD59x18__PowuOverflow(uint256 rAbs);
error PRBMathSD59x18__SqrtNegativeInput(int256 x);
error PRBMathSD59x18__SqrtOverflow(int256 x);
error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);
error PRBMathUD60x18__CeilOverflow(uint256 x);
error PRBMathUD60x18__ExpInputTooBig(uint256 x);
error PRBMathUD60x18__Exp2InputTooBig(uint256 x);
error PRBMathUD60x18__FromUintOverflow(uint256 x);
error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);
error PRBMathUD60x18__LogInputTooSmall(uint256 x);
error PRBMathUD60x18__SqrtOverflow(uint256 x);
error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);
library PRBMath {
struct SD59x18 {
int256 value;
}
struct UD60x18 {
uint256 value;
}
uint256 internal constant SCALE = 1e18;
uint256 internal constant SCALE_LPOTD = 262144;
uint256 internal constant SCALE_INVERSE =
78156646155174841979727994598816262306175212592076161876661_508869554232690281;
function exp2(uint256 x) internal pure returns (uint256 result) {
unchecked {
result = 0x800000000000000000000000000000000000000000000000;
if (x & 0x8000000000000000 > 0) {
result = (result * 0x16A09E667F3BCC909) >> 64;
}
if (x & 0x4000000000000000 > 0) {
result = (result * 0x1306FE0A31B7152DF) >> 64;
}
if (x & 0x2000000000000000 > 0) {
result = (result * 0x1172B83C7D517ADCE) >> 64;
}
if (x & 0x1000000000000000 > 0) {
result = (result * 0x10B5586CF9890F62A) >> 64;
}
if (x & 0x800000000000000 > 0) {
result = (result * 0x1059B0D31585743AE) >> 64;
}
if (x & 0x400000000000000 > 0) {
result = (result * 0x102C9A3E778060EE7) >> 64;
}
if (x & 0x200000000000000 > 0) {
result = (result * 0x10163DA9FB33356D8) >> 64;
}
if (x & 0x100000000000000 > 0) {
result = (result * 0x100B1AFA5ABCBED61) >> 64;
}
if (x & 0x80000000000000 > 0) {
result = (result * 0x10058C86DA1C09EA2) >> 64;
}
if (x & 0x40000000000000 > 0) {
result = (result * 0x1002C605E2E8CEC50) >> 64;
}
if (x & 0x20000000000000 > 0) {
result = (result * 0x100162F3904051FA1) >> 64;
}
if (x & 0x10000000000000 > 0) {
result = (result * 0x1000B175EFFDC76BA) >> 64;
}
if (x & 0x8000000000000 > 0) {
result = (result * 0x100058BA01FB9F96D) >> 64;
}
if (x & 0x4000000000000 > 0) {
result = (result * 0x10002C5CC37DA9492) >> 64;
}
if (x & 0x2000000000000 > 0) {
result = (result * 0x1000162E525EE0547) >> 64;
}
if (x & 0x1000000000000 > 0) {
result = (result * 0x10000B17255775C04) >> 64;
}
if (x & 0x800000000000 > 0) {
result = (result * 0x1000058B91B5BC9AE) >> 64;
}
if (x & 0x400000000000 > 0) {
result = (result * 0x100002C5C89D5EC6D) >> 64;
}
if (x & 0x200000000000 > 0) {
result = (result * 0x10000162E43F4F831) >> 64;
}
if (x & 0x100000000000 > 0) {
result = (result * 0x100000B1721BCFC9A) >> 64;
}
if (x & 0x80000000000 > 0) {
result = (result * 0x10000058B90CF1E6E) >> 64;
}
if (x & 0x40000000000 > 0) {
result = (result * 0x1000002C5C863B73F) >> 64;
}
if (x & 0x20000000000 > 0) {
result = (result * 0x100000162E430E5A2) >> 64;
}
if (x & 0x10000000000 > 0) {
result = (result * 0x1000000B172183551) >> 64;
}
if (x & 0x8000000000 > 0) {
result = (result * 0x100000058B90C0B49) >> 64;
}
if (x & 0x4000000000 > 0) {
result = (result * 0x10000002C5C8601CC) >> 64;
}
if (x & 0x2000000000 > 0) {
result = (result * 0x1000000162E42FFF0) >> 64;
}
if (x & 0x1000000000 > 0) {
result = (result * 0x10000000B17217FBB) >> 64;
}
if (x & 0x800000000 > 0) {
result = (result * 0x1000000058B90BFCE) >> 64;
}
if (x & 0x400000000 > 0) {
result = (result * 0x100000002C5C85FE3) >> 64;
}
if (x & 0x200000000 > 0) {
result = (result * 0x10000000162E42FF1) >> 64;
}
if (x & 0x100000000 > 0) {
result = (result * 0x100000000B17217F8) >> 64;
}
if (x & 0x80000000 > 0) {
result = (result * 0x10000000058B90BFC) >> 64;
}
if (x & 0x40000000 > 0) {
result = (result * 0x1000000002C5C85FE) >> 64;
}
if (x & 0x20000000 > 0) {
result = (result * 0x100000000162E42FF) >> 64;
}
if (x & 0x10000000 > 0) {
result = (result * 0x1000000000B17217F) >> 64;
}
if (x & 0x8000000 > 0) {
result = (result * 0x100000000058B90C0) >> 64;
}
if (x & 0x4000000 > 0) {
result = (result * 0x10000000002C5C860) >> 64;
}
if (x & 0x2000000 > 0) {
result = (result * 0x1000000000162E430) >> 64;
}
if (x & 0x1000000 > 0) {
result = (result * 0x10000000000B17218) >> 64;
}
if (x & 0x800000 > 0) {
result = (result * 0x1000000000058B90C) >> 64;
}
if (x & 0x400000 > 0) {
result = (result * 0x100000000002C5C86) >> 64;
}
if (x & 0x200000 > 0) {
result = (result * 0x10000000000162E43) >> 64;
}
if (x & 0x100000 > 0) {
result = (result * 0x100000000000B1721) >> 64;
}
if (x & 0x80000 > 0) {
result = (result * 0x10000000000058B91) >> 64;
}
if (x & 0x40000 > 0) {
result = (result * 0x1000000000002C5C8) >> 64;
}
if (x & 0x20000 > 0) {
result = (result * 0x100000000000162E4) >> 64;
}
if (x & 0x10000 > 0) {
result = (result * 0x1000000000000B172) >> 64;
}
if (x & 0x8000 > 0) {
result = (result * 0x100000000000058B9) >> 64;
}
if (x & 0x4000 > 0) {
result = (result * 0x10000000000002C5D) >> 64;
}
if (x & 0x2000 > 0) {
result = (result * 0x1000000000000162E) >> 64;
}
if (x & 0x1000 > 0) {
result = (result * 0x10000000000000B17) >> 64;
}
if (x & 0x800 > 0) {
result = (result * 0x1000000000000058C) >> 64;
}
if (x & 0x400 > 0) {
result = (result * 0x100000000000002C6) >> 64;
}
if (x & 0x200 > 0) {
result = (result * 0x10000000000000163) >> 64;
}
if (x & 0x100 > 0) {
result = (result * 0x100000000000000B1) >> 64;
}
if (x & 0x80 > 0) {
result = (result * 0x10000000000000059) >> 64;
}
if (x & 0x40 > 0) {
result = (result * 0x1000000000000002C) >> 64;
}
if (x & 0x20 > 0) {
result = (result * 0x10000000000000016) >> 64;
}
if (x & 0x10 > 0) {
result = (result * 0x1000000000000000B) >> 64;
}
if (x & 0x8 > 0) {
result = (result * 0x10000000000000006) >> 64;
}
if (x & 0x4 > 0) {
result = (result * 0x10000000000000003) >> 64;
}
if (x & 0x2 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
if (x & 0x1 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
result *= SCALE;
result >>= (191 - (x >> 64));
}
}
function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {
if (x >= 2**128) {
x >>= 128;
msb += 128;
}
if (x >= 2**64) {
x >>= 64;
msb += 64;
}
if (x >= 2**32) {
x >>= 32;
msb += 32;
}
if (x >= 2**16) {
x >>= 16;
msb += 16;
}
if (x >= 2**8) {
x >>= 8;
msb += 8;
}
if (x >= 2**4) {
x >>= 4;
msb += 4;
}
if (x >= 2**2) {
x >>= 2;
msb += 2;
}
if (x >= 2**1) {
msb += 1;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
unchecked {
result = prod0 / denominator;
}
return result;
}
if (prod1 >= denominator) {
revert PRBMath__MulDivOverflow(prod1, denominator);
}
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
unchecked {
uint256 lpotdod = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, lpotdod)
prod0 := div(prod0, lpotdod)
lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
prod0 |= prod1 * lpotdod;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 >= SCALE) {
revert PRBMath__MulDivFixedPointOverflow(prod1);
}
uint256 remainder;
uint256 roundUpUnit;
assembly {
remainder := mulmod(x, y, SCALE)
roundUpUnit := gt(remainder, 499999999999999999)
}
if (prod1 == 0) {
unchecked {
result = (prod0 / SCALE) + roundUpUnit;
return result;
}
}
assembly {
result := add(
mul(
or(
div(sub(prod0, remainder), SCALE_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))
),
SCALE_INVERSE
),
roundUpUnit
)
}
}
function mulDivSigned(
int256 x,
int256 y,
int256 denominator
) internal pure returns (int256 result) {
if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
revert PRBMath__MulDivSignedInputTooSmall();
}
uint256 ax;
uint256 ay;
uint256 ad;
unchecked {
ax = x < 0 ? uint256(-x) : uint256(x);
ay = y < 0 ? uint256(-y) : uint256(y);
ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);
}
uint256 rAbs = mulDiv(ax, ay, ad);
if (rAbs > uint256(type(int256).max)) {
revert PRBMath__MulDivSignedOverflow(rAbs);
}
uint256 sx;
uint256 sy;
uint256 sd;
assembly {
sx := sgt(x, sub(0, 1))
sy := sgt(y, sub(0, 1))
sd := sgt(denominator, sub(0, 1))
}
result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);
}
function sqrt(uint256 x) internal pure returns (uint256 result) {
if (x == 0) {
return 0;
}
uint256 xAux = uint256(x);
result = 1;
if (xAux >= 0x100000000000000000000000000000000) {
xAux >>= 128;
result <<= 64;
}
if (xAux >= 0x10000000000000000) {
xAux >>= 64;
result <<= 32;
}
if (xAux >= 0x100000000) {
xAux >>= 32;
result <<= 16;
}
if (xAux >= 0x10000) {
xAux >>= 16;
result <<= 8;
}
if (xAux >= 0x100) {
xAux >>= 8;
result <<= 4;
}
if (xAux >= 0x10) {
xAux >>= 4;
result <<= 2;
}
if (xAux >= 0x8) {
result <<= 1;
}
unchecked {
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
uint256 roundedDownResult = x / result;
return result >= roundedDownResult ? roundedDownResult : result;
}
}
}
文件 75 的 108:PRBMathUD60x18.sol
pragma solidity >=0.8.4;
import "./PRBMath.sol";
library PRBMathUD60x18 {
uint256 internal constant HALF_SCALE = 5e17;
uint256 internal constant LOG2_E = 1_442695040888963407;
uint256 internal constant MAX_UD60x18 =
115792089237316195423570985008687907853269984665640564039457_584007913129639935;
uint256 internal constant MAX_WHOLE_UD60x18 =
115792089237316195423570985008687907853269984665640564039457_000000000000000000;
uint256 internal constant SCALE = 1e18;
function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {
unchecked {
result = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
function ceil(uint256 x) internal pure returns (uint256 result) {
if (x > MAX_WHOLE_UD60x18) {
revert PRBMathUD60x18__CeilOverflow(x);
}
assembly {
let remainder := mod(x, SCALE)
let delta := sub(SCALE, remainder)
result := add(x, mul(delta, gt(remainder, 0)))
}
}
function div(uint256 x, uint256 y) internal pure returns (uint256 result) {
result = PRBMath.mulDiv(x, SCALE, y);
}
function e() internal pure returns (uint256 result) {
result = 2_718281828459045235;
}
function exp(uint256 x) internal pure returns (uint256 result) {
if (x >= 133_084258667509499441) {
revert PRBMathUD60x18__ExpInputTooBig(x);
}
unchecked {
uint256 doubleScaleProduct = x * LOG2_E;
result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
}
}
function exp2(uint256 x) internal pure returns (uint256 result) {
if (x >= 192e18) {
revert PRBMathUD60x18__Exp2InputTooBig(x);
}
unchecked {
uint256 x192x64 = (x << 64) / SCALE;
result = PRBMath.exp2(x192x64);
}
}
function floor(uint256 x) internal pure returns (uint256 result) {
assembly {
let remainder := mod(x, SCALE)
result := sub(x, mul(remainder, gt(remainder, 0)))
}
}
function frac(uint256 x) internal pure returns (uint256 result) {
assembly {
result := mod(x, SCALE)
}
}
function fromUint(uint256 x) internal pure returns (uint256 result) {
unchecked {
if (x > MAX_UD60x18 / SCALE) {
revert PRBMathUD60x18__FromUintOverflow(x);
}
result = x * SCALE;
}
}
function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {
if (x == 0) {
return 0;
}
unchecked {
uint256 xy = x * y;
if (xy / x != y) {
revert PRBMathUD60x18__GmOverflow(x, y);
}
result = PRBMath.sqrt(xy);
}
}
function inv(uint256 x) internal pure returns (uint256 result) {
unchecked {
result = 1e36 / x;
}
}
function ln(uint256 x) internal pure returns (uint256 result) {
unchecked {
result = (log2(x) * SCALE) / LOG2_E;
}
}
function log10(uint256 x) internal pure returns (uint256 result) {
if (x < SCALE) {
revert PRBMathUD60x18__LogInputTooSmall(x);
}
assembly {
switch x
case 1 { result := mul(SCALE, sub(0, 18)) }
case 10 { result := mul(SCALE, sub(1, 18)) }
case 100 { result := mul(SCALE, sub(2, 18)) }
case 1000 { result := mul(SCALE, sub(3, 18)) }
case 10000 { result := mul(SCALE, sub(4, 18)) }
case 100000 { result := mul(SCALE, sub(5, 18)) }
case 1000000 { result := mul(SCALE, sub(6, 18)) }
case 10000000 { result := mul(SCALE, sub(7, 18)) }
case 100000000 { result := mul(SCALE, sub(8, 18)) }
case 1000000000 { result := mul(SCALE, sub(9, 18)) }
case 10000000000 { result := mul(SCALE, sub(10, 18)) }
case 100000000000 { result := mul(SCALE, sub(11, 18)) }
case 1000000000000 { result := mul(SCALE, sub(12, 18)) }
case 10000000000000 { result := mul(SCALE, sub(13, 18)) }
case 100000000000000 { result := mul(SCALE, sub(14, 18)) }
case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }
case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }
case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }
case 1000000000000000000 { result := 0 }
case 10000000000000000000 { result := SCALE }
case 100000000000000000000 { result := mul(SCALE, 2) }
case 1000000000000000000000 { result := mul(SCALE, 3) }
case 10000000000000000000000 { result := mul(SCALE, 4) }
case 100000000000000000000000 { result := mul(SCALE, 5) }
case 1000000000000000000000000 { result := mul(SCALE, 6) }
case 10000000000000000000000000 { result := mul(SCALE, 7) }
case 100000000000000000000000000 { result := mul(SCALE, 8) }
case 1000000000000000000000000000 { result := mul(SCALE, 9) }
case 10000000000000000000000000000 { result := mul(SCALE, 10) }
case 100000000000000000000000000000 { result := mul(SCALE, 11) }
case 1000000000000000000000000000000 { result := mul(SCALE, 12) }
case 10000000000000000000000000000000 { result := mul(SCALE, 13) }
case 100000000000000000000000000000000 { result := mul(SCALE, 14) }
case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }
case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }
case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }
case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }
case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }
case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }
case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }
case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }
case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }
case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }
case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }
case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }
case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }
case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }
case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }
case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }
case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }
case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }
case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }
case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }
case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }
case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }
case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }
case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }
case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }
case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }
case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }
case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }
case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }
case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }
case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }
case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }
case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }
case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }
case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }
case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }
case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }
case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }
case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }
default {
result := MAX_UD60x18
}
}
if (result == MAX_UD60x18) {
unchecked {
result = (log2(x) * SCALE) / 3_321928094887362347;
}
}
}
function log2(uint256 x) internal pure returns (uint256 result) {
if (x < SCALE) {
revert PRBMathUD60x18__LogInputTooSmall(x);
}
unchecked {
uint256 n = PRBMath.mostSignificantBit(x / SCALE);
result = n * SCALE;
uint256 y = x >> n;
if (y == SCALE) {
return result;
}
for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {
y = (y * y) / SCALE;
if (y >= 2 * SCALE) {
result += delta;
y >>= 1;
}
}
}
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {
result = PRBMath.mulDivFixedPoint(x, y);
}
function pi() internal pure returns (uint256 result) {
result = 3_141592653589793238;
}
function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {
if (x == 0) {
result = y == 0 ? SCALE : uint256(0);
} else {
result = exp2(mul(log2(x), y));
}
}
function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {
result = y & 1 > 0 ? x : SCALE;
for (y >>= 1; y > 0; y >>= 1) {
x = PRBMath.mulDivFixedPoint(x, x);
if (y & 1 > 0) {
result = PRBMath.mulDivFixedPoint(result, x);
}
}
}
function scale() internal pure returns (uint256 result) {
result = SCALE;
}
function sqrt(uint256 x) internal pure returns (uint256 result) {
unchecked {
if (x > MAX_UD60x18 / SCALE) {
revert PRBMathUD60x18__SqrtOverflow(x);
}
result = PRBMath.sqrt(x * SCALE);
}
}
function toUint(uint256 x) internal pure returns (uint256 result) {
unchecked {
result = x / SCALE;
}
}
}
文件 76 的 108:PayableMulticall.sol
pragma solidity ^0.8.0;
import "../error/ErrorUtils.sol";
abstract contract PayableMulticall {
function multicall(bytes[] calldata data) external payable virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
if (!success) {
ErrorUtils.revertWithParsedMessage(result);
}
results[i] = result;
}
return results;
}
}
文件 77 的 108:Position.sol
pragma solidity ^0.8.0;
library Position {
struct Props {
Addresses addresses;
Numbers numbers;
Flags flags;
}
struct Addresses {
address account;
address market;
address collateralToken;
}
struct Numbers {
uint256 sizeInUsd;
uint256 sizeInTokens;
uint256 collateralAmount;
uint256 borrowingFactor;
uint256 fundingFeeAmountPerSize;
uint256 longTokenClaimableFundingAmountPerSize;
uint256 shortTokenClaimableFundingAmountPerSize;
uint256 increasedAtTime;
uint256 decreasedAtTime;
}
struct Flags {
bool isLong;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function market(Props memory props) internal pure returns (address) {
return props.addresses.market;
}
function setMarket(Props memory props, address value) internal pure {
props.addresses.market = value;
}
function collateralToken(Props memory props) internal pure returns (address) {
return props.addresses.collateralToken;
}
function setCollateralToken(Props memory props, address value) internal pure {
props.addresses.collateralToken = value;
}
function sizeInUsd(Props memory props) internal pure returns (uint256) {
return props.numbers.sizeInUsd;
}
function setSizeInUsd(Props memory props, uint256 value) internal pure {
props.numbers.sizeInUsd = value;
}
function sizeInTokens(Props memory props) internal pure returns (uint256) {
return props.numbers.sizeInTokens;
}
function setSizeInTokens(Props memory props, uint256 value) internal pure {
props.numbers.sizeInTokens = value;
}
function collateralAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.collateralAmount;
}
function setCollateralAmount(Props memory props, uint256 value) internal pure {
props.numbers.collateralAmount = value;
}
function borrowingFactor(Props memory props) internal pure returns (uint256) {
return props.numbers.borrowingFactor;
}
function setBorrowingFactor(Props memory props, uint256 value) internal pure {
props.numbers.borrowingFactor = value;
}
function fundingFeeAmountPerSize(Props memory props) internal pure returns (uint256) {
return props.numbers.fundingFeeAmountPerSize;
}
function setFundingFeeAmountPerSize(Props memory props, uint256 value) internal pure {
props.numbers.fundingFeeAmountPerSize = value;
}
function longTokenClaimableFundingAmountPerSize(Props memory props) internal pure returns (uint256) {
return props.numbers.longTokenClaimableFundingAmountPerSize;
}
function setLongTokenClaimableFundingAmountPerSize(Props memory props, uint256 value) internal pure {
props.numbers.longTokenClaimableFundingAmountPerSize = value;
}
function shortTokenClaimableFundingAmountPerSize(Props memory props) internal pure returns (uint256) {
return props.numbers.shortTokenClaimableFundingAmountPerSize;
}
function setShortTokenClaimableFundingAmountPerSize(Props memory props, uint256 value) internal pure {
props.numbers.shortTokenClaimableFundingAmountPerSize = value;
}
function increasedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.increasedAtTime;
}
function setIncreasedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.increasedAtTime = value;
}
function decreasedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.decreasedAtTime;
}
function setDecreasedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.decreasedAtTime = value;
}
function isLong(Props memory props) internal pure returns (bool) {
return props.flags.isLong;
}
function setIsLong(Props memory props, bool value) internal pure {
props.flags.isLong = value;
}
function getPositionKey(address _account, address _market, address _collateralToken, bool _isLong) internal pure returns (bytes32) {
bytes32 _key = keccak256(abi.encode(_account, _market, _collateralToken, _isLong));
return _key;
}
}
文件 78 的 108:PositionPricingUtils.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "../market/MarketUtils.sol";
import "../utils/Precision.sol";
import "../utils/Calc.sol";
import "./PricingUtils.sol";
import "../referral/IReferralStorage.sol";
import "../referral/ReferralUtils.sol";
library PositionPricingUtils {
using SignedMath for int256;
using SafeCast for uint256;
using SafeCast for int256;
using Position for Position.Props;
using Price for Price.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct GetPositionFeesParams {
DataStore dataStore;
IReferralStorage referralStorage;
Position.Props position;
Price.Props collateralTokenPrice;
bool forPositiveImpact;
address longToken;
address shortToken;
uint256 sizeDeltaUsd;
address uiFeeReceiver;
bool isLiquidation;
}
struct GetPriceImpactUsdParams {
DataStore dataStore;
Market.Props market;
int256 usdDelta;
bool isLong;
}
struct OpenInterestParams {
uint256 longOpenInterest;
uint256 shortOpenInterest;
uint256 nextLongOpenInterest;
uint256 nextShortOpenInterest;
}
struct PositionFees {
PositionReferralFees referral;
PositionProFees pro;
PositionFundingFees funding;
PositionBorrowingFees borrowing;
PositionUiFees ui;
PositionLiquidationFees liquidation;
Price.Props collateralTokenPrice;
uint256 positionFeeFactor;
uint256 protocolFeeAmount;
uint256 positionFeeReceiverFactor;
uint256 feeReceiverAmount;
uint256 feeAmountForPool;
uint256 positionFeeAmountForPool;
uint256 positionFeeAmount;
uint256 totalCostAmountExcludingFunding;
uint256 totalCostAmount;
uint256 totalDiscountAmount;
}
struct PositionProFees {
uint256 traderTier;
uint256 traderDiscountFactor;
uint256 traderDiscountAmount;
}
struct PositionLiquidationFees {
uint256 liquidationFeeUsd;
uint256 liquidationFeeAmount;
uint256 liquidationFeeReceiverFactor;
uint256 liquidationFeeAmountForFeeReceiver;
}
struct PositionReferralFees {
bytes32 referralCode;
address affiliate;
address trader;
uint256 totalRebateFactor;
uint256 affiliateRewardFactor;
uint256 adjustedAffiliateRewardFactor;
uint256 traderDiscountFactor;
uint256 totalRebateAmount;
uint256 traderDiscountAmount;
uint256 affiliateRewardAmount;
}
struct PositionBorrowingFees {
uint256 borrowingFeeUsd;
uint256 borrowingFeeAmount;
uint256 borrowingFeeReceiverFactor;
uint256 borrowingFeeAmountForFeeReceiver;
}
struct PositionFundingFees {
uint256 fundingFeeAmount;
uint256 claimableLongTokenAmount;
uint256 claimableShortTokenAmount;
uint256 latestFundingFeeAmountPerSize;
uint256 latestLongTokenClaimableFundingAmountPerSize;
uint256 latestShortTokenClaimableFundingAmountPerSize;
}
struct PositionUiFees {
address uiFeeReceiver;
uint256 uiFeeReceiverFactor;
uint256 uiFeeAmount;
}
function getPriceImpactUsd(GetPriceImpactUsdParams memory params) internal view returns (int256) {
OpenInterestParams memory openInterestParams = getNextOpenInterest(params);
int256 priceImpactUsd = _getPriceImpactUsd(params.dataStore, params.market.marketToken, openInterestParams);
if (priceImpactUsd >= 0) { return priceImpactUsd; }
(bool hasVirtualInventory, int256 virtualInventory) = MarketUtils.getVirtualInventoryForPositions(params.dataStore, params.market.indexToken);
if (!hasVirtualInventory) { return priceImpactUsd; }
OpenInterestParams memory openInterestParamsForVirtualInventory = getNextOpenInterestForVirtualInventory(params, virtualInventory);
int256 priceImpactUsdForVirtualInventory = _getPriceImpactUsd(params.dataStore, params.market.marketToken, openInterestParamsForVirtualInventory);
return priceImpactUsdForVirtualInventory < priceImpactUsd ? priceImpactUsdForVirtualInventory : priceImpactUsd;
}
function _getPriceImpactUsd(DataStore dataStore, address market, OpenInterestParams memory openInterestParams) internal view returns (int256) {
uint256 initialDiffUsd = Calc.diff(openInterestParams.longOpenInterest, openInterestParams.shortOpenInterest);
uint256 nextDiffUsd = Calc.diff(openInterestParams.nextLongOpenInterest, openInterestParams.nextShortOpenInterest);
bool isSameSideRebalance = openInterestParams.longOpenInterest <= openInterestParams.shortOpenInterest == openInterestParams.nextLongOpenInterest <= openInterestParams.nextShortOpenInterest;
uint256 impactExponentFactor = dataStore.getUint(Keys.positionImpactExponentFactorKey(market));
if (isSameSideRebalance) {
bool hasPositiveImpact = nextDiffUsd < initialDiffUsd;
uint256 impactFactor = MarketUtils.getAdjustedPositionImpactFactor(dataStore, market, hasPositiveImpact);
return PricingUtils.getPriceImpactUsdForSameSideRebalance(
initialDiffUsd,
nextDiffUsd,
impactFactor,
impactExponentFactor
);
} else {
(uint256 positiveImpactFactor, uint256 negativeImpactFactor) = MarketUtils.getAdjustedPositionImpactFactors(dataStore, market);
return PricingUtils.getPriceImpactUsdForCrossoverRebalance(
initialDiffUsd,
nextDiffUsd,
positiveImpactFactor,
negativeImpactFactor,
impactExponentFactor
);
}
}
function getNextOpenInterest(
GetPriceImpactUsdParams memory params
) internal view returns (OpenInterestParams memory) {
uint256 longOpenInterest = MarketUtils.getOpenInterest(
params.dataStore,
params.market,
true
);
uint256 shortOpenInterest = MarketUtils.getOpenInterest(
params.dataStore,
params.market,
false
);
return getNextOpenInterestParams(params, longOpenInterest, shortOpenInterest);
}
function getNextOpenInterestForVirtualInventory(
GetPriceImpactUsdParams memory params,
int256 virtualInventory
) internal pure returns (OpenInterestParams memory) {
uint256 longOpenInterest;
uint256 shortOpenInterest;
if (virtualInventory > 0) {
shortOpenInterest = virtualInventory.toUint256();
} else {
longOpenInterest = (-virtualInventory).toUint256();
}
if (params.usdDelta < 0) {
uint256 offset = (-params.usdDelta).toUint256();
longOpenInterest += offset;
shortOpenInterest += offset;
}
return getNextOpenInterestParams(params, longOpenInterest, shortOpenInterest);
}
function getNextOpenInterestParams(
GetPriceImpactUsdParams memory params,
uint256 longOpenInterest,
uint256 shortOpenInterest
) internal pure returns (OpenInterestParams memory) {
uint256 nextLongOpenInterest = longOpenInterest;
uint256 nextShortOpenInterest = shortOpenInterest;
if (params.isLong) {
if (params.usdDelta < 0 && (-params.usdDelta).toUint256() > longOpenInterest) {
revert Errors.UsdDeltaExceedsLongOpenInterest(params.usdDelta, longOpenInterest);
}
nextLongOpenInterest = Calc.sumReturnUint256(longOpenInterest, params.usdDelta);
} else {
if (params.usdDelta < 0 && (-params.usdDelta).toUint256() > shortOpenInterest) {
revert Errors.UsdDeltaExceedsShortOpenInterest(params.usdDelta, shortOpenInterest);
}
nextShortOpenInterest = Calc.sumReturnUint256(shortOpenInterest, params.usdDelta);
}
OpenInterestParams memory openInterestParams = OpenInterestParams(
longOpenInterest,
shortOpenInterest,
nextLongOpenInterest,
nextShortOpenInterest
);
return openInterestParams;
}
function getPositionFees(
GetPositionFeesParams memory params
) internal view returns (PositionFees memory) {
PositionFees memory fees = getPositionFeesAfterReferral(
params.dataStore,
params.referralStorage,
params.collateralTokenPrice,
params.forPositiveImpact,
params.position.account(),
params.position.market(),
params.sizeDeltaUsd
);
uint256 borrowingFeeUsd = MarketUtils.getBorrowingFees(params.dataStore, params.position);
fees.borrowing = getBorrowingFees(
params.dataStore,
params.collateralTokenPrice,
borrowingFeeUsd
);
if (params.isLiquidation) {
fees.liquidation = getLiquidationFees(params.dataStore, params.position.market(), params.sizeDeltaUsd, params.collateralTokenPrice);
}
fees.feeAmountForPool =
fees.positionFeeAmountForPool +
fees.borrowing.borrowingFeeAmount -
fees.borrowing.borrowingFeeAmountForFeeReceiver +
fees.liquidation.liquidationFeeAmount -
fees.liquidation.liquidationFeeAmountForFeeReceiver;
fees.feeReceiverAmount +=
fees.borrowing.borrowingFeeAmountForFeeReceiver +
fees.liquidation.liquidationFeeAmountForFeeReceiver;
fees.funding.latestFundingFeeAmountPerSize = MarketUtils.getFundingFeeAmountPerSize(
params.dataStore,
params.position.market(),
params.position.collateralToken(),
params.position.isLong()
);
fees.funding.latestLongTokenClaimableFundingAmountPerSize = MarketUtils.getClaimableFundingAmountPerSize(
params.dataStore,
params.position.market(),
params.longToken,
params.position.isLong()
);
fees.funding.latestShortTokenClaimableFundingAmountPerSize = MarketUtils.getClaimableFundingAmountPerSize(
params.dataStore,
params.position.market(),
params.shortToken,
params.position.isLong()
);
fees.funding = getFundingFees(
fees.funding,
params.position
);
fees.ui = getUiFees(
params.dataStore,
params.collateralTokenPrice,
params.sizeDeltaUsd,
params.uiFeeReceiver
);
fees.totalCostAmountExcludingFunding =
fees.positionFeeAmount
+ fees.borrowing.borrowingFeeAmount
+ fees.liquidation.liquidationFeeAmount
+ fees.ui.uiFeeAmount
- fees.totalDiscountAmount;
fees.totalCostAmount =
fees.totalCostAmountExcludingFunding
+ fees.funding.fundingFeeAmount;
return fees;
}
function getBorrowingFees(
DataStore dataStore,
Price.Props memory collateralTokenPrice,
uint256 borrowingFeeUsd
) internal view returns (PositionBorrowingFees memory) {
PositionBorrowingFees memory borrowingFees;
borrowingFees.borrowingFeeUsd = borrowingFeeUsd;
borrowingFees.borrowingFeeAmount = borrowingFeeUsd / collateralTokenPrice.min;
borrowingFees.borrowingFeeReceiverFactor = dataStore.getUint(Keys.BORROWING_FEE_RECEIVER_FACTOR);
borrowingFees.borrowingFeeAmountForFeeReceiver = Precision.applyFactor(borrowingFees.borrowingFeeAmount, borrowingFees.borrowingFeeReceiverFactor);
return borrowingFees;
}
function getFundingFees(
PositionFundingFees memory fundingFees,
Position.Props memory position
) internal pure returns (PositionFundingFees memory) {
fundingFees.fundingFeeAmount = MarketUtils.getFundingAmount(
fundingFees.latestFundingFeeAmountPerSize,
position.fundingFeeAmountPerSize(),
position.sizeInUsd(),
true
);
fundingFees.claimableLongTokenAmount = MarketUtils.getFundingAmount(
fundingFees.latestLongTokenClaimableFundingAmountPerSize,
position.longTokenClaimableFundingAmountPerSize(),
position.sizeInUsd(),
false
);
fundingFees.claimableShortTokenAmount = MarketUtils.getFundingAmount(
fundingFees.latestShortTokenClaimableFundingAmountPerSize,
position.shortTokenClaimableFundingAmountPerSize(),
position.sizeInUsd(),
false
);
return fundingFees;
}
function getUiFees(
DataStore dataStore,
Price.Props memory collateralTokenPrice,
uint256 sizeDeltaUsd,
address uiFeeReceiver
) internal view returns (PositionUiFees memory) {
PositionUiFees memory uiFees;
if (uiFeeReceiver == address(0)) {
return uiFees;
}
uiFees.uiFeeReceiver = uiFeeReceiver;
uiFees.uiFeeReceiverFactor = MarketUtils.getUiFeeFactor(dataStore, uiFeeReceiver);
uiFees.uiFeeAmount = Precision.applyFactor(sizeDeltaUsd, uiFees.uiFeeReceiverFactor) / collateralTokenPrice.min;
return uiFees;
}
function getPositionFeesAfterReferral(
DataStore dataStore,
IReferralStorage referralStorage,
Price.Props memory collateralTokenPrice,
bool forPositiveImpact,
address account,
address market,
uint256 sizeDeltaUsd
) internal view returns (PositionFees memory) {
PositionFees memory fees;
fees.collateralTokenPrice = collateralTokenPrice;
fees.referral.trader = account;
uint256 minAffiliateRewardFactor;
(
fees.referral.referralCode,
fees.referral.affiliate,
fees.referral.affiliateRewardFactor,
fees.referral.traderDiscountFactor,
minAffiliateRewardFactor
) = ReferralUtils.getReferralInfo(dataStore, referralStorage, account);
fees.positionFeeFactor = dataStore.getUint(Keys.positionFeeFactorKey(market, forPositiveImpact));
fees.positionFeeAmount = Precision.applyFactor(sizeDeltaUsd, fees.positionFeeFactor) / collateralTokenPrice.min;
fees.pro.traderTier = dataStore.getUint(Keys.proTraderTierKey(account));
if (fees.pro.traderTier > 0) {
fees.pro.traderDiscountFactor = dataStore.getUint(Keys.proDiscountFactorKey(fees.pro.traderTier));
if (fees.pro.traderDiscountFactor > 0) {
fees.pro.traderDiscountAmount = Precision.applyFactor(fees.positionFeeAmount, fees.pro.traderDiscountFactor);
}
}
if (fees.referral.referralCode != bytes32(0)) {
fees.referral.adjustedAffiliateRewardFactor = fees.referral.affiliateRewardFactor;
fees.referral.totalRebateFactor = fees.referral.affiliateRewardFactor + fees.referral.traderDiscountFactor;
if (fees.pro.traderDiscountFactor > fees.referral.traderDiscountFactor) {
fees.referral.adjustedAffiliateRewardFactor = fees.pro.traderDiscountFactor > fees.referral.totalRebateFactor
? minAffiliateRewardFactor
: fees.referral.totalRebateFactor - fees.pro.traderDiscountFactor;
if (fees.referral.adjustedAffiliateRewardFactor < minAffiliateRewardFactor) {
fees.referral.adjustedAffiliateRewardFactor = minAffiliateRewardFactor;
}
}
fees.referral.affiliateRewardAmount = Precision.applyFactor(fees.positionFeeAmount, fees.referral.adjustedAffiliateRewardFactor);
fees.referral.traderDiscountAmount = Precision.applyFactor(fees.positionFeeAmount, fees.referral.traderDiscountFactor);
fees.referral.totalRebateAmount = fees.referral.affiliateRewardAmount + fees.referral.traderDiscountAmount;
}
fees.totalDiscountAmount = fees.pro.traderDiscountAmount > fees.referral.traderDiscountAmount
? fees.pro.traderDiscountAmount
: fees.referral.traderDiscountAmount;
fees.protocolFeeAmount = fees.positionFeeAmount - fees.referral.affiliateRewardAmount - fees.totalDiscountAmount;
fees.positionFeeReceiverFactor = dataStore.getUint(Keys.POSITION_FEE_RECEIVER_FACTOR);
fees.feeReceiverAmount = Precision.applyFactor(fees.protocolFeeAmount, fees.positionFeeReceiverFactor);
fees.positionFeeAmountForPool = fees.protocolFeeAmount - fees.feeReceiverAmount;
return fees;
}
function getLiquidationFees(DataStore dataStore, address market, uint256 sizeInUsd, Price.Props memory collateralTokenPrice) internal view returns (PositionLiquidationFees memory) {
PositionLiquidationFees memory liquidationFees;
uint256 liquidationFeeFactor = dataStore.getUint(Keys.liquidationFeeFactorKey(market));
if (liquidationFeeFactor == 0) {
return liquidationFees;
}
liquidationFees.liquidationFeeUsd = Precision.applyFactor(sizeInUsd, liquidationFeeFactor);
liquidationFees.liquidationFeeAmount = Calc.roundUpDivision(liquidationFees.liquidationFeeUsd, collateralTokenPrice.min);
liquidationFees.liquidationFeeReceiverFactor = dataStore.getUint(Keys.LIQUIDATION_FEE_RECEIVER_FACTOR);
liquidationFees.liquidationFeeAmountForFeeReceiver = Precision.applyFactor(liquidationFees.liquidationFeeAmount, liquidationFees.liquidationFeeReceiverFactor);
return liquidationFees;
}
}
文件 79 的 108:PositionUtils.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "../utils/Precision.sol";
import "./Position.sol";
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../pricing/PositionPricingUtils.sol";
import "../order/BaseOrderUtils.sol";
library PositionUtils {
using SafeCast for uint256;
using SafeCast for int256;
using Price for Price.Props;
using Position for Position.Props;
using Order for Order.Props;
struct UpdatePositionParams {
BaseOrderUtils.ExecuteOrderParamsContracts contracts;
Market.Props market;
Order.Props order;
bytes32 orderKey;
Position.Props position;
bytes32 positionKey;
Order.SecondaryOrderType secondaryOrderType;
}
struct UpdatePositionParamsContracts {
DataStore dataStore;
EventEmitter eventEmitter;
Oracle oracle;
SwapHandler swapHandler;
IReferralStorage referralStorage;
}
struct WillPositionCollateralBeSufficientValues {
uint256 positionSizeInUsd;
uint256 positionCollateralAmount;
int256 realizedPnlUsd;
int256 openInterestDelta;
}
struct DecreasePositionCollateralValuesOutput {
address outputToken;
uint256 outputAmount;
address secondaryOutputToken;
uint256 secondaryOutputAmount;
}
struct DecreasePositionCollateralValues {
uint256 executionPrice;
uint256 remainingCollateralAmount;
int256 basePnlUsd;
int256 uncappedBasePnlUsd;
uint256 sizeDeltaInTokens;
int256 priceImpactUsd;
uint256 priceImpactDiffUsd;
DecreasePositionCollateralValuesOutput output;
}
struct DecreasePositionCache {
MarketUtils.MarketPrices prices;
int256 estimatedPositionPnlUsd;
int256 estimatedRealizedPnlUsd;
int256 estimatedRemainingPnlUsd;
address pnlToken;
Price.Props pnlTokenPrice;
Price.Props collateralTokenPrice;
uint256 initialCollateralAmount;
uint256 nextPositionSizeInUsd;
uint256 nextPositionBorrowingFactor;
}
struct GetPositionPnlUsdCache {
int256 positionValue;
int256 totalPositionPnl;
int256 uncappedTotalPositionPnl;
address pnlToken;
uint256 poolTokenAmount;
uint256 poolTokenPrice;
uint256 poolTokenUsd;
int256 poolPnl;
int256 cappedPoolPnl;
uint256 sizeDeltaInTokens;
int256 positionPnlUsd;
int256 uncappedPositionPnlUsd;
}
struct IsPositionLiquidatableInfo {
int256 remainingCollateralUsd;
int256 minCollateralUsd;
int256 minCollateralUsdForLeverage;
}
struct IsPositionLiquidatableCache {
int256 positionPnlUsd;
uint256 minCollateralFactor;
Price.Props collateralTokenPrice;
uint256 collateralUsd;
int256 usdDeltaForPriceImpact;
int256 priceImpactUsd;
bool hasPositiveImpact;
}
struct GetExecutionPriceForDecreaseCache {
int256 priceImpactUsd;
uint256 priceImpactDiffUsd;
uint256 executionPrice;
}
function getPositionPnlUsd(
DataStore dataStore,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
Position.Props memory position,
uint256 sizeDeltaUsd
) public view returns (int256, int256, uint256) {
GetPositionPnlUsdCache memory cache;
uint256 executionPrice = prices.indexTokenPrice.pickPriceForPnl(position.isLong(), false);
cache.positionValue = (position.sizeInTokens() * executionPrice).toInt256();
cache.totalPositionPnl = position.isLong() ? cache.positionValue - position.sizeInUsd().toInt256() : position.sizeInUsd().toInt256() - cache.positionValue;
cache.uncappedTotalPositionPnl = cache.totalPositionPnl;
if (cache.totalPositionPnl > 0) {
cache.pnlToken = position.isLong() ? market.longToken : market.shortToken;
cache.poolTokenAmount = MarketUtils.getPoolAmount(dataStore, market, cache.pnlToken);
cache.poolTokenPrice = position.isLong() ? prices.longTokenPrice.min : prices.shortTokenPrice.min;
cache.poolTokenUsd = cache.poolTokenAmount * cache.poolTokenPrice;
cache.poolPnl = MarketUtils.getPnl(
dataStore,
market,
prices.indexTokenPrice,
position.isLong(),
true
);
cache.cappedPoolPnl = MarketUtils.getCappedPnl(
dataStore,
market.marketToken,
position.isLong(),
cache.poolPnl,
cache.poolTokenUsd,
Keys.MAX_PNL_FACTOR_FOR_TRADERS
);
if (cache.cappedPoolPnl != cache.poolPnl && cache.cappedPoolPnl > 0 && cache.poolPnl > 0) {
cache.totalPositionPnl = Precision.mulDiv(cache.totalPositionPnl.toUint256(), cache.cappedPoolPnl, cache.poolPnl.toUint256());
}
}
if (position.sizeInUsd() == sizeDeltaUsd) {
cache.sizeDeltaInTokens = position.sizeInTokens();
} else {
if (position.isLong()) {
cache.sizeDeltaInTokens = Calc.roundUpDivision(position.sizeInTokens() * sizeDeltaUsd, position.sizeInUsd());
} else {
cache.sizeDeltaInTokens = position.sizeInTokens() * sizeDeltaUsd / position.sizeInUsd();
}
}
cache.positionPnlUsd = Precision.mulDiv(cache.totalPositionPnl, cache.sizeDeltaInTokens, position.sizeInTokens());
cache.uncappedPositionPnlUsd = Precision.mulDiv(cache.uncappedTotalPositionPnl, cache.sizeDeltaInTokens, position.sizeInTokens());
return (cache.positionPnlUsd, cache.uncappedPositionPnlUsd, cache.sizeDeltaInTokens);
}
function validateNonEmptyPosition(Position.Props memory position) internal pure {
if (position.sizeInUsd() == 0 && position.sizeInTokens() == 0 && position.collateralAmount() == 0) {
revert Errors.EmptyPosition();
}
}
function validatePosition(
DataStore dataStore,
IReferralStorage referralStorage,
Position.Props memory position,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
bool shouldValidateMinPositionSize,
bool shouldValidateMinCollateralUsd
) public view {
if (position.sizeInUsd() == 0 || position.sizeInTokens() == 0) {
revert Errors.InvalidPositionSizeValues(position.sizeInUsd(), position.sizeInTokens());
}
MarketUtils.validateEnabledMarket(dataStore, market.marketToken);
MarketUtils.validateMarketCollateralToken(market, position.collateralToken());
if (shouldValidateMinPositionSize) {
uint256 minPositionSizeUsd = dataStore.getUint(Keys.MIN_POSITION_SIZE_USD);
if (position.sizeInUsd() < minPositionSizeUsd) {
revert Errors.MinPositionSize(position.sizeInUsd(), minPositionSizeUsd);
}
}
(bool isLiquidatable, string memory reason, IsPositionLiquidatableInfo memory info) = isPositionLiquidatable(
dataStore,
referralStorage,
position,
market,
prices,
shouldValidateMinCollateralUsd
);
if (isLiquidatable) {
revert Errors.LiquidatablePosition(
reason,
info.remainingCollateralUsd,
info.minCollateralUsd,
info.minCollateralUsdForLeverage
);
}
}
function isPositionLiquidatable(
DataStore dataStore,
IReferralStorage referralStorage,
Position.Props memory position,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
bool shouldValidateMinCollateralUsd
) public view returns (bool, string memory, IsPositionLiquidatableInfo memory) {
IsPositionLiquidatableCache memory cache;
IsPositionLiquidatableInfo memory info;
(cache.positionPnlUsd, , ) = getPositionPnlUsd(
dataStore,
market,
prices,
position,
position.sizeInUsd()
);
cache.collateralTokenPrice = MarketUtils.getCachedTokenPrice(
position.collateralToken(),
market,
prices
);
cache.collateralUsd = position.collateralAmount() * cache.collateralTokenPrice.min;
cache.usdDeltaForPriceImpact = -position.sizeInUsd().toInt256();
cache.priceImpactUsd = PositionPricingUtils.getPriceImpactUsd(
PositionPricingUtils.GetPriceImpactUsdParams(
dataStore,
market,
cache.usdDeltaForPriceImpact,
position.isLong()
)
);
cache.hasPositiveImpact = cache.priceImpactUsd > 0;
if (cache.priceImpactUsd >= 0) {
cache.priceImpactUsd = 0;
} else {
uint256 maxPriceImpactFactor = MarketUtils.getMaxPositionImpactFactorForLiquidations(
dataStore,
market.marketToken
);
int256 maxNegativePriceImpactUsd = -Precision.applyFactor(position.sizeInUsd(), maxPriceImpactFactor).toInt256();
if (cache.priceImpactUsd < maxNegativePriceImpactUsd) {
cache.priceImpactUsd = maxNegativePriceImpactUsd;
}
}
PositionPricingUtils.GetPositionFeesParams memory getPositionFeesParams = PositionPricingUtils.GetPositionFeesParams(
dataStore,
referralStorage,
position,
cache.collateralTokenPrice,
cache.hasPositiveImpact,
market.longToken,
market.shortToken,
position.sizeInUsd(),
address(0),
false
);
PositionPricingUtils.PositionFees memory fees = PositionPricingUtils.getPositionFees(getPositionFeesParams);
uint256 collateralCostUsd = fees.totalCostAmount * cache.collateralTokenPrice.min;
info.remainingCollateralUsd =
cache.collateralUsd.toInt256()
+ cache.positionPnlUsd
+ cache.priceImpactUsd
- collateralCostUsd.toInt256();
cache.minCollateralFactor = MarketUtils.getMinCollateralFactor(dataStore, market.marketToken);
info.minCollateralUsdForLeverage = Precision.applyFactor(position.sizeInUsd(), cache.minCollateralFactor).toInt256();
if (shouldValidateMinCollateralUsd) {
info.minCollateralUsd = dataStore.getUint(Keys.MIN_COLLATERAL_USD).toInt256();
if (info.remainingCollateralUsd < info.minCollateralUsd) {
return (true, "min collateral", info);
}
}
if (info.remainingCollateralUsd <= 0) {
return (true, "< 0", info);
}
if (info.remainingCollateralUsd < info.minCollateralUsdForLeverage) {
return (true, "min collateral for leverage", info);
}
return (false, "", info);
}
function willPositionCollateralBeSufficient(
DataStore dataStore,
Market.Props memory market,
MarketUtils.MarketPrices memory prices,
address collateralToken,
bool isLong,
WillPositionCollateralBeSufficientValues memory values
) public view returns (bool, int256) {
Price.Props memory collateralTokenPrice = MarketUtils.getCachedTokenPrice(
collateralToken,
market,
prices
);
int256 remainingCollateralUsd = values.positionCollateralAmount.toInt256() * collateralTokenPrice.min.toInt256();
if (values.realizedPnlUsd < 0) {
remainingCollateralUsd = remainingCollateralUsd + values.realizedPnlUsd;
}
if (remainingCollateralUsd < 0) {
return (false, remainingCollateralUsd);
}
uint256 minCollateralFactor = MarketUtils.getMinCollateralFactorForOpenInterest(
dataStore,
market,
values.openInterestDelta,
isLong
);
uint256 minCollateralFactorForMarket = MarketUtils.getMinCollateralFactor(dataStore, market.marketToken);
if (minCollateralFactorForMarket > minCollateralFactor) {
minCollateralFactor = minCollateralFactorForMarket;
}
int256 minCollateralUsdForLeverage = Precision.applyFactor(values.positionSizeInUsd, minCollateralFactor).toInt256();
bool willBeSufficient = remainingCollateralUsd >= minCollateralUsdForLeverage;
return (willBeSufficient, remainingCollateralUsd);
}
function updateFundingAndBorrowingState(
DataStore dataStore,
EventEmitter eventEmitter,
Market.Props memory market,
MarketUtils.MarketPrices memory prices
) external {
MarketUtils.updateFundingState(
dataStore,
eventEmitter,
market,
prices
);
MarketUtils.updateCumulativeBorrowingFactor(
dataStore,
eventEmitter,
market,
prices,
true
);
MarketUtils.updateCumulativeBorrowingFactor(
dataStore,
eventEmitter,
market,
prices,
false
);
}
function updateTotalBorrowing(
PositionUtils.UpdatePositionParams memory params,
uint256 nextPositionSizeInUsd,
uint256 nextPositionBorrowingFactor
) internal {
MarketUtils.updateTotalBorrowing(
params.contracts.dataStore,
params.market.marketToken,
params.position.isLong(),
params.position.sizeInUsd(),
params.position.borrowingFactor(),
nextPositionSizeInUsd,
nextPositionBorrowingFactor
);
}
function incrementClaimableFundingAmount(
PositionUtils.UpdatePositionParams memory params,
PositionPricingUtils.PositionFees memory fees
) internal {
if (fees.funding.claimableLongTokenAmount > 0) {
MarketUtils.incrementClaimableFundingAmount(
params.contracts.dataStore,
params.contracts.eventEmitter,
params.market.marketToken,
params.market.longToken,
params.order.account(),
fees.funding.claimableLongTokenAmount
);
}
if (fees.funding.claimableShortTokenAmount > 0) {
MarketUtils.incrementClaimableFundingAmount(
params.contracts.dataStore,
params.contracts.eventEmitter,
params.market.marketToken,
params.market.shortToken,
params.order.account(),
fees.funding.claimableShortTokenAmount
);
}
}
function updateOpenInterest(
PositionUtils.UpdatePositionParams memory params,
int256 sizeDeltaUsd,
int256 sizeDeltaInTokens
) internal {
if (sizeDeltaUsd != 0) {
MarketUtils.applyDeltaToOpenInterest(
params.contracts.dataStore,
params.contracts.eventEmitter,
params.market,
params.position.collateralToken(),
params.position.isLong(),
sizeDeltaUsd
);
MarketUtils.applyDeltaToOpenInterestInTokens(
params.contracts.dataStore,
params.contracts.eventEmitter,
params.position.market(),
params.position.collateralToken(),
params.position.isLong(),
sizeDeltaInTokens
);
}
}
function handleReferral(
PositionUtils.UpdatePositionParams memory params,
PositionPricingUtils.PositionFees memory fees
) internal {
ReferralUtils.incrementAffiliateReward(
params.contracts.dataStore,
params.contracts.eventEmitter,
params.position.market(),
params.position.collateralToken(),
fees.referral.affiliate,
fees.referral.affiliateRewardAmount
);
}
function getExecutionPriceForIncrease(
UpdatePositionParams memory params,
Price.Props memory indexTokenPrice
) external view returns (int256, int256, uint256, uint256) {
if (params.order.sizeDeltaUsd() == 0) {
return (0, 0, 0, indexTokenPrice.pickPrice(params.position.isLong()));
}
int256 priceImpactUsd = PositionPricingUtils.getPriceImpactUsd(
PositionPricingUtils.GetPriceImpactUsdParams(
params.contracts.dataStore,
params.market,
params.order.sizeDeltaUsd().toInt256(),
params.order.isLong()
)
);
priceImpactUsd = MarketUtils.getCappedPositionImpactUsd(
params.contracts.dataStore,
params.market.marketToken,
indexTokenPrice,
priceImpactUsd,
params.order.sizeDeltaUsd()
);
int256 priceImpactAmount;
if (priceImpactUsd > 0) {
priceImpactAmount = priceImpactUsd / indexTokenPrice.max.toInt256();
} else {
priceImpactAmount = Calc.roundUpMagnitudeDivision(priceImpactUsd, indexTokenPrice.min);
}
uint256 baseSizeDeltaInTokens;
if (params.position.isLong()) {
baseSizeDeltaInTokens = params.order.sizeDeltaUsd() / indexTokenPrice.max;
} else {
baseSizeDeltaInTokens = Calc.roundUpDivision(params.order.sizeDeltaUsd(), indexTokenPrice.min);
}
int256 sizeDeltaInTokens;
if (params.position.isLong()) {
sizeDeltaInTokens = baseSizeDeltaInTokens.toInt256() + priceImpactAmount;
} else {
sizeDeltaInTokens = baseSizeDeltaInTokens.toInt256() - priceImpactAmount;
}
if (sizeDeltaInTokens < 0) {
revert Errors.PriceImpactLargerThanOrderSize(priceImpactUsd, params.order.sizeDeltaUsd());
}
uint256 executionPrice = BaseOrderUtils.getExecutionPriceForIncrease(
params.order.sizeDeltaUsd(),
sizeDeltaInTokens.toUint256(),
params.order.acceptablePrice(),
params.position.isLong()
);
return (priceImpactUsd, priceImpactAmount, sizeDeltaInTokens.toUint256(), executionPrice);
}
function getExecutionPriceForDecrease(
UpdatePositionParams memory params,
Price.Props memory indexTokenPrice
) external view returns (int256, uint256, uint256) {
uint256 sizeDeltaUsd = params.order.sizeDeltaUsd();
if (sizeDeltaUsd == 0) {
return (0, 0, indexTokenPrice.pickPrice(!params.position.isLong()));
}
GetExecutionPriceForDecreaseCache memory cache;
cache.priceImpactUsd = PositionPricingUtils.getPriceImpactUsd(
PositionPricingUtils.GetPriceImpactUsdParams(
params.contracts.dataStore,
params.market,
-sizeDeltaUsd.toInt256(),
params.order.isLong()
)
);
cache.priceImpactUsd = MarketUtils.getCappedPositionImpactUsd(
params.contracts.dataStore,
params.market.marketToken,
indexTokenPrice,
cache.priceImpactUsd,
sizeDeltaUsd
);
if (cache.priceImpactUsd < 0) {
uint256 maxPriceImpactFactor = MarketUtils.getMaxPositionImpactFactor(
params.contracts.dataStore,
params.market.marketToken,
false
);
int256 minPriceImpactUsd = -Precision.applyFactor(sizeDeltaUsd, maxPriceImpactFactor).toInt256();
if (cache.priceImpactUsd < minPriceImpactUsd) {
cache.priceImpactDiffUsd = (minPriceImpactUsd - cache.priceImpactUsd).toUint256();
cache.priceImpactUsd = minPriceImpactUsd;
}
}
cache.executionPrice = BaseOrderUtils.getExecutionPriceForDecrease(
indexTokenPrice,
params.position.sizeInUsd(),
params.position.sizeInTokens(),
sizeDeltaUsd,
cache.priceImpactUsd,
params.order.acceptablePrice(),
params.position.isLong()
);
return (cache.priceImpactUsd, cache.priceImpactDiffUsd, cache.executionPrice);
}
}
文件 80 的 108:Precision.sol
pragma solidity ^0.8.0;
import "prb-math/contracts/PRBMathUD60x18.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
library Precision {
using SafeCast for uint256;
using SignedMath for int256;
uint256 public constant FLOAT_PRECISION = 10 ** 30;
uint256 public constant FLOAT_PRECISION_SQRT = 10 ** 15;
uint256 public constant WEI_PRECISION = 10 ** 18;
uint256 public constant BASIS_POINTS_DIVISOR = 10000;
uint256 public constant FLOAT_TO_WEI_DIVISOR = 10 ** 12;
function applyFactor(uint256 value, uint256 factor) internal pure returns (uint256) {
return mulDiv(value, factor, FLOAT_PRECISION);
}
function applyFactor(uint256 value, int256 factor) internal pure returns (int256) {
return mulDiv(value, factor, FLOAT_PRECISION);
}
function applyFactor(uint256 value, int256 factor, bool roundUpMagnitude) internal pure returns (int256) {
return mulDiv(value, factor, FLOAT_PRECISION, roundUpMagnitude);
}
function mulDiv(uint256 value, uint256 numerator, uint256 denominator) internal pure returns (uint256) {
return Math.mulDiv(value, numerator, denominator);
}
function mulDiv(int256 value, uint256 numerator, uint256 denominator) internal pure returns (int256) {
return mulDiv(numerator, value, denominator);
}
function mulDiv(uint256 value, int256 numerator, uint256 denominator) internal pure returns (int256) {
uint256 result = mulDiv(value, numerator.abs(), denominator);
return numerator > 0 ? result.toInt256() : -result.toInt256();
}
function mulDiv(uint256 value, int256 numerator, uint256 denominator, bool roundUpMagnitude) internal pure returns (int256) {
uint256 result = mulDiv(value, numerator.abs(), denominator, roundUpMagnitude);
return numerator > 0 ? result.toInt256() : -result.toInt256();
}
function mulDiv(uint256 value, uint256 numerator, uint256 denominator, bool roundUpMagnitude) internal pure returns (uint256) {
if (roundUpMagnitude) {
return Math.mulDiv(value, numerator, denominator, Math.Rounding.Up);
}
return Math.mulDiv(value, numerator, denominator);
}
function applyExponentFactor(
uint256 floatValue,
uint256 exponentFactor
) internal pure returns (uint256) {
if (floatValue < FLOAT_PRECISION) {
return 0;
}
if (exponentFactor == FLOAT_PRECISION) {
return floatValue;
}
uint256 weiValue = PRBMathUD60x18.pow(
floatToWei(floatValue),
floatToWei(exponentFactor)
);
return weiToFloat(weiValue);
}
function toFactor(uint256 value, uint256 divisor, bool roundUpMagnitude) internal pure returns (uint256) {
if (value == 0) { return 0; }
if (roundUpMagnitude) {
return Math.mulDiv(value, FLOAT_PRECISION, divisor, Math.Rounding.Up);
}
return Math.mulDiv(value, FLOAT_PRECISION, divisor);
}
function toFactor(uint256 value, uint256 divisor) internal pure returns (uint256) {
return toFactor(value, divisor, false);
}
function toFactor(int256 value, uint256 divisor) internal pure returns (int256) {
uint256 result = toFactor(value.abs(), divisor);
return value > 0 ? result.toInt256() : -result.toInt256();
}
function floatToWei(uint256 value) internal pure returns (uint256) {
return value / FLOAT_TO_WEI_DIVISOR;
}
function weiToFloat(uint256 value) internal pure returns (uint256) {
return value * FLOAT_TO_WEI_DIVISOR;
}
function basisPointsToFloat(uint256 basisPoints) internal pure returns (uint256) {
return basisPoints * FLOAT_PRECISION / BASIS_POINTS_DIVISOR;
}
}
文件 81 的 108:Price.sol
pragma solidity ^0.8.0;
library Price {
struct Props {
uint256 min;
uint256 max;
}
function isEmpty(Props memory props) internal pure returns (bool) {
return props.min == 0 || props.max == 0;
}
function midPrice(Props memory props) internal pure returns (uint256) {
return (props.max + props.min) / 2;
}
function pickPrice(Props memory props, bool maximize) internal pure returns (uint256) {
return maximize ? props.max : props.min;
}
function pickPriceForPnl(Props memory props, bool isLong, bool maximize) internal pure returns (uint256) {
if (isLong) {
return maximize ? props.max : props.min;
}
return maximize ? props.min : props.max;
}
}
文件 82 的 108:PricingUtils.sol
pragma solidity ^0.8.0;
import "../utils/Calc.sol";
import "../utils/Precision.sol";
library PricingUtils {
function getPriceImpactUsdForSameSideRebalance(
uint256 initialDiffUsd,
uint256 nextDiffUsd,
uint256 impactFactor,
uint256 impactExponentFactor
) internal pure returns (int256) {
bool hasPositiveImpact = nextDiffUsd < initialDiffUsd;
uint256 deltaDiffUsd = Calc.diff(
applyImpactFactor(initialDiffUsd, impactFactor, impactExponentFactor),
applyImpactFactor(nextDiffUsd, impactFactor, impactExponentFactor)
);
int256 priceImpactUsd = Calc.toSigned(deltaDiffUsd, hasPositiveImpact);
return priceImpactUsd;
}
function getPriceImpactUsdForCrossoverRebalance(
uint256 initialDiffUsd,
uint256 nextDiffUsd,
uint256 positiveImpactFactor,
uint256 negativeImpactFactor,
uint256 impactExponentFactor
) internal pure returns (int256) {
uint256 positiveImpactUsd = applyImpactFactor(initialDiffUsd, positiveImpactFactor, impactExponentFactor);
uint256 negativeImpactUsd = applyImpactFactor(nextDiffUsd, negativeImpactFactor, impactExponentFactor);
uint256 deltaDiffUsd = Calc.diff(positiveImpactUsd, negativeImpactUsd);
int256 priceImpactUsd = Calc.toSigned(deltaDiffUsd, positiveImpactUsd > negativeImpactUsd);
return priceImpactUsd;
}
function applyImpactFactor(
uint256 diffUsd,
uint256 impactFactor,
uint256 impactExponentFactor
) internal pure returns (uint256) {
uint256 exponentValue = Precision.applyExponentFactor(diffUsd, impactExponentFactor);
return Precision.applyFactor(exponentValue, impactFactor);
}
}
文件 83 的 108:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
文件 84 的 108:ReferralEventUtils.sol
pragma solidity ^0.8.0;
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Cast.sol";
library ReferralEventUtils {
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
function emitAffiliateRewardUpdated(
EventEmitter eventEmitter,
address market,
address token,
address affiliate,
uint256 delta,
uint256 nextValue,
uint256 nextPoolValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "affiliate", affiliate);
eventData.uintItems.initItems(3);
eventData.uintItems.setItem(0, "delta", delta);
eventData.uintItems.setItem(1, "nextValue", nextValue);
eventData.uintItems.setItem(2, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog2(
"AffiliateRewardUpdated",
Cast.toBytes32(market),
Cast.toBytes32(affiliate),
eventData
);
}
function emitAffiliateRewardClaimed(
EventEmitter eventEmitter,
address market,
address token,
address affiliate,
address receiver,
uint256 amount,
uint256 nextPoolValue
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(4);
eventData.addressItems.setItem(0, "market", market);
eventData.addressItems.setItem(1, "token", token);
eventData.addressItems.setItem(2, "affiliate", affiliate);
eventData.addressItems.setItem(3, "receiver", receiver);
eventData.uintItems.initItems(2);
eventData.uintItems.setItem(0, "amount", amount);
eventData.uintItems.setItem(1, "nextPoolValue", nextPoolValue);
eventEmitter.emitEventLog1(
"AffiliateRewardClaimed",
Cast.toBytes32(affiliate),
eventData
);
}
}
文件 85 的 108:ReferralUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../event/EventEmitter.sol";
import "../market/MarketToken.sol";
import "../market/MarketUtils.sol";
import "./IReferralStorage.sol";
import "./ReferralEventUtils.sol";
import "../utils/Precision.sol";
library ReferralUtils {
function setTraderReferralCode(
IReferralStorage referralStorage,
address account,
bytes32 referralCode
) internal {
if (referralCode == bytes32(0)) { return; }
if (referralStorage.traderReferralCodes(account) != bytes32(0)) { return; }
referralStorage.setTraderReferralCode(account, referralCode);
}
function incrementAffiliateReward(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
address affiliate,
uint256 delta
) internal {
if (delta == 0) { return; }
uint256 nextValue = dataStore.incrementUint(Keys.affiliateRewardKey(market, token, affiliate), delta);
uint256 nextPoolValue = dataStore.incrementUint(Keys.affiliateRewardKey(market, token), delta);
ReferralEventUtils.emitAffiliateRewardUpdated(
eventEmitter,
market,
token,
affiliate,
delta,
nextValue,
nextPoolValue
);
}
function getReferralInfo(
DataStore dataStore,
IReferralStorage referralStorage,
address trader
) internal view returns (bytes32, address, uint256, uint256, uint256) {
bytes32 code = referralStorage.traderReferralCodes(trader);
address affiliate;
uint256 totalRebate;
uint256 discountShare;
uint256 minAffiliateRewardFactor;
if (code != bytes32(0)) {
affiliate = referralStorage.codeOwners(code);
uint256 referralTierLevel = referralStorage.referrerTiers(affiliate);
(totalRebate, discountShare) = referralStorage.tiers(referralTierLevel);
minAffiliateRewardFactor = dataStore.getUint(Keys.minAffiliateRewardFactorKey(referralTierLevel));
uint256 customDiscountShare = referralStorage.referrerDiscountShares(affiliate);
if (customDiscountShare != 0) {
discountShare = customDiscountShare;
}
}
uint256 traderDiscountFactor = Precision.basisPointsToFloat(totalRebate * discountShare / Precision.BASIS_POINTS_DIVISOR);
uint256 totalRebateFactor = Precision.basisPointsToFloat(totalRebate);
uint256 affiliateRewardFactor = totalRebateFactor - traderDiscountFactor;
return (
code,
affiliate,
affiliateRewardFactor,
traderDiscountFactor,
minAffiliateRewardFactor
);
}
function claimAffiliateReward(
DataStore dataStore,
EventEmitter eventEmitter,
address market,
address token,
address account,
address receiver
) external returns (uint256) {
bytes32 key = Keys.affiliateRewardKey(market, token, account);
uint256 rewardAmount = dataStore.getUint(key);
dataStore.setUint(key, 0);
uint256 nextPoolValue = dataStore.decrementUint(Keys.affiliateRewardKey(market, token), rewardAmount);
MarketToken(payable(market)).transferOut(
token,
receiver,
rewardAmount
);
MarketUtils.validateMarketTokenBalance(dataStore, market);
ReferralEventUtils.emitAffiliateRewardClaimed(
eventEmitter,
market,
token,
account,
receiver,
rewardAmount,
nextPoolValue
);
return rewardAmount;
}
}
文件 86 的 108:Role.sol
pragma solidity ^0.8.0;
library Role {
bytes32 public constant ROLE_ADMIN = keccak256(abi.encode("ROLE_ADMIN"));
bytes32 public constant TIMELOCK_ADMIN = keccak256(abi.encode("TIMELOCK_ADMIN"));
bytes32 public constant TIMELOCK_MULTISIG = keccak256(abi.encode("TIMELOCK_MULTISIG"));
bytes32 public constant CONFIG_KEEPER = keccak256(abi.encode("CONFIG_KEEPER"));
bytes32 public constant LIMITED_CONFIG_KEEPER = keccak256(abi.encode("LIMITED_CONFIG_KEEPER"));
bytes32 public constant CONTROLLER = keccak256(abi.encode("CONTROLLER"));
bytes32 public constant GOV_TOKEN_CONTROLLER = keccak256(abi.encode("GOV_TOKEN_CONTROLLER"));
bytes32 public constant ROUTER_PLUGIN = keccak256(abi.encode("ROUTER_PLUGIN"));
bytes32 public constant MARKET_KEEPER = keccak256(abi.encode("MARKET_KEEPER"));
bytes32 public constant FEE_KEEPER = keccak256(abi.encode("FEE_KEEPER"));
bytes32 public constant FEE_DISTRIBUTION_KEEPER = keccak256(abi.encode("FEE_DISTRIBUTION_KEEPER"));
bytes32 public constant ORDER_KEEPER = keccak256(abi.encode("ORDER_KEEPER"));
bytes32 public constant FROZEN_ORDER_KEEPER = keccak256(abi.encode("FROZEN_ORDER_KEEPER"));
bytes32 public constant PRICING_KEEPER = keccak256(abi.encode("PRICING_KEEPER"));
bytes32 public constant LIQUIDATION_KEEPER = keccak256(abi.encode("LIQUIDATION_KEEPER"));
bytes32 public constant ADL_KEEPER = keccak256(abi.encode("ADL_KEEPER"));
bytes32 public constant CONTRIBUTOR_KEEPER = keccak256(abi.encode("CONTRIBUTOR_KEEPER"));
bytes32 public constant CONTRIBUTOR_DISTRIBUTOR = keccak256(abi.encode("CONTRIBUTOR_DISTRIBUTOR"));
}
文件 87 的 108:RoleModule.sol
pragma solidity ^0.8.0;
import "./RoleStore.sol";
contract RoleModule {
RoleStore public immutable roleStore;
constructor(RoleStore _roleStore) {
roleStore = _roleStore;
}
modifier onlySelf() {
if (msg.sender != address(this)) {
revert Errors.Unauthorized(msg.sender, "SELF");
}
_;
}
modifier onlyTimelockMultisig() {
_validateRole(Role.TIMELOCK_MULTISIG, "TIMELOCK_MULTISIG");
_;
}
modifier onlyTimelockAdmin() {
_validateRole(Role.TIMELOCK_ADMIN, "TIMELOCK_ADMIN");
_;
}
modifier onlyConfigKeeper() {
_validateRole(Role.CONFIG_KEEPER, "CONFIG_KEEPER");
_;
}
modifier onlyLimitedConfigKeeper() {
_validateRole(Role.LIMITED_CONFIG_KEEPER, "LIMITED_CONFIG_KEEPER");
_;
}
modifier onlyController() {
_validateRole(Role.CONTROLLER, "CONTROLLER");
_;
}
modifier onlyGovTokenController() {
_validateRole(Role.GOV_TOKEN_CONTROLLER, "GOV_TOKEN_CONTROLLER");
_;
}
modifier onlyRouterPlugin() {
_validateRole(Role.ROUTER_PLUGIN, "ROUTER_PLUGIN");
_;
}
modifier onlyMarketKeeper() {
_validateRole(Role.MARKET_KEEPER, "MARKET_KEEPER");
_;
}
modifier onlyFeeKeeper() {
_validateRole(Role.FEE_KEEPER, "FEE_KEEPER");
_;
}
modifier onlyFeeDistributionKeeper() {
_validateRole(Role.FEE_DISTRIBUTION_KEEPER, "FEE_DISTRIBUTION_KEEPER");
_;
}
modifier onlyOrderKeeper() {
_validateRole(Role.ORDER_KEEPER, "ORDER_KEEPER");
_;
}
modifier onlyPricingKeeper() {
_validateRole(Role.PRICING_KEEPER, "PRICING_KEEPER");
_;
}
modifier onlyLiquidationKeeper() {
_validateRole(Role.LIQUIDATION_KEEPER, "LIQUIDATION_KEEPER");
_;
}
modifier onlyAdlKeeper() {
_validateRole(Role.ADL_KEEPER, "ADL_KEEPER");
_;
}
modifier onlyContributorKeeper() {
_validateRole(Role.CONTRIBUTOR_KEEPER, "CONTRIBUTOR_KEEPER");
_;
}
modifier onlyContributorDistributor() {
_validateRole(Role.CONTRIBUTOR_DISTRIBUTOR, "CONTRIBUTOR_DISTRIBUTOR");
_;
}
function _validateRole(bytes32 role, string memory roleName) internal view {
if (!roleStore.hasRole(msg.sender, role)) {
revert Errors.Unauthorized(msg.sender, roleName);
}
}
}
文件 88 的 108:RoleStore.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../utils/EnumerableValues.sol";
import "./Role.sol";
import "../error/Errors.sol";
contract RoleStore {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableValues for EnumerableSet.AddressSet;
using EnumerableValues for EnumerableSet.Bytes32Set;
EnumerableSet.Bytes32Set internal roles;
mapping(bytes32 => EnumerableSet.AddressSet) internal roleMembers;
mapping(address => mapping (bytes32 => bool)) roleCache;
modifier onlyRoleAdmin() {
if (!hasRole(msg.sender, Role.ROLE_ADMIN)) {
revert Errors.Unauthorized(msg.sender, "ROLE_ADMIN");
}
_;
}
constructor() {
_grantRole(msg.sender, Role.ROLE_ADMIN);
}
function grantRole(address account, bytes32 roleKey) external onlyRoleAdmin {
_grantRole(account, roleKey);
}
function revokeRole(address account, bytes32 roleKey) external onlyRoleAdmin {
_revokeRole(account, roleKey);
}
function hasRole(address account, bytes32 roleKey) public view returns (bool) {
return roleCache[account][roleKey];
}
function getRoleCount() external view returns (uint256) {
return roles.length();
}
function getRoles(uint256 start, uint256 end) external view returns (bytes32[] memory) {
return roles.valuesAt(start, end);
}
function getRoleMemberCount(bytes32 roleKey) external view returns (uint256) {
return roleMembers[roleKey].length();
}
function getRoleMembers(bytes32 roleKey, uint256 start, uint256 end) external view returns (address[] memory) {
return roleMembers[roleKey].valuesAt(start, end);
}
function _grantRole(address account, bytes32 roleKey) internal {
roles.add(roleKey);
roleMembers[roleKey].add(account);
roleCache[account][roleKey] = true;
}
function _revokeRole(address account, bytes32 roleKey) internal {
roleMembers[roleKey].remove(account);
roleCache[account][roleKey] = false;
if (roleMembers[roleKey].length() == 0) {
if (roleKey == Role.ROLE_ADMIN) {
revert Errors.ThereMustBeAtLeastOneRoleAdmin();
}
if (roleKey == Role.TIMELOCK_MULTISIG) {
revert Errors.ThereMustBeAtLeastOneTimelockMultiSig();
}
}
}
}
文件 89 的 108:Router.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../role/RoleModule.sol";
contract Router is RoleModule {
using SafeERC20 for IERC20;
constructor(RoleStore _roleStore) RoleModule(_roleStore) {}
function pluginTransfer(address token, address account, address receiver, uint256 amount) external onlyRouterPlugin {
IERC20(token).safeTransferFrom(account, receiver, amount);
}
}
文件 90 的 108:SafeCast.sol
pragma solidity ^0.8.0;
library SafeCast {
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
function toInt256(uint256 value) internal pure returns (int256) {
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
文件 91 的 108:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
文件 92 的 108:Shift.sol
pragma solidity ^0.8.0;
library Shift {
struct Props {
Addresses addresses;
Numbers numbers;
}
struct Addresses {
address account;
address receiver;
address callbackContract;
address uiFeeReceiver;
address fromMarket;
address toMarket;
}
struct Numbers {
uint256 marketTokenAmount;
uint256 minMarketTokens;
uint256 updatedAtTime;
uint256 executionFee;
uint256 callbackGasLimit;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function receiver(Props memory props) internal pure returns (address) {
return props.addresses.receiver;
}
function setReceiver(Props memory props, address value) internal pure {
props.addresses.receiver = value;
}
function callbackContract(Props memory props) internal pure returns (address) {
return props.addresses.callbackContract;
}
function setCallbackContract(Props memory props, address value) internal pure {
props.addresses.callbackContract = value;
}
function uiFeeReceiver(Props memory props) internal pure returns (address) {
return props.addresses.uiFeeReceiver;
}
function setUiFeeReceiver(Props memory props, address value) internal pure {
props.addresses.uiFeeReceiver = value;
}
function fromMarket(Props memory props) internal pure returns (address) {
return props.addresses.fromMarket;
}
function setFromMarket(Props memory props, address value) internal pure {
props.addresses.fromMarket = value;
}
function toMarket(Props memory props) internal pure returns (address) {
return props.addresses.toMarket;
}
function setToMarket(Props memory props, address value) internal pure {
props.addresses.toMarket = value;
}
function marketTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.marketTokenAmount;
}
function setMarketTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.marketTokenAmount = value;
}
function minMarketTokens(Props memory props) internal pure returns (uint256) {
return props.numbers.minMarketTokens;
}
function setMinMarketTokens(Props memory props, uint256 value) internal pure {
props.numbers.minMarketTokens = value;
}
function updatedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.updatedAtTime;
}
function setUpdatedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.updatedAtTime = value;
}
function executionFee(Props memory props) internal pure returns (uint256) {
return props.numbers.executionFee;
}
function setExecutionFee(Props memory props, uint256 value) internal pure {
props.numbers.executionFee = value;
}
function callbackGasLimit(Props memory props) internal pure returns (uint256) {
return props.numbers.callbackGasLimit;
}
function setCallbackGasLimit(Props memory props, uint256 value) internal pure {
props.numbers.callbackGasLimit = value;
}
}
文件 93 的 108:ShiftEventUtils.sol
pragma solidity ^0.8.0;
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Cast.sol";
import "./Shift.sol";
library ShiftEventUtils {
using Shift for Shift.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
function emitShiftCreated(
EventEmitter eventEmitter,
bytes32 key,
Shift.Props memory shift
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(5);
eventData.addressItems.setItem(0, "account", shift.account());
eventData.addressItems.setItem(1, "receiver", shift.receiver());
eventData.addressItems.setItem(2, "callbackContract", shift.callbackContract());
eventData.addressItems.setItem(3, "fromMarket", shift.fromMarket());
eventData.addressItems.setItem(4, "toMarket", shift.toMarket());
eventData.uintItems.initItems(5);
eventData.uintItems.setItem(0, "marketTokenAmount", shift.marketTokenAmount());
eventData.uintItems.setItem(1, "minMarketTokens", shift.minMarketTokens());
eventData.uintItems.setItem(2, "updatedAtTime", shift.updatedAtTime());
eventData.uintItems.setItem(3, "executionFee", shift.executionFee());
eventData.uintItems.setItem(4, "callbackGasLimit", shift.callbackGasLimit());
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventEmitter.emitEventLog2(
"ShiftCreated",
key,
Cast.toBytes32(shift.account()),
eventData
);
}
function emitShiftExecuted(
EventEmitter eventEmitter,
bytes32 key,
address account,
uint256 receivedMarketTokens
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "receivedMarketTokens", receivedMarketTokens);
eventEmitter.emitEventLog2(
"ShiftExecuted",
key,
Cast.toBytes32(account),
eventData
);
}
function emitShiftCancelled(
EventEmitter eventEmitter,
bytes32 key,
address account,
string memory reason,
bytes memory reasonBytes
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.stringItems.initItems(1);
eventData.stringItems.setItem(0, "reason", reason);
eventData.bytesItems.initItems(1);
eventData.bytesItems.setItem(0, "reasonBytes", reasonBytes);
eventEmitter.emitEventLog2(
"ShiftCancelled",
key,
Cast.toBytes32(account),
eventData
);
}
}
文件 94 的 108:ShiftStoreUtils.sol
pragma solidity ^0.8.0;
import "../data/Keys.sol";
import "../data/DataStore.sol";
import "./Shift.sol";
library ShiftStoreUtils {
using Shift for Shift.Props;
bytes32 public constant ACCOUNT = keccak256(abi.encode("ACCOUNT"));
bytes32 public constant RECEIVER = keccak256(abi.encode("RECEIVER"));
bytes32 public constant CALLBACK_CONTRACT = keccak256(abi.encode("CALLBACK_CONTRACT"));
bytes32 public constant UI_FEE_RECEIVER = keccak256(abi.encode("UI_FEE_RECEIVER"));
bytes32 public constant FROM_MARKET = keccak256(abi.encode("FROM_MARKET"));
bytes32 public constant TO_MARKET = keccak256(abi.encode("TO_MARKET"));
bytes32 public constant MARKET_TOKEN_AMOUNT = keccak256(abi.encode("MARKET_TOKEN_AMOUNT"));
bytes32 public constant MIN_MARKET_TOKENS = keccak256(abi.encode("MIN_MARKET_TOKENS"));
bytes32 public constant UPDATED_AT_TIME = keccak256(abi.encode("UPDATED_AT_TIME"));
bytes32 public constant EXECUTION_FEE = keccak256(abi.encode("EXECUTION_FEE"));
bytes32 public constant CALLBACK_GAS_LIMIT = keccak256(abi.encode("CALLBACK_GAS_LIMIT"));
function get(DataStore dataStore, bytes32 key) external view returns (Shift.Props memory) {
Shift.Props memory shift;
if (!dataStore.containsBytes32(Keys.SHIFT_LIST, key)) {
return shift;
}
shift.setAccount(dataStore.getAddress(
keccak256(abi.encode(key, ACCOUNT))
));
shift.setReceiver(dataStore.getAddress(
keccak256(abi.encode(key, RECEIVER))
));
shift.setCallbackContract(dataStore.getAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
));
shift.setUiFeeReceiver(dataStore.getAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
));
shift.setFromMarket(dataStore.getAddress(
keccak256(abi.encode(key, FROM_MARKET))
));
shift.setToMarket(dataStore.getAddress(
keccak256(abi.encode(key, TO_MARKET))
));
shift.setMarketTokenAmount(dataStore.getUint(
keccak256(abi.encode(key, MARKET_TOKEN_AMOUNT))
));
shift.setMinMarketTokens(dataStore.getUint(
keccak256(abi.encode(key, MIN_MARKET_TOKENS))
));
shift.setUpdatedAtTime(dataStore.getUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
));
shift.setExecutionFee(dataStore.getUint(
keccak256(abi.encode(key, EXECUTION_FEE))
));
shift.setCallbackGasLimit(dataStore.getUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
));
return shift;
}
function set(DataStore dataStore, bytes32 key, Shift.Props memory shift) external {
dataStore.addBytes32(
Keys.SHIFT_LIST,
key
);
dataStore.addBytes32(
Keys.accountShiftListKey(shift.account()),
key
);
dataStore.setAddress(
keccak256(abi.encode(key, ACCOUNT)),
shift.account()
);
dataStore.setAddress(
keccak256(abi.encode(key, RECEIVER)),
shift.receiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT)),
shift.callbackContract()
);
dataStore.setAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER)),
shift.uiFeeReceiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, FROM_MARKET)),
shift.fromMarket()
);
dataStore.setAddress(
keccak256(abi.encode(key, TO_MARKET)),
shift.toMarket()
);
dataStore.setUint(
keccak256(abi.encode(key, MARKET_TOKEN_AMOUNT)),
shift.marketTokenAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, MIN_MARKET_TOKENS)),
shift.minMarketTokens()
);
dataStore.setUint(
keccak256(abi.encode(key, UPDATED_AT_TIME)),
shift.updatedAtTime()
);
dataStore.setUint(
keccak256(abi.encode(key, EXECUTION_FEE)),
shift.executionFee()
);
dataStore.setUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT)),
shift.callbackGasLimit()
);
}
function remove(DataStore dataStore, bytes32 key, address account) external {
if (!dataStore.containsBytes32(Keys.SHIFT_LIST, key)) {
revert Errors.ShiftNotFound(key);
}
dataStore.removeBytes32(
Keys.SHIFT_LIST,
key
);
dataStore.removeBytes32(
Keys.accountShiftListKey(account),
key
);
dataStore.removeAddress(
keccak256(abi.encode(key, ACCOUNT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, FROM_MARKET))
);
dataStore.removeAddress(
keccak256(abi.encode(key, TO_MARKET))
);
dataStore.removeUint(
keccak256(abi.encode(key, MARKET_TOKEN_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, MIN_MARKET_TOKENS))
);
dataStore.removeUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
);
dataStore.removeUint(
keccak256(abi.encode(key, EXECUTION_FEE))
);
dataStore.removeUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
);
}
function getShiftCount(DataStore dataStore) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.SHIFT_LIST);
}
function getShiftKeys(DataStore dataStore, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.SHIFT_LIST, start, end);
}
function getAccountShiftCount(DataStore dataStore, address account) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.accountShiftListKey(account));
}
function getAccountShiftKeys(DataStore dataStore, address account, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.accountShiftListKey(account), start, end);
}
}
文件 95 的 108:ShiftUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "./ShiftVault.sol";
import "./ShiftStoreUtils.sol";
import "./ShiftEventUtils.sol";
import "../nonce/NonceUtils.sol";
import "../gas/GasUtils.sol";
import "../callback/CallbackUtils.sol";
import "../utils/AccountUtils.sol";
import "../deposit/ExecuteDepositUtils.sol";
import "../withdrawal/ExecuteWithdrawalUtils.sol";
library ShiftUtils {
using Deposit for Deposit.Props;
using Withdrawal for Withdrawal.Props;
using Shift for Shift.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct CreateShiftParams {
address receiver;
address callbackContract;
address uiFeeReceiver;
address fromMarket;
address toMarket;
uint256 minMarketTokens;
uint256 executionFee;
uint256 callbackGasLimit;
}
struct CreateShiftCache {
uint256 estimatedGasLimit;
uint256 oraclePriceCount;
bytes32 key;
}
struct ExecuteShiftParams {
DataStore dataStore;
EventEmitter eventEmitter;
ShiftVault shiftVault;
Oracle oracle;
bytes32 key;
address keeper;
uint256 startingGas;
}
struct ExecuteShiftCache {
Withdrawal.Props withdrawal;
bytes32 withdrawalKey;
ExecuteWithdrawalUtils.ExecuteWithdrawalParams executeWithdrawalParams;
Market.Props depositMarket;
uint256 initialLongTokenAmount;
uint256 initialShortTokenAmount;
Deposit.Props deposit;
bytes32 depositKey;
ExecuteDepositUtils.ExecuteDepositParams executeDepositParams;
uint256 receivedMarketTokens;
}
function createShift(
DataStore dataStore,
EventEmitter eventEmitter,
ShiftVault shiftVault,
address account,
CreateShiftParams memory params
) external returns (bytes32) {
AccountUtils.validateAccount(account);
if (params.fromMarket == params.toMarket) {
revert Errors.ShiftFromAndToMarketAreEqual(params.fromMarket);
}
address wnt = TokenUtils.wnt(dataStore);
uint256 wntAmount = shiftVault.recordTransferIn(wnt);
if (wntAmount < params.executionFee) {
revert Errors.InsufficientWntAmount(wntAmount, params.executionFee);
}
AccountUtils.validateReceiver(params.receiver);
uint256 marketTokenAmount = shiftVault.recordTransferIn(params.fromMarket);
if (marketTokenAmount == 0) {
revert Errors.EmptyShiftAmount();
}
params.executionFee = wntAmount;
Market.Props memory fromMarket = MarketUtils.getEnabledMarket(dataStore, params.fromMarket);
Market.Props memory toMarket = MarketUtils.getEnabledMarket(dataStore, params.toMarket);
if (fromMarket.longToken != toMarket.longToken) {
revert Errors.LongTokensAreNotEqual(fromMarket.longToken, toMarket.longToken);
}
if (fromMarket.shortToken != toMarket.shortToken) {
revert Errors.ShortTokensAreNotEqual(fromMarket.shortToken, toMarket.shortToken);
}
Shift.Props memory shift = Shift.Props(
Shift.Addresses(
account,
params.receiver,
params.callbackContract,
params.uiFeeReceiver,
params.fromMarket,
params.toMarket
),
Shift.Numbers(
marketTokenAmount,
params.minMarketTokens,
Chain.currentTimestamp(),
params.executionFee,
params.callbackGasLimit
)
);
CallbackUtils.validateCallbackGasLimit(dataStore, shift.callbackGasLimit());
CreateShiftCache memory cache;
cache.estimatedGasLimit = GasUtils.estimateExecuteShiftGasLimit(dataStore, shift);
cache.oraclePriceCount = GasUtils.estimateShiftOraclePriceCount();
GasUtils.validateExecutionFee(dataStore, cache.estimatedGasLimit, params.executionFee, cache.oraclePriceCount);
cache.key = NonceUtils.getNextKey(dataStore);
ShiftStoreUtils.set(dataStore, cache.key, shift);
ShiftEventUtils.emitShiftCreated(eventEmitter, cache.key, shift);
return cache.key;
}
function executeShift(
ExecuteShiftParams memory params,
Shift.Props memory shift
) external returns (uint256) {
params.startingGas -= gasleft() / 63;
ShiftStoreUtils.remove(params.dataStore, params.key, shift.account());
if (shift.account() == address(0)) {
revert Errors.EmptyShift();
}
if (shift.marketTokenAmount() == 0) {
revert Errors.EmptyShiftAmount();
}
ExecuteShiftCache memory cache;
cache.depositMarket = MarketStoreUtils.get(params.dataStore, shift.toMarket());
params.shiftVault.recordTransferIn(cache.depositMarket.longToken);
params.shiftVault.recordTransferIn(cache.depositMarket.shortToken);
cache.withdrawal = Withdrawal.Props(
Withdrawal.Addresses(
shift.account(),
address(params.shiftVault),
address(0),
shift.uiFeeReceiver(),
shift.fromMarket(),
new address[](0),
new address[](0)
),
Withdrawal.Numbers(
shift.marketTokenAmount(),
0,
0,
shift.updatedAtTime(),
0,
0
),
Withdrawal.Flags(
false
)
);
cache.withdrawalKey = NonceUtils.getNextKey(params.dataStore);
params.dataStore.addBytes32(
Keys.WITHDRAWAL_LIST,
cache.withdrawalKey
);
WithdrawalEventUtils.emitWithdrawalCreated(
params.eventEmitter,
cache.withdrawalKey,
cache.withdrawal,
Withdrawal.WithdrawalType.Shift
);
cache.executeWithdrawalParams = ExecuteWithdrawalUtils.ExecuteWithdrawalParams(
params.dataStore,
params.eventEmitter,
WithdrawalVault(payable(params.shiftVault)),
params.oracle,
cache.withdrawalKey,
params.keeper,
params.startingGas,
ISwapPricingUtils.SwapPricingType.Shift
);
ExecuteWithdrawalUtils.executeWithdrawal(
cache.executeWithdrawalParams,
cache.withdrawal
);
cache.initialLongTokenAmount = params.shiftVault.recordTransferIn(cache.depositMarket.longToken);
cache.initialShortTokenAmount = params.shiftVault.recordTransferIn(cache.depositMarket.shortToken);
cache.deposit = Deposit.Props(
Deposit.Addresses(
shift.account(),
shift.receiver(),
address(0),
address(0),
shift.toMarket(),
cache.depositMarket.longToken,
cache.depositMarket.shortToken,
new address[](0),
new address[](0)
),
Deposit.Numbers(
cache.initialLongTokenAmount,
cache.initialShortTokenAmount,
shift.minMarketTokens(),
shift.updatedAtTime(),
0,
0
),
Deposit.Flags(
false
)
);
cache.depositKey = NonceUtils.getNextKey(params.dataStore);
params.dataStore.addBytes32(
Keys.DEPOSIT_LIST,
cache.depositKey
);
DepositEventUtils.emitDepositCreated(params.eventEmitter, cache.depositKey, cache.deposit, Deposit.DepositType.Shift);
cache.executeDepositParams = ExecuteDepositUtils.ExecuteDepositParams(
params.dataStore,
params.eventEmitter,
DepositVault(payable(params.shiftVault)),
params.oracle,
cache.depositKey,
params.keeper,
params.startingGas,
ISwapPricingUtils.SwapPricingType.Shift,
false
);
cache.receivedMarketTokens = ExecuteDepositUtils.executeDeposit(
cache.executeDepositParams,
cache.deposit
);
ShiftEventUtils.emitShiftExecuted(
params.eventEmitter,
params.key,
shift.account(),
cache.receivedMarketTokens
);
EventUtils.EventLogData memory eventData;
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "receivedMarketTokens", cache.receivedMarketTokens);
CallbackUtils.afterShiftExecution(params.key, shift, eventData);
GasUtils.payExecutionFee(
params.dataStore,
params.eventEmitter,
params.shiftVault,
params.key,
shift.callbackContract(),
shift.executionFee(),
params.startingGas,
GasUtils.estimateShiftOraclePriceCount(),
params.keeper,
shift.receiver()
);
return cache.receivedMarketTokens;
}
function cancelShift(
DataStore dataStore,
EventEmitter eventEmitter,
ShiftVault shiftVault,
bytes32 key,
address keeper,
uint256 startingGas,
string memory reason,
bytes memory reasonBytes
) external {
startingGas -= gasleft() / 63;
Shift.Props memory shift = ShiftStoreUtils.get(dataStore, key);
if (shift.account() == address(0)) {
revert Errors.EmptyShift();
}
if (shift.marketTokenAmount() == 0) {
revert Errors.EmptyShiftAmount();
}
ShiftStoreUtils.remove(dataStore, key, shift.account());
shiftVault.transferOut(
shift.fromMarket(),
shift.account(),
shift.marketTokenAmount(),
false
);
ShiftEventUtils.emitShiftCancelled(
eventEmitter,
key,
shift.account(),
reason,
reasonBytes
);
EventUtils.EventLogData memory eventData;
CallbackUtils.afterShiftCancellation(key, shift, eventData);
GasUtils.payExecutionFee(
dataStore,
eventEmitter,
shiftVault,
key,
shift.callbackContract(),
shift.executionFee(),
startingGas,
GasUtils.estimateShiftOraclePriceCount(),
keeper,
shift.receiver()
);
}
}
文件 96 的 108:ShiftVault.sol
pragma solidity ^0.8.0;
import "../bank/StrictBank.sol";
contract ShiftVault is StrictBank {
constructor(RoleStore _roleStore, DataStore _dataStore) StrictBank(_roleStore, _dataStore) {}
}
文件 97 的 108:SignedMath.sol
pragma solidity ^0.8.0;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 98 的 108:StrictBank.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./Bank.sol";
contract StrictBank is Bank {
using SafeERC20 for IERC20;
mapping (address => uint256) public tokenBalances;
constructor(RoleStore _roleStore, DataStore _dataStore) Bank(_roleStore, _dataStore) {}
function recordTransferIn(address token) external onlyController returns (uint256) {
return _recordTransferIn(token);
}
function syncTokenBalance(address token) external onlyController returns (uint256) {
uint256 nextBalance = IERC20(token).balanceOf(address(this));
tokenBalances[token] = nextBalance;
return nextBalance;
}
function _recordTransferIn(address token) internal returns (uint256) {
uint256 prevBalance = tokenBalances[token];
uint256 nextBalance = IERC20(token).balanceOf(address(this));
tokenBalances[token] = nextBalance;
return nextBalance - prevBalance;
}
function _afterTransferOut(address token) internal override {
tokenBalances[token] = IERC20(token).balanceOf(address(this));
}
}
文件 99 的 108:SwapHandler.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../role/RoleModule.sol";
import "./SwapUtils.sol";
contract SwapHandler is ReentrancyGuard, RoleModule {
constructor(RoleStore _roleStore) RoleModule(_roleStore) {}
function swap(
SwapUtils.SwapParams memory params
)
external
nonReentrant
onlyController
returns (address, uint256)
{
return SwapUtils.swap(params);
}
}
文件 100 的 108:SwapPricingUtils.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "../market/MarketUtils.sol";
import "../utils/Precision.sol";
import "../utils/Calc.sol";
import "./PricingUtils.sol";
import "./ISwapPricingUtils.sol";
library SwapPricingUtils {
using SignedMath for int256;
using SafeCast for uint256;
using SafeCast for int256;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct GetPriceImpactUsdParams {
DataStore dataStore;
Market.Props market;
address tokenA;
address tokenB;
uint256 priceForTokenA;
uint256 priceForTokenB;
int256 usdDeltaForTokenA;
int256 usdDeltaForTokenB;
bool includeVirtualInventoryImpact;
}
struct EmitSwapInfoParams {
bytes32 orderKey;
address market;
address receiver;
address tokenIn;
address tokenOut;
uint256 tokenInPrice;
uint256 tokenOutPrice;
uint256 amountIn;
uint256 amountInAfterFees;
uint256 amountOut;
int256 priceImpactUsd;
int256 priceImpactAmount;
int256 tokenInPriceImpactAmount;
}
struct PoolParams {
uint256 poolUsdForTokenA;
uint256 poolUsdForTokenB;
uint256 nextPoolUsdForTokenA;
uint256 nextPoolUsdForTokenB;
}
struct SwapFees {
uint256 feeReceiverAmount;
uint256 feeAmountForPool;
uint256 amountAfterFees;
address uiFeeReceiver;
uint256 uiFeeReceiverFactor;
uint256 uiFeeAmount;
}
function getPriceImpactUsd(GetPriceImpactUsdParams memory params) external view returns (int256) {
PoolParams memory poolParams = getNextPoolAmountsUsd(params);
int256 priceImpactUsd = _getPriceImpactUsd(params.dataStore, params.market, poolParams);
if (priceImpactUsd >= 0) { return priceImpactUsd; }
if (!params.includeVirtualInventoryImpact) {
return priceImpactUsd;
}
(bool hasVirtualInventory, uint256 virtualPoolAmountForLongToken, uint256 virtualPoolAmountForShortToken) = MarketUtils.getVirtualInventoryForSwaps(
params.dataStore,
params.market.marketToken
);
if (!hasVirtualInventory) {
return priceImpactUsd;
}
uint256 virtualPoolAmountForTokenA;
uint256 virtualPoolAmountForTokenB;
if (params.tokenA == params.market.longToken) {
virtualPoolAmountForTokenA = virtualPoolAmountForLongToken;
virtualPoolAmountForTokenB = virtualPoolAmountForShortToken;
} else {
virtualPoolAmountForTokenA = virtualPoolAmountForShortToken;
virtualPoolAmountForTokenB = virtualPoolAmountForLongToken;
}
PoolParams memory poolParamsForVirtualInventory = getNextPoolAmountsParams(
params,
virtualPoolAmountForTokenA,
virtualPoolAmountForTokenB
);
int256 priceImpactUsdForVirtualInventory = _getPriceImpactUsd(params.dataStore, params.market, poolParamsForVirtualInventory);
return priceImpactUsdForVirtualInventory < priceImpactUsd ? priceImpactUsdForVirtualInventory : priceImpactUsd;
}
function _getPriceImpactUsd(DataStore dataStore, Market.Props memory market, PoolParams memory poolParams) internal view returns (int256) {
uint256 initialDiffUsd = Calc.diff(poolParams.poolUsdForTokenA, poolParams.poolUsdForTokenB);
uint256 nextDiffUsd = Calc.diff(poolParams.nextPoolUsdForTokenA, poolParams.nextPoolUsdForTokenB);
bool isSameSideRebalance = (poolParams.poolUsdForTokenA <= poolParams.poolUsdForTokenB) == (poolParams.nextPoolUsdForTokenA <= poolParams.nextPoolUsdForTokenB);
uint256 impactExponentFactor = dataStore.getUint(Keys.swapImpactExponentFactorKey(market.marketToken));
if (isSameSideRebalance) {
bool hasPositiveImpact = nextDiffUsd < initialDiffUsd;
uint256 impactFactor = MarketUtils.getAdjustedSwapImpactFactor(dataStore, market.marketToken, hasPositiveImpact);
return PricingUtils.getPriceImpactUsdForSameSideRebalance(
initialDiffUsd,
nextDiffUsd,
impactFactor,
impactExponentFactor
);
} else {
(uint256 positiveImpactFactor, uint256 negativeImpactFactor) = MarketUtils.getAdjustedSwapImpactFactors(dataStore, market.marketToken);
return PricingUtils.getPriceImpactUsdForCrossoverRebalance(
initialDiffUsd,
nextDiffUsd,
positiveImpactFactor,
negativeImpactFactor,
impactExponentFactor
);
}
}
function getNextPoolAmountsUsd(
GetPriceImpactUsdParams memory params
) internal view returns (PoolParams memory) {
uint256 poolAmountForTokenA = MarketUtils.getPoolAmount(params.dataStore, params.market, params.tokenA);
uint256 poolAmountForTokenB = MarketUtils.getPoolAmount(params.dataStore, params.market, params.tokenB);
return getNextPoolAmountsParams(
params,
poolAmountForTokenA,
poolAmountForTokenB
);
}
function getNextPoolAmountsParams(
GetPriceImpactUsdParams memory params,
uint256 poolAmountForTokenA,
uint256 poolAmountForTokenB
) internal pure returns (PoolParams memory) {
uint256 poolUsdForTokenA = poolAmountForTokenA * params.priceForTokenA;
uint256 poolUsdForTokenB = poolAmountForTokenB * params.priceForTokenB;
if (params.usdDeltaForTokenA < 0 && (-params.usdDeltaForTokenA).toUint256() > poolUsdForTokenA) {
revert Errors.UsdDeltaExceedsPoolValue(params.usdDeltaForTokenA, poolUsdForTokenA);
}
if (params.usdDeltaForTokenB < 0 && (-params.usdDeltaForTokenB).toUint256() > poolUsdForTokenB) {
revert Errors.UsdDeltaExceedsPoolValue(params.usdDeltaForTokenB, poolUsdForTokenB);
}
uint256 nextPoolUsdForTokenA = Calc.sumReturnUint256(poolUsdForTokenA, params.usdDeltaForTokenA);
uint256 nextPoolUsdForTokenB = Calc.sumReturnUint256(poolUsdForTokenB, params.usdDeltaForTokenB);
PoolParams memory poolParams = PoolParams(
poolUsdForTokenA,
poolUsdForTokenB,
nextPoolUsdForTokenA,
nextPoolUsdForTokenB
);
return poolParams;
}
function getSwapFees(
DataStore dataStore,
address marketToken,
uint256 amount,
bool forPositiveImpact,
address uiFeeReceiver,
ISwapPricingUtils.SwapPricingType swapPricingType
) internal view returns (SwapFees memory) {
SwapFees memory fees;
uint256 feeFactor;
if (swapPricingType == ISwapPricingUtils.SwapPricingType.Swap) {
feeFactor = dataStore.getUint(Keys.swapFeeFactorKey(marketToken, forPositiveImpact));
} else if (swapPricingType == ISwapPricingUtils.SwapPricingType.Shift) {
} else if (swapPricingType == ISwapPricingUtils.SwapPricingType.Atomic) {
feeFactor = dataStore.getUint(Keys.atomicSwapFeeFactorKey(marketToken));
} else if (swapPricingType == ISwapPricingUtils.SwapPricingType.Deposit) {
feeFactor = dataStore.getUint(Keys.depositFeeFactorKey(marketToken, forPositiveImpact));
} else if (swapPricingType == ISwapPricingUtils.SwapPricingType.Withdrawal) {
feeFactor = dataStore.getUint(Keys.withdrawalFeeFactorKey(marketToken, forPositiveImpact));
}
uint256 swapFeeReceiverFactor = dataStore.getUint(Keys.SWAP_FEE_RECEIVER_FACTOR);
uint256 feeAmount = Precision.applyFactor(amount, feeFactor);
fees.feeReceiverAmount = Precision.applyFactor(feeAmount, swapFeeReceiverFactor);
fees.feeAmountForPool = feeAmount - fees.feeReceiverAmount;
fees.uiFeeReceiver = uiFeeReceiver;
fees.uiFeeReceiverFactor = MarketUtils.getUiFeeFactor(dataStore, uiFeeReceiver);
fees.uiFeeAmount = Precision.applyFactor(amount, fees.uiFeeReceiverFactor);
fees.amountAfterFees = amount - feeAmount - fees.uiFeeAmount;
return fees;
}
function emitSwapInfo(
EventEmitter eventEmitter,
EmitSwapInfoParams memory params
) internal {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "orderKey", params.orderKey);
eventData.addressItems.initItems(4);
eventData.addressItems.setItem(0, "market", params.market);
eventData.addressItems.setItem(1, "receiver", params.receiver);
eventData.addressItems.setItem(2, "tokenIn", params.tokenIn);
eventData.addressItems.setItem(3, "tokenOut", params.tokenOut);
eventData.uintItems.initItems(5);
eventData.uintItems.setItem(0, "tokenInPrice", params.tokenInPrice);
eventData.uintItems.setItem(1, "tokenOutPrice", params.tokenOutPrice);
eventData.uintItems.setItem(2, "amountIn", params.amountIn);
eventData.uintItems.setItem(3, "amountInAfterFees", params.amountInAfterFees);
eventData.uintItems.setItem(4, "amountOut", params.amountOut);
eventData.intItems.initItems(3);
eventData.intItems.setItem(0, "priceImpactUsd", params.priceImpactUsd);
eventData.intItems.setItem(1, "priceImpactAmount", params.priceImpactAmount);
eventData.intItems.setItem(2, "tokenInPriceImpactAmount", params.tokenInPriceImpactAmount);
eventEmitter.emitEventLog1(
"SwapInfo",
Cast.toBytes32(params.market),
eventData
);
}
function emitSwapFeesCollected(
EventEmitter eventEmitter,
bytes32 tradeKey,
address market,
address token,
uint256 tokenPrice,
bytes32 swapFeeType,
SwapFees memory fees
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(2);
eventData.bytes32Items.setItem(0, "tradeKey", tradeKey);
eventData.bytes32Items.setItem(1, "swapFeeType", swapFeeType);
eventData.addressItems.initItems(3);
eventData.addressItems.setItem(0, "uiFeeReceiver", fees.uiFeeReceiver);
eventData.addressItems.setItem(1, "market", market);
eventData.addressItems.setItem(2, "token", token);
eventData.uintItems.initItems(6);
eventData.uintItems.setItem(0, "tokenPrice", tokenPrice);
eventData.uintItems.setItem(1, "feeReceiverAmount", fees.feeReceiverAmount);
eventData.uintItems.setItem(2, "feeAmountForPool", fees.feeAmountForPool);
eventData.uintItems.setItem(3, "amountAfterFees", fees.amountAfterFees);
eventData.uintItems.setItem(4, "uiFeeReceiverFactor", fees.uiFeeReceiverFactor);
eventData.uintItems.setItem(5, "uiFeeAmount", fees.uiFeeAmount);
eventEmitter.emitEventLog1(
"SwapFeesCollected",
Cast.toBytes32(market),
eventData
);
}
}
文件 101 的 108:SwapUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "../event/EventEmitter.sol";
import "../oracle/Oracle.sol";
import "../pricing/SwapPricingUtils.sol";
import "../fee/FeeUtils.sol";
library SwapUtils {
using SafeCast for uint256;
using SafeCast for int256;
using Price for Price.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct SwapParams {
DataStore dataStore;
EventEmitter eventEmitter;
Oracle oracle;
Bank bank;
bytes32 key;
address tokenIn;
uint256 amountIn;
Market.Props[] swapPathMarkets;
uint256 minOutputAmount;
address receiver;
address uiFeeReceiver;
bool shouldUnwrapNativeToken;
}
struct _SwapParams {
Market.Props market;
address tokenIn;
uint256 amountIn;
address receiver;
bool shouldUnwrapNativeToken;
}
struct SwapCache {
address tokenOut;
Price.Props tokenInPrice;
Price.Props tokenOutPrice;
uint256 amountIn;
uint256 amountInAfterFees;
uint256 amountOut;
uint256 poolAmountOut;
int256 priceImpactUsd;
int256 priceImpactAmount;
uint256 cappedDiffUsd;
int256 tokenInPriceImpactAmount;
}
event SwapReverted(string reason, bytes reasonBytes);
function swap(SwapParams memory params) external returns (address, uint256) {
if (params.amountIn == 0) {
return (params.tokenIn, params.amountIn);
}
if (params.swapPathMarkets.length == 0) {
if (params.amountIn < params.minOutputAmount) {
revert Errors.InsufficientOutputAmount(params.amountIn, params.minOutputAmount);
}
if (address(params.bank) != params.receiver) {
params.bank.transferOut(
params.tokenIn,
params.receiver,
params.amountIn,
params.shouldUnwrapNativeToken
);
}
return (params.tokenIn, params.amountIn);
}
if (address(params.bank) != params.swapPathMarkets[0].marketToken) {
params.bank.transferOut(
params.tokenIn,
params.swapPathMarkets[0].marketToken,
params.amountIn,
false
);
}
address tokenOut = params.tokenIn;
uint256 outputAmount = params.amountIn;
for (uint256 i; i < params.swapPathMarkets.length; i++) {
Market.Props memory market = params.swapPathMarkets[i];
bool flagExists = params.dataStore.getBool(Keys.swapPathMarketFlagKey(market.marketToken));
if (flagExists) {
revert Errors.DuplicatedMarketInSwapPath(market.marketToken);
}
params.dataStore.setBool(Keys.swapPathMarketFlagKey(market.marketToken), true);
uint256 nextIndex = i + 1;
address receiver;
if (nextIndex < params.swapPathMarkets.length) {
receiver = params.swapPathMarkets[nextIndex].marketToken;
} else {
receiver = params.receiver;
}
_SwapParams memory _params = _SwapParams(
market,
tokenOut,
outputAmount,
receiver,
i == params.swapPathMarkets.length - 1 ? params.shouldUnwrapNativeToken : false
);
(tokenOut, outputAmount) = _swap(params, _params);
}
for (uint256 i; i < params.swapPathMarkets.length; i++) {
Market.Props memory market = params.swapPathMarkets[i];
params.dataStore.setBool(Keys.swapPathMarketFlagKey(market.marketToken), false);
}
if (outputAmount < params.minOutputAmount) {
revert Errors.InsufficientSwapOutputAmount(outputAmount, params.minOutputAmount);
}
return (tokenOut, outputAmount);
}
function validateSwapOutputToken(
DataStore dataStore,
address[] memory swapPath,
address inputToken,
address expectedOutputToken
) internal view {
address outputToken = getOutputToken(dataStore, swapPath, inputToken);
if (outputToken != expectedOutputToken) {
revert Errors.InvalidSwapOutputToken(outputToken, expectedOutputToken);
}
}
function getOutputToken(
DataStore dataStore,
address[] memory swapPath,
address inputToken
) internal view returns (address) {
address outputToken = inputToken;
Market.Props[] memory markets = MarketUtils.getSwapPathMarkets(dataStore, swapPath);
uint256 marketCount = markets.length;
for (uint256 i; i < marketCount; i++) {
Market.Props memory market = markets[i];
outputToken = MarketUtils.getOppositeToken(outputToken, market);
}
return outputToken;
}
function _swap(SwapParams memory params, _SwapParams memory _params) internal returns (address, uint256) {
SwapCache memory cache;
if (_params.tokenIn != _params.market.longToken && _params.tokenIn != _params.market.shortToken) {
revert Errors.InvalidTokenIn(_params.tokenIn, _params.market.marketToken);
}
MarketUtils.validateSwapMarket(params.dataStore, _params.market);
cache.tokenOut = MarketUtils.getOppositeToken(_params.tokenIn, _params.market);
cache.tokenInPrice = params.oracle.getPrimaryPrice(_params.tokenIn);
cache.tokenOutPrice = params.oracle.getPrimaryPrice(cache.tokenOut);
cache.priceImpactUsd = SwapPricingUtils.getPriceImpactUsd(
SwapPricingUtils.GetPriceImpactUsdParams(
params.dataStore,
_params.market,
_params.tokenIn,
cache.tokenOut,
cache.tokenInPrice.midPrice(),
cache.tokenOutPrice.midPrice(),
(_params.amountIn * cache.tokenInPrice.midPrice()).toInt256(),
-(_params.amountIn * cache.tokenInPrice.midPrice()).toInt256(),
true
)
);
SwapPricingUtils.SwapFees memory fees = SwapPricingUtils.getSwapFees(
params.dataStore,
_params.market.marketToken,
_params.amountIn,
cache.priceImpactUsd > 0,
params.uiFeeReceiver,
ISwapPricingUtils.SwapPricingType.Swap
);
FeeUtils.incrementClaimableFeeAmount(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
_params.tokenIn,
fees.feeReceiverAmount,
Keys.SWAP_FEE_TYPE
);
FeeUtils.incrementClaimableUiFeeAmount(
params.dataStore,
params.eventEmitter,
params.uiFeeReceiver,
_params.market.marketToken,
_params.tokenIn,
fees.uiFeeAmount,
Keys.UI_SWAP_FEE_TYPE
);
if (cache.priceImpactUsd > 0) {
cache.amountIn = fees.amountAfterFees;
(cache.priceImpactAmount, cache.cappedDiffUsd) = MarketUtils.applySwapImpactWithCap(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
cache.tokenOut,
cache.tokenOutPrice,
cache.priceImpactUsd
);
if (cache.cappedDiffUsd != 0) {
(cache.tokenInPriceImpactAmount, ) = MarketUtils.applySwapImpactWithCap(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
_params.tokenIn,
cache.tokenInPrice,
cache.cappedDiffUsd.toInt256()
);
cache.amountIn += cache.tokenInPriceImpactAmount.toUint256();
}
cache.amountOut = cache.amountIn * cache.tokenInPrice.min / cache.tokenOutPrice.max;
cache.poolAmountOut = cache.amountOut;
cache.amountOut += cache.priceImpactAmount.toUint256();
} else {
(cache.priceImpactAmount, ) = MarketUtils.applySwapImpactWithCap(
params.dataStore,
params.eventEmitter,
_params.market.marketToken,
_params.tokenIn,
cache.tokenInPrice,
cache.priceImpactUsd
);
if (fees.amountAfterFees <= (-cache.priceImpactAmount).toUint256()) {
revert Errors.SwapPriceImpactExceedsAmountIn(fees.amountAfterFees, cache.priceImpactAmount);
}
cache.amountIn = fees.amountAfterFees - (-cache.priceImpactAmount).toUint256();
cache.amountOut = cache.amountIn * cache.tokenInPrice.min / cache.tokenOutPrice.max;
cache.poolAmountOut = cache.amountOut;
}
if (_params.receiver != _params.market.marketToken) {
MarketToken(payable(_params.market.marketToken)).transferOut(
cache.tokenOut,
_params.receiver,
cache.amountOut,
_params.shouldUnwrapNativeToken
);
}
MarketUtils.applyDeltaToPoolAmount(
params.dataStore,
params.eventEmitter,
_params.market,
_params.tokenIn,
(cache.amountIn + fees.feeAmountForPool).toInt256()
);
MarketUtils.applyDeltaToPoolAmount(
params.dataStore,
params.eventEmitter,
_params.market,
cache.tokenOut,
-cache.poolAmountOut.toInt256()
);
MarketUtils.MarketPrices memory prices = MarketUtils.MarketPrices(
params.oracle.getPrimaryPrice(_params.market.indexToken),
_params.tokenIn == _params.market.longToken ? cache.tokenInPrice : cache.tokenOutPrice,
_params.tokenIn == _params.market.shortToken ? cache.tokenInPrice : cache.tokenOutPrice
);
MarketUtils.validatePoolAmount(
params.dataStore,
_params.market,
_params.tokenIn
);
MarketUtils.validateReserve(
params.dataStore,
_params.market,
prices,
cache.tokenOut == _params.market.longToken
);
MarketUtils.validateMaxPnl(
params.dataStore,
_params.market,
prices,
_params.tokenIn == _params.market.longToken ? Keys.MAX_PNL_FACTOR_FOR_DEPOSITS : Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS,
cache.tokenOut == _params.market.shortToken ? Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS : Keys.MAX_PNL_FACTOR_FOR_DEPOSITS
);
SwapPricingUtils.EmitSwapInfoParams memory emitSwapInfoParams;
emitSwapInfoParams.orderKey = params.key;
emitSwapInfoParams.market = _params.market.marketToken;
emitSwapInfoParams.receiver = _params.receiver;
emitSwapInfoParams.tokenIn = _params.tokenIn;
emitSwapInfoParams.tokenOut = cache.tokenOut;
emitSwapInfoParams.tokenInPrice = cache.tokenInPrice.min;
emitSwapInfoParams.tokenOutPrice = cache.tokenOutPrice.max;
emitSwapInfoParams.amountIn = _params.amountIn;
emitSwapInfoParams.amountInAfterFees = fees.amountAfterFees;
emitSwapInfoParams.amountOut = cache.amountOut;
emitSwapInfoParams.priceImpactUsd = cache.priceImpactUsd;
emitSwapInfoParams.priceImpactAmount = cache.priceImpactAmount;
emitSwapInfoParams.tokenInPriceImpactAmount = cache.tokenInPriceImpactAmount;
SwapPricingUtils.emitSwapInfo(
params.eventEmitter,
emitSwapInfoParams
);
SwapPricingUtils.emitSwapFeesCollected(
params.eventEmitter,
params.key,
_params.market.marketToken,
_params.tokenIn,
cache.tokenInPrice.min,
Keys.SWAP_FEE_TYPE,
fees
);
return (cache.tokenOut, cache.amountOut);
}
}
文件 102 的 108:TokenUtils.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../data/DataStore.sol";
import "../data/Keys.sol";
import "../error/ErrorUtils.sol";
import "../utils/AccountUtils.sol";
import "./IWNT.sol";
library TokenUtils {
using Address for address;
using SafeERC20 for IERC20;
event TokenTransferReverted(string reason, bytes returndata);
event NativeTokenTransferReverted(string reason);
function wnt(DataStore dataStore) internal view returns (address) {
return dataStore.getAddress(Keys.WNT);
}
function transfer(
DataStore dataStore,
address token,
address receiver,
uint256 amount
) internal {
if (amount == 0) { return; }
AccountUtils.validateReceiver(receiver);
uint256 gasLimit = dataStore.getUint(Keys.tokenTransferGasLimit(token));
if (gasLimit == 0) {
revert Errors.EmptyTokenTranferGasLimit(token);
}
(bool success0, ) = nonRevertingTransferWithGasLimit(
IERC20(token),
receiver,
amount,
gasLimit
);
if (success0) { return; }
address holdingAddress = dataStore.getAddress(Keys.HOLDING_ADDRESS);
if (holdingAddress == address(0)) {
revert Errors.EmptyHoldingAddress();
}
(bool success1, bytes memory returndata) = nonRevertingTransferWithGasLimit(
IERC20(token),
holdingAddress,
amount,
gasLimit
);
if (success1) { return; }
(string memory reason, ) = ErrorUtils.getRevertMessage(returndata);
emit TokenTransferReverted(reason, returndata);
revert Errors.TokenTransferError(token, receiver, amount);
}
function sendNativeToken(
DataStore dataStore,
address receiver,
uint256 amount
) internal {
if (amount == 0) { return; }
AccountUtils.validateReceiver(receiver);
uint256 gasLimit = dataStore.getUint(Keys.NATIVE_TOKEN_TRANSFER_GAS_LIMIT);
bool success;
assembly {
success := call(
gasLimit,
receiver,
amount,
0,
0,
0,
0
)
}
if (success) { return; }
depositAndSendWrappedNativeToken(
dataStore,
receiver,
amount
);
}
function depositAndSendWrappedNativeToken(
DataStore dataStore,
address receiver,
uint256 amount
) internal {
if (amount == 0) { return; }
AccountUtils.validateReceiver(receiver);
address _wnt = wnt(dataStore);
IWNT(_wnt).deposit{value: amount}();
transfer(
dataStore,
_wnt,
receiver,
amount
);
}
function withdrawAndSendNativeToken(
DataStore dataStore,
address _wnt,
address receiver,
uint256 amount
) internal {
if (amount == 0) { return; }
AccountUtils.validateReceiver(receiver);
IWNT(_wnt).withdraw(amount);
uint256 gasLimit = dataStore.getUint(Keys.NATIVE_TOKEN_TRANSFER_GAS_LIMIT);
bool success;
assembly {
success := call(
gasLimit,
receiver,
amount,
0,
0,
0,
0
)
}
if (success) { return; }
depositAndSendWrappedNativeToken(
dataStore,
receiver,
amount
);
}
function nonRevertingTransferWithGasLimit(
IERC20 token,
address to,
uint256 amount,
uint256 gasLimit
) internal returns (bool, bytes memory) {
bytes memory data = abi.encodeWithSelector(token.transfer.selector, to, amount);
(bool success, bytes memory returndata) = address(token).call{ gas: gasLimit }(data);
if (success) {
if (returndata.length == 0) {
if (!address(token).isContract()) {
return (false, "Call to non-contract");
}
}
if (returndata.length > 0 && !abi.decode(returndata, (bool))) {
return (false, returndata);
}
return (true, returndata);
}
return (false, returndata);
}
}
文件 103 的 108:Uint256Mask.sol
pragma solidity ^0.8.0;
import "../error/Errors.sol";
library Uint256Mask {
struct Mask {
uint256 bits;
}
function validateUniqueAndSetIndex(
Mask memory mask,
uint256 index,
string memory label
) internal pure {
if (index >= 256) {
revert Errors.MaskIndexOutOfBounds(index, label);
}
uint256 bit = 1 << index;
if (mask.bits & bit != 0) {
revert Errors.DuplicatedIndex(index, label);
}
mask.bits = mask.bits | bit;
}
}
文件 104 的 108:Withdrawal.sol
pragma solidity ^0.8.0;
library Withdrawal {
enum WithdrawalType {
Normal,
Shift,
Glv
}
struct Props {
Addresses addresses;
Numbers numbers;
Flags flags;
}
struct Addresses {
address account;
address receiver;
address callbackContract;
address uiFeeReceiver;
address market;
address[] longTokenSwapPath;
address[] shortTokenSwapPath;
}
struct Numbers {
uint256 marketTokenAmount;
uint256 minLongTokenAmount;
uint256 minShortTokenAmount;
uint256 updatedAtTime;
uint256 executionFee;
uint256 callbackGasLimit;
}
struct Flags {
bool shouldUnwrapNativeToken;
}
function account(Props memory props) internal pure returns (address) {
return props.addresses.account;
}
function setAccount(Props memory props, address value) internal pure {
props.addresses.account = value;
}
function receiver(Props memory props) internal pure returns (address) {
return props.addresses.receiver;
}
function setReceiver(Props memory props, address value) internal pure {
props.addresses.receiver = value;
}
function callbackContract(Props memory props) internal pure returns (address) {
return props.addresses.callbackContract;
}
function setCallbackContract(Props memory props, address value) internal pure {
props.addresses.callbackContract = value;
}
function uiFeeReceiver(Props memory props) internal pure returns (address) {
return props.addresses.uiFeeReceiver;
}
function setUiFeeReceiver(Props memory props, address value) internal pure {
props.addresses.uiFeeReceiver = value;
}
function market(Props memory props) internal pure returns (address) {
return props.addresses.market;
}
function setMarket(Props memory props, address value) internal pure {
props.addresses.market = value;
}
function longTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.longTokenSwapPath;
}
function setLongTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.longTokenSwapPath = value;
}
function shortTokenSwapPath(Props memory props) internal pure returns (address[] memory) {
return props.addresses.shortTokenSwapPath;
}
function setShortTokenSwapPath(Props memory props, address[] memory value) internal pure {
props.addresses.shortTokenSwapPath = value;
}
function marketTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.marketTokenAmount;
}
function setMarketTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.marketTokenAmount = value;
}
function minLongTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.minLongTokenAmount;
}
function setMinLongTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.minLongTokenAmount = value;
}
function minShortTokenAmount(Props memory props) internal pure returns (uint256) {
return props.numbers.minShortTokenAmount;
}
function setMinShortTokenAmount(Props memory props, uint256 value) internal pure {
props.numbers.minShortTokenAmount = value;
}
function updatedAtTime(Props memory props) internal pure returns (uint256) {
return props.numbers.updatedAtTime;
}
function setUpdatedAtTime(Props memory props, uint256 value) internal pure {
props.numbers.updatedAtTime = value;
}
function executionFee(Props memory props) internal pure returns (uint256) {
return props.numbers.executionFee;
}
function setExecutionFee(Props memory props, uint256 value) internal pure {
props.numbers.executionFee = value;
}
function callbackGasLimit(Props memory props) internal pure returns (uint256) {
return props.numbers.callbackGasLimit;
}
function setCallbackGasLimit(Props memory props, uint256 value) internal pure {
props.numbers.callbackGasLimit = value;
}
function shouldUnwrapNativeToken(Props memory props) internal pure returns (bool) {
return props.flags.shouldUnwrapNativeToken;
}
function setShouldUnwrapNativeToken(Props memory props, bool value) internal pure {
props.flags.shouldUnwrapNativeToken = value;
}
}
文件 105 的 108:WithdrawalEventUtils.sol
pragma solidity ^0.8.0;
import "../event/EventEmitter.sol";
import "../event/EventUtils.sol";
import "../utils/Cast.sol";
import "./Withdrawal.sol";
import "../pricing/ISwapPricingUtils.sol";
library WithdrawalEventUtils {
using Withdrawal for Withdrawal.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
function emitWithdrawalCreated(
EventEmitter eventEmitter,
bytes32 key,
Withdrawal.Props memory withdrawal,
Withdrawal.WithdrawalType withdrawalType
) external {
EventUtils.EventLogData memory eventData;
eventData.addressItems.initItems(4);
eventData.addressItems.setItem(0, "account", withdrawal.account());
eventData.addressItems.setItem(1, "receiver", withdrawal.receiver());
eventData.addressItems.setItem(2, "callbackContract", withdrawal.callbackContract());
eventData.addressItems.setItem(3, "market", withdrawal.market());
eventData.addressItems.initArrayItems(2);
eventData.addressItems.setItem(0, "longTokenSwapPath", withdrawal.longTokenSwapPath());
eventData.addressItems.setItem(1, "shortTokenSwapPath", withdrawal.shortTokenSwapPath());
eventData.uintItems.initItems(7);
eventData.uintItems.setItem(0, "marketTokenAmount", withdrawal.marketTokenAmount());
eventData.uintItems.setItem(1, "minLongTokenAmount", withdrawal.minLongTokenAmount());
eventData.uintItems.setItem(2, "minShortTokenAmount", withdrawal.minShortTokenAmount());
eventData.uintItems.setItem(3, "updatedAtTime", withdrawal.updatedAtTime());
eventData.uintItems.setItem(4, "executionFee", withdrawal.executionFee());
eventData.uintItems.setItem(5, "callbackGasLimit", withdrawal.callbackGasLimit());
eventData.uintItems.setItem(6, "withdrawalType", uint256(withdrawalType));
eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "shouldUnwrapNativeToken", withdrawal.shouldUnwrapNativeToken());
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventEmitter.emitEventLog2(
"WithdrawalCreated",
key,
Cast.toBytes32(withdrawal.account()),
eventData
);
}
function emitWithdrawalExecuted(
EventEmitter eventEmitter,
bytes32 key,
address account,
ISwapPricingUtils.SwapPricingType swapPricingType
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "swapPricingType", uint256(swapPricingType));
eventEmitter.emitEventLog2(
"WithdrawalExecuted",
key,
Cast.toBytes32(account),
eventData
);
}
function emitWithdrawalCancelled(
EventEmitter eventEmitter,
bytes32 key,
address account,
string memory reason,
bytes memory reasonBytes
) external {
EventUtils.EventLogData memory eventData;
eventData.bytes32Items.initItems(1);
eventData.bytes32Items.setItem(0, "key", key);
eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "account", account);
eventData.stringItems.initItems(1);
eventData.stringItems.setItem(0, "reason", reason);
eventData.bytesItems.initItems(1);
eventData.bytesItems.setItem(0, "reasonBytes", reasonBytes);
eventEmitter.emitEventLog2(
"WithdrawalCancelled",
key,
Cast.toBytes32(account),
eventData
);
}
}
文件 106 的 108:WithdrawalStoreUtils.sol
pragma solidity ^0.8.0;
import "../data/Keys.sol";
import "../data/DataStore.sol";
import "./Withdrawal.sol";
library WithdrawalStoreUtils {
using Withdrawal for Withdrawal.Props;
bytes32 public constant ACCOUNT = keccak256(abi.encode("ACCOUNT"));
bytes32 public constant RECEIVER = keccak256(abi.encode("RECEIVER"));
bytes32 public constant CALLBACK_CONTRACT = keccak256(abi.encode("CALLBACK_CONTRACT"));
bytes32 public constant UI_FEE_RECEIVER = keccak256(abi.encode("UI_FEE_RECEIVER"));
bytes32 public constant MARKET = keccak256(abi.encode("MARKET"));
bytes32 public constant LONG_TOKEN_SWAP_PATH = keccak256(abi.encode("LONG_TOKEN_SWAP_PATH"));
bytes32 public constant SHORT_TOKEN_SWAP_PATH = keccak256(abi.encode("SHORT_TOKEN_SWAP_PATH"));
bytes32 public constant MARKET_TOKEN_AMOUNT = keccak256(abi.encode("MARKET_TOKEN_AMOUNT"));
bytes32 public constant MIN_LONG_TOKEN_AMOUNT = keccak256(abi.encode("MIN_LONG_TOKEN_AMOUNT"));
bytes32 public constant MIN_SHORT_TOKEN_AMOUNT = keccak256(abi.encode("MIN_SHORT_TOKEN_AMOUNT"));
bytes32 public constant UPDATED_AT_TIME = keccak256(abi.encode("UPDATED_AT_TIME"));
bytes32 public constant EXECUTION_FEE = keccak256(abi.encode("EXECUTION_FEE"));
bytes32 public constant CALLBACK_GAS_LIMIT = keccak256(abi.encode("CALLBACK_GAS_LIMIT"));
bytes32 public constant SHOULD_UNWRAP_NATIVE_TOKEN = keccak256(abi.encode("SHOULD_UNWRAP_NATIVE_TOKEN"));
function get(DataStore dataStore, bytes32 key) external view returns (Withdrawal.Props memory) {
Withdrawal.Props memory withdrawal;
if (!dataStore.containsBytes32(Keys.WITHDRAWAL_LIST, key)) {
return withdrawal;
}
withdrawal.setAccount(dataStore.getAddress(
keccak256(abi.encode(key, ACCOUNT))
));
withdrawal.setReceiver(dataStore.getAddress(
keccak256(abi.encode(key, RECEIVER))
));
withdrawal.setCallbackContract(dataStore.getAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
));
withdrawal.setUiFeeReceiver(dataStore.getAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
));
withdrawal.setMarket(dataStore.getAddress(
keccak256(abi.encode(key, MARKET))
));
withdrawal.setLongTokenSwapPath(dataStore.getAddressArray(
keccak256(abi.encode(key, LONG_TOKEN_SWAP_PATH))
));
withdrawal.setShortTokenSwapPath(dataStore.getAddressArray(
keccak256(abi.encode(key, SHORT_TOKEN_SWAP_PATH))
));
withdrawal.setMarketTokenAmount(dataStore.getUint(
keccak256(abi.encode(key, MARKET_TOKEN_AMOUNT))
));
withdrawal.setMinLongTokenAmount(dataStore.getUint(
keccak256(abi.encode(key, MIN_LONG_TOKEN_AMOUNT))
));
withdrawal.setMinShortTokenAmount(dataStore.getUint(
keccak256(abi.encode(key, MIN_SHORT_TOKEN_AMOUNT))
));
withdrawal.setUpdatedAtTime(dataStore.getUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
));
withdrawal.setExecutionFee(dataStore.getUint(
keccak256(abi.encode(key, EXECUTION_FEE))
));
withdrawal.setCallbackGasLimit(dataStore.getUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
));
withdrawal.setShouldUnwrapNativeToken(dataStore.getBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN))
));
return withdrawal;
}
function set(DataStore dataStore, bytes32 key, Withdrawal.Props memory withdrawal) external {
dataStore.addBytes32(
Keys.WITHDRAWAL_LIST,
key
);
dataStore.addBytes32(
Keys.accountWithdrawalListKey(withdrawal.account()),
key
);
dataStore.setAddress(
keccak256(abi.encode(key, ACCOUNT)),
withdrawal.account()
);
dataStore.setAddress(
keccak256(abi.encode(key, RECEIVER)),
withdrawal.receiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT)),
withdrawal.callbackContract()
);
dataStore.setAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER)),
withdrawal.uiFeeReceiver()
);
dataStore.setAddress(
keccak256(abi.encode(key, MARKET)),
withdrawal.market()
);
dataStore.setAddressArray(
keccak256(abi.encode(key, LONG_TOKEN_SWAP_PATH)),
withdrawal.longTokenSwapPath()
);
dataStore.setAddressArray(
keccak256(abi.encode(key, SHORT_TOKEN_SWAP_PATH)),
withdrawal.shortTokenSwapPath()
);
dataStore.setUint(
keccak256(abi.encode(key, MARKET_TOKEN_AMOUNT)),
withdrawal.marketTokenAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, MIN_LONG_TOKEN_AMOUNT)),
withdrawal.minLongTokenAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, MIN_SHORT_TOKEN_AMOUNT)),
withdrawal.minShortTokenAmount()
);
dataStore.setUint(
keccak256(abi.encode(key, UPDATED_AT_TIME)),
withdrawal.updatedAtTime()
);
dataStore.setUint(
keccak256(abi.encode(key, EXECUTION_FEE)),
withdrawal.executionFee()
);
dataStore.setUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT)),
withdrawal.callbackGasLimit()
);
dataStore.setBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN)),
withdrawal.shouldUnwrapNativeToken()
);
}
function remove(DataStore dataStore, bytes32 key, address account) external {
if (!dataStore.containsBytes32(Keys.WITHDRAWAL_LIST, key)) {
revert Errors.WithdrawalNotFound(key);
}
dataStore.removeBytes32(
Keys.WITHDRAWAL_LIST,
key
);
dataStore.removeBytes32(
Keys.accountWithdrawalListKey(account),
key
);
dataStore.removeAddress(
keccak256(abi.encode(key, ACCOUNT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, CALLBACK_CONTRACT))
);
dataStore.removeAddress(
keccak256(abi.encode(key, UI_FEE_RECEIVER))
);
dataStore.removeAddress(
keccak256(abi.encode(key, MARKET))
);
dataStore.removeAddressArray(
keccak256(abi.encode(key, LONG_TOKEN_SWAP_PATH))
);
dataStore.removeAddressArray(
keccak256(abi.encode(key, SHORT_TOKEN_SWAP_PATH))
);
dataStore.removeUint(
keccak256(abi.encode(key, MARKET_TOKEN_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, MIN_LONG_TOKEN_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, MIN_SHORT_TOKEN_AMOUNT))
);
dataStore.removeUint(
keccak256(abi.encode(key, UPDATED_AT_TIME))
);
dataStore.removeUint(
keccak256(abi.encode(key, EXECUTION_FEE))
);
dataStore.removeUint(
keccak256(abi.encode(key, CALLBACK_GAS_LIMIT))
);
dataStore.removeBool(
keccak256(abi.encode(key, SHOULD_UNWRAP_NATIVE_TOKEN))
);
}
function getWithdrawalCount(DataStore dataStore) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.WITHDRAWAL_LIST);
}
function getWithdrawalKeys(DataStore dataStore, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.WITHDRAWAL_LIST, start, end);
}
function getAccountWithdrawalCount(DataStore dataStore, address account) internal view returns (uint256) {
return dataStore.getBytes32Count(Keys.accountWithdrawalListKey(account));
}
function getAccountWithdrawalKeys(DataStore dataStore, address account, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
return dataStore.getBytes32ValuesAt(Keys.accountWithdrawalListKey(account), start, end);
}
}
文件 107 的 108:WithdrawalUtils.sol
pragma solidity ^0.8.0;
import "../data/DataStore.sol";
import "./WithdrawalVault.sol";
import "./WithdrawalStoreUtils.sol";
import "./WithdrawalEventUtils.sol";
import "../nonce/NonceUtils.sol";
import "../oracle/Oracle.sol";
import "../gas/GasUtils.sol";
import "../callback/CallbackUtils.sol";
import "../utils/Array.sol";
import "../utils/AccountUtils.sol";
library WithdrawalUtils {
using SafeCast for uint256;
using SafeCast for int256;
using Array for uint256[];
using Price for Price.Props;
using Withdrawal for Withdrawal.Props;
using EventUtils for EventUtils.AddressItems;
using EventUtils for EventUtils.UintItems;
using EventUtils for EventUtils.IntItems;
using EventUtils for EventUtils.BoolItems;
using EventUtils for EventUtils.Bytes32Items;
using EventUtils for EventUtils.BytesItems;
using EventUtils for EventUtils.StringItems;
struct CreateWithdrawalParams {
address receiver;
address callbackContract;
address uiFeeReceiver;
address market;
address[] longTokenSwapPath;
address[] shortTokenSwapPath;
uint256 minLongTokenAmount;
uint256 minShortTokenAmount;
bool shouldUnwrapNativeToken;
uint256 executionFee;
uint256 callbackGasLimit;
}
function createWithdrawal(
DataStore dataStore,
EventEmitter eventEmitter,
WithdrawalVault withdrawalVault,
address account,
CreateWithdrawalParams memory params
) external returns (bytes32) {
AccountUtils.validateAccount(account);
address wnt = TokenUtils.wnt(dataStore);
uint256 wntAmount = withdrawalVault.recordTransferIn(wnt);
if (wntAmount < params.executionFee) {
revert Errors.InsufficientWntAmount(wntAmount, params.executionFee);
}
AccountUtils.validateReceiver(params.receiver);
uint256 marketTokenAmount = withdrawalVault.recordTransferIn(params.market);
if (marketTokenAmount == 0) {
revert Errors.EmptyWithdrawalAmount();
}
params.executionFee = wntAmount;
MarketUtils.validateEnabledMarket(dataStore, params.market);
MarketUtils.validateSwapPath(dataStore, params.longTokenSwapPath);
MarketUtils.validateSwapPath(dataStore, params.shortTokenSwapPath);
Withdrawal.Props memory withdrawal = Withdrawal.Props(
Withdrawal.Addresses(
account,
params.receiver,
params.callbackContract,
params.uiFeeReceiver,
params.market,
params.longTokenSwapPath,
params.shortTokenSwapPath
),
Withdrawal.Numbers(
marketTokenAmount,
params.minLongTokenAmount,
params.minShortTokenAmount,
Chain.currentTimestamp(),
params.executionFee,
params.callbackGasLimit
),
Withdrawal.Flags(
params.shouldUnwrapNativeToken
)
);
CallbackUtils.validateCallbackGasLimit(dataStore, withdrawal.callbackGasLimit());
uint256 estimatedGasLimit = GasUtils.estimateExecuteWithdrawalGasLimit(dataStore, withdrawal);
uint256 oraclePriceCount = GasUtils.estimateWithdrawalOraclePriceCount(withdrawal.longTokenSwapPath().length + withdrawal.shortTokenSwapPath().length);
GasUtils.validateExecutionFee(dataStore, estimatedGasLimit, params.executionFee, oraclePriceCount);
bytes32 key = NonceUtils.getNextKey(dataStore);
WithdrawalStoreUtils.set(dataStore, key, withdrawal);
WithdrawalEventUtils.emitWithdrawalCreated(eventEmitter, key, withdrawal, Withdrawal.WithdrawalType.Normal);
return key;
}
function cancelWithdrawal(
DataStore dataStore,
EventEmitter eventEmitter,
WithdrawalVault withdrawalVault,
bytes32 key,
address keeper,
uint256 startingGas,
string memory reason,
bytes memory reasonBytes
) external {
startingGas -= gasleft() / 63;
Withdrawal.Props memory withdrawal = WithdrawalStoreUtils.get(dataStore, key);
if (withdrawal.account() == address(0)) {
revert Errors.EmptyWithdrawal();
}
if (withdrawal.marketTokenAmount() == 0) {
revert Errors.EmptyWithdrawalAmount();
}
WithdrawalStoreUtils.remove(dataStore, key, withdrawal.account());
withdrawalVault.transferOut(
withdrawal.market(),
withdrawal.account(),
withdrawal.marketTokenAmount(),
false
);
WithdrawalEventUtils.emitWithdrawalCancelled(
eventEmitter,
key,
withdrawal.account(),
reason,
reasonBytes
);
EventUtils.EventLogData memory eventData;
CallbackUtils.afterWithdrawalCancellation(key, withdrawal, eventData);
GasUtils.payExecutionFee(
dataStore,
eventEmitter,
withdrawalVault,
key,
withdrawal.callbackContract(),
withdrawal.executionFee(),
startingGas,
GasUtils.estimateWithdrawalOraclePriceCount(withdrawal.longTokenSwapPath().length + withdrawal.shortTokenSwapPath().length),
keeper,
withdrawal.receiver()
);
}
}
文件 108 的 108:WithdrawalVault.sol
pragma solidity ^0.8.0;
import "../bank/StrictBank.sol";
contract WithdrawalVault is StrictBank {
constructor(RoleStore _roleStore, DataStore _dataStore) StrictBank(_roleStore, _dataStore) {}
}
{
"compilationTarget": {
"contracts/router/ExchangeRouter.sol": "ExchangeRouter"
},
"evmVersion": "paris",
"libraries": {
"contracts/callback/CallbackUtils.sol:CallbackUtils": "0x41418793aa2b2d595b37398ec6af99ec6b40f48e",
"contracts/deposit/DepositStoreUtils.sol:DepositStoreUtils": "0xad3a89131048b85acf899f089f2fd17424cb77b2",
"contracts/fee/FeeUtils.sol:FeeUtils": "0xf7f06d4e6ab73058b25707c0c2c288c4f70b9da6",
"contracts/market/MarketEventUtils.sol:MarketEventUtils": "0x5d4520ab45b635b1b9e83b4890e7b87bc0a45b04",
"contracts/market/MarketStoreUtils.sol:MarketStoreUtils": "0x7f9d94e918985bee91a712c4ae26dc46f24c6583",
"contracts/order/OrderStoreUtils.sol:OrderStoreUtils": "0x3c2233b0caa8437827f03366556186f5e5899fa8",
"contracts/referral/ReferralUtils.sol:ReferralUtils": "0x4904c431effc77faa547789f0895ca9f93940e74",
"contracts/shift/ShiftStoreUtils.sol:ShiftStoreUtils": "0xab27c2a82d89b545a53a4f13f9dd42b70d4655df",
"contracts/withdrawal/WithdrawalStoreUtils.sol:WithdrawalStoreUtils": "0x41194c86fc1a915d568d79067a9bccc7d47d499a"
},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 10
},
"remappings": []
}
[{"inputs":[{"internalType":"contract Router","name":"_router","type":"address"},{"internalType":"contract RoleStore","name":"_roleStore","type":"address"},{"internalType":"contract DataStore","name":"_dataStore","type":"address"},{"internalType":"contract EventEmitter","name":"_eventEmitter","type":"address"},{"internalType":"contract IDepositHandler","name":"_depositHandler","type":"address"},{"internalType":"contract IWithdrawalHandler","name":"_withdrawalHandler","type":"address"},{"internalType":"contract IShiftHandler","name":"_shiftHandler","type":"address"},{"internalType":"contract IOrderHandler","name":"_orderHandler","type":"address"},{"internalType":"contract IExternalHandler","name":"_externalHandler","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"adjustedClaimableAmount","type":"uint256"},{"internalType":"uint256","name":"claimedAmount","type":"uint256"}],"name":"CollateralAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"DisabledFeature","type":"error"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"DisabledMarket","type":"error"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"EmptyAddressInMarketTokenBalanceValidation","type":"error"},{"inputs":[],"name":"EmptyDeposit","type":"error"},{"inputs":[],"name":"EmptyHoldingAddress","type":"error"},{"inputs":[],"name":"EmptyMarket","type":"error"},{"inputs":[],"name":"EmptyOrder","type":"error"},{"inputs":[],"name":"EmptyReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"EmptyTokenTranferGasLimit","type":"error"},{"inputs":[{"internalType":"uint256","name":"marketsLength","type":"uint256"},{"internalType":"uint256","name":"tokensLength","type":"uint256"}],"name":"InvalidClaimAffiliateRewardsInput","type":"error"},{"inputs":[{"internalType":"uint256","name":"marketsLength","type":"uint256"},{"internalType":"uint256","name":"tokensLength","type":"uint256"},{"internalType":"uint256","name":"timeKeysLength","type":"uint256"}],"name":"InvalidClaimCollateralInput","type":"error"},{"inputs":[{"internalType":"uint256","name":"marketsLength","type":"uint256"},{"internalType":"uint256","name":"tokensLength","type":"uint256"}],"name":"InvalidClaimFundingFeesInput","type":"error"},{"inputs":[{"internalType":"uint256","name":"marketsLength","type":"uint256"},{"internalType":"uint256","name":"tokensLength","type":"uint256"}],"name":"InvalidClaimUiFeesInput","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"InvalidClaimableFactor","type":"error"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"expectedMinBalance","type":"uint256"}],"name":"InvalidMarketTokenBalance","type":"error"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"claimableFundingFeeAmount","type":"uint256"}],"name":"InvalidMarketTokenBalanceForClaimableFunding","type":"error"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"InvalidMarketTokenBalanceForCollateralAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"uiFeeFactor","type":"uint256"},{"internalType":"uint256","name":"maxUiFeeFactor","type":"uint256"}],"name":"InvalidUiFeeFactor","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenTransferError","type":"error"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"string","name":"role","type":"string"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"cancelDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"cancelOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"cancelShift","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"cancelWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"markets","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"claimAffiliateRewards","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"markets","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"timeKeys","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"claimCollateral","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"markets","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"claimFundingFees","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"markets","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"claimUiFees","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"address","name":"uiFeeReceiver","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"initialLongToken","type":"address"},{"internalType":"address","name":"initialShortToken","type":"address"},{"internalType":"address[]","name":"longTokenSwapPath","type":"address[]"},{"internalType":"address[]","name":"shortTokenSwapPath","type":"address[]"},{"internalType":"uint256","name":"minMarketTokens","type":"uint256"},{"internalType":"bool","name":"shouldUnwrapNativeToken","type":"bool"},{"internalType":"uint256","name":"executionFee","type":"uint256"},{"internalType":"uint256","name":"callbackGasLimit","type":"uint256"}],"internalType":"struct DepositUtils.CreateDepositParams","name":"params","type":"tuple"}],"name":"createDeposit","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"cancellationReceiver","type":"address"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"address","name":"uiFeeReceiver","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"initialCollateralToken","type":"address"},{"internalType":"address[]","name":"swapPath","type":"address[]"}],"internalType":"struct IBaseOrderUtils.CreateOrderParamsAddresses","name":"addresses","type":"tuple"},{"components":[{"internalType":"uint256","name":"sizeDeltaUsd","type":"uint256"},{"internalType":"uint256","name":"initialCollateralDeltaAmount","type":"uint256"},{"internalType":"uint256","name":"triggerPrice","type":"uint256"},{"internalType":"uint256","name":"acceptablePrice","type":"uint256"},{"internalType":"uint256","name":"executionFee","type":"uint256"},{"internalType":"uint256","name":"callbackGasLimit","type":"uint256"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"uint256","name":"validFromTime","type":"uint256"}],"internalType":"struct IBaseOrderUtils.CreateOrderParamsNumbers","name":"numbers","type":"tuple"},{"internalType":"enum Order.OrderType","name":"orderType","type":"uint8"},{"internalType":"enum Order.DecreasePositionSwapType","name":"decreasePositionSwapType","type":"uint8"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"bool","name":"shouldUnwrapNativeToken","type":"bool"},{"internalType":"bool","name":"autoCancel","type":"bool"},{"internalType":"bytes32","name":"referralCode","type":"bytes32"}],"internalType":"struct IBaseOrderUtils.CreateOrderParams","name":"params","type":"tuple"}],"name":"createOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"address","name":"uiFeeReceiver","type":"address"},{"internalType":"address","name":"fromMarket","type":"address"},{"internalType":"address","name":"toMarket","type":"address"},{"internalType":"uint256","name":"minMarketTokens","type":"uint256"},{"internalType":"uint256","name":"executionFee","type":"uint256"},{"internalType":"uint256","name":"callbackGasLimit","type":"uint256"}],"internalType":"struct ShiftUtils.CreateShiftParams","name":"params","type":"tuple"}],"name":"createShift","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"address","name":"uiFeeReceiver","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address[]","name":"longTokenSwapPath","type":"address[]"},{"internalType":"address[]","name":"shortTokenSwapPath","type":"address[]"},{"internalType":"uint256","name":"minLongTokenAmount","type":"uint256"},{"internalType":"uint256","name":"minShortTokenAmount","type":"uint256"},{"internalType":"bool","name":"shouldUnwrapNativeToken","type":"bool"},{"internalType":"uint256","name":"executionFee","type":"uint256"},{"internalType":"uint256","name":"callbackGasLimit","type":"uint256"}],"internalType":"struct WithdrawalUtils.CreateWithdrawalParams","name":"params","type":"tuple"}],"name":"createWithdrawal","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"dataStore","outputs":[{"internalType":"contract DataStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositHandler","outputs":[{"internalType":"contract IDepositHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eventEmitter","outputs":[{"internalType":"contract EventEmitter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"address","name":"uiFeeReceiver","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address[]","name":"longTokenSwapPath","type":"address[]"},{"internalType":"address[]","name":"shortTokenSwapPath","type":"address[]"},{"internalType":"uint256","name":"minLongTokenAmount","type":"uint256"},{"internalType":"uint256","name":"minShortTokenAmount","type":"uint256"},{"internalType":"bool","name":"shouldUnwrapNativeToken","type":"bool"},{"internalType":"uint256","name":"executionFee","type":"uint256"},{"internalType":"uint256","name":"callbackGasLimit","type":"uint256"}],"internalType":"struct WithdrawalUtils.CreateWithdrawalParams","name":"params","type":"tuple"},{"components":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"providers","type":"address[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"internalType":"struct OracleUtils.SetPricesParams","name":"oracleParams","type":"tuple"}],"name":"executeAtomicWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"externalHandler","outputs":[{"internalType":"contract IExternalHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"externalCallTargets","type":"address[]"},{"internalType":"bytes[]","name":"externalCallDataList","type":"bytes[]"},{"internalType":"address[]","name":"refundTokens","type":"address[]"},{"internalType":"address[]","name":"refundReceivers","type":"address[]"}],"name":"makeExternalCalls","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"orderHandler","outputs":[{"internalType":"contract IOrderHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roleStore","outputs":[{"internalType":"contract RoleStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract Router","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendNativeToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendWnt","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"callbackContract","type":"address"}],"name":"setSavedCallbackContract","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"uiFeeFactor","type":"uint256"}],"name":"setUiFeeFactor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"shiftHandler","outputs":[{"internalType":"contract IShiftHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"}],"name":"simulateExecuteDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"}],"name":"simulateExecuteLatestDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"}],"name":"simulateExecuteLatestOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"}],"name":"simulateExecuteLatestShift","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"},{"internalType":"enum ISwapPricingUtils.SwapPricingType","name":"swapPricingType","type":"uint8"}],"name":"simulateExecuteLatestWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"}],"name":"simulateExecuteOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"}],"name":"simulateExecuteShift","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"components":[{"internalType":"address[]","name":"primaryTokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct Price.Props[]","name":"primaryPrices","type":"tuple[]"},{"internalType":"uint256","name":"minTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxTimestamp","type":"uint256"}],"internalType":"struct OracleUtils.SimulatePricesParams","name":"simulatedOracleParams","type":"tuple"},{"internalType":"enum ISwapPricingUtils.SwapPricingType","name":"swapPricingType","type":"uint8"}],"name":"simulateExecuteWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"uint256","name":"sizeDeltaUsd","type":"uint256"},{"internalType":"uint256","name":"acceptablePrice","type":"uint256"},{"internalType":"uint256","name":"triggerPrice","type":"uint256"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"uint256","name":"validFromTime","type":"uint256"},{"internalType":"bool","name":"autoCancel","type":"bool"}],"name":"updateOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawalHandler","outputs":[{"internalType":"contract IWithdrawalHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"}]