Skip to content

Commit

Permalink
Merge pull request #1 from equilibria-xyz/netted-markets
Browse files Browse the repository at this point in the history
Bipool Mechanism
  • Loading branch information
kbrizzle authored Jan 15, 2023
2 parents 6832873 + 43428c4 commit 396cf6b
Show file tree
Hide file tree
Showing 18 changed files with 606 additions and 345 deletions.
12 changes: 8 additions & 4 deletions packages/common/testutil/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { expect } from 'chai'

export interface Position {
maker: BigNumberish
taker: BigNumberish
long: BigNumberish
short: BigNumberish
makerNext: BigNumberish
takerNext: BigNumberish
longNext: BigNumberish
shortNext: BigNumberish
}

export interface ProgramInfo {
Expand All @@ -21,9 +23,11 @@ export interface ProgramInfo {

export function expectPositionEq(a: Position, b: Position): void {
expect(a.maker).to.equal(b.maker)
expect(a.taker).to.equal(b.taker)
expect(a.long).to.equal(b.long)
expect(a.short).to.equal(b.short)
expect(a.makerNext).to.equal(b.makerNext)
expect(a.takerNext).to.equal(b.takerNext)
expect(a.longNext).to.equal(b.longNext)
expect(a.shortNext).to.equal(b.shortNext)
}

export function expectProgramInfoEq(a: ProgramInfo, b: ProgramInfo): void {
Expand Down
39 changes: 21 additions & 18 deletions packages/perennial/contracts/Lens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract Lens is ILens {
_snapshot.collateral = collateral(market);
_snapshot.position = position(market);
_snapshot.fee = fees(market);
(_snapshot.openMakerInterest, _snapshot.openTakerInterest) = openInterest(market);
(_snapshot.openMakerInterest, _snapshot.openLongInterest, _snapshot.openShortInterest) = openInterest(market);
}

/**
Expand Down Expand Up @@ -83,8 +83,8 @@ contract Lens is ILens {
_snapshot.userAddress = account;
_snapshot.collateral = collateral(account, market);
_snapshot.maintenance = maintenance(account, market);
(_snapshot.nextMaker, _snapshot.nextTaker) = next(account, market);
(_snapshot.maker, _snapshot.taker) = position(account, market);
(_snapshot.nextMaker, _snapshot.nextLong, _snapshot.nextShort) = next(account, market);
(_snapshot.maker, _snapshot.long, _snapshot.short) = position(account, market);
_snapshot.liquidatable = liquidatable(account, market);
_snapshot.openInterest = openInterest(account, market);
_snapshot.exposure = exposure(account, market);
Expand Down Expand Up @@ -186,8 +186,9 @@ contract Lens is ILens {
* @param market Market address
* @return Market current funding rate
*/
function rate(IMarket market) public settle(market) returns (Fixed6) {
UFixed6 utilization_ = _latestPosition(market).utilization();
function rate(IMarket market) public settle(market) returns (UFixed6) {
MarketParameter memory marketParameter = market.parameter();
UFixed6 utilization_ = _latestPosition(market).utilization(marketParameter);
return market.parameter().utilizationCurve.compute(utilization_);
}

Expand All @@ -196,10 +197,11 @@ contract Lens is ILens {
* @param market Market address
* @return Market current funding extrapolated to a daily rate
*/
function dailyRate(IMarket market) public settle(market) returns (Fixed6) {
UFixed6 utilization_ = _latestPosition(market).utilization();
Fixed6 annualRate_ = market.parameter().utilizationCurve.compute(utilization_);
return annualRate_.div(Fixed6Lib.from(365));
function dailyRate(IMarket market) public settle(market) returns (UFixed6) {
MarketParameter memory marketParameter = market.parameter();
UFixed6 utilization_ = _latestPosition(market).utilization(marketParameter);
UFixed6 annualRate_ = market.parameter().utilizationCurve.compute(utilization_);
return annualRate_.div(UFixed6Lib.from(365));
}

/**
Expand All @@ -216,10 +218,10 @@ contract Lens is ILens {
* @param market Market address
* @return Market maker and taker position multiplied by latest price after settle
*/
function openInterest(IMarket market) public settle(market) returns (UFixed6, UFixed6) {
function openInterest(IMarket market) public settle(market) returns (UFixed6, UFixed6, UFixed6) {
Position memory _position = _latestPosition(market);
UFixed6 _price = _latestVersion(market).price.abs();
return (_position.maker.mul(_price), _position.taker.mul(_price));
return (_position.maker.mul(_price), _position.long.mul(_price), _position.short.mul(_price));
}

/**
Expand Down Expand Up @@ -279,10 +281,10 @@ contract Lens is ILens {
function next(address account, IMarket market)
public
settleAccount(account, market)
returns (UFixed6, UFixed6)
returns (UFixed6, UFixed6, UFixed6)
{
Account memory marketAccount = market.accounts(account);
return (marketAccount.nextMaker, marketAccount.nextTaker);
return (marketAccount.nextMaker, marketAccount.nextLong, marketAccount.nextShort);
}

/**
Expand All @@ -294,10 +296,10 @@ contract Lens is ILens {
function position(address account, IMarket market)
public
settleAccount(account, market)
returns (UFixed6, UFixed6)
returns (UFixed6, UFixed6, UFixed6)
{
Account memory marketAccount = market.accounts(account);
return (marketAccount.maker, marketAccount.taker);
return (marketAccount.maker, marketAccount.long, marketAccount.short);
}

/**
Expand All @@ -310,10 +312,10 @@ contract Lens is ILens {
function userPosition(address account, IMarket market)
public
settleAccount(account, market)
returns (UFixed6, UFixed6, UFixed6, UFixed6)
returns (UFixed6, UFixed6, UFixed6, UFixed6, UFixed6, UFixed6)
{
Account memory marketAccount = market.accounts(account);
return (marketAccount.maker, marketAccount.taker, marketAccount.nextMaker, marketAccount.nextTaker);
return (marketAccount.maker, marketAccount.long, marketAccount. short, marketAccount.nextMaker, marketAccount.nextLong, marketAccount.nextShort);
}

/**
Expand Down Expand Up @@ -342,12 +344,13 @@ contract Lens is ILens {
if (_position.maker.isZero()) { return UFixed6Lib.ZERO; }

Account memory marketAccount = market.accounts(account);
MarketParameter memory marketParameter = market.parameter();
UFixed6 _openInterest = openInterest(account, market);
if (marketAccount.maker.isZero()) {
return _openInterest; // Taker exposure is always 100% of openInterest
}

UFixed6 utilization = _position.utilization();
UFixed6 utilization = _position.utilization(marketParameter);
return utilization.mul(_openInterest); // Maker exposure is openInterest * utilization
}

Expand Down
38 changes: 21 additions & 17 deletions packages/perennial/contracts/Market.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ contract Market is IMarket, UInitializable, UOwnable {
_saveContext(context, account);
}

function update(UFixed6 newMaker, UFixed6 newTaker, Fixed6 newCollateral) external {
function update(UFixed6 newMaker, UFixed6 newLong, UFixed6 newShort, Fixed6 newCollateral) external {
CurrentContext memory context = _loadContext(msg.sender);
_settle(context);
_update(context, msg.sender, msg.sender, newMaker, newTaker, newCollateral, false);
_update(context, msg.sender, msg.sender, newMaker, newLong, newShort, newCollateral, false);
_saveContext(context, msg.sender);
}

Expand Down Expand Up @@ -155,7 +155,7 @@ contract Market is IMarket, UInitializable, UOwnable {
Fixed6 newCollateral = context.account.collateral.sub(liquidationReward);

// close position
_update(context, account, msg.sender, UFixed6Lib.ZERO, UFixed6Lib.ZERO, newCollateral, true);
_update(context, account, msg.sender, UFixed6Lib.ZERO, UFixed6Lib.ZERO, UFixed6Lib.ZERO, newCollateral, true);
context.account.liquidation = true;

emit Liquidation(account, msg.sender, liquidationReward);
Expand All @@ -166,26 +166,29 @@ contract Market is IMarket, UInitializable, UOwnable {
address account,
address receiver,
UFixed6 newMaker,
UFixed6 newTaker,
UFixed6 newLong,
UFixed6 newShort,
Fixed6 newCollateral,
bool force
) private {
_startGas(context, "_update before-update-after: %s");

// before
if (context.account.liquidation) revert MarketInLiquidationError();
if (context.marketParameter.closed && !newMaker.add(newTaker).isZero()) revert MarketClosedError();
if (context.marketParameter.closed && !newMaker.add(newLong).add(newShort).isZero()) revert MarketClosedError();

// update
if (newCollateral.eq(Fixed6Lib.MAX)) newCollateral = context.account.collateral;
(Fixed6 makerAmount, Fixed6 takerAmount, UFixed6 takerFee, Fixed6 collateralAmount) = context.account.update(
newMaker,
newTaker,
newCollateral,
context.currentOracleVersion,
context.marketParameter
);
context.position.update(makerAmount, takerAmount);
(Fixed6 makerAmount, Fixed6 longAmount, Fixed6 shortAmount, UFixed6 takerFee, Fixed6 collateralAmount) =
context.account.update(
newMaker,
newLong,
newShort,
newCollateral,
context.currentOracleVersion,
context.marketParameter
);
context.position.update(makerAmount, longAmount, shortAmount);
UFixed6 takerMarketFee = context.version.update(context.position, takerFee, context.marketParameter);
context.fee.update(takerMarketFee, context.protocolParameter);

Expand All @@ -202,7 +205,7 @@ contract Market is IMarket, UInitializable, UOwnable {
if (collateralAmount.sign() == -1) token.push(receiver, UFixed18.wrap(UFixed6.unwrap(collateralAmount.abs()) * 1e12));

// events
emit Updated(account, context.currentOracleVersion.version, newMaker, newTaker, newCollateral);
emit Updated(account, context.currentOracleVersion.version, newMaker, newLong, newShort, newCollateral);

_endGas(context);
}
Expand Down Expand Up @@ -314,12 +317,13 @@ contract Market is IMarket, UInitializable, UOwnable {
function _checkPosition(CurrentContext memory context) private pure {
if (
!context.marketParameter.closed &&
context.position.socializationFactorNext().lt(UFixed6Lib.ONE) &&
context.position.socializedNext() &&
(
context.account.nextTaker.gt(context.account.taker) ||
context.account.nextLong.gt(context.account.long) ||
context.account.nextShort.gt(context.account.short) ||
context.account.nextMaker.lt(context.account.maker)
)
) revert MarketInsufficientLiquidityError();
) revert MarketInsufficientLiquidityError(); //TODO: reevaluate this check

if (context.position.makerNext.gt(context.marketParameter.makerLimit))
revert MarketMakerOverLimitError();
Expand Down
25 changes: 14 additions & 11 deletions packages/perennial/contracts/interfaces/ILens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ interface ILens {
IMarket.MarketDefinition definition;
MarketParameter parameter;
address marketAddress;
Fixed6 rate;
Fixed6 dailyRate;
UFixed6 rate;
UFixed6 dailyRate;
OracleVersion latestVersion;
Fixed6 collateral;
Position position;
Fee fee;
UFixed6 openMakerInterest;
UFixed6 openTakerInterest;
UFixed6 openLongInterest;
UFixed6 openShortInterest;
}

/// @dev Snapshot of User state for a Market
Expand All @@ -31,9 +32,11 @@ interface ILens {
Fixed6 collateral;
UFixed6 maintenance;
UFixed6 maker;
UFixed6 taker;
UFixed6 long;
UFixed6 short;
UFixed6 nextMaker;
UFixed6 nextTaker;
UFixed6 nextLong;
UFixed6 nextShort;
bool liquidatable;
UFixed6 openInterest;
UFixed6 exposure;
Expand All @@ -59,18 +62,18 @@ interface ILens {
function position(IMarket market) external returns (Position memory);
function latestVersion(IMarket market) external returns (OracleVersion memory);
function atVersions(IMarket market, uint[] memory versions) external returns (OracleVersion[] memory);
function rate(IMarket market) external returns (Fixed6);
function openInterest(IMarket market) external returns (UFixed6, UFixed6);
function dailyRate(IMarket market) external returns (Fixed6);
function rate(IMarket market) external returns (UFixed6);
function openInterest(IMarket market) external returns (UFixed6, UFixed6, UFixed6);
function dailyRate(IMarket market) external returns (UFixed6);

// UserMarket Values
function collateral(address account, IMarket market) external returns (Fixed6);
function maintenance(address account, IMarket market) external returns (UFixed6);
function maintenanceNext(address account, IMarket market) external returns (UFixed6);
function liquidatable(address account, IMarket market) external returns (bool);
function next(address account, IMarket market) external returns (UFixed6, UFixed6);
function position(address account, IMarket market) external returns (UFixed6, UFixed6);
function userPosition(address account, IMarket market) external returns (UFixed6, UFixed6, UFixed6, UFixed6);
function next(address account, IMarket market) external returns (UFixed6, UFixed6, UFixed6);
function position(address account, IMarket market) external returns (UFixed6, UFixed6, UFixed6);
function userPosition(address account, IMarket market) external returns (UFixed6, UFixed6, UFixed6, UFixed6, UFixed6, UFixed6);
function openInterest(address account, IMarket market) external returns (UFixed6);
function exposure(address account, IMarket market) external returns (UFixed6);
function maintenanceRequired(
Expand Down
4 changes: 2 additions & 2 deletions packages/perennial/contracts/interfaces/IMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ interface IMarket is IOwnable {

event Settle(uint256 preVersion, uint256 toVersion);
event AccountSettle(address indexed account, uint256 preVersion, uint256 toVersion);
event Updated(address indexed account, uint256 version, UFixed6 newMaker, UFixed6 newTaker, Fixed6 newCollateral);
event Updated(address indexed account, uint256 version, UFixed6 newMaker, UFixed6 newLong, UFixed6 newShort, Fixed6 newCollateral);
event Liquidation(address indexed account, address liquidator, Fixed6 fee);
event FeeSettled(UFixed6 protocolFeeAmount, UFixed6 marketFeeAmount);
event CollateralSettled(address indexed account, Fixed6 amount, UFixed6 newShortfall);
Expand Down Expand Up @@ -68,7 +68,7 @@ interface IMarket is IOwnable {
function position() external view returns (Position memory);
function fee() external view returns (Fee memory);
function settle(address account) external;
function update(UFixed6 newMaker, UFixed6 newTaker, Fixed6 newCollateral) external;
function update(UFixed6 newMaker, UFixed6 newLong, UFixed6 newShort, Fixed6 newCollateral) external;
function updateTreasury(address newTreasury) external;
function parameter() external view returns (MarketParameter memory);
function updateParameter(MarketParameter memory newParameter) external;
Expand Down
Loading

0 comments on commit 396cf6b

Please sign in to comment.