diff --git a/src/bin/cashierd.rs b/src/bin/cashierd.rs index d46e1c5b3..85bfeb770 100644 --- a/src/bin/cashierd.rs +++ b/src/bin/cashierd.rs @@ -90,7 +90,8 @@ impl Cashierd { expand_path(&config.spend_params_path.clone())?, ), client_wallet.clone(), - ).await?; + ) + .await?; let client = Arc::new(Mutex::new(client)); @@ -119,14 +120,19 @@ impl Cashierd { for (network, _) in features.iter() { let keypairs_to_watch = cashier_wallet.get_deposit_token_keys_by_network(&network)?; - for keypair in keypairs_to_watch { + for (private_key, public_key, _token_id, mint_address) in keypairs_to_watch { let bridge = bridge.clone(); - let bridge_subscribtion = bridge.subscribe().await; + + let bridge_subscribtion = bridge.subscribe(Some(mint_address)).await; + bridge_subscribtion .sender .send(bridge::BridgeRequests { network: network.clone(), - payload: bridge::BridgeRequestsPayload::Watch(Some((keypair.0, keypair.1))), + payload: bridge::BridgeRequestsPayload::Watch(Some(( + private_key, + public_key, + ))), }) .await?; } @@ -139,20 +145,21 @@ impl Cashierd { cashier_wallet: Arc, recv_coin: async_channel::Receiver<(jubjub::SubgroupPoint, u64)>, ) -> Result<()> { - let bridge_subscribtion = bridge.subscribe().await; - // received drk coin let (drk_pub_key, amount) = recv_coin.recv().await?; debug!(target: "CASHIER DAEMON", "Receive coin with following address and amount: {}, {}" , drk_pub_key, amount); - // get public key, and asset_id of the token + // get public key, and token_id of the token let token = cashier_wallet.get_withdraw_token_public_key_by_dkey_public(&drk_pub_key)?; // send a request to bridge to send equivalent amount of // received drk coin to token publickey - if let Some((addr, network, _asset_id)) = token { + if let Some((addr, network, _token_id, mint_address)) = token { + + let bridge_subscribtion = bridge.subscribe(Some(mint_address)).await; + bridge_subscribtion .sender .send(bridge::BridgeRequests { @@ -191,7 +198,7 @@ impl Cashierd { } let network = NetworkName::from_str(args[0].as_str().unwrap()).unwrap(); - let token_id = &args[1].as_str().unwrap(); + let mut mint_address: String = args[1].as_str().unwrap().to_string(); let drk_pub_key = &args[2].as_str().unwrap(); if !self.features.contains_key(&network.clone()) { @@ -203,9 +210,13 @@ impl Cashierd { } let result: Result = async { - Self::check_token_id(&network, token_id)?; + let token_id = generate_id(&mint_address)?; - let asset_id = generate_id(token_id)?; + let mint_address_opt = Self::check_token_id(&network, &mint_address)?; + + if mint_address_opt.is_none() { + mint_address = String::new(); + } let drk_pub_key = bs58::decode(&drk_pub_key).into_vec()?; let drk_pub_key: jubjub::SubgroupPoint = deserialize(&drk_pub_key)?; @@ -216,7 +227,7 @@ impl Cashierd { .get_deposit_token_keys_by_dkey_public(&drk_pub_key, &network)?; let bridge = self.bridge.clone(); - let bridge_subscribtion = bridge.subscribe().await; + let bridge_subscribtion = bridge.subscribe(mint_address_opt).await; if check.is_empty() { bridge_subscribtion @@ -253,7 +264,8 @@ impl Cashierd { &token_priv, &serialize(&token_pub), &network, - &asset_id, + &token_id, + &mint_address, )?; return Ok(token_pub); @@ -284,7 +296,7 @@ impl Cashierd { } let network = NetworkName::from_str(args[0].as_str().unwrap()).unwrap(); - let token = &args[1].as_str().unwrap(); + let mut mint_address: String = args[1].as_str().unwrap().to_string(); let address = &args[2].as_str().unwrap(); let _amount = &args[3]; @@ -297,9 +309,15 @@ impl Cashierd { } let result: Result = async { - Self::check_token_id(&network, token)?; + let token_id = generate_id(&mint_address)?; + + let mint_address_opt = Self::check_token_id(&network, &mint_address)?; + + if mint_address_opt.is_none() { + // empty string + mint_address = String::new(); + } - let asset_id = generate_id(&token)?; let address = serialize(&address.to_string()); let cashier_public: jubjub::SubgroupPoint; @@ -319,7 +337,8 @@ impl Cashierd { &cashier_public, &cashier_secret, &network, - &asset_id, + &token_id, + &mint_address, )?; } @@ -345,37 +364,21 @@ impl Cashierd { )) } - fn check_token_id(network: &NetworkName, token_id: &str) -> Result<()> { + fn check_token_id(network: &NetworkName, token_id: &str) -> Result> { match network { #[cfg(feature = "sol")] NetworkName::Solana => { if token_id != "So11111111111111111111111111111111111111112" { - // This is supposed to be a token mint account now - use drk::service::sol::account_is_initialized_mint; - use drk::service::sol::SolFailed::BadSolAddress; - use solana_client::rpc_client::RpcClient; - use solana_sdk::pubkey::Pubkey; - - let pubkey = match Pubkey::from_str(token_id) { - Ok(v) => v, - Err(e) => return Err(Error::from(BadSolAddress(e.to_string()))), - }; - - // FIXME: Use network name from variable - let rpc = RpcClient::new("https://api.devnet.solana.com".to_string()); - if !account_is_initialized_mint(&rpc, &pubkey) { - return Err(Error::CashierInvalidTokenId( - "Given address is not a valid token mint".into(), - )); - } + return Ok(Some(token_id.to_string())); } + return Ok(None); } #[cfg(feature = "btc")] NetworkName::Bitcoin => { // Handle bitcoin address here if needed + Ok(None) } } - Ok(()) } async fn start(&self, executor: Arc>) -> Result<()> { diff --git a/src/bin/sol-test.rs b/src/bin/sol-test.rs index 13c0af29c..8b624b924 100644 --- a/src/bin/sol-test.rs +++ b/src/bin/sol-test.rs @@ -32,7 +32,7 @@ async fn run() -> Result<()> { .await?; let bridge2 = bridge.clone(); - let bridge_subscribtion = bridge2.subscribe().await; + let bridge_subscribtion = bridge2.subscribe(None).await; bridge_subscribtion .sender @@ -51,7 +51,7 @@ async fn run() -> Result<()> { _ => {} } - let bridge_subscribtion = bridge.subscribe().await; + let bridge_subscribtion = bridge.subscribe(None).await; bridge_subscribtion .sender diff --git a/src/service/bridge.rs b/src/service/bridge.rs index 50ec11dd8..d545807c9 100644 --- a/src/service/bridge.rs +++ b/src/service/bridge.rs @@ -93,12 +93,12 @@ impl Bridge { .map(|o| o.map_err(Error::from)) } - pub async fn subscribe(self: Arc) -> BridgeSubscribtion { + pub async fn subscribe(self: Arc, mint: Option) -> BridgeSubscribtion { debug!(target: "BRIDGE", "Start new subscription"); let (sender, req) = async_channel::unbounded(); let (rep, receiver) = async_channel::unbounded(); - smol::spawn(self.listen_for_new_subscription(req, rep)).detach(); + smol::spawn(self.listen_for_new_subscription(req, rep, mint)).detach(); BridgeSubscribtion { sender, receiver } } @@ -107,6 +107,7 @@ impl Bridge { self: Arc, req: async_channel::Receiver, rep: async_channel::Sender, + mint: Option, ) -> Result<()> { debug!(target: "BRIDGE", "Listen for new subscription"); let req = req.recv().await?; @@ -122,6 +123,14 @@ impl Bridge { return Ok(()); } + let mut mint_address: Option = mint.clone(); + + if mint.is_some() { + if mint.unwrap().is_empty() { + mint_address = None; + } + } + let client: Arc; // avoid deadlock { @@ -133,7 +142,7 @@ impl Bridge { BridgeRequestsPayload::Watch(val) => match val { Some((private_key, public_key)) => { let pub_key = client - .subscribe_with_keypair(private_key, public_key) + .subscribe_with_keypair(private_key, public_key, mint_address) .await?; let res = BridgeResponse { error: BridgeResponseError::NoError, @@ -142,7 +151,7 @@ impl Bridge { rep.send(res).await?; } None => { - let sub = client.subscribe().await?; + let sub = client.subscribe(mint_address).await?; let res = BridgeResponse { error: BridgeResponseError::NoError, payload: BridgeResponsePayload::Watch(sub.secret_key, sub.public_key), @@ -166,13 +175,14 @@ impl Bridge { #[async_trait] pub trait NetworkClient { - async fn subscribe(self: Arc) -> Result; + async fn subscribe(self: Arc, mint: Option) -> Result; // should check if the keypair in not already subscribed async fn subscribe_with_keypair( self: Arc, private_key: Vec, public_key: Vec, + mint: Option, ) -> Result; async fn get_notifier(self: Arc) -> Result>; diff --git a/src/service/btc.rs b/src/service/btc.rs index 31b17434a..5431200c3 100644 --- a/src/service/btc.rs +++ b/src/service/btc.rs @@ -149,7 +149,7 @@ impl BtcClient { #[async_trait] impl NetworkClient for BtcClient { - async fn subscribe(self: Arc) -> Result { + async fn subscribe(self: Arc, _mint: Option) -> Result { // Generate bitcoin keys let btc_keys = BitcoinKeys::new(self.network)?; let btc_privkey = btc_keys.clone(); @@ -174,6 +174,7 @@ impl NetworkClient for BtcClient { self: Arc, _private_key: Vec, _public_key: Vec, + _mint: Option, ) -> Result { // TODO this not implemented yet Ok(String::new()) diff --git a/src/service/sol.rs b/src/service/sol.rs index 782db14dd..abc574cb7 100644 --- a/src/service/sol.rs +++ b/src/service/sol.rs @@ -223,10 +223,6 @@ impl SolClient { debug!(target: "SOL BRIDGE", "Sending {} {:?} tokens to main wallet", amount / u64::pow(10, decimals as u32), mint); - if !account_is_initialized_mint(rpc, mint) { - return Err(SolFailed::MintIsNotValid(mint.to_string())); - } - // The token account from our main wallet let main_tok_pk = get_associated_token_address(&self.main_keypair.pubkey(), mint); // The token account from the deposit wallet @@ -302,27 +298,46 @@ impl SolClient { ) -> SolResult { debug!(target: "SOL BRIDGE", "Sending {} SOL to main wallet", lamports_to_sol(amount)); - let ix = system_instruction::transfer(&keypair.pubkey(), &self.main_keypair.pubkey(), amount); + let ix = + system_instruction::transfer(&keypair.pubkey(), &self.main_keypair.pubkey(), amount); let tx = Transaction::new_with_payer(&[ix], Some(&self.main_keypair.pubkey())); let signature = sign_and_send_transaction(&rpc, tx, vec![&self.main_keypair, keypair])?; debug!(target: "SOL BRIDGE", "Sent SOL to main wallet: {}", signature); Ok(signature) } + + fn check_mint_address(&self, mint_address: Option) -> SolResult> { + if let Some(mint_addr) = mint_address { + let pubkey = match Pubkey::from_str(&mint_addr) { + Ok(v) => v, + Err(e) => return Err(SolFailed::BadSolAddress(e.to_string())), + }; + + let rpc = RpcClient::new(self.rpc_server.to_string()); + + if !account_is_initialized_mint(&rpc, &pubkey) { + return Err(SolFailed::MintIsNotValid(mint_addr.to_string())); + } + + return Ok(Some(pubkey)); + } else { + return Ok(None); + } + } } #[async_trait] impl NetworkClient for SolClient { - async fn subscribe(self: Arc) -> Result { + async fn subscribe(self: Arc, mint_address: Option) -> Result { let keypair = Keypair::generate(&mut OsRng); let public_key = keypair.pubkey().to_string(); let secret_key = serialize(&keypair); - // TODO: Option for 2nd arg representing Token Mint account - let mint = Pubkey::from_str("F4wkXLN5n1ckejfnJoahGpgW3ffRsrvS9GGVME6ckxS9").unwrap(); - smol::spawn(self.handle_subscribe_request(keypair, Some(mint))).detach(); - //smol::spawn(self.handle_subscribe_request(keypair, None)).detach(); + let mint = self.check_mint_address(mint_address)?; + + smol::spawn(self.handle_subscribe_request(keypair, mint)).detach(); Ok(TokenSubscribtion { secret_key, @@ -335,15 +350,15 @@ impl NetworkClient for SolClient { self: Arc, private_key: Vec, _public_key: Vec, + mint_address: Option, ) -> Result { let keypair: Keypair = deserialize(&private_key)?; let public_key = keypair.pubkey().to_string(); - // TODO: Option for 2nd arg representing Token Mint account - let mint = Pubkey::from_str("F4wkXLN5n1ckejfnJoahGpgW3ffRsrvS9GGVME6ckxS9").unwrap(); - smol::spawn(self.handle_subscribe_request(keypair, Some(mint))).detach(); - //smol::spawn(self.handle_subscribe_request(keypair, None)).detach(); + let mint = self.check_mint_address(mint_address)?; + + smol::spawn(self.handle_subscribe_request(keypair, mint)).detach(); Ok(public_key) } @@ -355,7 +370,8 @@ impl NetworkClient for SolClient { async fn send(self: Arc, address: Vec, amount: u64) -> Result<()> { let rpc = RpcClient::new(self.rpc_server.to_string()); let address: Pubkey = deserialize(&address)?; - let instruction = system_instruction::transfer(&self.main_keypair.pubkey(), &address, amount); + let instruction = + system_instruction::transfer(&self.main_keypair.pubkey(), &address, amount); let mut tx = Transaction::new_with_payer(&[instruction], Some(&self.main_keypair.pubkey())); let bhq = BlockhashQuery::default();