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

frank/fuel #192

Merged
merged 4 commits into from
Jul 25, 2024
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
2 changes: 1 addition & 1 deletion protocol-v2
Submodule protocol-v2 updated 73 files
+36 −1 .github/workflows/main.yml
+3 −0 Anchor.toml
+30 −9 CHANGELOG.md
+13 −3 Cargo.lock
+4 −3 programs/drift/Cargo.toml
+94 −53 programs/drift/src/controller/insurance.rs
+1 −1 programs/drift/src/controller/liquidation.rs
+97 −14 programs/drift/src/controller/orders.rs
+10 −9 programs/drift/src/controller/orders/fuel_tests.rs
+58 −15 programs/drift/src/controller/pda.rs
+12 −0 programs/drift/src/error.rs
+5 −0 programs/drift/src/ids.rs
+417 −14 programs/drift/src/instructions/admin.rs
+32 −7 programs/drift/src/instructions/keeper.rs
+86 −5 programs/drift/src/instructions/pyth_pull_oracle.rs
+49 −4 programs/drift/src/instructions/user.rs
+47 −0 programs/drift/src/lib.rs
+0 −3 programs/drift/src/math/amm.rs
+1 −0 programs/drift/src/math/casting.rs
+1 −1 programs/drift/src/math/constants.rs
+21 −2 programs/drift/src/math/fuel.rs
+60 −0 programs/drift/src/math/fuel/tests.rs
+2 −1 programs/drift/src/math/fulfillment.rs
+4 −4 programs/drift/src/math/serum.rs
+1 −0 programs/drift/src/state/events.rs
+1 −0 programs/drift/src/state/fulfillment_params/mod.rs
+491 −0 programs/drift/src/state/fulfillment_params/openbook_v2.rs
+13 −0 programs/drift/src/state/oracle_map.rs
+4 −2 programs/drift/src/state/order_params.rs
+39 −1 programs/drift/src/state/order_params/tests.rs
+5 −3 programs/drift/src/state/paused_operations.rs
+4 −0 programs/drift/src/state/perp_market.rs
+6 −2 programs/drift/src/state/spot_market.rs
+42 −34 programs/drift/src/state/user.rs
+34 −0 programs/drift/src/state/user/tests.rs
+1 −1 programs/drift/src/validation/fee_structure.rs
+6 −2 programs/drift/src/validation/fee_structure/tests.rs
+6 −0 programs/drift/src/validation/whitelist.rs
+23 −0 programs/openbook_v2/Cargo.toml
+10 −0 programs/openbook_v2/README.md
+420 −0 programs/openbook_v2/src/account.rs
+2 −0 programs/openbook_v2/src/constants.rs
+26 −0 programs/openbook_v2/src/context.rs
+76 −0 programs/openbook_v2/src/lib.rs
+1 −1 sdk/VERSION
+1 −1 sdk/package.json
+15 −0 sdk/src/addresses/pda.ts
+120 −10 sdk/src/adminClient.ts
+13 −0 sdk/src/bankrun/bankrunConnection.ts
+2 −1 sdk/src/constants/numericConstants.ts
+114 −114 sdk/src/constants/perpMarkets.ts
+54 −40 sdk/src/constants/spotMarkets.ts
+203 −16 sdk/src/driftClient.ts
+344 −10 sdk/src/idl/drift.json
+3,854 −0 sdk/src/idl/openbook.json
+628 −0 sdk/src/idl/pyth_solana_receiver.json
+15 −1 sdk/src/math/fuel.ts
+28 −7 sdk/src/types.ts
+64 −7 sdk/src/user.ts
+214 −0 sdk/tests/ci/verifyConstants.ts
+30 −0 sdk/tests/dlob/helpers.ts
+1 −0 sdk/tests/user/helpers.ts
+2 −0 sdk/tests/user/test.ts
+2 −1 test-scripts/run-anchor-tests.sh
+1 −1 test-scripts/single-anchor-test.sh
+ tests/fixtures/openbook.so
+ tests/fixtures/pyth_solana_receiver.so
+153 −12 tests/fuel.ts
+257 −0 tests/openbookHelpers.ts
+372 −0 tests/openbookTest.ts
+1 −1 tests/perpLpRiskMitigation.ts
+17 −1 tests/pythPull.ts
+22 −1 tests/triggerSpotOrder.ts
5 changes: 5 additions & 0 deletions src/driftpy/constants/numeric_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,8 @@
OPEN_ORDER_MARGIN_REQUIREMENT = QUOTE_PRECISION / 100

LIQUIDATION_PCT_PRECISION = TEN_THOUSAND

FUEL_START_TS = 1722384000
FUEL_WINDOW = 60 * 60 * 24 * 28

GOV_SPOT_MARKET_INDEX = 15
109 changes: 109 additions & 0 deletions src/driftpy/drift_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
from driftpy.math.margin import *
from driftpy.math.spot_balance import get_strict_token_value
from driftpy.math.spot_market import *
from driftpy.math.fuel import (
calculate_spot_fuel_bonus,
calculate_perp_fuel_bonus,
calculate_insurance_fuel_bonus,
)
from driftpy.accounts.oracle import *
from driftpy.math.spot_position import (
get_worst_case_token_amounts,
Expand Down Expand Up @@ -1290,3 +1295,107 @@ def get_net_spot_market_value(
)

return total_asset_value - total_liability_value

def get_fuel_bonus(
self, now: int, include_settled: bool = True, include_unsettled: bool = True
) -> dict[str, int]:
user_account = self.get_user_account()
total_fuel = {
"insurance_fuel": 0,
"taker_fuel": 0,
"maker_fuel": 0,
"deposit_fuel": 0,
"borrow_fuel": 0,
"position_fuel": 0,
}

if include_settled:
user_stats = self.drift_client.get_user_stats().get_account()
total_fuel["taker_fuel"] += user_stats.fuel_taker
total_fuel["maker_fuel"] += user_stats.fuel_maker
total_fuel["deposit_fuel"] += user_stats.fuel_deposits
total_fuel["borrow_fuel"] += user_stats.fuel_borrows
total_fuel["position_fuel"] += user_stats.fuel_positions

if include_unsettled:
# fuel bonus numerator is the time since the last fuel bonus update, capped at the start of the fuel program
fuel_bonus_numerator = max(
now - max(user_account.last_fuel_bonus_update_ts, FUEL_START_TS), 0
)
if fuel_bonus_numerator > 0:
for spot_position in self.get_active_spot_positions():
spot_market_account = self.drift_client.get_spot_market_account(
spot_position.market_index
)
token_amount = self.get_token_amount(spot_position.market_index)
oracle_price_data = self.get_oracle_data_for_spot_market(
spot_position.market_index
)
twap_5min = calculate_live_oracle_twap(
spot_market_account.historical_oracle_data,
oracle_price_data,
now,
FIVE_MINUTE,
)
strict_oracle_price = StrictOraclePrice(
oracle_price_data.price, twap_5min
)
signed_token_value = get_strict_token_value(
token_amount, spot_market_account.decimals, strict_oracle_price
)
spot_fuel = calculate_spot_fuel_bonus(
spot_market_account, signed_token_value, fuel_bonus_numerator
)
if signed_token_value > 0:
total_fuel["deposit_fuel"] += spot_fuel
else:
total_fuel["borrow_fuel"] += spot_fuel

for perp_position in self.get_active_perp_positions():
oracle_price_data = self.get_oracle_data_for_perp_market(
perp_position.market_index
)
perp_market_account = self.drift_client.get_perp_market_account(
perp_position.market_index
)
base_asset_value = self.get_perp_position_value(
perp_position.market_index, oracle_price_data, False
)
total_fuel["position_fuel"] += calculate_perp_fuel_bonus(
perp_market_account, base_asset_value, fuel_bonus_numerator
)

user_stats = self.drift_client.get_user_stats().get_account()

if user_stats.if_staked_gov_token_amount > 0:
spot_market_account = self.drift_client.get_spot_market_account(
GOV_SPOT_MARKET_INDEX
)
fuel_bonus_numerator_user_stats = (
now - user_stats.last_fuel_bonus_update_ts
)
total_fuel["insurance_fuel"] += calculate_insurance_fuel_bonus(
spot_market_account,
user_stats.if_staked_gov_token_amount,
fuel_bonus_numerator_user_stats,
)

return total_fuel

def get_perp_position_value(
self,
market_index: int,
oracle_price_data: OraclePriceData,
include_open_orders: bool = False,
):
perp_position = self.get_perp_position_with_lp_settle(market_index)[
0
] or self.get_empty_position(market_index)

market = self.drift_client.get_perp_market_account(perp_position.market_index)

perp_position_value = calculate_base_asset_value_with_oracle(
market, perp_position, oracle_price_data, include_open_orders
)

return perp_position_value
7 changes: 2 additions & 5 deletions src/driftpy/idl/drift.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "2.85.0",
"version": "2.86.0",
"name": "drift",
"instructions": [
{
Expand Down Expand Up @@ -12762,8 +12762,5 @@
"name": "InvalidOpenbookV2Market",
"msg": "InvalidOpenbookV2Market"
}
],
"metadata": {
"address": "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH"
}
]
}
56 changes: 56 additions & 0 deletions src/driftpy/math/fuel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from driftpy.types import SpotMarketAccount, PerpMarketAccount
from driftpy.constants.numeric_constants import QUOTE_PRECISION, FUEL_WINDOW


def calculate_insurance_fuel_bonus(
spot_market: SpotMarketAccount, token_stake_amount: int, fuel_bonus_numerator: int
) -> int:
insurance_fund_fuel = (
abs(token_stake_amount) * fuel_bonus_numerator
) * spot_market.fuel_boost_insurance
insurace_fund_fuel_per_day = insurance_fund_fuel // FUEL_WINDOW
insurance_fund_fuel_scaled = insurace_fund_fuel_per_day // (QUOTE_PRECISION // 10)

return insurance_fund_fuel_scaled


def calculate_spot_fuel_bonus(
spot_market: SpotMarketAccount, signed_token_value: int, fuel_bonus_numerator: int
) -> int:
spot_fuel_scaled: int

# dust
if abs(signed_token_value) <= QUOTE_PRECISION:
spot_fuel_scaled = 0
elif signed_token_value > 0:
deposit_fuel = (
abs(signed_token_value) * fuel_bonus_numerator
) * spot_market.fuel_boost_deposits
deposit_fuel_per_day = deposit_fuel // FUEL_WINDOW
spot_fuel_scaled = deposit_fuel_per_day // (QUOTE_PRECISION // 10)
else:
borrow_fuel = (
abs(signed_token_value) * fuel_bonus_numerator
) * spot_market.fuel_boost_borrows
borrow_fuel_per_day = borrow_fuel // FUEL_WINDOW
spot_fuel_scaled = borrow_fuel_per_day // (QUOTE_PRECISION // 10)

return spot_fuel_scaled


def calculate_perp_fuel_bonus(
perp_market: PerpMarketAccount, base_asset_value: int, fuel_bonus_numerator: int
) -> int:
perp_fuel_scaled: int

# dust
if abs(base_asset_value) <= QUOTE_PRECISION:
perp_fuel_scaled = 0
else:
perp_fuel = (
abs(base_asset_value) * fuel_bonus_numerator
) * perp_market.fuel_boost_position
perp_fuel_per_day = perp_fuel // FUEL_WINDOW
perp_fuel_scaled = perp_fuel_per_day // (QUOTE_PRECISION // 10)

return perp_fuel_scaled
34 changes: 29 additions & 5 deletions src/driftpy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from typing import Optional
from urllib.parse import urlparse, urlunparse

from solders.pubkey import Pubkey # type: ignore
from solders.pubkey import Pubkey

from driftpy.constants.numeric_constants import FUEL_START_TS # type: ignore


def is_variant(enum, type: str) -> bool:
Expand Down Expand Up @@ -700,7 +702,10 @@ class PerpMarketAccount:
padding1: int = 0
quote_spot_market_index: Optional[int] = None
fee_adjustment: Optional[int] = None
padding: list[int] = field(default_factory=lambda: [0] * 46)
fuel_boost_taker: Optional[int] = None
fuel_boost_maker: Optional[int] = None
fuel_boost_position: Optional[int] = None
padding: list[int] = field(default_factory=lambda: [0] * 43)


@dataclass
Expand Down Expand Up @@ -774,12 +779,21 @@ class SpotMarketAccount:
oracle_source: OracleSource
status: MarketStatus
asset_tier: AssetTier
padding1: list[int] = field(default_factory=lambda: [0] * 6)
paused_operations: int
if_paused_operations: int
fee_adjustment: int
max_token_borrows_fraction: int
flash_loan_amount: Optional[int] = None
flash_loan_initial_token_amount: Optional[int] = None
total_swap_fee: Optional[int] = None
scale_initial_asset_weight_start: Optional[int] = None
padding: list[int] = field(default_factory=lambda: [0] * 48)
min_borrow_rate: Optional[int] = None
fuel_boost_deposits: Optional[int] = None
fuel_boost_borrows: Optional[int] = None
fuel_boost_taker: Optional[int] = None
fuel_boost_maker: Optional[int] = None
fuel_boost_insurance: Optional[int] = None
padding: list[int] = field(default_factory=lambda: [0] * 42)


@dataclass
Expand Down Expand Up @@ -857,6 +871,7 @@ class UserAccount:
has_open_order: bool
open_auctions: int
has_open_auction: bool
last_fuel_bonus_update_ts: int
padding: list[int] = field(default_factory=lambda: [0] * 21)


Expand Down Expand Up @@ -893,7 +908,16 @@ class UserStatsAccount:
number_of_sub_accounts_created: int
is_referrer: bool
disable_update_perp_bid_ask_twap: bool
padding: list[int] = field(default_factory=lambda: [0] * 50)
padding1: list[int] = (field(default_factory=lambda: [0] * 2),)
last_fuel_bonus_update_ts: int = (0,)
fuel_insurance: int = (0,)
fuel_deposits: int = (0,)
fuel_borrows: int = (0,)
fuel_positions: int = (0,)
fuel_taker: int = (0,)
fuel_maker: int = (0,)
if_staked_gov_token_amount: int = (0,)
padding: list[int] = field(default_factory=lambda: [0] * 12)


@dataclass
Expand Down
18 changes: 12 additions & 6 deletions tests/dlob_test_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,11 @@
oracle_source=OracleSource.Pyth(),
historical_oracle_data=mock_historical_oracle_data,
historical_index_data=mock_historical_index_data,
padding1=[0] * 6,
padding=[0] * 48,
expiry_ts=0,
paused_operations=0,
if_paused_operations=0,
fee_adjustment=0,
max_token_borrows_fraction=0,
),
SpotMarketAccount(
status=MarketStatus.Active(),
Expand Down Expand Up @@ -360,9 +362,11 @@
oracle_source=OracleSource.Pyth(),
historical_oracle_data=mock_historical_oracle_data,
historical_index_data=mock_historical_index_data,
padding1=[0] * 6,
padding=[0] * 48,
expiry_ts=0,
paused_operations=0,
if_paused_operations=0,
fee_adjustment=0,
max_token_borrows_fraction=0,
),
SpotMarketAccount(
status=MarketStatus.Active(),
Expand Down Expand Up @@ -415,8 +419,10 @@
oracle_source=OracleSource.Pyth(),
historical_oracle_data=mock_historical_oracle_data,
historical_index_data=mock_historical_index_data,
padding1=[0] * 6,
padding=[0] * 48,
expiry_ts=0,
paused_operations=0,
if_paused_operations=0,
fee_adjustment=0,
max_token_borrows_fraction=0,
),
]
1 change: 1 addition & 0 deletions tests/math/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
has_open_order=False,
open_auctions=0,
has_open_auction=False,
last_fuel_bonus_update_ts=0,
padding=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
)

Expand Down
1 change: 1 addition & 0 deletions update_idl.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
git submodule update --remote --merge --recursive &&
cd protocol-v2/ &&
anchor build &&
cp target/idl/* ../src/driftpy/idl/
Loading