Skip to content

Commit a0c2bc8

Browse files
feat: add get user balance cli command (#547)
1 parent 66c89a8 commit a0c2bc8

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

README_SEND_PROOFS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ This commands also allows the usage of the flags:
5252
- Note: `--amount` flag parameter must be with the shown format, followed by the `ether` keyword to specify how many ethers you wish to deposit to the batcher.
5353

5454
After depositing funds, you can verify the Service has correctly received them, executing the following command:
55+
5556
```bash
56-
cast call <payment_service_smart_contract_address> "UserBalances(address)(uint256)" <address>
57+
aligned get-user-balance --user_addr <user_addr>
5758
```
5859

5960
## 3. Send your proof to the batcher

batcher/aligned/src/main.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ use log::{error, info};
2020

2121
use aligned_sdk::sdk::{get_verification_key_commitment, submit_multiple, verify_proof_onchain};
2222

23+
use ethers::utils::format_ether;
2324
use ethers::utils::hex;
2425
use ethers::utils::parse_ether;
26+
use transaction::eip2718::TypedTransaction;
2527

2628
use crate::AlignedCommands::DepositToBatcher;
29+
use crate::AlignedCommands::GetUserBalance;
2730
use crate::AlignedCommands::GetVerificationKeyCommitment;
2831
use crate::AlignedCommands::Submit;
2932
use crate::AlignedCommands::VerifyProofOnchain;
@@ -54,6 +57,8 @@ pub enum AlignedCommands {
5457
name = "deposit-to-batcher"
5558
)]
5659
DepositToBatcher(DepositToBatcherArgs),
60+
#[clap(about = "Get user balance from the batcher", name = "get-user-balance")]
61+
GetUserBalance(GetUserBalanceArgs),
5762
}
5863

5964
#[derive(Parser, Debug)]
@@ -158,6 +163,29 @@ pub struct GetVerificationKeyCommitmentArgs {
158163
output_file: Option<PathBuf>,
159164
}
160165

166+
#[derive(Parser, Debug)]
167+
#[command(version, about, long_about = None)]
168+
pub struct GetUserBalanceArgs {
169+
#[arg(
170+
name = "Batcher Eth Address",
171+
long = "batcher_addr",
172+
default_value = "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0"
173+
)]
174+
batcher_eth_address: String,
175+
#[arg(
176+
name = "Ethereum RPC provider address",
177+
long = "rpc",
178+
default_value = "http://localhost:8545"
179+
)]
180+
eth_rpc_url: String,
181+
#[arg(
182+
name = "The user's Ethereum address",
183+
long = "user_addr",
184+
required = true
185+
)]
186+
user_address: String,
187+
}
188+
161189
#[derive(Debug, Clone, ValueEnum)]
162190
enum ChainArg {
163191
Devnet,
@@ -410,6 +438,35 @@ async fn main() -> Result<(), AlignedError> {
410438
error!("Transaction failed");
411439
}
412440
}
441+
GetUserBalance(get_user_balance_args) => {
442+
let eth_rpc_url = get_user_balance_args.eth_rpc_url;
443+
444+
let eth_rpc_provider = Provider::<Http>::try_from(eth_rpc_url).map_err(|e| {
445+
SubmitError::EthError(format!("Error while connecting to Ethereum: {}", e))
446+
})?;
447+
448+
let user_address =
449+
Address::from_str(&get_user_balance_args.user_address).map_err(|e| {
450+
SubmitError::EthError(format!("Error while parsing user address: {}", e))
451+
})?;
452+
453+
let batcher_addr = Address::from_str(&get_user_balance_args.batcher_eth_address)
454+
.map_err(|e| {
455+
SubmitError::EthError(format!("Error while parsing batcher address: {}", e))
456+
})?;
457+
458+
let balance = get_user_balance(eth_rpc_provider, batcher_addr, user_address)
459+
.await
460+
.map_err(|e| {
461+
SubmitError::EthError(format!("Error while getting user balance: {}", e))
462+
})?;
463+
464+
info!(
465+
"User {} has {} ether in the batcher",
466+
user_address,
467+
format_ether(balance)
468+
);
469+
}
413470
}
414471

415472
Ok(())
@@ -494,3 +551,33 @@ fn save_response(
494551

495552
Ok(())
496553
}
554+
555+
pub async fn get_user_balance(
556+
provider: Provider<Http>,
557+
contract_address: Address,
558+
user_address: Address,
559+
) -> Result<U256, ProviderError> {
560+
let selector = &ethers::utils::keccak256("UserBalances(address)".as_bytes())[..4];
561+
562+
let encoded_params = ethers::abi::encode(&[ethers::abi::Token::Address(user_address)]);
563+
564+
let mut call_data = selector.to_vec();
565+
call_data.extend_from_slice(&encoded_params);
566+
567+
let tx = TypedTransaction::Legacy(TransactionRequest {
568+
to: Some(NameOrAddress::Address(contract_address)),
569+
data: Some(Bytes(call_data.into())),
570+
..Default::default()
571+
});
572+
573+
let result = provider.call_raw(&tx).await?;
574+
575+
if result.len() == 32 {
576+
let balance = U256::from_big_endian(&result);
577+
Ok(balance)
578+
} else {
579+
Err(ProviderError::CustomError(
580+
"Invalid response from contract".to_string(),
581+
))
582+
}
583+
}

0 commit comments

Comments
 (0)