use crate::client::LightconeClient;
use crate::domain::market::Market;
use crate::error::SdkError;
use crate::program::instructions;
use crate::program::types::{
BuildDepositParams, BuildMergeParams, DepositToGlobalAltContext, DepositToGlobalParams,
ExtendPositionTokensParams, GlobalToMarketDepositParams, InitPositionTokensParams,
RedeemWinningsParams, WithdrawFromGlobalParams, WithdrawFromPositionParams,
};
use crate::shared::DepositSource;
use solana_instruction::Instruction;
use solana_pubkey::Pubkey;
use solana_transaction::Transaction;
pub struct DepositBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
market: Option<&'a Market>,
deposit_source: Option<DepositSource>,
}
impl<'a> DepositBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient, deposit_source: DepositSource) -> Self {
Self {
client,
user: None,
mint: None,
amount: None,
market: None,
deposit_source: Some(deposit_source),
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn market(mut self, market: &'a Market) -> Self {
self.market = Some(market);
self
}
pub fn deposit_source(mut self, source: DepositSource) -> Self {
self.deposit_source = Some(source);
self
}
pub fn with_market_deposit_source(mut self, market: &'a Market) -> Self {
self.deposit_source = Some(DepositSource::Market);
self.market = Some(market);
self
}
pub fn with_global_deposit_source(mut self) -> Self {
self.deposit_source = Some(DepositSource::Global);
self
}
pub async fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let source = self
.client
.resolve_deposit_source(self.deposit_source)
.await;
let program_id = &self.client.program_id;
match source {
DepositSource::Global => Ok(instructions::build_deposit_to_global_ix(
&DepositToGlobalParams { user, mint, amount },
program_id,
)),
DepositSource::Market => {
let market = self.market.ok_or(SdkError::MissingMarketContext(
"market is required for Market deposit source",
))?;
let market_pubkey = market
.pubkey
.to_pubkey()
.map_err(|error| SdkError::Validation(error))?;
let num_outcomes = market.outcomes.len() as u8;
Ok(instructions::build_deposit_ix(
&BuildDepositParams {
user,
market: market_pubkey,
deposit_mint: mint,
amount,
},
num_outcomes,
program_id,
))
}
}
}
pub async fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix().await?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx().await?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct MergeBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
market: Option<&'a Market>,
}
impl<'a> MergeBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
user: None,
mint: None,
amount: None,
market: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn market(mut self, market: &'a Market) -> Self {
self.market = Some(market);
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let market = self.market.ok_or(SdkError::MissingMarketContext(
"market is required for merge",
))?;
let market_pubkey = market
.pubkey
.to_pubkey()
.map_err(|error| SdkError::Validation(error))?;
let num_outcomes = market.outcomes.len() as u8;
let program_id = &self.client.program_id;
Ok(instructions::build_merge_ix(
&BuildMergeParams {
user,
market: market_pubkey,
deposit_mint: mint,
amount,
},
num_outcomes,
program_id,
))
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct WithdrawBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
deposit_source: Option<DepositSource>,
market: Option<&'a Market>,
outcome_index: Option<u8>,
}
impl<'a> WithdrawBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient, deposit_source: DepositSource) -> Self {
Self {
client,
user: None,
mint: None,
amount: None,
deposit_source: Some(deposit_source),
market: None,
outcome_index: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn deposit_source(mut self, source: DepositSource) -> Self {
self.deposit_source = Some(source);
self
}
pub fn with_global_deposit_source(mut self) -> Self {
self.deposit_source = Some(DepositSource::Global);
self
}
pub fn with_market_deposit_source(mut self, market: &'a Market) -> Self {
self.deposit_source = Some(DepositSource::Market);
self.market = Some(market);
self
}
pub fn market(mut self, market: &'a Market) -> Self {
self.market = Some(market);
self
}
pub fn outcome_index(mut self, outcome_index: u8) -> Self {
self.outcome_index = Some(outcome_index);
self
}
pub async fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let source = self
.client
.resolve_deposit_source(self.deposit_source)
.await;
let program_id = &self.client.program_id;
match source {
DepositSource::Global => Ok(instructions::build_withdraw_from_global_ix(
&WithdrawFromGlobalParams { user, mint, amount },
program_id,
)),
DepositSource::Market => {
let market = self.market.ok_or(SdkError::MissingMarketContext(
"market is required for Market withdrawal",
))?;
let market_pubkey = market
.pubkey
.to_pubkey()
.map_err(|error| SdkError::Validation(error))?;
let outcome_index = self.outcome_index.ok_or_else(|| {
SdkError::Validation("outcome_index is required for Market withdrawal".into())
})?;
Ok(instructions::build_withdraw_from_position_ix(
&WithdrawFromPositionParams {
user,
market: market_pubkey,
mint,
amount,
outcome_index,
},
program_id,
))
}
}
}
pub async fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix().await?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx().await?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct RedeemWinningsBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
market: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
outcome_index: Option<u8>,
}
impl<'a> RedeemWinningsBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
user: None,
market: None,
mint: None,
amount: None,
outcome_index: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn market(mut self, market: Pubkey) -> Self {
self.market = Some(market);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn outcome_index(mut self, outcome_index: u8) -> Self {
self.outcome_index = Some(outcome_index);
self
}
pub fn winning_outcome(self, winning_outcome: u8) -> Self {
self.outcome_index(winning_outcome)
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let market = self
.market
.ok_or_else(|| SdkError::Validation("market is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let outcome_index = self
.outcome_index
.ok_or_else(|| SdkError::Validation("outcome_index is required".into()))?;
Ok(instructions::build_redeem_winnings_ix(
&RedeemWinningsParams {
user,
market,
deposit_mint: mint,
amount,
},
outcome_index,
&self.client.program_id,
))
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct WithdrawFromPositionBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
market: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
outcome_index: Option<u8>,
}
impl<'a> WithdrawFromPositionBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
user: None,
market: None,
mint: None,
amount: None,
outcome_index: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn market(mut self, market: Pubkey) -> Self {
self.market = Some(market);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn outcome_index(mut self, outcome_index: u8) -> Self {
self.outcome_index = Some(outcome_index);
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let market = self
.market
.ok_or_else(|| SdkError::Validation("market is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let outcome_index = self
.outcome_index
.ok_or_else(|| SdkError::Validation("outcome_index is required".into()))?;
Ok(instructions::build_withdraw_from_position_ix(
&WithdrawFromPositionParams {
user,
market,
mint,
amount,
outcome_index,
},
&self.client.program_id,
))
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct InitPositionTokensBuilder<'a> {
client: &'a LightconeClient,
payer: Option<Pubkey>,
user: Option<Pubkey>,
market: Option<Pubkey>,
deposit_mints: Option<Vec<Pubkey>>,
recent_slot: Option<u64>,
num_outcomes: Option<u8>,
}
impl<'a> InitPositionTokensBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
payer: None,
user: None,
market: None,
deposit_mints: None,
recent_slot: None,
num_outcomes: None,
}
}
pub fn payer(mut self, payer: Pubkey) -> Self {
self.payer = Some(payer);
self
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn market(mut self, market: Pubkey) -> Self {
self.market = Some(market);
self
}
pub fn deposit_mints(mut self, deposit_mints: Vec<Pubkey>) -> Self {
self.deposit_mints = Some(deposit_mints);
self
}
pub fn recent_slot(mut self, recent_slot: u64) -> Self {
self.recent_slot = Some(recent_slot);
self
}
pub fn num_outcomes(mut self, num_outcomes: u8) -> Self {
self.num_outcomes = Some(num_outcomes);
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let payer = self
.payer
.ok_or_else(|| SdkError::Validation("payer is required".into()))?;
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let market = self
.market
.ok_or_else(|| SdkError::Validation("market is required".into()))?;
let deposit_mints = self
.deposit_mints
.ok_or_else(|| SdkError::Validation("deposit_mints is required".into()))?;
let recent_slot = self
.recent_slot
.ok_or_else(|| SdkError::Validation("recent_slot is required".into()))?;
let num_outcomes = self
.num_outcomes
.ok_or_else(|| SdkError::Validation("num_outcomes is required".into()))?;
Ok(instructions::build_init_position_tokens_ix(
&InitPositionTokensParams {
payer,
user,
market,
deposit_mints,
recent_slot,
},
num_outcomes,
&self.client.program_id,
))
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.payer
.ok_or_else(|| SdkError::Validation("payer is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct ExtendPositionTokensBuilder<'a> {
client: &'a LightconeClient,
operator: Option<Pubkey>,
user: Option<Pubkey>,
market: Option<Pubkey>,
lookup_table: Option<Pubkey>,
deposit_mints: Option<Vec<Pubkey>>,
num_outcomes: Option<u8>,
}
impl<'a> ExtendPositionTokensBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
operator: None,
user: None,
market: None,
lookup_table: None,
deposit_mints: None,
num_outcomes: None,
}
}
pub fn operator(mut self, operator: Pubkey) -> Self {
self.operator = Some(operator);
self
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn market(mut self, market: Pubkey) -> Self {
self.market = Some(market);
self
}
pub fn lookup_table(mut self, lookup_table: Pubkey) -> Self {
self.lookup_table = Some(lookup_table);
self
}
pub fn deposit_mints(mut self, deposit_mints: Vec<Pubkey>) -> Self {
self.deposit_mints = Some(deposit_mints);
self
}
pub fn num_outcomes(mut self, num_outcomes: u8) -> Self {
self.num_outcomes = Some(num_outcomes);
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let operator = self
.operator
.ok_or_else(|| SdkError::Validation("operator is required".into()))?;
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let market = self
.market
.ok_or_else(|| SdkError::Validation("market is required".into()))?;
let lookup_table = self
.lookup_table
.ok_or_else(|| SdkError::Validation("lookup_table is required".into()))?;
let deposit_mints = self
.deposit_mints
.ok_or_else(|| SdkError::Validation("deposit_mints is required".into()))?;
let num_outcomes = self
.num_outcomes
.ok_or_else(|| SdkError::Validation("num_outcomes is required".into()))?;
Ok(instructions::build_extend_position_tokens_ix(
&ExtendPositionTokensParams {
operator,
user,
market,
lookup_table,
deposit_mints,
},
num_outcomes,
&self.client.program_id,
)?)
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let operator = self
.operator
.ok_or_else(|| SdkError::Validation("operator is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&operator)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct DepositToGlobalBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
alt_context: Option<DepositToGlobalAltContext>,
}
impl<'a> DepositToGlobalBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
user: None,
mint: None,
amount: None,
alt_context: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn create_alt(mut self, recent_slot: u64) -> Self {
self.alt_context = Some(DepositToGlobalAltContext::Create { recent_slot });
self
}
pub fn extend_alt(mut self, lookup_table: Pubkey) -> Self {
self.alt_context = Some(DepositToGlobalAltContext::Extend { lookup_table });
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let params = DepositToGlobalParams { user, mint, amount };
Ok(match self.alt_context {
Some(alt_context) => instructions::build_deposit_to_global_ix_with_alt(
¶ms,
alt_context,
&self.client.program_id,
),
None => instructions::build_deposit_to_global_ix(¶ms, &self.client.program_id),
})
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct WithdrawFromGlobalBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
}
impl<'a> WithdrawFromGlobalBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
user: None,
mint: None,
amount: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
Ok(instructions::build_withdraw_from_global_ix(
&WithdrawFromGlobalParams { user, mint, amount },
&self.client.program_id,
))
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}
pub struct GlobalToMarketDepositBuilder<'a> {
client: &'a LightconeClient,
user: Option<Pubkey>,
market: Option<Pubkey>,
mint: Option<Pubkey>,
amount: Option<u64>,
num_outcomes: Option<u8>,
}
impl<'a> GlobalToMarketDepositBuilder<'a> {
pub(crate) fn new(client: &'a LightconeClient) -> Self {
Self {
client,
user: None,
market: None,
mint: None,
amount: None,
num_outcomes: None,
}
}
pub fn user(mut self, user: Pubkey) -> Self {
self.user = Some(user);
self
}
pub fn market(mut self, market: Pubkey) -> Self {
self.market = Some(market);
self
}
pub fn mint(mut self, mint: Pubkey) -> Self {
self.mint = Some(mint);
self
}
pub fn amount(mut self, amount: u64) -> Self {
self.amount = Some(amount);
self
}
pub fn num_outcomes(mut self, num_outcomes: u8) -> Self {
self.num_outcomes = Some(num_outcomes);
self
}
pub fn build_ix(self) -> Result<Instruction, SdkError> {
let user = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let market = self
.market
.ok_or_else(|| SdkError::Validation("market is required".into()))?;
let mint = self
.mint
.ok_or_else(|| SdkError::Validation("mint is required".into()))?;
let amount = self
.amount
.ok_or_else(|| SdkError::Validation("amount is required".into()))?;
let num_outcomes = self
.num_outcomes
.ok_or_else(|| SdkError::Validation("num_outcomes is required".into()))?;
Ok(instructions::build_global_to_market_deposit_ix(
&GlobalToMarketDepositParams {
user,
market,
deposit_mint: mint,
amount,
},
num_outcomes,
&self.client.program_id,
))
}
pub fn build_tx(self) -> Result<Transaction, SdkError> {
let payer = self
.user
.ok_or_else(|| SdkError::Validation("user is required".into()))?;
let instruction = self.build_ix()?;
Ok(Transaction::new_with_payer(&[instruction], Some(&payer)))
}
pub async fn sign_and_submit(self) -> Result<String, SdkError> {
let client = self.client;
let transaction = self.build_tx()?;
client.sign_and_submit_tx(transaction).await
}
}