Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 60 additions & 31 deletions contracts/config/Config.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ contract Config is ReentrancyGuard, RoleModule, BasicMulticall {
eventEmitter = _eventEmitter;

_initAllowedBaseKeys();
_initAllowedLimitedBaseKeys();
// _initAllowedLimitedBaseKeys();
}

modifier onlyKeeper() {
Expand Down Expand Up @@ -231,6 +231,32 @@ contract Config is ReentrancyGuard, RoleModule, BasicMulticall {
);
}

function setBaselineSwap(
address market,
uint256 baselineSwapPerDay,
bool longsPayShorts
) external onlyConfigKeeper nonReentrant {
dataStore.setBool(Keys.baselineSwapLongsPayShortsKey(market), longsPayShorts);
dataStore.setUint(Keys.baselineSwapPerDayKey(market), baselineSwapPerDay);

EventUtils.EventLogData memory eventData;

eventData.addressItems.initItems(1);
eventData.addressItems.setItem(0, "market", market);

eventData.uintItems.initItems(1);
eventData.uintItems.setItem(0, "baselineSwapPerDay", baselineSwapPerDay);

eventData.boolItems.initItems(1);
eventData.boolItems.setItem(0, "longsPayShorts", longsPayShorts);

eventEmitter.emitEventLog1(
"SetBaselineSwap",
Cast.toBytes32(market),
eventData
);
}

// @dev set a bool value
// @param baseKey the base key of the value to set
// @param data the additional data to be combined with the base key
Expand Down Expand Up @@ -554,32 +580,35 @@ contract Config is ReentrancyGuard, RoleModule, BasicMulticall {

allowedBaseKeys[Keys.DATA_STREAM_INVERTED] = true;
allowedBaseKeys[Keys.DATA_STREAM_SPREAD_REDUCTION_FACTOR] = true;
}

function _initAllowedLimitedBaseKeys() internal {
allowedLimitedBaseKeys[Keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1] = true;
allowedLimitedBaseKeys[Keys.ESTIMATED_GAS_FEE_PER_ORACLE_PRICE] = true;
allowedLimitedBaseKeys[Keys.ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR] = true;

allowedLimitedBaseKeys[Keys.EXECUTION_GAS_FEE_BASE_AMOUNT_V2_1] = true;
allowedLimitedBaseKeys[Keys.EXECUTION_GAS_FEE_PER_ORACLE_PRICE] = true;
allowedLimitedBaseKeys[Keys.EXECUTION_GAS_FEE_MULTIPLIER_FACTOR] = true;

allowedLimitedBaseKeys[Keys.MAX_FUNDING_FACTOR_PER_SECOND] = true;
allowedLimitedBaseKeys[Keys.MIN_FUNDING_FACTOR_PER_SECOND] = true;
allowedLimitedBaseKeys[Keys.FUNDING_INCREASE_FACTOR_PER_SECOND] = true;
allowedLimitedBaseKeys[Keys.FUNDING_DECREASE_FACTOR_PER_SECOND] = true;

allowedLimitedBaseKeys[Keys.MAX_POOL_AMOUNT] = true;
allowedLimitedBaseKeys[Keys.MAX_POOL_USD_FOR_DEPOSIT] = true;
allowedLimitedBaseKeys[Keys.MAX_OPEN_INTEREST] = true;

allowedLimitedBaseKeys[Keys.GLV_MAX_MARKET_TOKEN_BALANCE_USD] = true;
allowedLimitedBaseKeys[Keys.GLV_MAX_MARKET_TOKEN_BALANCE_AMOUNT] = true;

allowedLimitedBaseKeys[Keys.PRO_TRADER_TIER] = true;
allowedBaseKeys[Keys.BASELINE_SWAP_LONGS_PAY_SHORTS] = true;
allowedBaseKeys[Keys.BASELINE_SWAP_PER_DAY] = true;
}

// function _initAllowedLimitedBaseKeys() internal {
// allowedLimitedBaseKeys[Keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1] = true;
// allowedLimitedBaseKeys[Keys.ESTIMATED_GAS_FEE_PER_ORACLE_PRICE] = true;
// allowedLimitedBaseKeys[Keys.ESTIMATED_GAS_FEE_MULTIPLIER_FACTOR] = true;
//
// allowedLimitedBaseKeys[Keys.EXECUTION_GAS_FEE_BASE_AMOUNT_V2_1] = true;
// allowedLimitedBaseKeys[Keys.EXECUTION_GAS_FEE_PER_ORACLE_PRICE] = true;
// allowedLimitedBaseKeys[Keys.EXECUTION_GAS_FEE_MULTIPLIER_FACTOR] = true;
//
// allowedLimitedBaseKeys[Keys.MAX_FUNDING_FACTOR_PER_SECOND] = true;
// allowedLimitedBaseKeys[Keys.MIN_FUNDING_FACTOR_PER_SECOND] = true;
// allowedLimitedBaseKeys[Keys.FUNDING_INCREASE_FACTOR_PER_SECOND] = true;
// allowedLimitedBaseKeys[Keys.FUNDING_DECREASE_FACTOR_PER_SECOND] = true;
//
// allowedLimitedBaseKeys[Keys.MAX_POOL_AMOUNT] = true;
// allowedLimitedBaseKeys[Keys.MAX_POOL_USD_FOR_DEPOSIT] = true;
// allowedLimitedBaseKeys[Keys.MAX_OPEN_INTEREST] = true;
//
// allowedLimitedBaseKeys[Keys.GLV_MAX_MARKET_TOKEN_BALANCE_USD] = true;
// allowedLimitedBaseKeys[Keys.GLV_MAX_MARKET_TOKEN_BALANCE_AMOUNT] = true;
//
// allowedLimitedBaseKeys[Keys.PRO_TRADER_TIER] = true;
// }

// @dev validate that the baseKey is allowed to be used
// @param baseKey the base key to validate
function _validateKey(bytes32 baseKey) internal view {
Expand All @@ -591,13 +620,13 @@ contract Config is ReentrancyGuard, RoleModule, BasicMulticall {
return;
}

if (roleStore.hasRole(msg.sender, Role.LIMITED_CONFIG_KEEPER)) {
if (!allowedLimitedBaseKeys[baseKey]) {
revert Errors.InvalidBaseKey(baseKey);
}

return;
}
// if (roleStore.hasRole(msg.sender, Role.LIMITED_CONFIG_KEEPER)) {
// if (!allowedLimitedBaseKeys[baseKey]) {
// revert Errors.InvalidBaseKey(baseKey);
// }
//
// return;
// }

revert Errors.InvalidBaseKey(baseKey);
}
Expand Down
25 changes: 25 additions & 0 deletions contracts/data/Keys.sol
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,11 @@ library Keys {
// @dev constant for user initiated cancel reason
string public constant USER_INITIATED_CANCEL = "USER_INITIATED_CANCEL";

// @dev key for the baseline swap direction (true for long to short, false for short to long) for a market
bytes32 public constant BASELINE_SWAP_LONGS_PAY_SHORTS = keccak256(abi.encode("BASELINE_SWAP_LONGS_PAY_SHORTS"));
// @dev key for the baseline swap amount per day for a market
bytes32 public constant BASELINE_SWAP_PER_DAY = keccak256(abi.encode("BASELINE_SWAP_PER_DAY"));

// @dev function used to calculate fullKey for a given market parameter
// @param baseKey the base key for the market parameter
// @param data the additional data for the market parameter
Expand Down Expand Up @@ -2126,4 +2131,24 @@ library Keys {
token
));
}

// @dev key for the baseline swap direction (true for long to short, false for short to long) for a market
// @param market the market to check
// @return key for baseline swap direction
function baselineSwapLongsPayShortsKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
BASELINE_SWAP_LONGS_PAY_SHORTS,
market
));
}

// @dev key for the baseline swap amount per day for a market
// @param market the market to check
// @return key for baseline swap amount per day
function baselineSwapPerDayKey(address market) internal pure returns (bytes32) {
return keccak256(abi.encode(
BASELINE_SWAP_PER_DAY,
market
));
}
}
27 changes: 26 additions & 1 deletion contracts/market/MarketUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,31 @@ library MarketUtils {
cache.fundingUsd = Precision.applyFactor(cache.sizeOfLargerSide, cache.durationInSeconds * result.fundingFactorPerSecond);
cache.fundingUsd = cache.fundingUsd / divisor;

// calculate a baseline swap rate for certain markets (e.g. forex markets)
// and adjust the fundingUsd value accordingly
bool swapLongsPayShorts = dataStore.getBool(Keys.baselineSwapLongsPayShortsKey(market.marketToken));
uint256 swapPerDay = dataStore.getUint(Keys.baselineSwapPerDayKey(market.marketToken));
uint256 swapPerSecond = swapPerDay / 86400;

if (swapPerSecond > 0) {
uint256 baselineSwapUsd = Precision.applyFactor(
swapLongsPayShorts ? cache.shortOpenInterest : cache.longOpenInterest,
cache.durationInSeconds * swapPerSecond
);

if (result.longsPayShorts == swapLongsPayShorts) {
cache.fundingUsd += baselineSwapUsd;

} else {
if (cache.fundingUsd >= baselineSwapUsd) {
cache.fundingUsd -= baselineSwapUsd;
} else {
cache.fundingUsd = baselineSwapUsd - cache.fundingUsd;
result.longsPayShorts = !result.longsPayShorts;
}
}
}

// split the fundingUsd value by long and short collateral
// e.g. if the fundingUsd value is $500, and there is $1000 of long open interest using long collateral and $4000 of long open interest
// with short collateral, then $100 of funding fees should be paid from long positions using long collateral, $400 of funding fees
Expand Down Expand Up @@ -1720,7 +1745,7 @@ library MarketUtils {
// @param market the position's market
// @param prices the prices of the market tokens
// @return the borrowing fees for a position
function getNextBorrowingFees(DataStore dataStore, Position.Props memory position, Market.Props memory market, MarketPrices memory prices) internal view returns (uint256) {
function getNextBorrowingFees(DataStore dataStore, Position.Props memory position, Market.Props memory market, MarketPrices memory prices) external view returns (uint256) {
(uint256 nextCumulativeBorrowingFactor, /* uint256 delta */) = getNextCumulativeBorrowingFactor(
dataStore,
market,
Expand Down
2 changes: 1 addition & 1 deletion deploy/deployReaderPositionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createDeployFunction } from "../utils/deploy";

const func = createDeployFunction({
contractName: "ReaderPositionUtils",
libraryNames: ["MarketStoreUtils", "PositionStoreUtils", "PositionUtils", "ReaderPricingUtils"],
libraryNames: ["MarketUtils", "MarketStoreUtils", "PositionStoreUtils", "PositionUtils", "ReaderPricingUtils"],
});

export default func;
26 changes: 13 additions & 13 deletions test/config/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@ describe("Config", () => {
.withArgs(keys.POOL_AMOUNT);
});

it("allows LIMITED_CONFIG_KEEPER to set allowedLimitedBaseKeys", async () => {
expect(await dataStore.getAddress(keys.HOLDING_ADDRESS)).eq(AddressZero);
await config.connect(user0).setAddress(keys.HOLDING_ADDRESS, "0x", user1.address);
expect(await dataStore.getAddress(keys.HOLDING_ADDRESS)).eq(user1.address);

await expect(config.connect(user2).setAddress(keys.HOLDING_ADDRESS, "0x", user2.address))
.to.be.revertedWithCustomError(errorsContract, "InvalidBaseKey")
.withArgs(keys.HOLDING_ADDRESS);

expect(await dataStore.getUint(keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1), "0");
await config.connect(user2).setUint(keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1, "0x", "200");
expect(await dataStore.getUint(keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1), "200");
});
// it("allows LIMITED_CONFIG_KEEPER to set allowedLimitedBaseKeys", async () => {
// expect(await dataStore.getAddress(keys.HOLDING_ADDRESS)).eq(AddressZero);
// await config.connect(user0).setAddress(keys.HOLDING_ADDRESS, "0x", user1.address);
// expect(await dataStore.getAddress(keys.HOLDING_ADDRESS)).eq(user1.address);
//
// await expect(config.connect(user2).setAddress(keys.HOLDING_ADDRESS, "0x", user2.address))
// .to.be.revertedWithCustomError(errorsContract, "InvalidBaseKey")
// .withArgs(keys.HOLDING_ADDRESS);
//
// expect(await dataStore.getUint(keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1), "0");
// await config.connect(user2).setUint(keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1, "0x", "200");
// expect(await dataStore.getUint(keys.ESTIMATED_GAS_FEE_BASE_AMOUNT_V2_1), "200");
// });

it("setBool", async () => {
const key = keys.isMarketDisabledKey(ethUsdMarket.marketToken);
Expand Down
11 changes: 11 additions & 0 deletions utils/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ export const VALID_FROM_TIME = hashString("VALID_FROM_TIME");

export const ASSET_TOKEN = hashString("ASSET_TOKEN");

export const BASELINE_SWAP_LONGS_PAY_SHORTS = hashString("BASELINE_SWAP_LONGS_PAY_SHORTS");
export const BASELINE_SWAP_PER_DAY = hashString("BASELINE_SWAP_PER_DAY");

export function accountDepositListKey(account) {
return hashData(["bytes32", "address"], [ACCOUNT_DEPOSIT_LIST, account]);
}
Expand Down Expand Up @@ -816,3 +819,11 @@ export function withdrawableBuybackTokenAmountKey(buybackToken: string) {
export function assetTokenKey(asset: string) {
return hashData(["bytes32", "string"], [ASSET_TOKEN, asset]);
}

export function baselineSwapLongsPayShortsKey(market: string) {
return hashData(["bytes32", "address"], [BASELINE_SWAP_LONGS_PAY_SHORTS, market]);
}

export function baselineSwapPerDayKey(market: string) {
return hashData(["bytes32", "address"], [BASELINE_SWAP_PER_DAY, market]);
}