hypercall_signer/
exchange.rs1use alloy::{
2 primitives::{Address, U256},
3 providers::DynProvider,
4 sol,
5};
6use hypercall_db::NonceWriter;
7use hypercall_types::WalletAddress;
8
9use crate::RsmSignerError;
10
11sol! {
12 #[sol(rpc)]
13 contract Exchange {
14 function isNonceUsed(address signer, uint256 nonce) external view returns (bool);
15 }
16}
17
18pub async fn repair_nonce_tracker_for_signer(
25 db: &dyn NonceWriter,
26 provider: &DynProvider,
27 exchange_address: Address,
28 signer_address: WalletAddress,
29) -> Result<(), RsmSignerError> {
30 let saved = db
31 .get_rsm_signer_nonce(&signer_address)
32 .await
33 .map_err(|error| {
34 RsmSignerError::PersistenceFailed(format!(
35 "failed to load RSM signer nonce tracker: {}",
36 error
37 ))
38 })?;
39 let mut next_nonce = match saved {
40 Some(record) => u64::try_from(record.next_nonce).map_err(|_| {
41 RsmSignerError::PersistenceFailed(format!(
42 "persisted next_nonce {} for signer {} is negative",
43 record.next_nonce, signer_address
44 ))
45 })?,
46 None => 0,
47 };
48
49 let exchange = Exchange::new(exchange_address, provider);
50 while exchange
51 .isNonceUsed(signer_address.inner(), U256::from(next_nonce))
52 .call()
53 .await
54 .map_err(|error| {
55 RsmSignerError::SigningFailed(format!(
56 "failed to query Exchange.isNonceUsed({}, {}): {}",
57 signer_address, next_nonce, error
58 ))
59 })?
60 {
61 next_nonce = next_nonce.checked_add(1).ok_or_else(|| {
62 RsmSignerError::PersistenceFailed(
63 "RSM nonce overflow while repairing tracker".to_string(),
64 )
65 })?;
66 }
67
68 db.save_rsm_signer_nonce(&hypercall_db::RsmSignerNonceRecord {
69 signer_address,
70 next_nonce: i64::try_from(next_nonce).map_err(|_| {
71 RsmSignerError::PersistenceFailed(format!(
72 "next_nonce {} exceeds i64 range",
73 next_nonce
74 ))
75 })?,
76 last_synced_nonce: Some(i64::try_from(next_nonce).map_err(|_| {
77 RsmSignerError::PersistenceFailed(format!(
78 "next_nonce {} exceeds i64 range",
79 next_nonce
80 ))
81 })?),
82 created_at: None,
83 updated_at: None,
84 })
85 .await
86 .map_err(|error| {
87 RsmSignerError::PersistenceFailed(format!(
88 "failed to persist repaired RSM nonce tracker: {}",
89 error
90 ))
91 })?;
92
93 Ok(())
94}
95
96pub async fn is_nonce_used_for_signer(
100 provider: &DynProvider,
101 exchange_address: Address,
102 signer_address: WalletAddress,
103 nonce: u64,
104) -> Result<bool, RsmSignerError> {
105 let exchange = Exchange::new(exchange_address, provider);
106 exchange
107 .isNonceUsed(signer_address.inner(), U256::from(nonce))
108 .call()
109 .await
110 .map_err(|error| {
111 RsmSignerError::SigningFailed(format!("failed to check nonce on-chain: {}", error))
112 })
113}