Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add synthetic orderbook #487

Open
wants to merge 55 commits into
base: v2.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
1197e7b
first pass math
kbrizzle Oct 24, 2024
69c5be1
cleanup version
kbrizzle Oct 27, 2024
370003c
implement checkpoint
kbrizzle Oct 27, 2024
df1d671
add more tracking to version
kbrizzle Oct 27, 2024
6cc9c9d
update risk parameter requirement
kbrizzle Oct 27, 2024
9eed415
add close before spread settlement logic
kbrizzle Oct 27, 2024
c86426f
changes
kbrizzle Nov 2, 2024
d330bf6
update payer side of spread
kbrizzle Nov 4, 2024
3dc733b
spread receiver implementation
kbrizzle Nov 10, 2024
06bf5e4
cleanup attribution logic
kbrizzle Nov 13, 2024
4d1df93
use root synbook
kbrizzle Nov 15, 2024
1862999
resolve stack too deep
kbrizzle Nov 15, 2024
5e884e2
add natspec
kbrizzle Nov 15, 2024
7a84464
Merge branch 'v2.4' into britz-synthetic-orderbook
kbrizzle Nov 16, 2024
f34d971
update non-version type tests
kbrizzle Nov 16, 2024
a903204
version storage test
kbrizzle Nov 16, 2024
936992b
fix version bugs
kbrizzle Nov 17, 2024
6bf3f02
start version tests
kbrizzle Nov 27, 2024
62bd4cd
add matching lib
kbrizzle Dec 12, 2024
e7b7547
update storage
kbrizzle Dec 14, 2024
320fd09
comkpile
kbrizzle Dec 15, 2024
fd31d43
consolidate accumulators
kbrizzle Dec 15, 2024
6eea37d
fix naming
kbrizzle Dec 15, 2024
fb08be5
more naming
kbrizzle Dec 15, 2024
233c2fb
warnings
kbrizzle Dec 15, 2024
13b3cbf
compile without optimizer
kbrizzle Dec 16, 2024
7cbe3e8
version storage test
kbrizzle Dec 16, 2024
42d7e3e
add tester
kbrizzle Dec 17, 2024
80197c0
matching lib basic tests
kbrizzle Dec 17, 2024
2694693
fix exposure match
kbrizzle Dec 20, 2024
db4b061
add new basic test
kbrizzle Dec 20, 2024
95778a2
first leg of match test
kbrizzle Dec 21, 2024
0f22c49
add match tests
kbrizzle Dec 22, 2024
5341c1e
add helper func tests
kbrizzle Dec 22, 2024
0008e4d
fill tests
kbrizzle Dec 22, 2024
0a022e2
fill socialization tests
kbrizzle Dec 22, 2024
952158a
fix divide by zero
kbrizzle Dec 23, 2024
90f86aa
exposure open / close tests
kbrizzle Dec 23, 2024
b39c0b1
Merge branch 'v2.4' into britz-synthetic-orderbook
kbrizzle Dec 23, 2024
a1fe8a0
fix taker position close order
kbrizzle Dec 23, 2024
0f0e290
fix execute taker apply
kbrizzle Dec 25, 2024
341d5f3
matching lib tests
kbrizzle Dec 26, 2024
907447f
update version tests
kbrizzle Dec 27, 2024
36b1764
support guarantee
kbrizzle Dec 28, 2024
5dbcd34
non-taker unit tests
kbrizzle Dec 29, 2024
d437e55
long / short unit tests
kbrizzle Dec 31, 2024
f634f61
closing test, fix checkpoint
kbrizzle Dec 31, 2024
f8e54e4
unit tests complete
kbrizzle Dec 31, 2024
3358404
non-fees tests
kbrizzle Jan 1, 2025
061c3ed
fee impact tests
kbrizzle Jan 2, 2025
edfe08c
fees tests
kbrizzle Jan 2, 2025
c1026d8
tests complete
kbrizzle Jan 2, 2025
bea5c63
cleanup
kbrizzle Jan 2, 2025
ec237b1
Merge branch 'v2.4' into britz-synthetic-orderbook
kbrizzle Jan 2, 2025
a164e27
update tests after merge
kbrizzle Jan 2, 2025
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"devDependencies": {
"@codechecks/client": "^0.1.10",
"@defi-wonderland/smock": "^2.0.7",
"@equilibria/root": "2.3.0-rc8",
"@equilibria/root": "2.4.0-rc0",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.6",
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
"@nomicfoundation/hardhat-toolbox": "2.0.2",
Expand Down
106 changes: 67 additions & 39 deletions packages/common/testutil/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BigNumber, BigNumberish, utils, constants } from 'ethers'
import { expect } from 'chai'
import exp from 'constants'

export interface OracleVersion {
valid: boolean
Expand Down Expand Up @@ -45,8 +46,10 @@ export interface Order {

export interface Guarantee {
orders: BigNumberish
takerPos: BigNumberish
takerNeg: BigNumberish
longPos: BigNumberish
longNeg: BigNumberish
shortPos: BigNumberish
shortNeg: BigNumberish
notional: BigNumberish
takerFee: BigNumberish
referral: BigNumberish
Expand All @@ -67,7 +70,6 @@ export interface Global {
riskFee: BigNumberish
latestPrice: BigNumberish
pAccumulator: PAccumulator
exposure: BigNumberish
}

export interface Local {
Expand All @@ -80,14 +82,24 @@ export interface Local {
export interface Version {
valid: boolean
price: BigNumberish
makerValue: Accumulator
longValue: Accumulator
shortValue: Accumulator
makerPosExposure: BigNumberish
makerNegExposure: BigNumberish
longPosExposure: BigNumberish
longNegExposure: BigNumberish
shortPosExposure: BigNumberish
shortNegExposure: BigNumberish
makerPreValue: Accumulator
longPreValue: Accumulator
shortPreValue: Accumulator
makerCloseValue: Accumulator
longCloseValue: Accumulator
shortCloseValue: Accumulator
longPostValue: Accumulator
shortPostValue: Accumulator
spreadPos: Accumulator
spreadNeg: Accumulator
makerFee: Accumulator
takerFee: Accumulator
makerOffset: Accumulator
takerPosOffset: Accumulator
takerNegOffset: Accumulator
settlementFee: Accumulator
liquidationFee: Accumulator
}
Expand All @@ -110,10 +122,11 @@ export interface MarketParameter {
settle: boolean
}

export interface AdiabaticFee {
linearFee: BigNumberish
proportionalFee: BigNumberish
adiabaticFee: BigNumberish
export interface SynBook {
d0: BigNumberish
d1: BigNumberish
d2: BigNumberish
d3: BigNumberish
scale: BigNumberish
}

Expand All @@ -133,8 +146,7 @@ export interface PController {
export interface RiskParameter {
margin: BigNumberish
maintenance: BigNumberish
takerFee: AdiabaticFee
makerFee: AdiabaticFee
synBook: SynBook
makerLimit: BigNumberish
efficiencyLimit: BigNumberish
liquidationFee: BigNumberish
Expand Down Expand Up @@ -190,8 +202,10 @@ export function expectOrderEq(a: Order, b: Order): void {

export function expectGuaranteeEq(a: Guarantee, b: Guarantee): void {
expect(a.orders).to.equal(b.orders, 'Order:Orders')
expect(a.takerPos).to.equal(b.takerPos, 'Order:TakerPos')
expect(a.takerNeg).to.equal(b.takerNeg, 'Order:TakerNeg')
expect(a.longPos).to.equal(b.longPos, 'Order:LongPos')
expect(a.longNeg).to.equal(b.longNeg, 'Order:LongNeg')
expect(a.shortPos).to.equal(b.shortPos, 'Order:ShortPos')
expect(a.shortNeg).to.equal(b.shortNeg, 'Order:ShortNeg')
expect(a.notional).to.equal(b.notional, 'Order:Notional')
expect(a.takerFee).to.equal(b.takerFee, 'Order:TakerFee')
expect(a.referral).to.equal(b.referral, 'Order:Referral')
Expand All @@ -211,7 +225,6 @@ export function expectGlobalEq(a: Global, b: Global): void {
expect(a.oracleFee).to.equal(b.oracleFee, 'Global:OracleFee')
expect(a.riskFee).to.equal(b.riskFee, 'Global:RiskFee')
expect(a.latestPrice).to.equal(b.latestPrice, 'Global:LatestPrice')
expect(a.exposure).to.equal(b.exposure, 'Global:Exposure')
}

export function expectLocalEq(a: Local, b: Local): void {
Expand All @@ -224,14 +237,18 @@ export function expectLocalEq(a: Local, b: Local): void {
export function expectVersionEq(a: Version, b: Version): void {
expect(a.valid).to.equal(b.valid, 'Version:Valid')
expect(a.price).to.equal(b.price, 'Version:Price')
expect(a.makerValue._value).to.equal(b.makerValue._value, 'Version:MakerValue')
expect(a.longValue._value).to.equal(b.longValue._value, 'Version:LongValue')
expect(a.shortValue._value).to.equal(b.shortValue._value, 'Version:ShortValue')
expect(a.makerPreValue._value).to.equal(b.makerPreValue._value, 'Version:MakerPreValue')
expect(a.longPreValue._value).to.equal(b.longPreValue._value, 'Version:LongPreValue')
expect(a.shortPreValue._value).to.equal(b.shortPreValue._value, 'Version:ShortPreValue')
expect(a.makerCloseValue._value).to.equal(b.makerCloseValue._value, 'Version:MakerCloseValue')
expect(a.longCloseValue._value).to.equal(b.longCloseValue._value, 'Version:LongCloseValue')
expect(a.shortCloseValue._value).to.equal(b.shortCloseValue._value, 'Version:ShortCloseValue')
expect(a.longPostValue._value).to.equal(b.longPostValue._value, 'Version:LongPostValue')
expect(a.shortPostValue._value).to.equal(b.shortPostValue._value, 'Version:ShortPostValue')
expect(a.spreadPos._value).to.equal(b.spreadPos._value, 'Version:SpreadPos')
expect(a.spreadNeg._value).to.equal(b.spreadNeg._value, 'Version:SpreadNeg')
expect(a.makerFee._value).to.equal(b.makerFee._value, 'Version:MakerFee')
expect(a.takerFee._value).to.equal(b.takerFee._value, 'Version:TakerFee')
expect(a.makerOffset._value).to.equal(b.makerOffset._value, 'Version:MakerOffset')
expect(a.takerPosOffset._value).to.equal(b.takerPosOffset._value, 'Version:TakerPosOffset')
expect(a.takerNegOffset._value).to.equal(b.takerNegOffset._value, 'Version:TakerNegOffset')
expect(a.settlementFee._value).to.equal(b.settlementFee._value, 'Version:SettlementFee')
expect(a.liquidationFee._value).to.equal(b.liquidationFee._value, 'Version:LiquidationFee')
}
Expand Down Expand Up @@ -289,7 +306,6 @@ export const DEFAULT_GLOBAL: Global = {
_value: 0,
_skew: 0,
},
exposure: 0,
}

export const DEFAULT_LOCAL: Local = {
Expand All @@ -316,8 +332,10 @@ export const DEFAULT_ORDER: Order = {

export const DEFAULT_GUARANTEE: Guarantee = {
orders: 0,
takerPos: 0,
takerNeg: 0,
longPos: 0,
longNeg: 0,
shortPos: 0,
shortNeg: 0,
notional: 0,
takerFee: 0,
referral: 0,
Expand All @@ -326,14 +344,24 @@ export const DEFAULT_GUARANTEE: Guarantee = {
export const DEFAULT_VERSION: Version = {
valid: true,
price: 0,
makerValue: { _value: 0 },
longValue: { _value: 0 },
shortValue: { _value: 0 },
makerPosExposure: 0,
makerNegExposure: 0,
longPosExposure: 0,
longNegExposure: 0,
shortPosExposure: 0,
shortNegExposure: 0,
makerPreValue: { _value: 0 },
longPreValue: { _value: 0 },
shortPreValue: { _value: 0 },
makerCloseValue: { _value: 0 },
longCloseValue: { _value: 0 },
shortCloseValue: { _value: 0 },
longPostValue: { _value: 0 },
shortPostValue: { _value: 0 },
spreadPos: { _value: 0 },
spreadNeg: { _value: 0 },
makerFee: { _value: 0 },
takerFee: { _value: 0 },
makerOffset: { _value: 0 },
takerPosOffset: { _value: 0 },
takerNegOffset: { _value: 0 },
settlementFee: { _value: 0 },
liquidationFee: { _value: 0 },
}
Expand Down Expand Up @@ -362,10 +390,11 @@ export const DEFAULT_MARKET_PARAMETER: MarketParameter = {
settle: false,
}

export const DEFAULT_ADIABATIC_FEE: AdiabaticFee = {
linearFee: 0,
proportionalFee: 0,
adiabaticFee: 0,
export const DEFAULT_SYN_BOOK: SynBook = {
d0: 0,
d1: 0,
d2: 0,
d3: 0,
scale: 0,
}

Expand All @@ -385,8 +414,7 @@ export const DEFAULT_PCONTROLLER: PController = {
export const DEFAULT_RISK_PARAMETER: RiskParameter = {
margin: 0,
maintenance: 0,
takerFee: DEFAULT_ADIABATIC_FEE,
makerFee: DEFAULT_ADIABATIC_FEE,
synBook: DEFAULT_SYN_BOOK,
makerLimit: 0,
efficiencyLimit: 0,
liquidationFee: 0,
Expand Down
26 changes: 0 additions & 26 deletions packages/core/contracts/Market.sol
Original file line number Diff line number Diff line change
Expand Up @@ -334,19 +334,7 @@ contract Market is IMarket, Instance, ReentrancyGuard {
/// @notice Updates the risk parameter set of the market
/// @param newRiskParameter The new risk parameter set
function updateRiskParameter(RiskParameter memory newRiskParameter) external onlyCoordinator {
// load latest state
Global memory newGlobal = _global.read();
Position memory latestPosition = _position.read();
RiskParameter memory latestRiskParameter = _riskParameter.read();

// update risk parameter (first to capture truncation)
_riskParameter.validateAndStore(newRiskParameter, IMarketFactory(address(factory())).parameter());
newRiskParameter = _riskParameter.read();

// update global exposure
newGlobal.update(latestRiskParameter, newRiskParameter, latestPosition);
_global.store(newGlobal);

emit RiskParameterUpdated(newRiskParameter);
}

Expand Down Expand Up @@ -388,20 +376,6 @@ contract Market is IMarket, Instance, ReentrancyGuard {
}
}

/// @notice Settles any exposure that has accrued to the market
/// @dev Resets exposure to zero, caller pays or receives to net out the exposure
function claimExposure() external onlyOwner {
Global memory newGlobal = _global.read();

if (newGlobal.exposure.sign() == 1) token.push(msg.sender, UFixed18Lib.from(newGlobal.exposure.abs()));
if (newGlobal.exposure.sign() == -1) token.pull(msg.sender, UFixed18Lib.from(newGlobal.exposure.abs()));

emit ExposureClaimed(msg.sender, newGlobal.exposure);

newGlobal.exposure = Fixed6Lib.ZERO;
_global.store(newGlobal);
}

/// @notice Returns the current parameter set
function parameter() external view returns (MarketParameter memory) {
return _parameter.read();
Expand Down
1 change: 0 additions & 1 deletion packages/core/contracts/interfaces/IMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ interface IMarket is IInstance {
/// @param receiver Delegated operator of the account, or the account itself
/// @param amount Collateral transferred from market to receiver
event FeeClaimed(address indexed account, address indexed receiver, UFixed6 amount);
event ExposureClaimed(address indexed account, Fixed6 amount);
event ParameterUpdated(MarketParameter newParameter);
event RiskParameterUpdated(RiskParameter newRiskParameter);

Expand Down
57 changes: 38 additions & 19 deletions packages/core/contracts/libs/CheckpointLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ struct CheckpointAccumulationResult {
/// @dev Trade fee accumulated for this checkpoint
UFixed6 tradeFee;

/// @dev Trade price impact accumulated for this checkpoint
Fixed6 offset;
/// @dev Spread accumulated for this checkpoint
Fixed6 spread;

/// @dev Settlement fee charged for this checkpoint
UFixed6 settlementFee;
Expand Down Expand Up @@ -73,10 +73,10 @@ library CheckpointLib {
CheckpointAccumulationResult memory result;

// accumulate
result.collateral = _accumulateCollateral(context.latestPositionLocal, fromVersion, toVersion);
result.collateral = _accumulateCollateral(context.latestPositionLocal, order, fromVersion, toVersion);
result.priceOverride = _accumulatePriceOverride(guarantee, toVersion);
(result.tradeFee, result.subtractiveFee, result.solverFee) = _accumulateFee(order, guarantee, toVersion);
result.offset = _accumulateOffset(order, guarantee, toVersion);
result.spread = _accumulateSpread(order, guarantee, toVersion);
result.settlementFee = _accumulateSettlementFee(order, guarantee, toVersion);
result.liquidationFee = _accumulateLiquidationFee(order, toVersion);

Expand All @@ -89,7 +89,7 @@ library CheckpointLib {
.add(result.collateral) // incorporate collateral change at this settlement
.add(result.priceOverride); // incorporate price override pnl at this settlement
next.transfer = order.collateral;
next.tradeFee = Fixed6Lib.from(result.tradeFee).add(result.offset);
next.tradeFee = Fixed6Lib.from(result.tradeFee).add(result.spread);
next.settlementFee = result.settlementFee.add(result.liquidationFee);

emit IMarket.AccountPositionProcessed(context.account, orderId, order, result);
Expand All @@ -106,7 +106,7 @@ library CheckpointLib {
response.collateral = result.collateral
.add(result.priceOverride)
.sub(Fixed6Lib.from(result.tradeFee))
.sub(result.offset)
.sub(result.spread)
.sub(Fixed6Lib.from(result.settlementFee));
response.liquidationFee = result.liquidationFee;
response.subtractiveFee = result.subtractiveFee;
Expand All @@ -119,12 +119,34 @@ library CheckpointLib {
/// @param toVersion The next version
function _accumulateCollateral(
Position memory fromPosition,
Order memory order,
Version memory fromVersion,
Version memory toVersion
) private pure returns (Fixed6) {
return toVersion.makerValue.accumulated(fromVersion.makerValue, fromPosition.maker)
.add(toVersion.longValue.accumulated(fromVersion.longValue, fromPosition.long))
.add(toVersion.shortValue.accumulated(fromVersion.shortValue, fromPosition.short));
) private pure returns (Fixed6 collateral) {
// calculate position after closes
Position memory closedPosition = fromPosition.clone();
closedPosition.updateClose(order);

// calculate position after order
Position memory toPosition = fromPosition.clone();
toPosition.update(order);

// collateral change pre position change
collateral = collateral
.add(toVersion.makerPreValue.accumulated(fromVersion.makerPreValue, fromPosition.maker))
.add(toVersion.longPreValue.accumulated(fromVersion.longPreValue, fromPosition.long))
.add(toVersion.shortPreValue.accumulated(fromVersion.shortPreValue, fromPosition.short));

// collateral change after applying closing portion of order
collateral = collateral
.add(toVersion.makerCloseValue.accumulated(fromVersion.makerCloseValue, closedPosition.maker))
.add(toVersion.longCloseValue.accumulated(fromVersion.longCloseValue, closedPosition.long))
.add(toVersion.shortCloseValue.accumulated(fromVersion.shortCloseValue, closedPosition.short));

// collateral change after applying entire order
collateral = collateral
.add(toVersion.longPostValue.accumulated(fromVersion.longPostValue, toPosition.long))
.add(toVersion.shortPostValue.accumulated(fromVersion.shortPostValue, toPosition.short));
}

/// @notice Accumulate trade fees for the next position
Expand Down Expand Up @@ -161,26 +183,23 @@ library CheckpointLib {

tradeFee = makerFee.add(takerFee);
subtractiveFee = makerSubtractiveFee.add(takerSubtractiveFee).sub(solverFee);

}

/// @notice Accumulate price offset for the next position
/// @dev This includes adjustment for linear, proportional, and adiabatic order fees
/// @notice Accumulate spread charged for the next position
/// @param order The next order
/// @param guarantee The next guarantee
/// @param toVersion The next version
function _accumulateOffset(
function _accumulateSpread(
Order memory order,
Guarantee memory guarantee,
Version memory toVersion
) private pure returns (Fixed6) {
(UFixed6 takerPos, UFixed6 takerNeg) =
(order.takerPos().sub(guarantee.takerPos), order.takerNeg().sub(guarantee.takerNeg));
(UFixed6 exposurePos, UFixed6 exposureNeg) = order.exposure(guarantee, toVersion);

// flip sign because we want the accumulator to round up correctly, but need charged spread to be positive
return Fixed6Lib.ZERO
.sub(toVersion.makerOffset.accumulated(Accumulator6(Fixed6Lib.ZERO), order.makerTotal()))
.sub(toVersion.takerPosOffset.accumulated(Accumulator6(Fixed6Lib.ZERO), takerPos))
.sub(toVersion.takerNegOffset.accumulated(Accumulator6(Fixed6Lib.ZERO), takerNeg));
.sub(toVersion.spreadPos.accumulated(Accumulator6(Fixed6Lib.ZERO), exposurePos))
.sub(toVersion.spreadNeg.accumulated(Accumulator6(Fixed6Lib.ZERO), exposureNeg));
}


Expand Down
Loading
Loading