use crate::client::LightconeClient;
use crate::domain::position::builders::{
DepositBuilder, DepositToGlobalBuilder, ExtendPositionTokensBuilder,
GlobalToMarketDepositBuilder, InitPositionTokensBuilder, MergeBuilder, RedeemWinningsBuilder,
WithdrawBuilder, WithdrawFromGlobalBuilder, WithdrawFromPositionBuilder,
};
use crate::domain::position::wire::{MarketPositionsResponse, PositionsResponse};
use crate::domain::position::DepositTokenBalance;
use crate::error::SdkError;
use crate::http::RetryPolicy;
use crate::program::instructions;
use crate::program::types::{
ClosePositionAltParams, ClosePositionTokenAccountsParams, DepositToGlobalAltContext,
DepositToGlobalParams, ExtendPositionTokensParams, GlobalToMarketDepositParams,
InitPositionTokensParams, RedeemWinningsParams, WithdrawFromGlobalParams,
WithdrawFromPositionParams,
};
use crate::shared::PubkeyStr;
use solana_instruction::Instruction;
use solana_pubkey::Pubkey;
use solana_transaction::Transaction;
use std::collections::HashMap;
pub struct Positions<'a> {
pub(crate) client: &'a LightconeClient,
}
impl<'a> Positions<'a> {
pub fn pda(&self, owner: &Pubkey, market: &Pubkey) -> Pubkey {
crate::program::pda::get_position_pda(owner, market, &self.client.program_id).0
}
pub async fn get(&self, user_pubkey: &str) -> Result<PositionsResponse, SdkError> {
let url = format!(
"{}/api/users/{}/positions",
self.client.http.base_url(),
user_pubkey
);
self.client.http.get(&url, RetryPolicy::Idempotent).await
}
pub async fn get_for_market(
&self,
user_pubkey: &str,
market_pubkey: &str,
) -> Result<MarketPositionsResponse, SdkError> {
let url = format!(
"{}/api/users/{}/markets/{}/positions",
self.client.http.base_url(),
user_pubkey,
market_pubkey
);
self.client.http.get(&url, RetryPolicy::Idempotent).await
}
pub async fn positions(&self) -> Result<PositionsResponse, SdkError> {
let url = format!("{}/api/users/positions", self.client.http.base_url());
self.client.http.get(&url, RetryPolicy::Idempotent).await
}
pub async fn positions_with_cookies(
&self,
cookie_header: &str,
) -> Result<PositionsResponse, SdkError> {
let url = format!("{}/api/users/positions", self.client.http.base_url());
self.client
.http
.get_with_cookies(&url, RetryPolicy::Idempotent, cookie_header)
.await
}
pub async fn positions_for_market(
&self,
market_pubkey: &str,
) -> Result<MarketPositionsResponse, SdkError> {
let url = format!(
"{}/api/users/markets/{}/positions",
self.client.http.base_url(),
market_pubkey
);
self.client.http.get(&url, RetryPolicy::Idempotent).await
}
pub async fn positions_for_market_with_cookies(
&self,
market_pubkey: &str,
cookie_header: &str,
) -> Result<MarketPositionsResponse, SdkError> {
let url = format!(
"{}/api/users/markets/{}/positions",
self.client.http.base_url(),
market_pubkey
);
self.client
.http
.get_with_cookies(&url, RetryPolicy::Idempotent, cookie_header)
.await
}
pub async fn deposit_token_balances(
&self,
) -> Result<HashMap<PubkeyStr, DepositTokenBalance>, SdkError> {
let url = format!(
"{}/api/users/deposit-token-balances",
self.client.http.base_url()
);
self.client.http.get(&url, RetryPolicy::Idempotent).await
}
pub async fn deposit_token_balances_with_cookies(
&self,
cookie_header: &str,
) -> Result<HashMap<PubkeyStr, DepositTokenBalance>, SdkError> {
let url = format!(
"{}/api/users/deposit-token-balances",
self.client.http.base_url()
);
self.client
.http
.get_with_cookies(&url, RetryPolicy::Idempotent, cookie_header)
.await
}
pub fn redeem_winnings_ix(
&self,
params: &RedeemWinningsParams,
outcome_index: u8,
) -> Instruction {
let pid = &self.client.program_id;
instructions::build_redeem_winnings_ix(params, outcome_index, pid)
}
pub fn redeem_winnings_tx(
&self,
params: RedeemWinningsParams,
outcome_index: u8,
) -> Result<Transaction, SdkError> {
let ix = self.redeem_winnings_ix(¶ms, outcome_index);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.user)))
}
pub fn withdraw_from_position_ix(&self, params: &WithdrawFromPositionParams) -> Instruction {
let pid = &self.client.program_id;
instructions::build_withdraw_from_position_ix(params, pid)
}
pub fn withdraw_from_position_tx(
&self,
params: WithdrawFromPositionParams,
) -> Result<Transaction, SdkError> {
let ix = self.withdraw_from_position_ix(¶ms);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.user)))
}
pub fn init_position_tokens_ix(
&self,
params: &InitPositionTokensParams,
num_outcomes: u8,
) -> Instruction {
let pid = &self.client.program_id;
instructions::build_init_position_tokens_ix(params, num_outcomes, pid)
}
pub fn init_position_tokens_tx(
&self,
params: InitPositionTokensParams,
num_outcomes: u8,
) -> Result<Transaction, SdkError> {
let ix = self.init_position_tokens_ix(¶ms, num_outcomes);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.payer)))
}
pub fn extend_position_tokens_ix(
&self,
params: &ExtendPositionTokensParams,
num_outcomes: u8,
) -> Result<Instruction, SdkError> {
let pid = &self.client.program_id;
Ok(instructions::build_extend_position_tokens_ix(
params,
num_outcomes,
pid,
)?)
}
pub fn extend_position_tokens_tx(
&self,
params: ExtendPositionTokensParams,
num_outcomes: u8,
) -> Result<Transaction, SdkError> {
let ix = self.extend_position_tokens_ix(¶ms, num_outcomes)?;
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.operator)))
}
pub fn close_position_alt_ix(&self, params: &ClosePositionAltParams) -> Instruction {
let pid = &self.client.program_id;
instructions::build_close_position_alt_ix(params, pid)
}
pub fn close_position_alt_tx(
&self,
params: ClosePositionAltParams,
) -> Result<Transaction, SdkError> {
let ix = self.close_position_alt_ix(¶ms);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.operator)))
}
pub fn close_position_token_accounts_ix(
&self,
params: &ClosePositionTokenAccountsParams,
num_outcomes: u8,
) -> Result<Instruction, SdkError> {
let pid = &self.client.program_id;
Ok(instructions::build_close_position_token_accounts_ix(
params,
num_outcomes,
pid,
)?)
}
pub fn close_position_token_accounts_tx(
&self,
params: ClosePositionTokenAccountsParams,
num_outcomes: u8,
) -> Result<Transaction, SdkError> {
let ix = self.close_position_token_accounts_ix(¶ms, num_outcomes)?;
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.operator)))
}
pub fn deposit_to_global_ix(&self, params: &DepositToGlobalParams) -> Instruction {
let pid = &self.client.program_id;
instructions::build_deposit_to_global_ix(params, pid)
}
pub fn deposit_to_global_ix_with_alt(
&self,
params: &DepositToGlobalParams,
alt_context: DepositToGlobalAltContext,
) -> Instruction {
let pid = &self.client.program_id;
instructions::build_deposit_to_global_ix_with_alt(params, alt_context, pid)
}
pub fn deposit_to_global_tx(
&self,
params: DepositToGlobalParams,
) -> Result<Transaction, SdkError> {
let ix = self.deposit_to_global_ix(¶ms);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.user)))
}
pub fn deposit_to_global_tx_with_alt(
&self,
params: DepositToGlobalParams,
alt_context: DepositToGlobalAltContext,
) -> Result<Transaction, SdkError> {
let ix = self.deposit_to_global_ix_with_alt(¶ms, alt_context);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.user)))
}
pub fn global_to_market_deposit_ix(
&self,
params: &GlobalToMarketDepositParams,
num_outcomes: u8,
) -> Instruction {
let pid = &self.client.program_id;
instructions::build_global_to_market_deposit_ix(params, num_outcomes, pid)
}
pub fn global_to_market_deposit_tx(
&self,
params: GlobalToMarketDepositParams,
num_outcomes: u8,
) -> Result<Transaction, SdkError> {
let ix = self.global_to_market_deposit_ix(¶ms, num_outcomes);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.user)))
}
pub fn withdraw_from_global_ix(&self, params: &WithdrawFromGlobalParams) -> Instruction {
let pid = &self.client.program_id;
instructions::build_withdraw_from_global_ix(params, pid)
}
pub fn withdraw_from_global_tx(
&self,
params: WithdrawFromGlobalParams,
) -> Result<Transaction, SdkError> {
let ix = self.withdraw_from_global_ix(¶ms);
Ok(Transaction::new_with_payer(&[ix], Some(¶ms.user)))
}
pub async fn deposit(&self) -> DepositBuilder<'a> {
let deposit_source = self.client.deposit_source().await;
DepositBuilder::new(self.client, deposit_source)
}
pub fn merge(&self) -> MergeBuilder<'a> {
MergeBuilder::new(self.client)
}
pub async fn withdraw(&self) -> WithdrawBuilder<'a> {
let deposit_source = self.client.deposit_source().await;
WithdrawBuilder::new(self.client, deposit_source)
}
pub fn redeem_winnings(&self) -> RedeemWinningsBuilder<'a> {
RedeemWinningsBuilder::new(self.client)
}
pub fn withdraw_from_position(&self) -> WithdrawFromPositionBuilder<'a> {
WithdrawFromPositionBuilder::new(self.client)
}
pub fn init_position_tokens(&self) -> InitPositionTokensBuilder<'a> {
InitPositionTokensBuilder::new(self.client)
}
pub fn extend_position_tokens(&self) -> ExtendPositionTokensBuilder<'a> {
ExtendPositionTokensBuilder::new(self.client)
}
pub fn deposit_to_global(&self) -> DepositToGlobalBuilder<'a> {
DepositToGlobalBuilder::new(self.client)
}
pub fn withdraw_from_global(&self) -> WithdrawFromGlobalBuilder<'a> {
WithdrawFromGlobalBuilder::new(self.client)
}
pub fn global_to_market_deposit(&self) -> GlobalToMarketDepositBuilder<'a> {
GlobalToMarketDepositBuilder::new(self.client)
}
}
#[cfg(feature = "solana-rpc")]
impl<'a> Positions<'a> {
pub async fn get_onchain(
&self,
owner: &Pubkey,
market: &Pubkey,
) -> Result<Option<crate::program::accounts::Position>, SdkError> {
let rpc = crate::rpc::resolve_solana_rpc(self.client).await?;
let pda = self.pda(owner, market);
match rpc.get_account(&pda).await {
Ok(account) => Ok(Some(crate::program::accounts::Position::deserialize(
&account.data,
)?)),
Err(_) => Ok(None),
}
}
}