1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::http_client::HttpClient;
use crate::seller_service::SellRequest;
use crate::util::healthz;
use crate::{
    buyer,
    provider::Provider,
    util::{env, pubkey_to_string, string_to_pubkey},
};
use actix_web::post;
use actix_web::web::Json;
use actix_web::{App, Error, HttpResponse, HttpServer};
use log::info;
use serde::{Deserialize, Serialize};
use serde_json::json;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair;
use solana_sdk::signer::EncodableKey;

#[derive(Deserialize, Serialize)]
pub struct BuyRequest {
    #[serde(
        serialize_with = "pubkey_to_string",
        deserialize_with = "string_to_pubkey"
    )]
    pub amm_pool: Pubkey,
    #[serde(
        serialize_with = "pubkey_to_string",
        deserialize_with = "string_to_pubkey"
    )]
    pub input_mint: Pubkey,
    #[serde(
        serialize_with = "pubkey_to_string",
        deserialize_with = "string_to_pubkey"
    )]
    pub output_mint: Pubkey,
    pub amount: u64,
}

#[post("/buy")]
async fn handle_buy(
    buy_request: Json<BuyRequest>,
) -> Result<HttpResponse, Error> {
    info!(
        "handling buy req {}",
        serde_json::to_string_pretty(&buy_request)?
    );
    let mint = buy_request.output_mint;
    tokio::spawn(async move {
        let wallet = Keypair::read_from_file(env("FUND_KEYPAIR_PATH"))
            .expect("read fund keypair");
        let provider = &Provider::new(env("RPC_URL").to_string());
        buyer::swap(
            &buy_request.amm_pool,
            &buy_request.input_mint,
            &buy_request.output_mint,
            buy_request.amount,
            &wallet,
            provider,
        )
        .await
        .expect("buy");
        HttpClient::new()
            .sell(&SellRequest {
                amm_pool: buy_request.amm_pool,
                input_mint: buy_request.output_mint,
                output_mint: buy_request.input_mint,
                lamports_spent: buy_request.amount,
                insta: None,
            })
            .await
    });

    Ok(HttpResponse::Ok()
        .json(json!({"status": format!("OK, trigerred buy of {}", mint.to_string())})))
}

pub struct BalanceContext {
    pub lamports: u64,
}

pub async fn run_buyer_service() -> std::io::Result<()> {
    info!("Running buyer service on 8080");
    HttpServer::new(move || App::new().service(handle_buy).service(healthz))
        .bind(("0.0.0.0", 8080))?
        .run()
        .await
}