-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add account subscription interface
- Loading branch information
Showing
18 changed files
with
413 additions
and
370 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .get_accounts import * | ||
from .types import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .drift_client import * | ||
from .user import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
from anchorpy import Program | ||
from solana.publickey import PublicKey | ||
from solana.rpc.commitment import Commitment | ||
|
||
from driftpy.accounts import get_state_account_and_slot, get_spot_market_account_and_slot, \ | ||
get_perp_market_account_and_slot | ||
from driftpy.accounts.oracle import get_oracle_price_data_and_slot | ||
from driftpy.accounts.types import DriftClientAccountSubscriber, DataAndSlot | ||
from typing import Optional | ||
|
||
from driftpy.types import PerpMarket, SpotMarket, OraclePriceData, State | ||
|
||
|
||
class CachedDriftClientAccountSubscriber(DriftClientAccountSubscriber): | ||
def __init__(self, program: Program, commitment: Commitment = "confirmed"): | ||
self.program = program | ||
self.commitment = commitment | ||
self.cache = None | ||
|
||
async def update_cache(self): | ||
if self.cache is None: | ||
self.cache = {} | ||
|
||
state_and_slot = await get_state_account_and_slot(self.program) | ||
self.cache["state"] = state_and_slot | ||
|
||
oracle_data = {} | ||
|
||
spot_markets = [] | ||
for i in range(state_and_slot.data.number_of_spot_markets): | ||
spot_market_and_slot = await get_spot_market_account_and_slot(self.program, i) | ||
spot_markets.append(spot_market_and_slot) | ||
|
||
oracle_price_data_and_slot = await get_oracle_price_data_and_slot( | ||
self.program.provider.connection, | ||
spot_market_and_slot.data.oracle, | ||
spot_market_and_slot.data.oracle_source | ||
|
||
) | ||
oracle_data[str(spot_market_and_slot.data.oracle)] = oracle_price_data_and_slot | ||
|
||
self.cache["spot_markets"] = spot_markets | ||
|
||
perp_markets = [] | ||
for i in range(state_and_slot.data.number_of_markets): | ||
perp_market_and_slot = await get_perp_market_account_and_slot(self.program, i) | ||
perp_markets.append(perp_market_and_slot) | ||
|
||
oracle_price_data_and_slot = await get_oracle_price_data_and_slot( | ||
self.program.provider.connection, | ||
perp_market_and_slot.data.amm.oracle, | ||
perp_market_and_slot.data.amm.oracle_source | ||
) | ||
oracle_data[str(perp_market_and_slot.data.amm.oracle)] = oracle_price_data_and_slot | ||
|
||
self.cache["perp_markets"] = perp_markets | ||
|
||
self.cache["oracle_price_data"] = oracle_data | ||
|
||
async def get_state_account_and_slot(self) -> Optional[DataAndSlot[State]]: | ||
await self.cache_if_needed() | ||
return self.cache["state"] | ||
|
||
async def get_perp_market_and_slot(self, market_index: int) -> Optional[DataAndSlot[PerpMarket]]: | ||
await self.cache_if_needed() | ||
return self.cache["perp_markets"][market_index] | ||
|
||
async def get_spot_market_and_slot(self, market_index: int) -> Optional[DataAndSlot[SpotMarket]]: | ||
await self.cache_if_needed() | ||
return self.cache["spot_markets"][market_index] | ||
|
||
async def get_oracle_data_and_slot(self, oracle: PublicKey) -> Optional[DataAndSlot[OraclePriceData]]: | ||
await self.cache_if_needed() | ||
return self.cache["oracle_price_data"][str(oracle)] | ||
|
||
async def cache_if_needed(self): | ||
if self.cache is None: | ||
await self.update_cache() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from typing import Optional | ||
|
||
from anchorpy import Program | ||
from solana.publickey import PublicKey | ||
from solana.rpc.commitment import Commitment | ||
|
||
from driftpy.accounts import get_user_account_and_slot | ||
from driftpy.accounts import UserAccountSubscriber, DataAndSlot | ||
from driftpy.types import User | ||
|
||
|
||
class CachedUserAccountSubscriber(UserAccountSubscriber): | ||
def __init__(self, user_pubkey: PublicKey, program: Program, commitment: Commitment = "confirmed"): | ||
self.program = program | ||
self.commitment = commitment | ||
self.user_pubkey = user_pubkey | ||
self.user_and_slot = None | ||
|
||
async def update_cache(self): | ||
user_and_slot = await get_user_account_and_slot(self.program, self.user_pubkey) | ||
self.user_and_slot = user_and_slot | ||
|
||
async def get_user_account_and_slot(self) -> Optional[DataAndSlot[User]]: | ||
await self.cache_if_needed() | ||
return self.user_and_slot | ||
|
||
async def cache_if_needed(self): | ||
if self.user_and_slot is None: | ||
await self.update_cache() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import base64 | ||
from typing import cast | ||
from solana.publickey import PublicKey | ||
from anchorpy import Program, ProgramAccount | ||
from solana.rpc.commitment import Commitment | ||
|
||
from driftpy.types import * | ||
from driftpy.addresses import * | ||
from .types import DataAndSlot, T | ||
|
||
|
||
async def get_account_data_and_slot(address: PublicKey, program: Program, commitment: Commitment = "processed") -> Optional[ | ||
DataAndSlot[T]]: | ||
account_info = await program.provider.connection.get_account_info( | ||
address, | ||
encoding="base64", | ||
commitment=commitment, | ||
) | ||
|
||
if not account_info["result"]["value"]: | ||
return None | ||
|
||
slot = account_info["result"]["context"]["slot"] | ||
data = base64.b64decode(account_info["result"]["value"]["data"][0]) | ||
|
||
decoded_data = program.coder.accounts.decode(data) | ||
|
||
return DataAndSlot(slot, decoded_data) | ||
|
||
|
||
async def get_state_account_and_slot(program: Program) -> DataAndSlot[State]: | ||
state_public_key = get_state_public_key(program.program_id) | ||
return await get_account_data_and_slot(state_public_key, program) | ||
|
||
|
||
async def get_state_account(program: Program) -> State: | ||
return (await get_state_account_and_slot(program)).data | ||
|
||
|
||
async def get_if_stake_account( | ||
program: Program, authority: PublicKey, spot_market_index: int | ||
) -> InsuranceFundStake: | ||
if_stake_pk = get_insurance_fund_stake_public_key( | ||
program.program_id, authority, spot_market_index | ||
) | ||
response = await program.account["InsuranceFundStake"].fetch(if_stake_pk) | ||
return cast(InsuranceFundStake, response) | ||
|
||
|
||
async def get_user_stats_account( | ||
program: Program, | ||
authority: PublicKey, | ||
) -> UserStats: | ||
user_stats_public_key = get_user_stats_account_public_key( | ||
program.program_id, | ||
authority, | ||
) | ||
response = await program.account["UserStats"].fetch(user_stats_public_key) | ||
return cast(UserStats, response) | ||
|
||
async def get_user_account_and_slot( | ||
program: Program, | ||
user_public_key: PublicKey, | ||
) -> DataAndSlot[User]: | ||
return await get_account_data_and_slot(user_public_key, program) | ||
|
||
async def get_user_account( | ||
program: Program, | ||
user_public_key: PublicKey, | ||
) -> User: | ||
return (await get_user_account_and_slot(program, user_public_key)).data | ||
|
||
|
||
async def get_perp_market_account_and_slot(program: Program, market_index: int) -> Optional[DataAndSlot[PerpMarket]]: | ||
perp_market_public_key = get_perp_market_public_key(program.program_id, market_index) | ||
return await get_account_data_and_slot(perp_market_public_key, program) | ||
|
||
|
||
async def get_perp_market_account(program: Program, market_index: int) -> PerpMarket: | ||
return (await get_perp_market_account_and_slot(program, market_index)).data | ||
|
||
|
||
async def get_all_perp_market_accounts(program: Program) -> list[ProgramAccount]: | ||
return await program.account["PerpMarket"].all() | ||
|
||
|
||
async def get_spot_market_account_and_slot( | ||
program: Program, spot_market_index: int | ||
) -> DataAndSlot[SpotMarket]: | ||
spot_market_public_key = get_spot_market_public_key( | ||
program.program_id, spot_market_index | ||
) | ||
return await get_account_data_and_slot(spot_market_public_key, program) | ||
|
||
|
||
async def get_spot_market_account( | ||
program: Program, spot_market_index: int | ||
) -> SpotMarket: | ||
return (await get_spot_market_account_and_slot(program, spot_market_index)).data | ||
|
||
|
||
async def get_all_spot_market_accounts(program: Program) -> list[ProgramAccount]: | ||
return await program.account["SpotMarket"].all() |
Oops, something went wrong.