strike_sdk/chain/
vault.rs1use alloy::primitives::{Address, Bytes, U256};
4use alloy::providers::DynProvider;
5use alloy::rpc::types::TransactionRequest;
6use alloy::sol_types::SolCall;
7use std::sync::Arc;
8use tokio::sync::Mutex;
9use tracing::info;
10
11use crate::chain::send_tx;
12use crate::config::StrikeConfig;
13use crate::contracts::MockUSDT;
14use crate::error::{Result, StrikeError};
15use crate::nonce::NonceSender;
16
17pub struct VaultClient<'a> {
19 provider: &'a DynProvider,
20 signer_addr: Option<Address>,
21 config: &'a StrikeConfig,
22 nonce_sender: Option<Arc<Mutex<NonceSender>>>,
23}
24
25impl<'a> VaultClient<'a> {
26 pub(crate) fn new(
27 provider: &'a DynProvider,
28 signer_addr: Option<Address>,
29 config: &'a StrikeConfig,
30 nonce_sender: Option<Arc<Mutex<NonceSender>>>,
31 ) -> Self {
32 Self {
33 provider,
34 signer_addr,
35 config,
36 nonce_sender,
37 }
38 }
39
40 fn require_wallet(&self) -> Result<Address> {
41 self.signer_addr.ok_or(StrikeError::NoWallet)
42 }
43
44 pub async fn approve_usdt(&self) -> Result<()> {
48 let signer = self.require_wallet()?;
49 let usdt = MockUSDT::new(self.config.addresses.usdt, self.provider);
50 let vault = self.config.addresses.vault;
51
52 if let Ok(current) = usdt.allowance(signer, vault).call().await {
53 if current >= (U256::MAX >> 1) {
54 info!("vault already approved for USDT — skipping");
55 return Ok(());
56 }
57 }
58
59 info!("approving vault for max USDT spend...");
60
61 let calldata = MockUSDT::approveCall {
62 spender: vault,
63 value: U256::MAX,
64 }
65 .abi_encode();
66
67 let mut tx = TransactionRequest::default()
68 .to(self.config.addresses.usdt)
69 .input(Bytes::from(calldata).into());
70 tx.gas = Some(100_000);
71
72 let pending = send_tx(self.provider, &self.nonce_sender, tx).await?;
73 let receipt = pending
74 .get_receipt()
75 .await
76 .map_err(|e| StrikeError::Contract(e.to_string()))?;
77 info!(tx = %receipt.transaction_hash, "vault approved for USDT");
78 Ok(())
79 }
80
81 pub async fn usdt_balance(&self, address: Address) -> Result<U256> {
83 let usdt = MockUSDT::new(self.config.addresses.usdt, self.provider);
84 usdt.balanceOf(address)
85 .call()
86 .await
87 .map_err(|e| StrikeError::Contract(e.to_string()))
88 }
89
90 pub async fn usdt_allowance(&self, owner: Address) -> Result<U256> {
92 let usdt = MockUSDT::new(self.config.addresses.usdt, self.provider);
93 usdt.allowance(owner, self.config.addresses.vault)
94 .call()
95 .await
96 .map_err(|e| StrikeError::Contract(e.to_string()))
97 }
98}