gmsol-sdk 0.9.0

GMX-Solana is an extension of GMX on the Solana blockchain.
Documentation
use std::collections::HashSet;

use gmsol_solana_utils::{AtomicGroup, IntoAtomicGroup, ParallelGroup};
use serde::{Deserialize, Serialize};
use tsify_next::Tsify;
use wasm_bindgen::prelude::*;

use crate::{
    builders::{shift::CreateShift, token::PrepareTokenAccounts, user::PrepareUser, StoreProgram},
    js::instructions::BuildTransactionOptions,
    serde::StringPubkey,
};

use super::{TransactionGroup, TransactionGroupOptions};

#[derive(Debug, Serialize, Deserialize, Tsify, Clone)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct CreateShiftParamsJs {
    pub from_market_token: StringPubkey,
    pub to_market_token: StringPubkey,
    #[serde(default)]
    pub receiver: Option<StringPubkey>,
    #[serde(default)]
    pub from_market_token_amount: Option<u128>,
    #[serde(default)]
    pub min_to_market_token_amount: Option<u128>,
    #[serde(default)]
    pub skip_to_market_token_ata_creation: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct CreateShiftOptions {
    pub recent_blockhash: String,
    pub payer: StringPubkey,
    #[serde(default)]
    pub program: Option<StoreProgram>,
    #[serde(default)]
    pub compute_unit_price_micro_lamports: Option<u64>,
    #[serde(default)]
    pub compute_unit_min_priority_lamports: Option<u64>,
    #[serde(default)]
    pub transaction_group: TransactionGroupOptions,
}

#[wasm_bindgen]
pub struct CreateShiftsBuilder {
    payer: StringPubkey,
    tokens: HashSet<StringPubkey>,
    groups: Vec<AtomicGroup>,
    transaction_group: TransactionGroupOptions,
    build: BuildTransactionOptions,
}

#[wasm_bindgen]
pub fn create_shifts_builder(
    shifts: Vec<CreateShiftParamsJs>,
    options: CreateShiftOptions,
) -> crate::Result<CreateShiftsBuilder> {
    let mut tokens = HashSet::default();
    let mut groups: Vec<AtomicGroup> = Vec::with_capacity(shifts.len());

    for params in shifts.into_iter() {
        tokens.insert(params.to_market_token);

        let program = options.program.clone().unwrap_or_default();
        let builder = CreateShift::builder()
            .program(program)
            .payer(options.payer)
            .from_market_token(params.from_market_token)
            .to_market_token(params.to_market_token)
            .from_market_token_amount(
                params
                    .from_market_token_amount
                    .unwrap_or_default()
                    .try_into()?,
            )
            .min_to_market_token_amount(
                params
                    .min_to_market_token_amount
                    .unwrap_or_default()
                    .try_into()?,
            )
            .skip_to_market_token_ata_creation(
                params.skip_to_market_token_ata_creation.unwrap_or_default(),
            );

        let built = if let Some(r) = params.receiver {
            builder.receiver(r).build()
        } else {
            builder.build()
        };

        let ag = built.into_atomic_group(&())?;
        groups.push(ag);
    }

    Ok(CreateShiftsBuilder {
        payer: options.payer,
        tokens,
        groups,
        transaction_group: options.transaction_group,
        build: BuildTransactionOptions {
            recent_blockhash: options.recent_blockhash,
            compute_unit_price_micro_lamports: options.compute_unit_price_micro_lamports,
            compute_unit_min_priority_lamports: options.compute_unit_min_priority_lamports,
        },
    })
}

#[wasm_bindgen]
impl CreateShiftsBuilder {
    pub fn build_with_options(
        self,
        transaction_group: Option<TransactionGroupOptions>,
        build: Option<BuildTransactionOptions>,
    ) -> crate::Result<TransactionGroup> {
        let mut group = transaction_group.unwrap_or(self.transaction_group).build();

        let prepare_user = PrepareUser::builder()
            .payer(self.payer)
            .build()
            .into_atomic_group(&())?;

        let prepare_tokens = PrepareTokenAccounts::builder()
            .owner(self.payer)
            .payer(self.payer)
            .tokens(self.tokens)
            .build()
            .into_atomic_group(&())?;

        let build = build.unwrap_or(self.build);
        TransactionGroup::new(
            group
                .add(prepare_user)?
                .add(prepare_tokens)?
                .add(self.groups.into_iter().collect::<ParallelGroup>())?
                .optimize(false),
            &build.recent_blockhash,
            build.compute_unit_price_micro_lamports,
            build.compute_unit_min_priority_lamports,
        )
    }
}

#[wasm_bindgen]
pub fn create_shifts(
    shifts: Vec<CreateShiftParamsJs>,
    options: CreateShiftOptions,
) -> crate::Result<TransactionGroup> {
    create_shifts_builder(shifts, options)?.build_with_options(None, None)
}