-
-
Save al-f4lc0n/bedd32697390069be3efac1c906096a4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use bitcoin::{ absolute, transaction::Version, Address, Amount, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut }; | |
| use bitcoin::consensus::encode::serialize_hex; | |
| use bitcoincore_rpc::{json, Client as BitcoinClient, RpcApi as _}; | |
| use clarity::types::{chainstate::StacksAddress, Address as _}; | |
| use clarity::vm::types::{PrincipalData, StandardPrincipalData}; | |
| use emily_client::apis::configuration::{ApiKey, Configuration}; | |
| use emily_client::apis::deposit_api; | |
| use emily_client::models::CreateDepositRequestBody; | |
| use sbtc::deposits::{DepositScriptInputs, ReclaimScriptInputs}; | |
| use signer::config::Settings; | |
| use signer::keys::PublicKey; | |
| use signer::stacks::api::{StacksClient, StacksInteract}; | |
| use std::str::FromStr; | |
| /* secret key: | |
| spawn knee orchard patrol merge forget dust position daring short bridge elevator attitude leopard opera appear auction limit magic hover tunnel museum quantum manual | |
| */ | |
| const TEST_AUDITOR_STACKS_ADDR: &str = "ST2BEV097EV2R9ZMFRMRT904QB5RFYMA0683TC111"; | |
| const TEST_CONFIG_PATH: &str = "signer/src/config/default.toml"; | |
| const TEST_DEPLOYER_STACKS_ADDR: &str = "SN3R84XZYA63QS28932XQF3G1J8R9PC3W76P9CSQS"; | |
| const TEST_DEPOSIT_LOCK_TIME: u32 = 10; | |
| const TEST_BTC_MINER_ADDRESS: &str = "miEJtNKa3ASpA19v5ZhvbKTEieYjLpzCYT"; | |
| #[tokio::main] | |
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | |
| println!("┏ xxxx"); | |
| many_deposits_in_one_btc_tx( | |
| 100, // number_of_deposits | |
| 1000000, // per_deposit_amount | |
| 100000, // per_deposit_max_fee | |
| 100000, // btc_tx_fee | |
| ).await?; | |
| println!("┗ end"); | |
| Ok(()) | |
| } | |
| fn get_emily_client_config() -> Result<Configuration, Box<dyn std::error::Error>> { | |
| let settings = Settings::new(Some(TEST_CONFIG_PATH))?; | |
| let emily_api_endpoint = settings.emily.endpoints.first().unwrap().clone(); | |
| Ok(Configuration { | |
| base_path: emily_api_endpoint.to_string().trim_end_matches("/").to_string(), | |
| api_key: Some(ApiKey { | |
| prefix: None, | |
| key: emily_api_endpoint.username().to_string(), | |
| }), | |
| ..Default::default() | |
| }) | |
| } | |
| fn get_stacks_client() -> Result<StacksClient, Box<dyn std::error::Error>> { | |
| let settings = Settings::new(Some(TEST_CONFIG_PATH))?; | |
| let url = settings | |
| .stacks | |
| .endpoints | |
| .first() | |
| .expect("No Stacks endpoints configured"); | |
| Ok(StacksClient::new(url.clone()).expect("Failed to create Stacks client")) | |
| } | |
| fn get_btc_client() -> Result<BitcoinClient, Box<dyn std::error::Error>> { | |
| let settings = Settings::new(Some(TEST_CONFIG_PATH))?; | |
| let bitcoin_url = format!( | |
| "{}wallet/depositor", | |
| settings | |
| .bitcoin | |
| .rpc_endpoints | |
| .first() | |
| .expect("No Bitcoin RPC endpoints configured") | |
| ); | |
| let btc_client = BitcoinClient::new( | |
| &bitcoin_url, | |
| bitcoincore_rpc::Auth::UserPass("devnet".into(), "devnet".into()), | |
| ).expect("Failed to create Bitcoin RPC client"); | |
| Ok(btc_client) | |
| } | |
| async fn get_current_aggregate_key() -> Result<PublicKey, Box<dyn std::error::Error>> { | |
| let stacks_client = get_stacks_client()?; | |
| let deployer = PrincipalData::parse_standard_principal(&TEST_DEPLOYER_STACKS_ADDR) | |
| .map(StacksAddress::from)?; | |
| match stacks_client.get_current_signers_aggregate_key(&deployer).await? { | |
| Some(aggregate_key) => Ok(aggregate_key), | |
| _ => Err(Box::from("no aggregate key")), | |
| } | |
| } | |
| async fn many_deposits_in_one_btc_tx( | |
| number_of_deposits: u64, | |
| per_deposit_amount: u64, | |
| per_deposit_max_fee: u64, | |
| btc_tx_fee: u64, | |
| ) -> Result<(), Box<dyn std::error::Error>> { | |
| let aggregate_key = get_current_aggregate_key().await?; | |
| let deposit_script = DepositScriptInputs { | |
| signers_public_key: aggregate_key.into(), | |
| max_fee: per_deposit_max_fee, | |
| recipient: PrincipalData::Standard(StandardPrincipalData::from( | |
| StacksAddress::from_string(TEST_AUDITOR_STACKS_ADDR).unwrap(), | |
| )), | |
| }; | |
| let reclaim_script = ReclaimScriptInputs::try_new( | |
| TEST_DEPOSIT_LOCK_TIME, | |
| ScriptBuf::from_bytes(vec![]) | |
| )?; | |
| let btc_client = get_btc_client()?; | |
| let total_spend = Amount::from_sat(number_of_deposits * per_deposit_amount + btc_tx_fee); | |
| let opts = json::ListUnspentQueryOptions { | |
| minimum_amount: Some(total_spend), | |
| ..Default::default() | |
| }; | |
| let unspent = btc_client | |
| .list_unspent(Some(1), None, None, None, Some(opts))? | |
| .into_iter() | |
| .next() | |
| .unwrap(); | |
| let mut unsigned_tx = Transaction { | |
| input: vec![TxIn { | |
| previous_output: OutPoint { | |
| txid: unspent.txid, | |
| vout: unspent.vout, | |
| }, | |
| script_sig: Default::default(), | |
| sequence: Sequence::ZERO, | |
| witness: Default::default(), | |
| }], | |
| output: vec![ | |
| TxOut { | |
| value: unspent.amount - total_spend, | |
| script_pubkey: unspent.script_pub_key, | |
| }, | |
| ], | |
| version: Version::TWO, | |
| lock_time: absolute::LockTime::ZERO, | |
| }; | |
| for _ in 0..number_of_deposits { | |
| unsigned_tx.output.push(TxOut { | |
| value: Amount::from_sat(per_deposit_amount), | |
| script_pubkey: sbtc::deposits::to_script_pubkey( | |
| deposit_script.deposit_script(), | |
| reclaim_script.reclaim_script(), | |
| ), | |
| },); | |
| } | |
| let signed_tx = btc_client.sign_raw_transaction_with_wallet(&unsigned_tx, None, None)?; | |
| let txid = btc_client.send_raw_transaction(&signed_tx.hex)?; | |
| println!("┃ btc tx sent: {:?}", txid); | |
| let emily_client_config = get_emily_client_config()?; | |
| for i in 0..number_of_deposits { | |
| deposit_api::create_deposit( | |
| &emily_client_config, | |
| CreateDepositRequestBody { | |
| bitcoin_tx_output_index: i as u32 + 1, | |
| bitcoin_txid: txid.to_string(), | |
| deposit_script: deposit_script.deposit_script().to_hex_string(), | |
| reclaim_script: reclaim_script.reclaim_script().to_hex_string(), | |
| transaction_hex: serialize_hex(&unsigned_tx), | |
| }, | |
| ).await?; | |
| println!("┃ deposit[{:?}] request created", i + 1); | |
| } | |
| Ok(()) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment