gmsol_sdk/builders/
utils.rs1use anchor_spl::associated_token::get_associated_token_address_with_program_id;
2use gmsol_solana_utils::client_traits::FromRpcClientWith;
3use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
4use typed_builder::TypedBuilder;
5
6use crate::{
7 builders::{market::MarketTokenIxBuilder, store_program::StoreProgramIxBuilder},
8 serde::StringPubkey,
9};
10
11use super::NonceBytes;
12
13pub(crate) fn generate_nonce() -> NonceBytes {
14 use rand::{distributions::Standard, Rng};
15
16 let pubkey = rand::thread_rng()
17 .sample_iter(Standard)
18 .take(32)
19 .collect::<Vec<u8>>()
20 .try_into()
21 .unwrap();
22 StringPubkey(pubkey)
23}
24
25pub(crate) fn prepare_ata(
26 payer: &Pubkey,
27 owner: &Pubkey,
28 token: Option<&Pubkey>,
29 token_program_id: &Pubkey,
30) -> Option<(Pubkey, Instruction)> {
31 use anchor_spl::associated_token::spl_associated_token_account::instruction;
32
33 let token = token?;
34
35 let ata = get_associated_token_address_with_program_id(owner, token, token_program_id);
36
37 let prepare = instruction::create_associated_token_account_idempotent(
38 payer,
39 owner,
40 token,
41 token_program_id,
42 );
43
44 Some((ata, prepare))
45}
46
47pub(crate) fn get_ata_or_owner(
48 owner: &Pubkey,
49 mint: &Pubkey,
50 should_unwrap_native_token: bool,
51) -> Pubkey {
52 get_ata_or_owner_with_program_id(
53 owner,
54 mint,
55 should_unwrap_native_token,
56 &anchor_spl::token::ID,
57 )
58}
59
60pub(crate) fn get_ata_or_owner_with_program_id(
61 owner: &Pubkey,
62 mint: &Pubkey,
63 should_unwrap_native_token: bool,
64 token_program_id: &Pubkey,
65) -> Pubkey {
66 use anchor_spl::{
67 associated_token::get_associated_token_address_with_program_id,
68 token::spl_token::native_mint,
69 };
70
71 if should_unwrap_native_token && *mint == native_mint::ID {
72 *owner
73 } else {
74 get_associated_token_address_with_program_id(owner, mint, token_program_id)
75 }
76}
77
78#[cfg_attr(js, derive(tsify_next::Tsify))]
80#[cfg_attr(js, tsify(from_wasm_abi))]
81#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
82#[derive(Debug, Clone, TypedBuilder)]
83pub struct PoolTokenHint {
84 #[builder(setter(into))]
86 pub long_token: StringPubkey,
87 #[builder(setter(into))]
89 pub short_token: StringPubkey,
90}
91
92impl PoolTokenHint {
93 pub fn is_collateral_long(&self, collateral: &Pubkey) -> Result<bool, crate::SolanaUtilsError> {
97 if *collateral == *self.long_token {
98 Ok(true)
99 } else if *collateral == *self.short_token {
100 Ok(false)
101 } else {
102 Err(crate::SolanaUtilsError::custom(
103 "invalid hint: `collateral` is not one of the specified long or short tokens",
104 ))
105 }
106 }
107}
108
109impl<T> FromRpcClientWith<T> for PoolTokenHint
110where
111 T: StoreProgramIxBuilder + MarketTokenIxBuilder,
112{
113 async fn from_rpc_client_with<'a>(
114 builder: &'a T,
115 client: &'a impl gmsol_solana_utils::client_traits::RpcClient,
116 ) -> gmsol_solana_utils::Result<Self> {
117 use crate::{programs::gmsol_store::accounts::Market, utils::zero_copy::ZeroCopy};
118 use gmsol_solana_utils::client_traits::RpcClientExt;
119
120 let market_address = builder
121 .store_program()
122 .find_market_address(builder.market_token());
123 let market = client
124 .get_anchor_account::<ZeroCopy<Market>>(&market_address, Default::default())
125 .await?
126 .0;
127
128 Ok(Self {
129 long_token: market.meta.long_token_mint.into(),
130 short_token: market.meta.short_token_mint.into(),
131 })
132 }
133}