mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-07-20 17:53:44 +00:00
switch base91 to hex, add duration time
This commit is contained in:
@ -5,7 +5,7 @@ use tokio::net::TcpListener;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
struct OrderRequest {
|
||||
robohash_base91: String,
|
||||
robohash_hex: String,
|
||||
amount_satoshi: u64,
|
||||
order_type: String,
|
||||
bond_ratio: u8,
|
||||
@ -16,7 +16,7 @@ async fn receive_order(Json(order): Json<OrderRequest>) {
|
||||
println!("Received order: {:?}", order);
|
||||
|
||||
// Access individual fields
|
||||
let robohash = &order.robohash_base91;
|
||||
let robohash = &order.robohash_hex;
|
||||
let amount = order.amount_satoshi;
|
||||
let order_type = &order.order_type;
|
||||
let bond_ratio = order.bond_ratio;
|
||||
|
14
taptrade-cli-demo/trader/Cargo.lock
generated
14
taptrade-cli-demo/trader/Cargo.lock
generated
@ -137,12 +137,6 @@ 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"
|
||||
@ -575,6 +569,12 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex_lit"
|
||||
version = "0.1.1"
|
||||
@ -1586,10 +1586,10 @@ name = "trader"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base91",
|
||||
"bdk",
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
"hex",
|
||||
"log",
|
||||
"musig2",
|
||||
"rand_core",
|
||||
|
@ -5,10 +5,10 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
base91 = "0.1.0"
|
||||
bdk = "0.29.0"
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.11.3"
|
||||
hex = "0.4.3"
|
||||
log = "0.4.21"
|
||||
musig2 = "0.0.11"
|
||||
rand_core = "0.6.4"
|
||||
|
@ -1,7 +1,8 @@
|
||||
ELECTRUM_ENDPOINT="ssl://mempool.space:40002" # testnet 4 electrum server
|
||||
COORDINATOR_ENDPOINT="http://127.0.0.1:3000"
|
||||
ROBOHASH_BASE91="o!kfNkee;RF?m6FT87:1bjASE2/(1NFTnR;ILmHB<1p/vP%STz~IWolNDJa.#PmTI)sfBk+Gs!,(w8M" # "base91 of hex of sha256 of robot21"
|
||||
ROBOHASH_HEX="26ee3dee4815655d223c3505162fd4610294a9542f89bb3d3e9748f534ac10ae" # sha256 of "robot21"
|
||||
TRADE_TYPE="buy"
|
||||
PAYOUT_ADDRESS="tb1p45daj2eaza6drcd85c3wvn0zrpqxuduk3rzcmla4eu7a02cep9kqjzkc64"
|
||||
BOND_RATIO=5
|
||||
XPRV="tprv8ZgxMBicQKsPdHuCSjhQuSZP1h6ZTeiRqREYS5guGPdtL7D1uNLpnJmb2oJep99Esq1NbNZKVJBNnD2ZhuXSK7G5eFmmcx73gsoa65e2U32" # wallet xprv
|
||||
OFFER_DURATION_HOURS=48
|
||||
|
@ -1,10 +1,13 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
use crate::wallet::get_wallet_xprv;
|
||||
use anyhow::{anyhow, Result};
|
||||
use bdk::bitcoin::bip32::ExtendedPrivKey;
|
||||
use hex;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{
|
||||
env,
|
||||
io::{self, Write},
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Coordinator;
|
||||
@ -19,11 +22,12 @@ pub enum OfferType {
|
||||
pub struct TraderSettings {
|
||||
pub electrum_endpoint: String,
|
||||
pub coordinator_endpoint: String,
|
||||
pub robosats_robohash_base91: String,
|
||||
pub robosats_robohash_hex: String,
|
||||
pub trade_type: OfferType,
|
||||
pub payout_address: String,
|
||||
pub bond_ratio: u8,
|
||||
pub wallet_xprv: ExtendedPrivKey,
|
||||
pub duration_unix_ts: u64, // until when the order should stay available
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -39,14 +43,6 @@ fn hash256(input: &String) -> [u8; 32] {
|
||||
hasher.finalize().into()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
impl OfferType {
|
||||
pub fn value(&self) -> u64 {
|
||||
match self {
|
||||
@ -87,11 +83,17 @@ impl CliSettings {
|
||||
}
|
||||
}
|
||||
|
||||
// parses the hours input string and returns the unix timestamp + the trade duration in seconds
|
||||
fn hours_to_ts(hours: &String) -> Result<u64> {
|
||||
let duration: u64 = hours.parse()?;
|
||||
Ok(SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() + duration * 3600)
|
||||
}
|
||||
|
||||
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 robosats_robohash_hex = hex::encode(&hash256(&Self::get_user_input(
|
||||
"Enter your robosats robot key: ", // just for testing purposes, to be improved to the real robohash spec
|
||||
)));
|
||||
let trade_type: OfferType = Self::get_trade_type(None);
|
||||
let payout_address = Self::get_user_input(
|
||||
@ -101,14 +103,18 @@ impl CliSettings {
|
||||
let wallet_xprv = Self::check_xprv_input(Some(Self::get_user_input(
|
||||
"Enter funded testnet wallet xprv or leave empty to generate: ",
|
||||
)))?;
|
||||
let duration_unix_ts: u64 = Self::hours_to_ts(&Self::get_user_input(
|
||||
"How many hours should the offer stay online: ",
|
||||
))?;
|
||||
Ok(TraderSettings {
|
||||
electrum_endpoint,
|
||||
coordinator_endpoint,
|
||||
robosats_robohash_base91,
|
||||
robosats_robohash_hex,
|
||||
trade_type,
|
||||
payout_address,
|
||||
bond_ratio,
|
||||
wallet_xprv,
|
||||
duration_unix_ts,
|
||||
})
|
||||
}
|
||||
|
||||
@ -126,11 +132,12 @@ impl CliSettings {
|
||||
Ok(TraderSettings {
|
||||
electrum_endpoint: env::var("ELECTRUM_ENDPOINT")?,
|
||||
coordinator_endpoint: env::var("COORDINATOR_ENDPOINT")?,
|
||||
robosats_robohash_base91: env::var("ROBOHASH_BASE91")?,
|
||||
robosats_robohash_hex: env::var("ROBOHASH_HEX")?,
|
||||
trade_type: Self::get_trade_type(Some(env::var("TRADE_TYPE")?)),
|
||||
payout_address: env::var("PAYOUT_ADDRESS")?,
|
||||
bond_ratio: env::var("BOND_RATIO")?.parse()?,
|
||||
wallet_xprv: Self::check_xprv_input(Some(env::var("XPRV")?))?,
|
||||
duration_unix_ts: Self::hours_to_ts(&env::var("OFFER_DURATION_HOURS")?)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,36 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OfferCreationResponse {
|
||||
pub bond_address: String,
|
||||
pub locking_amount: u64, // validate
|
||||
}
|
||||
|
||||
// maker step 1
|
||||
// requesting to create an offer on the orderbook (POST request)
|
||||
#[derive(Serialize)]
|
||||
pub struct OrderRequest {
|
||||
pub robohash_base91: String,
|
||||
pub amount_satoshi: u64,
|
||||
pub order_type: String, // buy or sell
|
||||
pub bond_ratio: u8, // [2, 50]
|
||||
pub robohash_hex: String, // identifier of the trader
|
||||
pub amount_satoshi: u64, // amount in satoshi to buy or sell
|
||||
pub is_buy_order: bool, // true if buy, false if sell
|
||||
pub bond_ratio: u8, // [2, 50]% of trading amount
|
||||
pub offer_duration_ts: u64, // unix timestamp how long the offer should stay available
|
||||
}
|
||||
|
||||
// coordinator answer to maker step 1
|
||||
// direct Json answer to step 1 (same request)
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OfferCreationResponse {
|
||||
pub bond_address: String, // address the bond has to be locked to
|
||||
pub locking_amount_sat: u64, // min amount of the bond output in sat
|
||||
}
|
||||
|
||||
// maker step 2
|
||||
// (submission of signed bond and other data neccessary to coordinate the trade)
|
||||
#[derive(Serialize)]
|
||||
pub struct BondSubmissionRequest {
|
||||
pub robohash_base91: String,
|
||||
pub signed_bond_base91: String,
|
||||
pub robohash_hex: String,
|
||||
pub signed_bond_hex: String, // signed bond transaction, hex encoded
|
||||
pub payout_address: String, // does this make sense here?
|
||||
pub musig_pub_nonce_base91: String,
|
||||
pub musig_pubkey_base91: String,
|
||||
pub musig_pub_nonce_hex: String,
|
||||
pub musig_pubkey_hex: String,
|
||||
}
|
||||
|
||||
pub struct OrderActivatedResponse {
|
||||
pub order_id_hex: String,
|
||||
pub bond_locked_until_timestamp: u128, // unix timestamp. Do not touch bond till then unless offer gets taken.
|
||||
}
|
||||
|
@ -9,22 +9,23 @@ use api::{OfferCreationResponse, OrderRequest};
|
||||
impl OfferCreationResponse {
|
||||
fn _format_request(trader_setup: &TraderSettings) -> OrderRequest {
|
||||
let amount: u64;
|
||||
let trade_type = match &trader_setup.trade_type {
|
||||
let is_buy_order = match &trader_setup.trade_type {
|
||||
OfferType::Buy(val) => {
|
||||
amount = *val;
|
||||
"buy"
|
||||
true
|
||||
}
|
||||
OfferType::Sell(val) => {
|
||||
amount = *val;
|
||||
"sell"
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
OrderRequest {
|
||||
robohash_base91: trader_setup.robosats_robohash_base91.clone(),
|
||||
robohash_hex: trader_setup.robosats_robohash_hex.clone(),
|
||||
amount_satoshi: amount,
|
||||
order_type: trade_type.to_string(),
|
||||
is_buy_order,
|
||||
bond_ratio: trader_setup.bond_ratio,
|
||||
offer_duration_ts: trader_setup.duration_unix_ts,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,6 @@ use crate::wallet::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use bdk::database::MemoryDatabase;
|
||||
// use bdk::{
|
||||
// bitcoin::block,
|
||||
// blockchain::{Blockchain, ElectrumBlockchain},
|
||||
// electrum_client::Client,
|
||||
// wallet::AddressIndex::LastUnused,
|
||||
// Wallet,
|
||||
// };
|
||||
|
||||
pub struct ActiveOffer {}
|
||||
|
||||
@ -22,20 +15,17 @@ impl ActiveOffer {
|
||||
trading_wallet: &TradingWallet,
|
||||
maker_config: &TraderSettings,
|
||||
) -> Result<ActiveOffer> {
|
||||
let offer_conditions = OfferCreationResponse::fetch(maker_config)?;
|
||||
let trading_wallet = &trading_wallet.wallet;
|
||||
|
||||
// let offer_conditions = OfferCreationResponse::fetch(maker_config)?;
|
||||
let offer_conditions = OfferCreationResponse {
|
||||
// hardcoded for testing, locking_address is owned by .env xprv
|
||||
locking_amount: 90000,
|
||||
locking_amount_sat: 90000,
|
||||
bond_address: "tb1pfdvgfzwp8vhmelpv8w9kezz7nsmxw68jz6yehgze6mzx0t6r9t2qv9ynmm"
|
||||
.to_string(),
|
||||
};
|
||||
|
||||
let bond = Bond::assemble(trading_wallet, &offer_conditions, maker_config)?;
|
||||
|
||||
let payout_pubkey = trading_wallet.get_address(bdk::wallet::AddressIndex::LastUnused)?;
|
||||
|
||||
let musig_data = MuSigData::create(&maker_config.wallet_xprv, trading_wallet.secp_ctx())?;
|
||||
|
||||
Ok(ActiveOffer {})
|
||||
|
@ -44,7 +44,7 @@ impl Bond {
|
||||
));
|
||||
|
||||
builder
|
||||
.add_recipient(address.script_pubkey(), bond_target.locking_amount)
|
||||
.add_recipient(address.script_pubkey(), bond_target.locking_amount_sat)
|
||||
.do_not_spend_change()
|
||||
.fee_rate(FeeRate::from_sat_per_vb(201.0));
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
ELECTRUM_ENDPOINT="ssl://mempool.space:40002" # testnet 4 electrum server
|
||||
COORDINATOR_ENDPOINT="http://127.0.0.1:3000"
|
||||
ROBOHASH_BASE91="n!DyWmzXG3"1"*$S(GH<r+!G/!!u^aFTe%!x(iee}R[+vv+S4t^a<mAk!I{ybCQiD2%Idj>G4RB2gvM" # "base91 of hex of sha256 of robot22"
|
||||
ROBOHASH_HEX="169b6049cf865eba7d01e1ad26975f1d5ff29d570297ff18d40a53c8281dff5d" # sha256 of "robot22"
|
||||
TRADE_TYPE="sell"
|
||||
PAYOUT_ADDRESS="tb1p37qg73t5y0l4un3q5dknzl8fgfhemghaap67wns45pzgrw2tasrq6kesxm"
|
||||
BOND_RATIO=5
|
||||
XPRV="tprv8ZgxMBicQKsPdHuCSjhQuSZP1h6ZTeiRqREYS5guGPdtL7D1uNLpnJmb2oJep99Esq1NbNZKVJBNnD2ZhuXSK7G5eFmmcx73gsoa65e2U32" # wallet xprv
|
||||
OFFER_DURATION_HOURS=48
|
||||
|
Reference in New Issue
Block a user