mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-08-09 03:20:03 +00:00
add method to request order creation
This commit is contained in:
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -1,8 +1,8 @@
|
||||
{
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"taptrade-cli-demo/coordinator/Cargo.toml",
|
||||
"taptrade-cli-demo/trader/Cargo.toml",
|
||||
"${workspaceFolder}/taptrade-cli-demo/coordinator/Cargo.toml",
|
||||
"${workspaceFolder}/taptrade-cli-demo/trader/Cargo.toml",
|
||||
],
|
||||
"nixEnvSelector.suggestion": true,
|
||||
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix"
|
||||
}
|
||||
}
|
||||
|
79
taptrade-cli-demo/trader/Cargo.lock
generated
79
taptrade-cli-demo/trader/Cargo.lock
generated
@ -122,6 +122,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base91"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4eb5fbae7b5ee422f239444a3dca9bdf5ecb3abf3af1bf87c8097db3f7bc025"
|
||||
|
||||
[[package]]
|
||||
name = "bdk"
|
||||
version = "0.29.0"
|
||||
@ -203,6 +209,15 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@ -295,6 +310,15 @@ version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
@ -319,6 +343,26 @@ version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "electrum-client"
|
||||
version = "0.18.0"
|
||||
@ -468,6 +512,16 @@ dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@ -1202,6 +1256,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@ -1433,10 +1498,12 @@ name = "trader"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base91",
|
||||
"bdk",
|
||||
"clap",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1445,6 +1512,12 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
@ -1495,6 +1568,12 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
|
@ -5,7 +5,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
base91 = "0.1.0"
|
||||
bdk = "0.29.0"
|
||||
clap = { version = "4.5.4", features = ["derive", "cargo"] }
|
||||
reqwest = { version = "0.12.4", features = ["blocking", "json"] }
|
||||
serde = "1.0.203"
|
||||
sha2 = "0.10.8"
|
||||
|
@ -1,12 +1,25 @@
|
||||
use clap::{command, Arg, Command, ArgMatches};
|
||||
use std::io::{self, Write};
|
||||
use anyhow::{anyhow, Result};
|
||||
use sha2::{Sha256, Digest};
|
||||
use base91;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Coordinator;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OfferType {
|
||||
Buy(u32),
|
||||
Sell(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TraderSettings {
|
||||
pub electrum_endpoint: String,
|
||||
pub coordinator_endpoint: String,
|
||||
pub robosats_robohash_base91: String,
|
||||
pub trade_type: OfferType,
|
||||
pub payout_address: String,
|
||||
pub bond_ratio: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -16,76 +29,143 @@ pub enum CliSettings {
|
||||
Maker(TraderSettings)
|
||||
}
|
||||
|
||||
trait ArgMatchesParser {
|
||||
fn parse_into_enum(&self) -> CliSettings;
|
||||
fn hash256(input: &String) -> [u8; 32] {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(input.as_bytes());
|
||||
hasher.finalize().into()
|
||||
}
|
||||
|
||||
impl ArgMatchesParser for ArgMatches {
|
||||
fn parse_into_enum(&self) -> CliSettings {
|
||||
if let Some(_mode) = self.subcommand_matches("coordinator") {
|
||||
CliSettings::Coordinator(Coordinator { })
|
||||
} else if let Some(mode) = self.subcommand_matches("trader") {
|
||||
let trader_settings = TraderSettings {
|
||||
coordinator_endpoint: mode.get_one::<String>("coordinator-ep")
|
||||
.expect("Coordinator endpoint not provided!").clone(),
|
||||
electrum_endpoint: mode.get_one::<String>("electrum-ep")
|
||||
.expect("Electrum endpoint not provided").clone()
|
||||
};
|
||||
if mode.contains_id("maker") {
|
||||
CliSettings::Maker( trader_settings )
|
||||
} else if mode.contains_id("taker") {
|
||||
CliSettings::Taker( trader_settings )
|
||||
} else {
|
||||
panic!("Wrong arguments for Trader mode!")
|
||||
}
|
||||
} else {
|
||||
panic!("Select either coordinator or trader mode!")
|
||||
}
|
||||
}
|
||||
// Robosats uses base91 encoded sha256 hash of the private robot key
|
||||
fn bytes_to_base91(input: &[u8; 32]) -> String {
|
||||
let encoded_robohash: String = base91::EncodeIterator::new(input.iter().copied())
|
||||
.as_char_iter()
|
||||
.collect();
|
||||
encoded_robohash
|
||||
}
|
||||
|
||||
pub fn parse_cli_args() -> CliSettings {
|
||||
command!()
|
||||
.about("RoboSats taproot onchain trade pipeline CLI demonstrator. Don't use with real funds.")
|
||||
.subcommand(
|
||||
Command::new("coordinator")
|
||||
.about("Run in coordinator mode.")
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("trader")
|
||||
.about("Two available trader modes: Maker and Taker. Select one and provide Coordinator and Electum endpoint")
|
||||
.arg(
|
||||
Arg::new("taker")
|
||||
.short('t')
|
||||
.long("taker")
|
||||
.help("Run program as taker")
|
||||
.num_args(0)
|
||||
.conflicts_with("maker")
|
||||
)
|
||||
.arg (
|
||||
Arg::new("maker")
|
||||
.short('m')
|
||||
.long("maker")
|
||||
.num_args(0)
|
||||
.help("Run program as maker")
|
||||
.conflicts_with("taker")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("coordinator-ep")
|
||||
.short('p')
|
||||
.long("endpoint")
|
||||
.required(true)
|
||||
.help("Communication endpoint of the coordinator to connect to")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("electrum-ep")
|
||||
.short('e')
|
||||
.long("electrum")
|
||||
.required(true)
|
||||
.help("URL of the electrum endpoint")
|
||||
)
|
||||
)
|
||||
.arg_required_else_help(true)
|
||||
.get_matches()
|
||||
.parse_into_enum()
|
||||
impl CliSettings {
|
||||
fn get_user_input(prompt: &str) -> String {
|
||||
let mut buffer = String::new();
|
||||
print!("{}", prompt);
|
||||
io::stdout().flush().unwrap();
|
||||
io::stdin()
|
||||
.read_line(&mut buffer)
|
||||
.expect("Failed to read line!");
|
||||
buffer.trim().to_string()
|
||||
}
|
||||
|
||||
fn get_trade_type() -> OfferType {
|
||||
let trade_type = Self::get_user_input("Do you want to buy or sell satoshis: ");
|
||||
match trade_type.as_str() {
|
||||
"buy" => OfferType::Buy(Self::get_user_input("How many satoshi do you want to buy: ").parse().unwrap()),
|
||||
"sell" => OfferType::Sell(Self::get_user_input("How many satoshi do you want to sell: ").parse().unwrap()),
|
||||
_ => panic!("Wrong offer type, you can only buy or sell"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trader_settings() -> Result<TraderSettings> {
|
||||
let electrum_endpoint = Self::get_user_input("Enter electrum endpoint: ");
|
||||
let coordinator_endpoint = Self::get_user_input("Enter coordinator endpoint: ");
|
||||
let robosats_robohash_base91 = bytes_to_base91(&hash256(&Self::get_user_input("Enter your robosats robot key: ")));
|
||||
let trade_type = Self::get_trade_type();
|
||||
let payout_address = Self::get_user_input("Enter a payout address for refunded bonds or your trade payout: "); // bdk can be used for validation
|
||||
let bond_ratio: u8 = Self::get_user_input("Enter bond ration in [2, 50]%: ").parse()?;
|
||||
Ok(TraderSettings {
|
||||
electrum_endpoint,
|
||||
coordinator_endpoint,
|
||||
robosats_robohash_base91,
|
||||
trade_type,
|
||||
payout_address,
|
||||
bond_ratio
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_cli_args() -> Result<Self> {
|
||||
let mode = Self::get_user_input("Enter mode, 'taker' or 'maker': ");
|
||||
let trader_settings = Self::get_trader_settings()?;
|
||||
match mode.to_lowercase().as_str() {
|
||||
"maker" => Ok(Self::Maker(trader_settings)),
|
||||
"taker" => Ok(Self::Taker(trader_settings)),
|
||||
_ => Err(anyhow!("Either select maker or taker!")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// old cli parser using clap
|
||||
|
||||
// use clap::{command, Arg, Command, ArgMatches};
|
||||
|
||||
// trait ArgMatchesParser {
|
||||
// fn parse_into_enum(&self) -> CliSettings;
|
||||
// }
|
||||
|
||||
// impl ArgMatchesParser for ArgMatches {
|
||||
// fn parse_into_enum(&self) -> CliSettings {
|
||||
// if let Some(_mode) = self.subcommand_matches("coordinator") {
|
||||
// CliSettings::Coordinator(Coordinator { })
|
||||
// } else if let Some(mode) = self.subcommand_matches("trader") {
|
||||
// let trader_settings = TraderSettings {
|
||||
// coordinator_endpoint: mode.get_one::<String>("coordinator-ep")
|
||||
// .expect("Coordinator endpoint not provided!").clone(),
|
||||
// electrum_endpoint: mode.get_one::<String>("electrum-ep")
|
||||
// .expect("Electrum endpoint not provided").clone()
|
||||
// };
|
||||
// if mode.contains_id("maker") {
|
||||
// CliSettings::Maker( trader_settings )
|
||||
// } else if mode.contains_id("taker") {
|
||||
// CliSettings::Taker( trader_settings )
|
||||
// } else {
|
||||
// panic!("Wrong arguments for Trader mode!")
|
||||
// }
|
||||
// } else {
|
||||
// panic!("Select either coordinator or trader mode!")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn parse_cli_args() -> CliSettings {
|
||||
// command!()
|
||||
// .about("RoboSats taproot onchain trade pipeline CLI demonstrator. Don't use with real funds.")
|
||||
// .subcommand(
|
||||
// Command::new("coordinator")
|
||||
// .about("Run in coordinator mode.")
|
||||
// )
|
||||
// .subcommand(
|
||||
// Command::new("trader")
|
||||
// .about("Two available trader modes: Maker and Taker. Select one and provide Coordinator and Electum endpoint")
|
||||
// .arg(
|
||||
// Arg::new("taker")
|
||||
// .short('t')
|
||||
// .long("taker")
|
||||
// .help("Run program as taker")
|
||||
// .num_args(0)
|
||||
// .conflicts_with("maker")
|
||||
// )
|
||||
// .arg (
|
||||
// Arg::new("maker")
|
||||
// .short('m')
|
||||
// .long("maker")
|
||||
// .num_args(0)
|
||||
// .help("Run program as maker")
|
||||
// .conflicts_with("taker")
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::new("coordinator-ep")
|
||||
// .short('p')
|
||||
// .long("endpoint")
|
||||
// .required(true)
|
||||
// .help("Communication endpoint of the coordinator to connect to")
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::new("electrum-ep")
|
||||
// .short('e')
|
||||
// .long("electrum")
|
||||
// .required(true)
|
||||
// .help("URL of the electrum endpoint")
|
||||
// )
|
||||
// )
|
||||
// .arg_required_else_help(true)
|
||||
// .get_matches()
|
||||
// .parse_into_enum()
|
||||
// }
|
||||
|
@ -1,14 +1,51 @@
|
||||
use reqwest;
|
||||
use anyhow::Result;
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::cli::{TraderSettings, OfferType};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OfferConditions {
|
||||
pub struct OfferCreationResponse {
|
||||
pub locking_address: String,
|
||||
}
|
||||
|
||||
pub fn fetch_offer(coordinator_ep: &String) -> Result<OfferConditions> {
|
||||
let res = reqwest::blocking::get(format!("{}{}", coordinator_ep, "/create-offer"))?;
|
||||
let offer_conditions: OfferConditions = res.json()?;
|
||||
Ok(offer_conditions)
|
||||
#[derive(Serialize)]
|
||||
struct OrderRequest {
|
||||
robohash_base91: String,
|
||||
amount_satoshi: u32,
|
||||
order_type: String, // buy or sell
|
||||
bond_ratio: u8 // [x > 2, 50]
|
||||
}
|
||||
|
||||
impl OfferCreationResponse {
|
||||
fn _format_request(trader_setup: &TraderSettings) -> OrderRequest {
|
||||
let amount: u32;
|
||||
let trade_type = match &trader_setup.trade_type {
|
||||
OfferType::Buy(val) => {
|
||||
amount = *val;
|
||||
"buy"
|
||||
},
|
||||
OfferType::Sell(val) => {
|
||||
amount = *val;
|
||||
"sell"
|
||||
}
|
||||
};
|
||||
|
||||
OrderRequest {
|
||||
robohash_base91: trader_setup.robosats_robohash_base91.clone(),
|
||||
amount_satoshi: amount,
|
||||
order_type: trade_type.to_string(),
|
||||
bond_ratio: trader_setup.bond_ratio,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch(trader_setup: &TraderSettings) -> Result<OfferCreationResponse> {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client.post(format!("{}{}", trader_setup.coordinator_endpoint, "/create-offer"))
|
||||
.json(&Self::_format_request(trader_setup))
|
||||
.send()?
|
||||
.json::<OfferCreationResponse>()?;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,22 +5,20 @@ mod trading;
|
||||
|
||||
use core::panic;
|
||||
|
||||
use cli::{parse_cli_args, CliSettings};
|
||||
use cli::CliSettings;
|
||||
use anyhow::Result;
|
||||
use communication::fetch_offer;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mode = parse_cli_args();
|
||||
dbg!(mode);
|
||||
|
||||
if let CliSettings::Maker(maker_config) = mode {
|
||||
trading::maker::run_maker(maker_config)?;
|
||||
} else if CliSettings::Taker(taker_data) = mode {
|
||||
trading::taker::run_taker(taker_data)?;
|
||||
} else {
|
||||
panic!("Wrong mode selected!")
|
||||
}
|
||||
|
||||
|
||||
let mode = CliSettings::parse_cli_args()?;
|
||||
dbg!("CLI input :", &mode);
|
||||
|
||||
// if let CliSettings::Maker(maker_data) = &mode {
|
||||
// trading::maker::run_maker(maker_data)?;
|
||||
// } else if let CliSettings::Taker(taker_data) = &mode {
|
||||
// trading::taker::run_taker(taker_data)?;
|
||||
// } else {
|
||||
// panic!("Wrong mode selected!")
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
// use utils;
|
||||
use anyhow::Result;
|
||||
use crate::cli::TraderSettings;
|
||||
use crate::communication::fetch_offer;
|
||||
use crate::communication::create_offer;
|
||||
|
||||
pub fn run_maker(maker_config: &TraderSettings) -> Result<()> {
|
||||
let offer_conditions = fetch_offer(&maker_config.coordinator_endpoint)?;
|
||||
let offer_conditions = create_offer(maker_config)?;
|
||||
// maker_utils::maker(offer_conditions, maker_config)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user