switch base91 to hex, add duration time

This commit is contained in:
Felix
2024-06-12 16:00:42 +00:00
parent 0ad4b5d761
commit f513d17454
10 changed files with 76 additions and 64 deletions

View File

@ -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;

View File

@ -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",

View File

@ -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"

View File

@ -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

View File

@ -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")?)?,
})
}

View File

@ -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.
}

View File

@ -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,
}
}

View File

@ -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 {})

View File

@ -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));

View File

@ -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