use anyhow::{anyhow, Result};
use borsh::BorshDeserialize;
use equanetwork::{NetworkSwap, NetworkSwapInstructionArgs, Vault};
use solana_address::Address;
use solana_instruction::Instruction;
use solana_signer::Signer;
use crate::{
config::{Command, Config, NetworkCommand},
log_context,
transaction::process_instructions,
};
use super::helpers::{addr, ensure_ata, pk, require_signer, vault_pda};
fn load_vault(rpc: &solana_client::rpc_client::RpcClient, vault: Address) -> Result<Vault> {
let account = rpc
.get_account(&pk(vault))
.map_err(|e| anyhow!("fetch vault {}: {e}", pk(vault)))?;
Vault::try_from_slice(&account.data).map_err(|e| anyhow!("decode vault {}: {e}", pk(vault)))
}
pub fn handle(config: &Config) -> Result<()> {
let Command::Network {
command:
NetworkCommand::Swap {
network,
input_mint,
output_mint,
amount,
minimum_output_amount,
allow_partial_fill,
},
} = &config.command
else {
unreachable!()
};
let signer = require_signer(config)?;
let rpc = config.rpc_client();
let user = signer.pubkey();
let vault_in = vault_pda(network, input_mint);
let vault_out = vault_pda(network, output_mint);
let vault_in_acc = load_vault(&rpc, vault_in)?;
let vault_out_acc = load_vault(&rpc, vault_out)?;
let mut ixs: Vec<Instruction> = Vec::new();
let user_input_ata = ensure_ata(&rpc, &mut ixs, &signer, &user, input_mint);
let user_output_ata = ensure_ata(&rpc, &mut ixs, &signer, &user, output_mint);
let network_input_ata = ensure_ata(&rpc, &mut ixs, &signer, network, input_mint);
let network_output_ata = ensure_ata(&rpc, &mut ixs, &signer, network, output_mint);
log_context!(
action => "network_swap",
user => user.to_string(),
network => network.to_string(),
input_mint => input_mint.to_string(),
output_mint => output_mint.to_string(),
amount => *amount,
minimum_output_amount => *minimum_output_amount,
allow_partial_fill => *allow_partial_fill,
);
ixs.push(
NetworkSwap {
user: addr(user),
network: addr(*network),
vault_in,
vault_out,
input_mint: addr(*input_mint),
output_mint: addr(*output_mint),
user_input_ata: addr(user_input_ata),
user_output_ata: addr(user_output_ata),
network_input_ata: addr(network_input_ata),
network_output_ata: addr(network_output_ata),
price_source_in: vault_in_acc.price_source,
price_source_out: vault_out_acc.price_source,
price_feed_in: vault_in_acc.price_feed,
price_feed_out: vault_out_acc.price_feed,
token_program_in: addr(spl_token_interface::ID),
token_program_out: addr(spl_token_interface::ID),
memo_program: addr(spl_memo_interface::v3::ID),
instructions_sysvar: addr(solana_pubkey::pubkey!(
"Sysvar1nstructions1111111111111111111111111"
)),
}
.instruction(NetworkSwapInstructionArgs {
input_amount: *amount,
minimum_output_amount: *minimum_output_amount,
allow_partial_fill: *allow_partial_fill,
}),
);
process_instructions(&rpc, &[signer], &ixs)
}